@alivault/pico 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/{index-BXfOqRXc.js → index-Cv9CWbsI.js} +9 -9
  3. package/.output/public/assets/routes-FmISceu0.js +2160 -0
  4. package/.output/public/assets/styles-DgbW000h.css +2 -0
  5. package/.output/server/_libs/@base-ui/react+[...].mjs +106 -1
  6. package/.output/server/_libs/@dnd-kit/core+[...].mjs +1 -1
  7. package/.output/server/_libs/@pierre/diffs+[...].mjs +36 -5
  8. package/.output/server/_libs/@pierre/trees+[...].mjs +1 -1
  9. package/.output/server/_libs/@radix-ui/react-dialog+[...].mjs +1 -1
  10. package/.output/server/_libs/@radix-ui/react-primitive+[...].mjs +1 -1
  11. package/.output/server/_libs/@tanstack/react-router+[...].mjs +1 -1
  12. package/.output/server/_libs/@tanstack/react-router-ssr-query+[...].mjs +1 -1
  13. package/.output/server/_libs/cmdk.mjs +1 -1
  14. package/.output/server/_libs/dnd-kit__accessibility.mjs +1 -1
  15. package/.output/server/_libs/dnd-kit__sortable.mjs +1 -1
  16. package/.output/server/_libs/hast-util-from-parse5+[...].mjs +1 -1
  17. package/.output/server/_libs/hast-util-raw+[...].mjs +1 -1
  18. package/.output/server/_libs/hast-util-to-jsx-runtime+[...].mjs +1 -1
  19. package/.output/server/_libs/lucide-react.mjs +78 -11
  20. package/.output/server/_libs/mdast-util-gfm+[...].mjs +1 -1
  21. package/.output/server/_libs/next-themes.mjs +1 -1
  22. package/.output/server/_libs/radix-ui__react-compose-refs.mjs +1 -1
  23. package/.output/server/_libs/radix-ui__react-context.mjs +1 -1
  24. package/.output/server/_libs/react-markdown+[...].mjs +1 -1
  25. package/.output/server/_libs/sonner.mjs +1 -1
  26. package/.output/server/_libs/tanstack__react-hotkeys.mjs +1 -1
  27. package/.output/server/_libs/tanstack__react-query.mjs +1 -1
  28. package/.output/server/_libs/tanstack__react-store.mjs +1 -1
  29. package/.output/server/_libs/vaul.mjs +1 -1
  30. package/.output/server/_ssr/{router-DIdiRf-y.mjs → router-BfWi4RfZ.mjs} +976 -374
  31. package/.output/server/_ssr/{routes-7x8dHcec.mjs → routes-CSvcOSyF.mjs} +5535 -2345
  32. package/.output/server/_ssr/{routes-bPw2DezY.mjs → routes-D6yf6dMU.mjs} +46 -32
  33. package/.output/server/_ssr/ssr.mjs +3 -3
  34. package/.output/server/{_tanstack-start-manifest_v-CMhyz9t-.mjs → _tanstack-start-manifest_v-Am6Tm4xr.mjs} +9 -4
  35. package/.output/server/index.mjs +533 -533
  36. package/package.json +1 -1
  37. package/.output/public/assets/routes-CnNf4Tfg.js +0 -2160
  38. package/.output/public/assets/styles-DueiniTy.css +0 -2
@@ -1,8 +1,8 @@
1
1
  import { i as __toESM } from "../_runtime.mjs";
2
- import { X as require_react, Y as require_jsx_runtime } from "../_libs/@base-ui/react+[...].mjs";
2
+ import { $ as require_react, Q as require_jsx_runtime } from "../_libs/@base-ui/react+[...].mjs";
3
3
  import { a as createRouter, c as createRootRoute, n as Scripts, r as HeadContent, s as createFileRoute } from "../_libs/@tanstack/react-router+[...].mjs";
4
- import { a as TriangleAlert, g as OctagonX, j as CircleCheck, y as Info } from "../_libs/lucide-react.mjs";
5
- import { B as extractMessageText$1, I as createCompactionSummaryItem, N as assistantBlocksFromMessage, P as buildItemsFromSync, V as extractToolText, W as mergeAssistantBlocksForStreaming, _ as Route$49, bt as toolCategoryFromTool, k as TooltipProvider, n as APPLIED_THEME_STORAGE_KEY, t as APPLIED_THEME_CLASSES, x as Spinner, z as extractMessageImages } from "./routes-bPw2DezY.mjs";
4
+ import { F as CircleCheck, S as Info, _ as OctagonX, a as TriangleAlert } from "../_libs/lucide-react.mjs";
5
+ import { A as TooltipProvider, B as extractMessageImages, F as buildItemsFromSync, G as mergeAssistantBlocksForStreaming, H as extractToolText, L as createCompactionSummaryItem, P as assistantBlocksFromMessage, S as Spinner, V as extractMessageText$1, n as APPLIED_THEME_STORAGE_KEY, t as APPLIED_THEME_CLASSES, v as Route$54, xt as toolCategoryFromTool } from "./routes-D6yf6dMU.mjs";
6
6
  import { t as QueryClient } from "../_libs/tanstack__query-core.mjs";
7
7
  import { t as setupRouterSsrQueryIntegration } from "../_libs/@tanstack/react-router-ssr-query+[...].mjs";
8
8
  import { n as HotkeysProvider } from "../_libs/tanstack__react-hotkeys.mjs";
@@ -20,7 +20,7 @@ import os, { homedir } from "node:os";
20
20
  import { performance } from "node:perf_hooks";
21
21
  import { isMainThread } from "node:worker_threads";
22
22
  import { execSync, spawn } from "node:child_process";
23
- //#region node_modules/.nitro/vite/services/ssr/assets/router-DIdiRf-y.js
23
+ //#region node_modules/.nitro/vite/services/ssr/assets/router-BfWi4RfZ.js
24
24
  var import_react = /* @__PURE__ */ __toESM(require_react());
25
25
  var import_jsx_runtime = require_jsx_runtime();
26
26
  var Toaster$1 = ({ ...props }) => {
@@ -71,7 +71,7 @@ function AppProviders({ children }) {
71
71
  })
72
72
  });
73
73
  }
74
- var styles_default = "/assets/styles-DueiniTy.css";
74
+ var styles_default = "/assets/styles-DgbW000h.css";
75
75
  var TANSTACK_DEVTOOLS_SETTINGS_KEY = "tanstack_devtools_settings";
76
76
  var TANSTACK_DEVTOOLS_DEFAULTS_STORAGE_KEY = "pico-tanstack-devtools-defaults-v1";
77
77
  var TANSTACK_DEVTOOLS_CONFIG = {
@@ -79,7 +79,7 @@ var TANSTACK_DEVTOOLS_CONFIG = {
79
79
  openHotkey: ["Control", "`"],
80
80
  triggerHidden: true
81
81
  };
82
- var Route$48 = createRootRoute({
82
+ var Route$53 = createRootRoute({
83
83
  head: () => ({
84
84
  meta: [
85
85
  { charSet: "utf-8" },
@@ -142,25 +142,30 @@ function RootDocument({ children }) {
142
142
  })]
143
143
  });
144
144
  }
145
+ function subscribeTanStackDevtoolsReady() {
146
+ return () => {};
147
+ }
148
+ function getTanStackDevtoolsReadySnapshot() {
149
+ try {
150
+ if (window.localStorage.getItem(TANSTACK_DEVTOOLS_DEFAULTS_STORAGE_KEY) !== "true") {
151
+ const rawSettings = window.localStorage.getItem(TANSTACK_DEVTOOLS_SETTINGS_KEY);
152
+ const parsedSettings = rawSettings ? JSON.parse(rawSettings) : void 0;
153
+ const existingSettings = parsedSettings && typeof parsedSettings === "object" && !Array.isArray(parsedSettings) ? parsedSettings : {};
154
+ window.localStorage.setItem(TANSTACK_DEVTOOLS_SETTINGS_KEY, JSON.stringify({
155
+ ...existingSettings,
156
+ openHotkey: TANSTACK_DEVTOOLS_CONFIG.openHotkey,
157
+ triggerHidden: TANSTACK_DEVTOOLS_CONFIG.triggerHidden
158
+ }));
159
+ window.localStorage.setItem(TANSTACK_DEVTOOLS_DEFAULTS_STORAGE_KEY, "true");
160
+ }
161
+ } catch {}
162
+ return true;
163
+ }
164
+ function getTanStackDevtoolsServerSnapshot() {
165
+ return false;
166
+ }
145
167
  function AppTanStackDevtools() {
146
- const [isReady, setIsReady] = import_react.useState(false);
147
- import_react.useEffect(() => {
148
- try {
149
- if (window.localStorage.getItem(TANSTACK_DEVTOOLS_DEFAULTS_STORAGE_KEY) !== "true") {
150
- const rawSettings = window.localStorage.getItem(TANSTACK_DEVTOOLS_SETTINGS_KEY);
151
- const parsedSettings = rawSettings ? JSON.parse(rawSettings) : void 0;
152
- const existingSettings = parsedSettings && typeof parsedSettings === "object" && !Array.isArray(parsedSettings) ? parsedSettings : {};
153
- window.localStorage.setItem(TANSTACK_DEVTOOLS_SETTINGS_KEY, JSON.stringify({
154
- ...existingSettings,
155
- openHotkey: TANSTACK_DEVTOOLS_CONFIG.openHotkey,
156
- triggerHidden: TANSTACK_DEVTOOLS_CONFIG.triggerHidden
157
- }));
158
- window.localStorage.setItem(TANSTACK_DEVTOOLS_DEFAULTS_STORAGE_KEY, "true");
159
- }
160
- } catch {}
161
- setIsReady(true);
162
- }, []);
163
- if (!isReady) return null;
168
+ if (!import_react.useSyncExternalStore(subscribeTanStackDevtoolsReady, getTanStackDevtoolsReadySnapshot, getTanStackDevtoolsServerSnapshot)) return null;
164
169
  }
165
170
  var PI_CODING_AGENT_PACKAGES = ["@earendil-works/pi-coding-agent", "@mariozechner/pi-coding-agent"];
166
171
  function normalizeSdkDir(candidate) {
@@ -455,7 +460,7 @@ async function generateSessionNameWithLlm(entry, text, imageCount) {
455
460
  headers: auth.headers,
456
461
  reasoningEffort: "minimal"
457
462
  });
458
- const raw = Array.isArray(response?.content) ? response.content.filter((block) => block?.type === "text" && typeof block.text === "string").map((block) => block.text).join(" ") : "";
463
+ const raw = Array.isArray(response?.content) ? response.content.flatMap((block) => block?.type === "text" && typeof block.text === "string" ? [block.text] : []).join(" ") : "";
459
464
  if (!raw.trim()) return { reason: `refinement model ${model.provider}/${model.id} returned no text` };
460
465
  const cleaned = cleanupSessionNameCandidate(raw);
461
466
  if (!cleaned) return { reason: `refinement model ${model.provider}/${model.id} returned no usable title` };
@@ -743,7 +748,14 @@ function updateToolBlock(state, callId, update) {
743
748
  for (let itemIndex = state.items.length - 1; itemIndex >= 0; itemIndex -= 1) {
744
749
  const item = state.items[itemIndex];
745
750
  if (item?.kind !== "assistant") continue;
746
- const blockIndex = item.blocks.findIndex((block) => block.type === "tool" && block.callId === callId);
751
+ let blockIndex = -1;
752
+ for (let index = item.blocks.length - 1; index >= 0; index -= 1) {
753
+ const block = item.blocks[index];
754
+ if (block?.type === "tool" && block.callId === callId) {
755
+ blockIndex = index;
756
+ break;
757
+ }
758
+ }
747
759
  if (blockIndex < 0) continue;
748
760
  const block = item.blocks[blockIndex];
749
761
  if (block?.type !== "tool") return;
@@ -936,7 +948,8 @@ function applyRetainedConversationEvent(state, event) {
936
948
  }];
937
949
  return;
938
950
  }
939
- state.items = state.items.filter((entry) => !(entry.kind === "assistant" && entry.streaming && entry.blocks.length === 0)).map((entry) => {
951
+ state.items = state.items.flatMap((entry) => {
952
+ if (entry.kind === "assistant" && entry.streaming && entry.blocks.length === 0) return [];
940
953
  if (entry.kind !== "assistant") return entry;
941
954
  if (!entry.streaming && entry.done !== false) return entry;
942
955
  return {
@@ -967,7 +980,7 @@ function extractSessionListMessageText(message) {
967
980
  const content = message.content;
968
981
  if (typeof content === "string") return content;
969
982
  if (!Array.isArray(content)) return "";
970
- return content.filter((part) => isRecord(part) && part.type === "text").map((part) => typeof part.text === "string" ? part.text : "").join("\n");
983
+ return content.flatMap((part) => isRecord(part) && part.type === "text" ? [typeof part.text === "string" ? part.text : ""] : []).join("\n");
971
984
  }
972
985
  function extractSessionListImagePreview(message) {
973
986
  const content = message.content;
@@ -1209,12 +1222,12 @@ function extractMessageText(message) {
1209
1222
  const content = message.content;
1210
1223
  if (typeof content === "string") return content.trim();
1211
1224
  if (!Array.isArray(content)) return "";
1212
- return content.filter((part) => part?.type === "text" && typeof part.text === "string").map((part) => part.text).join(" ").trim();
1225
+ return content.flatMap((part) => part?.type === "text" && typeof part.text === "string" ? [part.text] : []).join(" ").trim();
1213
1226
  }
1214
1227
  function extractSessionContentText(content) {
1215
1228
  if (typeof content === "string") return content.trim();
1216
1229
  if (!Array.isArray(content)) return "";
1217
- const text = content.filter((part) => Boolean(part) && typeof part === "object" && part.type === "text" && typeof part.text === "string").map((part) => part.text).join(" ").trim();
1230
+ const text = content.flatMap((part) => part && typeof part === "object" && part.type === "text" && typeof part.text === "string" ? [part.text] : []).join(" ").trim();
1218
1231
  if (text) return text;
1219
1232
  const imageCount = content.filter((part) => part && typeof part === "object" && (part.type === "image" || part.type === "input_image")).length;
1220
1233
  if (imageCount > 0) return `${imageCount} image${imageCount === 1 ? "" : "s"}`;
@@ -1318,15 +1331,22 @@ function serializeSessionTreeNode(node) {
1318
1331
  if (entry.type === "custom") serialized.entry.customType = typeof entry.customType === "string" ? entry.customType : "custom";
1319
1332
  if (entry.type === "label") serialized.entry.label = typeof entry.label === "string" ? entry.label : void 0;
1320
1333
  if (entry.type === "session_info") serialized.entry.name = typeof entry.name === "string" ? entry.name : "";
1321
- serialized.children = (Array.isArray(node.children) ? node.children : []).map((child) => serializeSessionTreeNode(child)).filter((child) => Boolean(child));
1334
+ serialized.children = (Array.isArray(node.children) ? node.children : []).flatMap((child) => {
1335
+ const treeNode = serializeSessionTreeNode(child);
1336
+ return treeNode ? [treeNode] : [];
1337
+ });
1322
1338
  return serialized;
1323
1339
  }
1324
1340
  function extractForkableUserMessages(entry) {
1325
1341
  const messages = entry.session.getUserMessagesForForking?.();
1326
- if (Array.isArray(messages) && messages.length > 0) return messages.map((message) => ({
1327
- entryId: typeof message.entryId === "string" ? message.entryId.trim() : "",
1328
- text: typeof message.text === "string" ? message.text.trim() : ""
1329
- })).filter((message) => Boolean(message.entryId && message.text));
1342
+ if (Array.isArray(messages) && messages.length > 0) return messages.flatMap((message) => {
1343
+ const entryId = typeof message.entryId === "string" ? message.entryId.trim() : "";
1344
+ const text = typeof message.text === "string" ? message.text.trim() : "";
1345
+ return entryId && text ? [{
1346
+ entryId,
1347
+ text
1348
+ }] : [];
1349
+ });
1330
1350
  const stack = [...entry.session.sessionManager.getTree?.() ?? []];
1331
1351
  const results = [];
1332
1352
  while (stack.length > 0) {
@@ -1351,7 +1371,7 @@ async function createForkedInMemorySessionManager(options) {
1351
1371
  if (!leafId) return nextManager;
1352
1372
  const branchEntries = sourceManager.getBranch?.(leafId);
1353
1373
  if (!Array.isArray(branchEntries) || branchEntries.length === 0) throw new Error(`Entry ${leafId} not found`);
1354
- const pathWithoutLabels = branchEntries.filter((branchEntry) => branchEntry?.type !== "label").map((branchEntry) => cloneSessionData(branchEntry));
1374
+ const pathWithoutLabels = branchEntries.flatMap((branchEntry) => branchEntry?.type !== "label" ? [cloneSessionData(branchEntry)] : []);
1355
1375
  const header = cloneSessionData(sourceManager.getHeader?.() ?? nextManager.fileEntries?.[0]);
1356
1376
  if (!header) throw new Error("Failed to initialize forked in-memory session.");
1357
1377
  nextManager.fileEntries = [header, ...pathWithoutLabels];
@@ -1471,6 +1491,9 @@ async function createPicoEditToolDefinition(sdk, cwd) {
1471
1491
  }
1472
1492
  };
1473
1493
  }
1494
+ function gitTextContains(text, query) {
1495
+ return text.indexOf(query) >= 0;
1496
+ }
1474
1497
  var GIT_STATUS_CACHE_TTL_MS = 5e3;
1475
1498
  var GIT_CHANGES_CACHE_TTL_MS = 5e3;
1476
1499
  var GIT_COMMITS_DEFAULT_LIMIT = 50;
@@ -1655,7 +1678,10 @@ function parseCommandNullList(output) {
1655
1678
  return output.split("\0").filter((entry) => typeof entry === "string" && entry.length > 0);
1656
1679
  }
1657
1680
  function parseCommandLines(output, { trim = false } = {}) {
1658
- return output.split(/\r?\n/).map((entry) => trim ? entry.trim() : entry).filter((entry) => Boolean(trim ? entry : entry.length));
1681
+ return output.split(/\r?\n/).flatMap((entry) => {
1682
+ const line = trim ? entry.trim() : entry;
1683
+ return trim ? line ? [line] : [] : line.length ? [line] : [];
1684
+ });
1659
1685
  }
1660
1686
  function isGitCommitGraphLine(line) {
1661
1687
  const tabIndex = line.indexOf(" ");
@@ -1711,7 +1737,10 @@ function enrichGitCommitGraphLinesWithStats(lines, statsByHash) {
1711
1737
  });
1712
1738
  }
1713
1739
  function gitCommandErrorMessage(fallback, result) {
1714
- const details = [result.stderr, result.stdout].map((value) => value.trim()).filter(Boolean).join("\n");
1740
+ const details = [result.stderr, result.stdout].flatMap((value) => {
1741
+ const detail = value.trim();
1742
+ return detail ? [detail] : [];
1743
+ }).join("\n");
1715
1744
  if (result.timedOut) return `${fallback}: command timed out`;
1716
1745
  if (details) return `${fallback}: ${details}`;
1717
1746
  return fallback;
@@ -1743,7 +1772,10 @@ function deriveHeuristicCommitMessage(files) {
1743
1772
  }
1744
1773
  if (addedCount > modifiedCount && addedCount >= deletedCount) return `Add ${files.length} files`;
1745
1774
  if (deletedCount > modifiedCount && deletedCount >= addedCount) return `Remove ${files.length} files`;
1746
- const commonDirectory = files.map((file) => file.path.split("/").slice(0, -1).join("/")).filter(Boolean).reduce((common, directory) => {
1775
+ const commonDirectory = files.flatMap((file) => {
1776
+ const directory = file.path.split("/").slice(0, -1).join("/");
1777
+ return directory ? [directory] : [];
1778
+ }).reduce((common, directory) => {
1747
1779
  if (common === void 0) return directory;
1748
1780
  return common === directory ? common : "";
1749
1781
  }, void 0);
@@ -1771,12 +1803,31 @@ function parseGitStatusEntries(output) {
1771
1803
  }
1772
1804
  return files;
1773
1805
  }
1806
+ function parseGitNameStatusEntries(output) {
1807
+ const entries = parseCommandNullList(output);
1808
+ const files = [];
1809
+ for (let index = 0; index < entries.length; index += 1) {
1810
+ const status = entries[index];
1811
+ if (typeof status !== "string" || !status) continue;
1812
+ const isRenamedOrCopied = status.startsWith("R") || status.startsWith("C");
1813
+ const previousPath = isRenamedOrCopied ? entries[index + 1] : void 0;
1814
+ const filePath = isRenamedOrCopied ? entries[index + 2] : entries[index + 1];
1815
+ index += isRenamedOrCopied ? 2 : 1;
1816
+ if (typeof filePath !== "string" || !filePath) continue;
1817
+ files.push({
1818
+ status: /^[RC]\d+/.test(status) ? status.slice(0, 1) : status,
1819
+ path: filePath,
1820
+ ...typeof previousPath === "string" && previousPath ? { previousPath } : {}
1821
+ });
1822
+ }
1823
+ return files;
1824
+ }
1774
1825
  function parseGitNumstatEntries(output) {
1775
1826
  const entries = parseCommandNullList(output);
1776
1827
  const diffs = /* @__PURE__ */ new Map();
1777
1828
  for (let index = 0; index < entries.length; index += 1) {
1778
1829
  const entry = entries[index];
1779
- if (typeof entry !== "string" || !entry.includes(" ")) continue;
1830
+ if (typeof entry !== "string" || !gitTextContains(entry, " ")) continue;
1780
1831
  const [addedRaw = "", deletedRaw = "", ...pathParts] = entry.split(" ");
1781
1832
  let filePath = pathParts.join(" ");
1782
1833
  let previousPath;
@@ -1797,7 +1848,10 @@ function parseGitNumstatEntries(output) {
1797
1848
  return diffs;
1798
1849
  }
1799
1850
  function parseGitRefRows(output) {
1800
- return parseCommandLines(output).map((line) => line.split("\0")).filter((fields) => fields.some((field) => typeof field === "string" && field.length > 0));
1851
+ return parseCommandLines(output).flatMap((line) => {
1852
+ const fields = line.split("\0");
1853
+ return fields.some((field) => typeof field === "string" && field.length > 0) ? [fields] : [];
1854
+ });
1801
1855
  }
1802
1856
  function parseGitBranchTrack(track, upstream) {
1803
1857
  const trackValue = typeof track === "string" ? track.trim() : "";
@@ -1852,12 +1906,28 @@ function assertGitFilePath(path) {
1852
1906
  if (normalizedPath.split(/[\\/]+/).some((part) => part === "..")) throw new Error("file path must stay inside the repository");
1853
1907
  return normalizedPath.replaceAll("\\", "/");
1854
1908
  }
1909
+ function assertGitCommitHash(commit) {
1910
+ const normalizedCommit = typeof commit === "string" ? commit.trim() : "";
1911
+ if (!normalizedCommit) throw new Error("commit is required");
1912
+ if (!/^[0-9a-f]{5,40}$/i.test(normalizedCommit)) throw new Error("commit must be a valid hash");
1913
+ return normalizedCommit;
1914
+ }
1915
+ function assertGitTagName(tagName) {
1916
+ const normalizedTagName = typeof tagName === "string" ? tagName.trim() : "";
1917
+ if (!normalizedTagName) throw new Error("tag name is required");
1918
+ if (normalizedTagName.startsWith("-") || /\s/.test(normalizedTagName)) throw new Error("Invalid tag name");
1919
+ return normalizedTagName;
1920
+ }
1921
+ function normalizeGitResetMode(mode) {
1922
+ if (mode === "soft" || mode === "mixed" || mode === "hard") return mode;
1923
+ throw new Error("reset mode must be soft, mixed, or hard");
1924
+ }
1855
1925
  function parseGitRemoteBranches(output) {
1856
1926
  const branches = [];
1857
1927
  for (const fields of parseGitRefRows(output)) {
1858
1928
  const [name = "", hash = "", subject = "", relativeDate = "", committerDate = ""] = fields;
1859
1929
  const branchName = typeof name === "string" ? name.trim() : "";
1860
- if (!branchName || !branchName.includes("/") || /\/HEAD$/i.test(branchName)) continue;
1930
+ if (!branchName || !gitTextContains(branchName, "/") || /\/HEAD$/i.test(branchName)) continue;
1861
1931
  branches.push({
1862
1932
  name: branchName,
1863
1933
  hash: typeof hash === "string" && hash.trim() ? hash.trim() : void 0,
@@ -2086,11 +2156,12 @@ async function readDirectoryGitFileReview(cwd, path, previousPath) {
2086
2156
  const normalizedPreviousPath = previousPath ? assertGitFilePath(previousPath) : void 0;
2087
2157
  if (!normalizedCwd) return null;
2088
2158
  if (!await isInsideWorkTree(normalizedCwd)) return null;
2159
+ const [oldContent, newContent] = await Promise.all([readGitHeadFileContent(normalizedCwd, normalizedPreviousPath || normalizedPath), readWorktreeFileContent(normalizedCwd, normalizedPath)]);
2089
2160
  return {
2090
2161
  path: normalizedPath,
2091
2162
  previousPath: normalizedPreviousPath,
2092
- oldContent: await readGitHeadFileContent(normalizedCwd, normalizedPreviousPath || normalizedPath),
2093
- newContent: await readWorktreeFileContent(normalizedCwd, normalizedPath)
2163
+ oldContent,
2164
+ newContent
2094
2165
  };
2095
2166
  }
2096
2167
  async function readDirectoryGitFileDiff(cwd, path) {
@@ -2409,14 +2480,20 @@ async function readUnpushedCommitMessages(cwd) {
2409
2480
  });
2410
2481
  return result.code === 0 ? parseCommandLines(result.stdout, { trim: true }).filter(Boolean) : [];
2411
2482
  }
2483
+ async function runGitPushCommand(cwd, context) {
2484
+ return await runCommand("git", context.force ? ["push", "--force-with-lease"] : ["push"], {
2485
+ cwd,
2486
+ timeoutMs: GIT_ACTION_TIMEOUT_MS
2487
+ });
2488
+ }
2412
2489
  async function pushDirectoryGitChanges(cwd, { force = false } = {}) {
2413
2490
  const normalizedCwd = normalizeGitCwd(cwd);
2414
2491
  if (!normalizedCwd) throw new Error("cwd is required");
2415
2492
  if (!await isInsideWorkTree(normalizedCwd)) throw new Error("No git repository detected");
2416
2493
  const pushedCommitMessages = await readUnpushedCommitMessages(normalizedCwd);
2417
- const result = await runCommand("git", force ? ["push", "--force-with-lease"] : ["push"], {
2418
- cwd: normalizedCwd,
2419
- timeoutMs: GIT_ACTION_TIMEOUT_MS
2494
+ const result = await runGitPushCommand(normalizedCwd, {
2495
+ force,
2496
+ pushedCommitMessages
2420
2497
  });
2421
2498
  if (result.code !== 0) throw new Error(gitCommandErrorMessage(force ? "Failed to force push changes" : "Failed to push changes", result));
2422
2499
  invalidateDirectoryGitCaches(normalizedCwd);
@@ -2467,6 +2544,294 @@ async function checkoutDirectoryGitBranch(cwd, branch, options = {}) {
2467
2544
  stderr: result.stderr
2468
2545
  };
2469
2546
  }
2547
+ function gitCommitActionLabel(action) {
2548
+ switch (action) {
2549
+ case "checkout": return "checkout commit";
2550
+ case "cherry-pick": return "cherry-pick commit";
2551
+ case "revert": return "revert commit";
2552
+ case "tag": return "tag commit";
2553
+ case "reset": return "reset branch";
2554
+ case "rebase": return "rebase branch";
2555
+ case "drop": return "drop commit";
2556
+ case "squash": return "squash commits";
2557
+ }
2558
+ }
2559
+ function remoteBaseUrlFromGitUrl(remoteUrl) {
2560
+ const trimmed = remoteUrl.trim();
2561
+ if (!trimmed) return "";
2562
+ const scpLikeMatch = trimmed.match(/^git@([^:]+):(.+)$/);
2563
+ if (scpLikeMatch) {
2564
+ const host = scpLikeMatch[1];
2565
+ const path = scpLikeMatch[2]?.replace(/\.git$/i, "");
2566
+ return host && path ? `https://${host}/${path}` : "";
2567
+ }
2568
+ try {
2569
+ const url = new URL(trimmed);
2570
+ if (url.protocol === "ssh:" && url.username === "git") return `https://${url.host}${url.pathname.replace(/\.git$/i, "")}`;
2571
+ if (url.protocol === "http:" || url.protocol === "https:") {
2572
+ url.username = "";
2573
+ url.password = "";
2574
+ url.pathname = url.pathname.replace(/\.git$/i, "");
2575
+ url.search = "";
2576
+ url.hash = "";
2577
+ return url.toString().replace(/\/$/, "");
2578
+ }
2579
+ } catch {}
2580
+ return "";
2581
+ }
2582
+ function commitUrlPathForHost(host, commit) {
2583
+ return host.toLowerCase().includes("gitlab") ? `/-/commit/${commit}` : `/commit/${commit}`;
2584
+ }
2585
+ async function readPrimaryRemoteName(cwd) {
2586
+ const branchResult = await runCommand("git", [
2587
+ "symbolic-ref",
2588
+ "--quiet",
2589
+ "--short",
2590
+ "HEAD"
2591
+ ], {
2592
+ cwd,
2593
+ timeoutMs: 1500
2594
+ });
2595
+ const branch = branchResult.code === 0 ? branchResult.stdout.trim() : "";
2596
+ if (branch) {
2597
+ const branchRemoteResult = await runCommand("git", [
2598
+ "config",
2599
+ "--get",
2600
+ `branch.${branch}.remote`
2601
+ ], {
2602
+ cwd,
2603
+ timeoutMs: 1500
2604
+ });
2605
+ const branchRemote = branchRemoteResult.stdout.trim();
2606
+ if (branchRemoteResult.code === 0 && branchRemote) return branchRemote;
2607
+ }
2608
+ const pushDefaultResult = await runCommand("git", [
2609
+ "config",
2610
+ "--get",
2611
+ "remote.pushDefault"
2612
+ ], {
2613
+ cwd,
2614
+ timeoutMs: 1500
2615
+ });
2616
+ const pushDefault = pushDefaultResult.stdout.trim();
2617
+ if (pushDefaultResult.code === 0 && pushDefault) return pushDefault;
2618
+ return "origin";
2619
+ }
2620
+ async function readDirectoryGitCommitFiles(cwd, commit) {
2621
+ const normalizedCwd = normalizeGitCwd(cwd);
2622
+ const normalizedCommit = assertGitCommitHash(commit);
2623
+ if (!normalizedCwd) return null;
2624
+ if (!await isInsideWorkTree(normalizedCwd)) return null;
2625
+ const [statusResult, numstatResult] = await Promise.all([runCommand("git", [
2626
+ "show",
2627
+ "--name-status",
2628
+ "-z",
2629
+ "--find-renames=50%",
2630
+ "--format=",
2631
+ normalizedCommit
2632
+ ], {
2633
+ cwd: normalizedCwd,
2634
+ timeoutMs: 1e4
2635
+ }), runCommand("git", [
2636
+ "show",
2637
+ "--numstat",
2638
+ "-z",
2639
+ "--find-renames=50%",
2640
+ "--format=",
2641
+ normalizedCommit
2642
+ ], {
2643
+ cwd: normalizedCwd,
2644
+ timeoutMs: 1e4
2645
+ })]);
2646
+ if (statusResult.code !== 0) throw new Error(gitCommandErrorMessage("Failed to read commit files", statusResult));
2647
+ if (numstatResult.code !== 0) throw new Error(gitCommandErrorMessage("Failed to read commit file stats", numstatResult));
2648
+ const stats = parseGitNumstatEntries(numstatResult.stdout);
2649
+ return parseGitNameStatusEntries(statusResult.stdout).map((file) => ({
2650
+ ...file,
2651
+ ...stats.get(file.path)
2652
+ }));
2653
+ }
2654
+ async function readDirectoryGitCommitDiff(cwd, commit, mode = "commit", path, previousPath) {
2655
+ const normalizedCwd = normalizeGitCwd(cwd);
2656
+ const normalizedCommit = assertGitCommitHash(commit);
2657
+ const normalizedPath = path ? assertGitFilePath(path) : void 0;
2658
+ const normalizedPreviousPath = previousPath ? assertGitFilePath(previousPath) : void 0;
2659
+ if (!normalizedCwd) return null;
2660
+ if (!await isInsideWorkTree(normalizedCwd)) return null;
2661
+ const pathArgs = normalizedPath ? ["--", ...uniqueGitActionPaths([normalizedPreviousPath, normalizedPath])] : [];
2662
+ const result = await runCommand("git", mode === "head" ? [
2663
+ "diff",
2664
+ "--patch",
2665
+ "--no-color",
2666
+ "--no-ext-diff",
2667
+ "--find-renames=50%",
2668
+ `${normalizedCommit}..HEAD`,
2669
+ ...pathArgs
2670
+ ] : mode === "previous" ? [
2671
+ "diff",
2672
+ "--patch",
2673
+ "--no-color",
2674
+ "--no-ext-diff",
2675
+ "--find-renames=50%",
2676
+ `${normalizedCommit}^`,
2677
+ normalizedCommit,
2678
+ ...pathArgs
2679
+ ] : [
2680
+ "show",
2681
+ "--patch",
2682
+ "--no-color",
2683
+ "--no-ext-diff",
2684
+ "--find-renames=50%",
2685
+ "--format=",
2686
+ normalizedCommit,
2687
+ ...pathArgs
2688
+ ], {
2689
+ cwd: normalizedCwd,
2690
+ timeoutMs: 3e4
2691
+ });
2692
+ if (result.code !== 0) throw new Error(gitCommandErrorMessage("Failed to read commit diff", result));
2693
+ const title = mode === "head" ? `${normalizedCommit.slice(0, 7)}..HEAD` : mode === "previous" ? `${normalizedCommit.slice(0, 7)}^..${normalizedCommit.slice(0, 7)}` : normalizedCommit.slice(0, 7);
2694
+ return {
2695
+ commit: normalizedCommit,
2696
+ mode,
2697
+ title: normalizedPath ? `${title}:${normalizedPath}` : title,
2698
+ ...normalizedPath ? { path: normalizedPath } : {},
2699
+ ...normalizedPreviousPath ? { previousPath: normalizedPreviousPath } : {},
2700
+ patch: result.stdout.trim()
2701
+ };
2702
+ }
2703
+ async function readDirectoryGitCommitRemoteUrl(cwd, commit) {
2704
+ const normalizedCwd = normalizeGitCwd(cwd);
2705
+ const normalizedCommit = assertGitCommitHash(commit);
2706
+ if (!normalizedCwd) return null;
2707
+ if (!await isInsideWorkTree(normalizedCwd)) return null;
2708
+ const remoteResult = await runCommand("git", [
2709
+ "remote",
2710
+ "get-url",
2711
+ await readPrimaryRemoteName(normalizedCwd)
2712
+ ], {
2713
+ cwd: normalizedCwd,
2714
+ timeoutMs: 1500
2715
+ });
2716
+ if (remoteResult.code !== 0 || !remoteResult.stdout.trim()) throw new Error("No remote URL found");
2717
+ const baseUrl = remoteBaseUrlFromGitUrl(remoteResult.stdout);
2718
+ if (!baseUrl) throw new Error("Remote URL cannot be opened in the browser");
2719
+ return {
2720
+ commit: normalizedCommit,
2721
+ remoteUrl: `${baseUrl}${commitUrlPathForHost(new URL(baseUrl).host, normalizedCommit)}`
2722
+ };
2723
+ }
2724
+ async function runDirectoryGitCommitAction(cwd, action, commit, options = {}) {
2725
+ const normalizedCwd = normalizeGitCwd(cwd);
2726
+ const normalizedCommit = assertGitCommitHash(commit);
2727
+ if (!normalizedCwd) throw new Error("cwd is required");
2728
+ if (!await isInsideWorkTree(normalizedCwd)) throw new Error("No git repository detected");
2729
+ let result;
2730
+ switch (action) {
2731
+ case "checkout":
2732
+ result = await runCommand("git", [
2733
+ "switch",
2734
+ "--detach",
2735
+ normalizedCommit
2736
+ ], {
2737
+ cwd: normalizedCwd,
2738
+ timeoutMs: GIT_ACTION_TIMEOUT_MS
2739
+ });
2740
+ break;
2741
+ case "cherry-pick":
2742
+ result = await runCommand("git", ["cherry-pick", normalizedCommit], {
2743
+ cwd: normalizedCwd,
2744
+ timeoutMs: GIT_ACTION_TIMEOUT_MS
2745
+ });
2746
+ break;
2747
+ case "revert":
2748
+ result = await runCommand("git", [
2749
+ "revert",
2750
+ "--no-edit",
2751
+ normalizedCommit
2752
+ ], {
2753
+ cwd: normalizedCwd,
2754
+ timeoutMs: GIT_ACTION_TIMEOUT_MS
2755
+ });
2756
+ break;
2757
+ case "tag":
2758
+ result = await runCommand("git", [
2759
+ "tag",
2760
+ assertGitTagName(options.tagName || ""),
2761
+ normalizedCommit
2762
+ ], {
2763
+ cwd: normalizedCwd,
2764
+ timeoutMs: GIT_ACTION_TIMEOUT_MS
2765
+ });
2766
+ break;
2767
+ case "reset":
2768
+ result = await runCommand("git", [
2769
+ "reset",
2770
+ `--${normalizeGitResetMode(options.resetMode)}`,
2771
+ normalizedCommit
2772
+ ], {
2773
+ cwd: normalizedCwd,
2774
+ timeoutMs: GIT_ACTION_TIMEOUT_MS
2775
+ });
2776
+ break;
2777
+ case "rebase":
2778
+ result = await runCommand("git", ["rebase", normalizedCommit], {
2779
+ cwd: normalizedCwd,
2780
+ timeoutMs: GIT_ACTION_TIMEOUT_MS
2781
+ });
2782
+ break;
2783
+ case "drop":
2784
+ result = await runCommand("git", [
2785
+ "rebase",
2786
+ "--onto",
2787
+ `${normalizedCommit}^`,
2788
+ normalizedCommit,
2789
+ "HEAD"
2790
+ ], {
2791
+ cwd: normalizedCwd,
2792
+ timeoutMs: GIT_ACTION_TIMEOUT_MS
2793
+ });
2794
+ break;
2795
+ case "squash": {
2796
+ const message = cleanupCommitMessageCandidate(options.message || "");
2797
+ if (!message) throw new Error("commit message is required");
2798
+ const resetResult = await runCommand("git", [
2799
+ "reset",
2800
+ "--soft",
2801
+ normalizedCommit
2802
+ ], {
2803
+ cwd: normalizedCwd,
2804
+ timeoutMs: GIT_ACTION_TIMEOUT_MS
2805
+ });
2806
+ if (resetResult.code !== 0) throw new Error(gitCommandErrorMessage("Failed to squash commits", resetResult));
2807
+ if ((await runCommand("git", [
2808
+ "diff",
2809
+ "--cached",
2810
+ "--quiet"
2811
+ ], {
2812
+ cwd: normalizedCwd,
2813
+ timeoutMs: 5e3
2814
+ })).code === 0) throw new Error("No commits after this commit to squash");
2815
+ result = await runCommand("git", [
2816
+ "commit",
2817
+ "-m",
2818
+ message
2819
+ ], {
2820
+ cwd: normalizedCwd,
2821
+ timeoutMs: GIT_ACTION_TIMEOUT_MS
2822
+ });
2823
+ result.stdout = [resetResult.stdout, result.stdout].filter(Boolean).join("\n");
2824
+ result.stderr = [resetResult.stderr, result.stderr].filter(Boolean).join("\n");
2825
+ break;
2826
+ }
2827
+ }
2828
+ if (result.code !== 0) throw new Error(gitCommandErrorMessage(`Failed to ${gitCommitActionLabel(action)}`, result));
2829
+ invalidateDirectoryGitCaches(normalizedCwd);
2830
+ return {
2831
+ stdout: result.stdout,
2832
+ stderr: result.stderr
2833
+ };
2834
+ }
2470
2835
  async function generateDirectoryGitCommitMessage(cwd, modelRegistry) {
2471
2836
  const normalizedCwd = normalizeGitCwd(cwd);
2472
2837
  if (!normalizedCwd) throw new Error("cwd is required");
@@ -2544,7 +2909,7 @@ async function generateDirectoryGitCommitMessage(cwd, modelRegistry) {
2544
2909
  headers: auth.headers,
2545
2910
  reasoningEffort: "low"
2546
2911
  });
2547
- const message = cleanupCommitMessageCandidate(Array.isArray(response?.content) ? response.content.filter((block) => block?.type === "text" && typeof block.text === "string").map((block) => block.text).join("\n") : "");
2912
+ const message = cleanupCommitMessageCandidate(Array.isArray(response?.content) ? response.content.flatMap((block) => block?.type === "text" && typeof block.text === "string" ? [block.text] : []).join("\n") : "");
2548
2913
  if (message) return {
2549
2914
  message,
2550
2915
  source: "ai"
@@ -2710,10 +3075,11 @@ var GitWatchManager = class {
2710
3075
  }
2711
3076
  async resolveDirectory(state) {
2712
3077
  const generation = state.generation;
3078
+ if (this.directories.get(state.cwd) !== state) return;
2713
3079
  const repository = await resolveDirectoryGitRepository(state.cwd).catch(() => null);
3080
+ if (!repository) return;
2714
3081
  if (this.directories.get(state.cwd) !== state) return;
2715
3082
  if (state.generation !== generation) return;
2716
- if (!repository) return;
2717
3083
  const repoKey = repositoryWatchKey(repository);
2718
3084
  state.repoKey = repoKey;
2719
3085
  (this.repositories.get(repoKey) ?? this.createRepositoryWatch(repoKey, repository)).subscribers.add(state.cwd);
@@ -3067,6 +3433,7 @@ function getApiKeyProviderDisplayName(providerId) {
3067
3433
  return API_KEY_LOGIN_PROVIDER_NAMES[providerId] ?? providerId;
3068
3434
  }
3069
3435
  var STATE_SYNC_SCALAR_FIELDS = [
3436
+ "activationRevision",
3070
3437
  "sessionKey",
3071
3438
  "draft",
3072
3439
  "streaming",
@@ -3144,7 +3511,10 @@ function sanitizeMessageContentPart(part) {
3144
3511
  function sanitizeSessionMessage(message) {
3145
3512
  const role = typeof message?.role === "string" ? message.role : "";
3146
3513
  const metadata = message?.metadata && typeof message.metadata === "object" ? message.metadata : void 0;
3147
- const sanitizedContent = Array.isArray(message?.content) ? message.content.map((part) => sanitizeMessageContentPart(part)).filter((part) => Boolean(part)) : typeof message?.content === "string" ? message.content : void 0;
3514
+ const sanitizedContent = Array.isArray(message?.content) ? message.content.flatMap((part) => {
3515
+ const sanitizedPart = sanitizeMessageContentPart(part);
3516
+ return sanitizedPart ? [sanitizedPart] : [];
3517
+ }) : typeof message?.content === "string" ? message.content : void 0;
3148
3518
  return {
3149
3519
  ...role ? { role } : {},
3150
3520
  ...sanitizedContent !== void 0 ? { content: sanitizedContent } : {},
@@ -3216,10 +3586,11 @@ function createStateSyncPatch(previous, next) {
3216
3586
  let changed = false;
3217
3587
  const patch = {
3218
3588
  type: "state_sync",
3589
+ activationRevision: next.activationRevision,
3219
3590
  sessionKey: next.sessionKey
3220
3591
  };
3221
3592
  for (const field of STATE_SYNC_SCALAR_FIELDS) {
3222
- if (field === "sessionKey") continue;
3593
+ if (field === "activationRevision" || field === "sessionKey") continue;
3223
3594
  const nextValue = next[field];
3224
3595
  if (Object.is(previous.scalarValues[field], nextValue)) continue;
3225
3596
  patch[field] = nextValue;
@@ -3254,17 +3625,17 @@ function createInitialUiState() {
3254
3625
  }
3255
3626
  function normalizePromptImages(rawImages) {
3256
3627
  if (!Array.isArray(rawImages)) return [];
3257
- return rawImages.map((image) => {
3258
- if (!image || typeof image !== "object") return void 0;
3628
+ return rawImages.flatMap((image) => {
3629
+ if (!image || typeof image !== "object") return [];
3259
3630
  const mimeType = typeof image.mimeType === "string" ? image.mimeType.trim() : "";
3260
3631
  const data = typeof image.data === "string" ? image.data.trim() : "";
3261
- if (!mimeType || !/^image\//i.test(mimeType) || !data) return void 0;
3262
- return {
3632
+ if (!mimeType || !/^image\//i.test(mimeType) || !data) return [];
3633
+ return [{
3263
3634
  type: "image",
3264
3635
  mimeType,
3265
3636
  data
3266
- };
3267
- }).filter((image) => Boolean(image)).slice(0, 8);
3637
+ }];
3638
+ }).slice(0, 8);
3268
3639
  }
3269
3640
  function serializeModel(model) {
3270
3641
  if (!model) return void 0;
@@ -3471,7 +3842,10 @@ var PicoRuntime = class {
3471
3842
  });
3472
3843
  }
3473
3844
  listAvailableModels(entry) {
3474
- return entry.services.modelRegistry.getAvailable().map((model) => serializeModel(model)).filter((model) => Boolean(model)).sort((left, right) => {
3845
+ return entry.services.modelRegistry.getAvailable().flatMap((model) => {
3846
+ const serializedModel = serializeModel(model);
3847
+ return serializedModel ? [serializedModel] : [];
3848
+ }).sort((left, right) => {
3475
3849
  const providerCompare = (left.provider || "").localeCompare(right.provider || "");
3476
3850
  if (providerCompare !== 0) return providerCompare;
3477
3851
  return (left.name || left.id).localeCompare(right.name || right.id);
@@ -3491,6 +3865,7 @@ var PicoRuntime = class {
3491
3865
  const next = {
3492
3866
  id,
3493
3867
  clients: /* @__PURE__ */ new Set(),
3868
+ activeRevision: 0,
3494
3869
  activeKey: void 0,
3495
3870
  draftKey: void 0,
3496
3871
  sessionScope: process.cwd(),
@@ -3524,13 +3899,13 @@ var PicoRuntime = class {
3524
3899
  return false;
3525
3900
  }
3526
3901
  async disposeUnreferencedSessionEntries() {
3527
- const candidates = [...this.sessionEntries.values()];
3528
- for (const entry of candidates) {
3529
- if (this.sessionEntries.get(entry.key) !== entry) continue;
3530
- if (this.isSessionEntryReferenced(entry)) continue;
3531
- if (this.isSessionBusyForDone(entry)) continue;
3532
- await this.disposeSessionEntry(entry);
3533
- }
3902
+ const candidates = [...this.sessionEntries.values()].filter((entry) => {
3903
+ if (this.sessionEntries.get(entry.key) !== entry) return false;
3904
+ if (this.isSessionEntryReferenced(entry)) return false;
3905
+ if (this.isSessionBusyForDone(entry)) return false;
3906
+ return true;
3907
+ });
3908
+ await Promise.all(candidates.map((entry) => this.disposeSessionEntry(entry)));
3534
3909
  }
3535
3910
  async cleanupInactiveContexts() {
3536
3911
  for (const context of this.contexts.values()) {
@@ -3579,11 +3954,12 @@ var PicoRuntime = class {
3579
3954
  }
3580
3955
  return lastValue;
3581
3956
  }
3582
- currentStatePayload(entry) {
3957
+ currentStatePayload(entry, context) {
3583
3958
  const draft = this.isDraftEntry(entry);
3584
3959
  const historyTotalCount = entry.session.messages.length;
3585
3960
  return {
3586
3961
  type: "state_sync",
3962
+ activationRevision: context.activeRevision,
3587
3963
  sessionKey: entry.key,
3588
3964
  items: entry.retainedConversationItems,
3589
3965
  pendingUserMessages: entry.pendingUserMessages.map((message) => clonePendingUserMessage(message)),
@@ -3708,12 +4084,12 @@ var PicoRuntime = class {
3708
4084
  });
3709
4085
  }
3710
4086
  async listEntriesForDirectory(allSessions, directoryPath) {
3711
- const sessions = allSessions.filter((entry) => entry.cwd === directoryPath).map((entry) => ({ ...entry }));
3712
- const byPath = new Map(sessions.filter((entry) => entry.path).map((entry) => [entry.path, entry]));
3713
- const byId = new Map(sessions.filter((entry) => entry.id).map((entry) => [entry.id, entry]));
3714
- for (const entry of this.sessionEntries.values()) {
3715
- if (entry.cwd !== directoryPath || !this.hasVisibleSessionContent(entry)) continue;
3716
- const fallback = await this.sessionFallbackInfo(entry);
4087
+ const sessions = allSessions.flatMap((entry) => entry.cwd === directoryPath ? [{ ...entry }] : []);
4088
+ const byPath = new Map(sessions.flatMap((entry) => entry.path ? [[entry.path, entry]] : []));
4089
+ const byId = new Map(sessions.flatMap((entry) => entry.id ? [[entry.id, entry]] : []));
4090
+ const fallbackEntries = [...this.sessionEntries.values()].filter((entry) => entry.cwd === directoryPath && this.hasVisibleSessionContent(entry));
4091
+ const fallbacks = await Promise.all(fallbackEntries.map((entry) => this.sessionFallbackInfo(entry)));
4092
+ for (const fallback of fallbacks) {
3717
4093
  const existing = (fallback.path ? byPath.get(fallback.path) : void 0) || (fallback.id ? byId.get(fallback.id) : void 0);
3718
4094
  if (existing) {
3719
4095
  this.mergeSessionListEntry(existing, fallback);
@@ -3726,7 +4102,7 @@ var PicoRuntime = class {
3726
4102
  return sessions.sort((left, right) => this.compareSessionListEntriesByLastUserMessage(left, right));
3727
4103
  }
3728
4104
  buildStreamingPaths() {
3729
- return new Set([...this.sessionEntries.values()].filter((entry) => this.getEntryStreamingState(entry)).map((entry) => this.getSessionPath(entry)));
4105
+ return new Set([...this.sessionEntries.values()].flatMap((entry) => this.getEntryStreamingState(entry) ? [this.getSessionPath(entry)] : []));
3730
4106
  }
3731
4107
  async collectDirectoryEntries(allSessions, directories) {
3732
4108
  const entriesByDirectory = /* @__PURE__ */ new Map();
@@ -3928,7 +4304,7 @@ var PicoRuntime = class {
3928
4304
  if (!entry) return;
3929
4305
  const startedAt = performance.now();
3930
4306
  const payloadStartedAt = performance.now();
3931
- const payload = this.currentStatePayload(entry);
4307
+ const payload = this.currentStatePayload(entry, context);
3932
4308
  const payloadDurationMs = roundedDurationMs(payloadStartedAt);
3933
4309
  let sentCount = 0;
3934
4310
  for (const client of context.clients) if (this.sendStatePayloadToClient(context, client, payload, options)) sentCount += 1;
@@ -3986,6 +4362,14 @@ var PicoRuntime = class {
3986
4362
  }
3987
4363
  await Promise.all(connectedContexts.map((context) => this.sendSessionsToContext(context)));
3988
4364
  }
4365
+ async activateContextsSessionAndBroadcast(contexts, entry) {
4366
+ await Promise.all(contexts.map((context) => this.activateContextSession(context, entry)));
4367
+ await this.broadcastSessionsAll();
4368
+ }
4369
+ async bindSessionEntryAndBroadcast(entry) {
4370
+ await this.bindSessionEntry(entry);
4371
+ await Promise.all([this.broadcastEntryState(entry), this.broadcastSessionsAll()]);
4372
+ }
3989
4373
  syncGitWatchDirectories() {
3990
4374
  const cwds = /* @__PURE__ */ new Set();
3991
4375
  for (const context of this.contexts.values()) {
@@ -4157,6 +4541,7 @@ var PicoRuntime = class {
4157
4541
  async activateContextSession(context, entry, options) {
4158
4542
  const previousActiveKey = context.activeKey;
4159
4543
  const startedAt = performance.now();
4544
+ context.activeRevision += 1;
4160
4545
  await activateContextSession({
4161
4546
  context,
4162
4547
  entry,
@@ -4185,6 +4570,7 @@ var PicoRuntime = class {
4185
4570
  this.syncGitWatchDirectories();
4186
4571
  this.logSessionLoadDebug("context_session:activate", {
4187
4572
  contextId: context.id,
4573
+ activeRevision: context.activeRevision,
4188
4574
  previousActiveKey,
4189
4575
  notify: options?.notify !== false,
4190
4576
  statusDurationMs,
@@ -4609,25 +4995,26 @@ var PicoRuntime = class {
4609
4995
  }
4610
4996
  pendingMessagesFromClientUpdate(entry, pendingMessagesUpdate) {
4611
4997
  const pendingMessages = entry.pendingUserMessages.map((message) => clonePendingUserMessage(message));
4612
- const normalizedUpdates = Array.isArray(pendingMessagesUpdate) ? pendingMessagesUpdate.map((message) => {
4998
+ const normalizedUpdates = Array.isArray(pendingMessagesUpdate) ? pendingMessagesUpdate.flatMap((message) => {
4999
+ const pendingId = typeof message?.pendingId === "string" ? message.pendingId : "";
5000
+ if (!pendingId) return [];
4613
5001
  const hasImages = hasOwnProperty(message, "images");
4614
5002
  const hasText = hasOwnProperty(message, "text");
4615
- return {
4616
- pendingId: typeof message?.pendingId === "string" ? message.pendingId : "",
5003
+ return [{
5004
+ pendingId,
4617
5005
  hasImages,
4618
5006
  hasText,
4619
5007
  images: hasImages ? normalizePromptImages(message?.images) : [],
4620
5008
  streamingBehavior: normalizePendingStreamingBehavior(message?.streamingBehavior),
4621
5009
  text: hasText && typeof message?.text === "string" ? message.text : ""
4622
- };
4623
- }).filter((message) => Boolean(message.pendingId)) : [];
4624
- if (normalizedUpdates.length !== pendingMessages.length) throw new Error("pendingMessages must include every pending prompt exactly once.");
5010
+ }];
5011
+ }) : [];
4625
5012
  const pendingMessagesById = new Map(pendingMessages.map((message) => [message.pendingId, message]));
4626
5013
  if (pendingMessagesById.size !== pendingMessages.length) throw new Error("Pending prompt order is out of date. Refresh and try again.");
4627
5014
  const nextPendingMessages = [];
4628
5015
  for (const update of normalizedUpdates) {
4629
5016
  const existing = pendingMessagesById.get(update.pendingId);
4630
- if (!existing) throw new Error("pendingMessages must include every pending prompt exactly once.");
5017
+ if (!existing) continue;
4631
5018
  const text = update.hasText ? update.text : existing.text;
4632
5019
  const images = update.hasImages ? update.images : existing.images;
4633
5020
  if (!text.trim() && images.length === 0) throw new Error("Pending prompt text or image is required.");
@@ -4642,23 +5029,30 @@ var PicoRuntime = class {
4642
5029
  if (pendingMessagesById.size > 0) throw new Error("pendingMessages must include every pending prompt exactly once.");
4643
5030
  return sortPendingUserMessages(nextPendingMessages);
4644
5031
  }
5032
+ async replayPendingUserMessages(entry, pendingMessages, index = 0) {
5033
+ const pendingMessage = pendingMessages[index];
5034
+ if (!pendingMessage) return;
5035
+ const text = pendingMessage.text;
5036
+ const images = normalizePromptImages(pendingMessage.images);
5037
+ if (text.trim() || images.length > 0) await entry.session.prompt(text, {
5038
+ ...images.length > 0 ? { images } : {},
5039
+ streamingBehavior: pendingMessage.streamingBehavior
5040
+ });
5041
+ await this.replayPendingUserMessages(entry, pendingMessages, index + 1);
5042
+ }
4645
5043
  async replacePendingUserMessages(entry, pendingMessages) {
4646
5044
  const nextPending = sortPendingUserMessages(pendingMessages);
4647
5045
  const canReplayPending = Boolean(entry.session.isStreaming);
4648
- if (!canReplayPending && nextPending.length > 0) throw new Error("Pending prompts can only be changed while the session is streaming.");
5046
+ if (!canReplayPending) {
5047
+ entry.pendingUserMessages = nextPending;
5048
+ await this.broadcastEntryState(entry);
5049
+ return entry.pendingUserMessages;
5050
+ }
4649
5051
  entry.pendingQueueMutation = true;
4650
5052
  try {
4651
5053
  entry.session.clearQueue();
4652
5054
  entry.pendingUserMessages = [];
4653
- if (canReplayPending) for (const pendingMessage of nextPending) {
4654
- const text = pendingMessage.text;
4655
- const images = normalizePromptImages(pendingMessage.images);
4656
- if (!text.trim() && images.length === 0) continue;
4657
- await entry.session.prompt(text, {
4658
- ...images.length > 0 ? { images } : {},
4659
- streamingBehavior: pendingMessage.streamingBehavior
4660
- });
4661
- }
5055
+ if (canReplayPending) await this.replayPendingUserMessages(entry, nextPending);
4662
5056
  entry.pendingUserMessages = nextPending;
4663
5057
  this.reconcilePendingUserMessages(entry);
4664
5058
  } finally {
@@ -4779,11 +5173,9 @@ var PicoRuntime = class {
4779
5173
  sessionId: void 0,
4780
5174
  sessionFile: void 0
4781
5175
  };
4782
- for (const context of viewers()) {
4783
- context.draftKey = result.entry.key;
4784
- await this.activateContextSession(context, result.entry);
4785
- }
4786
- await this.broadcastSessionsAll();
5176
+ const activeViewers = viewers();
5177
+ for (const context of activeViewers) context.draftKey = result.entry.key;
5178
+ await this.activateContextsSessionAndBroadcast(activeViewers, result.entry);
4787
5179
  return {
4788
5180
  sessionId: void 0,
4789
5181
  sessionFile: void 0
@@ -4793,8 +5185,7 @@ var PicoRuntime = class {
4793
5185
  const branchedPath = session.sessionManager.createBranchedSession?.(branchEntryId);
4794
5186
  if (!branchedPath) return { cancelled: true };
4795
5187
  const nextEntry = await this.ensureSessionEntryByPath(branchedPath);
4796
- for (const context of viewers()) await this.activateContextSession(context, nextEntry);
4797
- await this.broadcastSessionsAll();
5188
+ await this.activateContextsSessionAndBroadcast(viewers(), nextEntry);
4798
5189
  return {
4799
5190
  sessionId: nextEntry.session.sessionId,
4800
5191
  sessionFile: nextEntry.session.sessionFile
@@ -4825,8 +5216,7 @@ var PicoRuntime = class {
4825
5216
  sessionId: entry.session.sessionId,
4826
5217
  sessionFile: entry.session.sessionFile
4827
5218
  };
4828
- for (const context of viewers()) await this.activateContextSession(context, nextEntry);
4829
- await this.broadcastSessionsAll();
5219
+ await this.activateContextsSessionAndBroadcast(viewers(), nextEntry);
4830
5220
  return {
4831
5221
  sessionId: nextEntry.session.sessionId,
4832
5222
  sessionFile: nextEntry.session.sessionFile
@@ -4834,9 +5224,7 @@ var PicoRuntime = class {
4834
5224
  },
4835
5225
  reload: async () => {
4836
5226
  await session.reload?.();
4837
- await this.bindSessionEntry(entry);
4838
- await this.broadcastEntryState(entry);
4839
- await this.broadcastSessionsAll();
5227
+ await this.bindSessionEntryAndBroadcast(entry);
4840
5228
  }
4841
5229
  },
4842
5230
  shutdownHandler: () => {
@@ -4995,7 +5383,7 @@ var PicoRuntime = class {
4995
5383
  const bootstrapStartedAt = performance.now();
4996
5384
  try {
4997
5385
  const stateStartedAt = performance.now();
4998
- this.sendStatePayloadToClient(context, client, this.currentStatePayload(activeEntry), { forceFull: true });
5386
+ this.sendStatePayloadToClient(context, client, this.currentStatePayload(activeEntry, context), { forceFull: true });
4999
5387
  this.logSessionLoadDebug("events_response:bootstrap_state", {
5000
5388
  contextId: context.id,
5001
5389
  clientId: client.id,
@@ -5162,7 +5550,6 @@ var PicoRuntime = class {
5162
5550
  const pendingMessages = Array.isArray(body.pendingMessages) ? body.pendingMessages : Array.isArray(body.pendingIds) ? body.pendingIds.map((pendingId) => ({ pendingId })) : null;
5163
5551
  if (!pendingMessages) throw new Error("pendingMessages must be an array");
5164
5552
  const nextPendingMessages = this.pendingMessagesFromClientUpdate(activeEntry, pendingMessages);
5165
- if (!activeEntry.session.isStreaming && nextPendingMessages.length > 0) throw new Error("Pending prompts can only be changed while the session is streaming.");
5166
5553
  await this.replacePendingUserMessages(activeEntry, nextPendingMessages);
5167
5554
  return {
5168
5555
  ok: true,
@@ -5181,7 +5568,9 @@ var PicoRuntime = class {
5181
5568
  const pendingMessages = activeEntry.pendingUserMessages.map((message) => clonePendingUserMessage(message));
5182
5569
  const pendingIndex = pendingMessages.findIndex((message) => message.pendingId === pendingId);
5183
5570
  if (pendingIndex === -1) {
5184
- if (normalizeClientPendingId(pendingId)) {
5571
+ const isKnownClientPendingId = Boolean(normalizeClientPendingId(pendingId));
5572
+ const isKnownServerPendingId = pendingId.startsWith("pending:");
5573
+ if (isKnownClientPendingId || isKnownServerPendingId) {
5185
5574
  activeEntry.canceledPendingUserMessageIds.add(pendingId);
5186
5575
  return {
5187
5576
  ok: true,
@@ -5192,7 +5581,6 @@ var PicoRuntime = class {
5192
5581
  }
5193
5582
  activeEntry.canceledPendingUserMessageIds.delete(pendingId);
5194
5583
  pendingMessages.splice(pendingIndex, 1);
5195
- if (!activeEntry.session.isStreaming && pendingMessages.length > 0) throw new Error("Pending prompts can only be changed while the session is streaming.");
5196
5584
  await this.replacePendingUserMessages(activeEntry, pendingMessages);
5197
5585
  return {
5198
5586
  ok: true,
@@ -5332,7 +5720,10 @@ var PicoRuntime = class {
5332
5720
  return {
5333
5721
  leafId,
5334
5722
  streamingEntryId,
5335
- tree: (manager.getTree() || []).map((node) => serializeSessionTreeNode(node)).filter((node) => Boolean(node)).map((node) => markStreamingNode(node))
5723
+ tree: (manager.getTree() || []).flatMap((node) => {
5724
+ const treeNode = serializeSessionTreeNode(node);
5725
+ return treeNode ? [markStreamingNode(treeNode)] : [];
5726
+ })
5336
5727
  };
5337
5728
  }
5338
5729
  async getSessionTreeForRequest(request) {
@@ -5532,6 +5923,27 @@ var PicoRuntime = class {
5532
5923
  name: nextName
5533
5924
  };
5534
5925
  }
5926
+ async setSessionReadState(request, body) {
5927
+ const { context } = await this.resolveRequest(request);
5928
+ const sessionPath = typeof body.path === "string" ? body.path.trim() : "";
5929
+ const unread = typeof body.unread === "boolean" ? body.unread : false;
5930
+ if (!sessionPath) throw new Error("path is required");
5931
+ if (unread) context.unreadFinished.add(sessionPath);
5932
+ else context.unreadFinished.delete(sessionPath);
5933
+ const loadedEntry = [...this.sessionEntries.values()].find((entry) => this.getSessionPath(entry) === sessionPath);
5934
+ if (loadedEntry) this.sendSessionStatusToContext(context, loadedEntry);
5935
+ else this.sendToContext(context, {
5936
+ type: "session_status",
5937
+ sessionPath,
5938
+ unread
5939
+ });
5940
+ await this.sendSessionsToContext(context);
5941
+ return {
5942
+ ok: true,
5943
+ path: sessionPath,
5944
+ unread
5945
+ };
5946
+ }
5535
5947
  async writeMovedSessionFile(sessionPath, nextCwd, targetSessionDirectory) {
5536
5948
  const sourcePath = resolve(sessionPath);
5537
5949
  const targetPath = resolve(await uniqueSessionMovePath(sourcePath, targetSessionDirectory));
@@ -5563,20 +5975,23 @@ var PicoRuntime = class {
5563
5975
  const previousPath = resolve(sessionPath);
5564
5976
  const previousEntry = loadedEntries[0];
5565
5977
  const previousCwd = previousEntry?.cwd || "";
5566
- const affectedContexts = [...this.contexts.values()].map((context) => ({
5567
- context,
5568
- wasActive: loadedEntries.some((entry) => context.activeKey === entry.key),
5569
- wasDraft: loadedEntries.some((entry) => context.draftKey === entry.key)
5570
- })).filter((entry) => entry.wasActive || entry.wasDraft);
5978
+ const affectedContexts = [...this.contexts.values()].flatMap((context) => {
5979
+ const wasActive = loadedEntries.some((entry) => context.activeKey === entry.key);
5980
+ const wasDraft = loadedEntries.some((entry) => context.draftKey === entry.key);
5981
+ return wasActive || wasDraft ? [{
5982
+ context,
5983
+ wasActive,
5984
+ wasDraft
5985
+ }] : [];
5986
+ });
5571
5987
  const nextPath = await this.writeMovedSessionFile(previousPath, nextCwd, targetSessionDirectory);
5572
- for (const loadedEntry of loadedEntries) await this.disposeSessionEntry(loadedEntry);
5988
+ await Promise.all(loadedEntries.map((loadedEntry) => this.disposeSessionEntry(loadedEntry)));
5573
5989
  let nextEntry;
5574
5990
  if (affectedContexts.some((entry) => entry.wasActive)) {
5575
5991
  nextEntry = await this.ensureSessionEntryByPath(nextPath);
5576
- for (const affected of affectedContexts) {
5577
- if (affected.wasDraft) affected.context.draftKey = void 0;
5578
- if (affected.wasActive) await this.activateContextSession(affected.context, nextEntry, { refreshSessions: false });
5579
- }
5992
+ const activeNextEntry = nextEntry;
5993
+ for (const affected of affectedContexts) if (affected.wasDraft) affected.context.draftKey = void 0;
5994
+ await Promise.all(affectedContexts.flatMap((affected) => affected.wasActive ? [this.activateContextSession(affected.context, activeNextEntry, { refreshSessions: false })] : []));
5580
5995
  } else for (const affected of affectedContexts) if (affected.wasDraft) affected.context.draftKey = void 0;
5581
5996
  for (const context of this.contexts.values()) if (context.unreadFinished.delete(previousPath)) context.unreadFinished.add(nextPath);
5582
5997
  this.invalidateSessionIndexCache();
@@ -5621,21 +6036,20 @@ var PicoRuntime = class {
5621
6036
  const allSessions = await this.listSessionIndexEntries();
5622
6037
  const directorySessions = await this.listEntriesForDirectory(allSessions, directory);
5623
6038
  const streamingPaths = this.buildStreamingPaths();
5624
- const activeKeys = new Set([...this.contexts.values()].map((ctx) => ctx.activeKey).filter(Boolean));
5625
- const activePaths = new Set([...this.sessionEntries.values()].filter((entry) => activeKeys.has(entry.key)).map((entry) => this.getSessionPath(entry)));
6039
+ const activeKeys = new Set([...this.contexts.values()].flatMap((ctx) => ctx.activeKey ? [ctx.activeKey] : []));
6040
+ const activePaths = new Set([...this.sessionEntries.values()].flatMap((entry) => activeKeys.has(entry.key) ? [this.getSessionPath(entry)] : []));
5626
6041
  const includeActiveSession = body.includeActiveSession === true;
5627
- const matchingSessions = directorySessions.map((entry) => {
6042
+ const matchingSessions = directorySessions.flatMap((entry) => {
5628
6043
  const activityAt = normalizeModifiedTimestamp(entry.lastUserMessageAt) || normalizeModifiedTimestamp(entry.modified);
5629
- return {
6044
+ const serializedEntry = {
5630
6045
  ...this.serializeSessionListEntry(entry, context, streamingPaths),
5631
6046
  activityAt
5632
6047
  };
5633
- }).filter((entry) => {
5634
- if (!entry.path) return false;
5635
- if (streamingPaths.has(entry.path)) return false;
5636
- if (!includeActiveSession && activePaths.has(entry.path)) return false;
5637
- const activityTime = modifiedTimestampValue(entry.activityAt);
5638
- return activityTime > 0 && activityTime < cutoffTime;
6048
+ if (!serializedEntry.path) return [];
6049
+ if (streamingPaths.has(serializedEntry.path)) return [];
6050
+ if (!includeActiveSession && activePaths.has(serializedEntry.path)) return [];
6051
+ const activityTime = modifiedTimestampValue(serializedEntry.activityAt);
6052
+ return activityTime > 0 && activityTime < cutoffTime ? [serializedEntry] : [];
5639
6053
  });
5640
6054
  if (body.dryRun !== false) return {
5641
6055
  ok: true,
@@ -5645,10 +6059,10 @@ var PicoRuntime = class {
5645
6059
  deletedSessionIds: [],
5646
6060
  matchingSessions
5647
6061
  };
5648
- const deletedSessionIds = matchingSessions.map((session) => session.id).filter((id) => Boolean(id));
5649
- const matchingPaths = matchingSessions.map((session) => session.path).filter((path) => Boolean(path));
6062
+ const deletedSessionIds = matchingSessions.flatMap((session) => session.id ? [session.id] : []);
6063
+ const matchingPaths = matchingSessions.flatMap((session) => session.path ? [session.path] : []);
5650
6064
  const matchingPathSet = new Set(matchingPaths);
5651
- await Promise.all([...this.sessionEntries.values()].filter((entry) => matchingPathSet.has(this.getSessionPath(entry))).map((entry) => this.disposeSessionEntry(entry)));
6065
+ await Promise.all([...this.sessionEntries.values()].flatMap((entry) => matchingPathSet.has(this.getSessionPath(entry)) ? [this.disposeSessionEntry(entry)] : []));
5652
6066
  for (const ctx of this.contexts.values()) for (const sessionPath of matchingPaths) ctx.unreadFinished.delete(sessionPath);
5653
6067
  await Promise.all(matchingPaths.map((sessionPath) => this.trashOrDeleteSessionFile(sessionPath)));
5654
6068
  this.invalidateSessionIndexCache();
@@ -5664,23 +6078,32 @@ var PicoRuntime = class {
5664
6078
  }
5665
6079
  async deleteSessions(request, body) {
5666
6080
  const { context } = await this.resolveRequest(request);
5667
- const paths = Array.isArray(body.paths) ? body.paths.filter((path) => typeof path === "string").map((path) => path.trim()).filter(Boolean) : [];
6081
+ const paths = Array.isArray(body.paths) ? body.paths.flatMap((path) => {
6082
+ if (typeof path !== "string") return [];
6083
+ const trimmedPath = path.trim();
6084
+ return trimmedPath ? [trimmedPath] : [];
6085
+ }) : [];
5668
6086
  const sessionPaths = [...new Set(paths)];
5669
6087
  if (sessionPaths.length === 0) throw new Error("paths are required");
5670
6088
  const sessionPathSet = new Set(sessionPaths);
5671
6089
  const loadedEntries = [...this.sessionEntries.values()].filter((entry) => sessionPathSet.has(this.getSessionPath(entry)));
5672
- let replacementEntry;
5673
- for (const loadedEntry of loadedEntries) {
6090
+ const replacementRequests = loadedEntries.flatMap((loadedEntry) => {
5674
6091
  const affectedContexts = [...this.contexts.values()].filter((ctx) => ctx.activeKey === loadedEntry.key);
5675
- if (affectedContexts.length > 0) {
5676
- const nextReplacementEntry = await this.createNewSessionEntry(loadedEntry.cwd, { draft: true });
5677
- replacementEntry = replacementEntry ?? nextReplacementEntry;
5678
- for (const affected of affectedContexts) {
5679
- affected.draftKey = nextReplacementEntry.key;
5680
- await this.activateContextSession(affected, nextReplacementEntry);
5681
- }
5682
- }
6092
+ return affectedContexts.length > 0 ? [{
6093
+ affectedContexts,
6094
+ cwd: loadedEntry.cwd
6095
+ }] : [];
6096
+ });
6097
+ const replacementResults = await Promise.all(replacementRequests.map(async (request) => ({
6098
+ affectedContexts: request.affectedContexts,
6099
+ entry: await this.createNewSessionEntry(request.cwd, { draft: true })
6100
+ })));
6101
+ let replacementEntry;
6102
+ for (const result of replacementResults) {
6103
+ replacementEntry = replacementEntry ?? result.entry;
6104
+ for (const affected of result.affectedContexts) affected.draftKey = result.entry.key;
5683
6105
  }
6106
+ await Promise.all(replacementResults.flatMap((result) => result.affectedContexts.map((affected) => this.activateContextSession(affected, result.entry))));
5684
6107
  for (const ctx of this.contexts.values()) for (const sessionPath of sessionPaths) ctx.unreadFinished.delete(sessionPath);
5685
6108
  await Promise.all(loadedEntries.map((entry) => this.disposeSessionEntry(entry)));
5686
6109
  await Promise.all(sessionPaths.map((sessionPath) => this.trashOrDeleteSessionFile(sessionPath)));
@@ -5742,15 +6165,15 @@ var PicoRuntime = class {
5742
6165
  authType: "oauth",
5743
6166
  ...authStatus(provider.id)
5744
6167
  })).sort((left, right) => left.name.localeCompare(right.name));
5745
- const apiKeyOptions = Array.from(providerIds).filter((providerId) => {
5746
- if (BUILT_IN_API_KEY_LOGIN_PROVIDERS.has(providerId)) return true;
5747
- return !oauthProviderIds.has(providerId);
5748
- }).map((providerId) => ({
5749
- id: providerId,
5750
- name: getApiKeyProviderDisplayName(providerId),
5751
- authType: "api_key",
5752
- ...authStatus(providerId)
5753
- })).sort((left, right) => left.name.localeCompare(right.name));
6168
+ const apiKeyOptions = Array.from(providerIds).flatMap((providerId) => {
6169
+ if (!BUILT_IN_API_KEY_LOGIN_PROVIDERS.has(providerId) && oauthProviderIds.has(providerId)) return [];
6170
+ return [{
6171
+ id: providerId,
6172
+ name: getApiKeyProviderDisplayName(providerId),
6173
+ authType: "api_key",
6174
+ ...authStatus(providerId)
6175
+ }];
6176
+ }).sort((left, right) => left.name.localeCompare(right.name));
5754
6177
  const nameByProvider = new Map([...oauthOptions, ...apiKeyOptions].map((option) => [option.id, option.name]));
5755
6178
  const authTypeByProvider = new Map([...oauthOptions, ...apiKeyOptions].map((option) => [option.id, option.authType]));
5756
6179
  return {
@@ -5997,14 +6420,14 @@ var PicoRuntime = class {
5997
6420
  pending.resolve({ cancelled: true });
5998
6421
  } catch {}
5999
6422
  this.pendingUiRequests.clear();
6000
- for (const entry of this.sessionEntries.values()) await this.disposeSessionEntry(entry);
6423
+ await Promise.all([...this.sessionEntries.values()].map((entry) => this.disposeSessionEntry(entry)));
6001
6424
  }
6002
6425
  };
6003
6426
  function getPicoRuntime() {
6004
6427
  globalThis.__picoRuntime ??= new PicoRuntime();
6005
6428
  return globalThis.__picoRuntime;
6006
6429
  }
6007
- var Route$47 = createFileRoute("/events")({ server: { handlers: { GET: ({ request }) => getPicoRuntime().createEventsResponse(request) } } });
6430
+ var Route$52 = createFileRoute("/events")({ server: { handlers: { GET: ({ request }) => getPicoRuntime().createEventsResponse(request) } } });
6008
6431
  function jsonResponse(data, init = 200) {
6009
6432
  const responseInit = typeof init === "number" ? { status: init } : init;
6010
6433
  const headers = new Headers(responseInit.headers);
@@ -6040,7 +6463,7 @@ function routeErrorResponse(error, fallbackMessage) {
6040
6463
  async function readRequestJson(request) {
6041
6464
  return await request.json().catch(() => ({}));
6042
6465
  }
6043
- var Route$46 = createFileRoute("/api/thinking")({ server: { handlers: { POST: async ({ request }) => {
6466
+ var Route$51 = createFileRoute("/api/thinking")({ server: { handlers: { POST: async ({ request }) => {
6044
6467
  try {
6045
6468
  const body = await readRequestJson(request);
6046
6469
  return jsonResponse(await getPicoRuntime().setThinking(request, body));
@@ -6048,7 +6471,7 @@ var Route$46 = createFileRoute("/api/thinking")({ server: { handlers: { POST: as
6048
6471
  return routeErrorResponse(error, "Failed to update thinking level");
6049
6472
  }
6050
6473
  } } } });
6051
- var Route$45 = createFileRoute("/api/slash-command")({ server: { handlers: { POST: async ({ request }) => {
6474
+ var Route$50 = createFileRoute("/api/slash-command")({ server: { handlers: { POST: async ({ request }) => {
6052
6475
  try {
6053
6476
  const body = await readRequestJson(request);
6054
6477
  return jsonResponse(await getPicoRuntime().runSlashCommand(request, body));
@@ -6056,7 +6479,7 @@ var Route$45 = createFileRoute("/api/slash-command")({ server: { handlers: { POS
6056
6479
  return routeErrorResponse(error, "Failed to run slash command");
6057
6480
  }
6058
6481
  } } } });
6059
- var Route$44 = createFileRoute("/api/provider-usage")({ server: { handlers: { GET: async ({ request }) => {
6482
+ var Route$49 = createFileRoute("/api/provider-usage")({ server: { handlers: { GET: async ({ request }) => {
6060
6483
  const provider = new URL(request.url).searchParams.get("provider") || void 0;
6061
6484
  try {
6062
6485
  return jsonResponse({
@@ -6067,7 +6490,7 @@ var Route$44 = createFileRoute("/api/provider-usage")({ server: { handlers: { GE
6067
6490
  return routeErrorResponse(error, "Failed to read provider usage");
6068
6491
  }
6069
6492
  } } } });
6070
- var Route$43 = createFileRoute("/api/prompt")({ server: { handlers: { POST: async ({ request }) => {
6493
+ var Route$48 = createFileRoute("/api/prompt")({ server: { handlers: { POST: async ({ request }) => {
6071
6494
  try {
6072
6495
  const body = await readRequestJson(request);
6073
6496
  return jsonResponse(await getPicoRuntime().prompt(request, body));
@@ -6097,6 +6520,9 @@ var DIRECTORY_SEARCH_IGNORE_DIRECTORIES = new Set([
6097
6520
  function displayPath(value = "") {
6098
6521
  return String(value).replace(/\\/g, "/");
6099
6522
  }
6523
+ function projectPathTextContains(text, query) {
6524
+ return text.indexOf(query) >= 0;
6525
+ }
6100
6526
  function expandHomeDirectory(inputPath) {
6101
6527
  if (inputPath === "~") return os.homedir();
6102
6528
  if (inputPath.startsWith("~/")) return `${os.homedir()}${inputPath.slice(1)}`;
@@ -6165,13 +6591,12 @@ async function listPathCompletionEntries(prefix, baseCwd) {
6165
6591
  return [];
6166
6592
  }
6167
6593
  const normalizedSearchPrefix = searchPrefix.toLowerCase();
6168
- const suggestions = [];
6169
- for (const entry of entries) {
6170
- if (!entry.name.toLowerCase().startsWith(normalizedSearchPrefix)) continue;
6594
+ const matchingEntries = entries.filter((entry) => entry.name.toLowerCase().startsWith(normalizedSearchPrefix));
6595
+ const suggestions = await Promise.all(matchingEntries.map(async (entry) => {
6171
6596
  const isDirectory = await completionEntryIsDirectory(entry, join(searchDir, entry.name));
6172
6597
  let completionPath;
6173
6598
  if (displayPrefix.endsWith("/") || displayPrefix.endsWith("\\")) completionPath = `${displayPrefix}${entry.name}`;
6174
- else if (displayPrefix.includes("/") || displayPrefix.includes("\\")) if (displayPrefix === "~") completionPath = `~/${entry.name}`;
6599
+ else if (projectPathTextContains(displayPrefix, "/") || projectPathTextContains(displayPrefix, "\\")) if (displayPrefix === "~") completionPath = `~/${entry.name}`;
6175
6600
  else if (displayPrefix.startsWith("~/")) {
6176
6601
  const parentDir = dirname(displayPrefix.slice(2));
6177
6602
  completionPath = parentDir === "." ? `~/${entry.name}` : `~/${displayPath(parentDir)}/${entry.name}`;
@@ -6184,13 +6609,12 @@ async function listPathCompletionEntries(prefix, baseCwd) {
6184
6609
  }
6185
6610
  else if (displayPrefix.startsWith("~")) completionPath = `~/${entry.name}`;
6186
6611
  else completionPath = entry.name;
6187
- const value = isDirectory ? `${displayPath(completionPath)}/` : displayPath(completionPath);
6188
- suggestions.push({
6189
- value,
6612
+ return {
6613
+ value: isDirectory ? `${displayPath(completionPath)}/` : displayPath(completionPath),
6190
6614
  label: `${entry.name}${isDirectory ? "/" : ""}`,
6191
6615
  isDirectory
6192
- });
6193
- }
6616
+ };
6617
+ }));
6194
6618
  suggestions.sort((left, right) => {
6195
6619
  if (left.isDirectory && !right.isDirectory) return -1;
6196
6620
  if (!left.isDirectory && right.isDirectory) return 1;
@@ -6257,7 +6681,7 @@ async function runFdSearch(command, args) {
6257
6681
  const displayedLine = displayPath(line);
6258
6682
  const hasTrailingSeparator = displayedLine.endsWith("/");
6259
6683
  const normalizedPath = hasTrailingSeparator ? displayedLine.slice(0, -1) : displayedLine;
6260
- if (normalizedPath === ".git" || normalizedPath.startsWith(".git/") || normalizedPath.includes("/.git/")) continue;
6684
+ if (normalizedPath === ".git" || normalizedPath.startsWith(".git/") || projectPathTextContains(normalizedPath, "/.git/")) continue;
6261
6685
  results.push({
6262
6686
  path: displayedLine,
6263
6687
  isDirectory: hasTrailingSeparator
@@ -6267,52 +6691,72 @@ async function runFdSearch(command, args) {
6267
6691
  });
6268
6692
  });
6269
6693
  }
6694
+ async function runFdSearchCandidates(args) {
6695
+ return (await Promise.all(["fd", "fdfind"].map((command) => runFdSearch(command, args)))).find((result) => result !== void 0);
6696
+ }
6270
6697
  function escapePathQueryRegex(value = "") {
6271
6698
  return String(value).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6272
6699
  }
6273
6700
  function buildFdPathQuery(query = "") {
6274
6701
  const normalized = displayPath(query);
6275
- if (!normalized.includes("/")) return normalized;
6702
+ if (!projectPathTextContains(normalized, "/")) return normalized;
6276
6703
  const hasTrailingSeparator = normalized.endsWith("/");
6277
6704
  const trimmed = normalized.replace(/^\/+|\/+$/g, "");
6278
6705
  if (!trimmed) return normalized;
6279
6706
  const separatorPattern = "[\\\\/]";
6280
- const segments = trimmed.split("/").filter(Boolean).map((segment) => escapePathQueryRegex(segment));
6707
+ const segments = trimmed.split("/").flatMap((segment) => segment ? [escapePathQueryRegex(segment)] : []);
6281
6708
  if (segments.length === 0) return normalized;
6282
6709
  let pattern = segments.join(separatorPattern);
6283
6710
  if (hasTrailingSeparator) pattern += separatorPattern;
6284
6711
  return pattern;
6285
6712
  }
6713
+ async function readDirectoryEntries(directory) {
6714
+ try {
6715
+ return await readdir(directory, {
6716
+ withFileTypes: true,
6717
+ encoding: "utf8"
6718
+ });
6719
+ } catch {
6720
+ return [];
6721
+ }
6722
+ }
6723
+ async function walkDirectoryFallbackLayer({ baseDir, normalizedQuery, currentDirs, matches, maxResults }) {
6724
+ if (currentDirs.length === 0 || matches.length >= maxResults) return;
6725
+ const directoryEntries = await Promise.all(currentDirs.map(async (currentDir) => ({
6726
+ currentDir,
6727
+ entries: await readDirectoryEntries(currentDir)
6728
+ })));
6729
+ const nextDirs = [];
6730
+ for (const { currentDir, entries } of directoryEntries) for (const entry of entries) {
6731
+ if (matches.length >= maxResults) break;
6732
+ if (WALK_IGNORE_DIRECTORIES.has(entry.name)) continue;
6733
+ const fullPath = join(currentDir, entry.name);
6734
+ const relativePath = displayPath(path.relative(baseDir, fullPath));
6735
+ const isDirectory = entry.isDirectory();
6736
+ const displayValue = isDirectory ? `${relativePath}/` : relativePath;
6737
+ if (!normalizedQuery || projectPathTextContains(displayValue.toLowerCase(), normalizedQuery)) matches.push({
6738
+ path: displayValue,
6739
+ isDirectory
6740
+ });
6741
+ if (isDirectory) nextDirs.push(fullPath);
6742
+ }
6743
+ await walkDirectoryFallbackLayer({
6744
+ baseDir,
6745
+ normalizedQuery,
6746
+ currentDirs: nextDirs,
6747
+ matches,
6748
+ maxResults
6749
+ });
6750
+ }
6286
6751
  async function walkDirectoryWithFallback(baseDir, query = "", maxResults = 100) {
6287
- const queue = [baseDir];
6288
6752
  const matches = [];
6289
- const normalizedQuery = displayPath(query).toLowerCase();
6290
- while (queue.length > 0 && matches.length < maxResults) {
6291
- const currentDir = queue.shift();
6292
- if (!currentDir) continue;
6293
- let entries;
6294
- try {
6295
- entries = await readdir(currentDir, {
6296
- withFileTypes: true,
6297
- encoding: "utf8"
6298
- });
6299
- } catch {
6300
- continue;
6301
- }
6302
- for (const entry of entries) {
6303
- if (matches.length >= maxResults) break;
6304
- if (WALK_IGNORE_DIRECTORIES.has(entry.name)) continue;
6305
- const fullPath = join(currentDir, entry.name);
6306
- const relativePath = displayPath(path.relative(baseDir, fullPath));
6307
- const isDirectory = entry.isDirectory();
6308
- const displayValue = isDirectory ? `${relativePath}/` : relativePath;
6309
- if (!normalizedQuery || displayValue.toLowerCase().includes(normalizedQuery)) matches.push({
6310
- path: displayValue,
6311
- isDirectory
6312
- });
6313
- if (isDirectory) queue.push(fullPath);
6314
- }
6315
- }
6753
+ await walkDirectoryFallbackLayer({
6754
+ baseDir,
6755
+ normalizedQuery: displayPath(query).toLowerCase(),
6756
+ currentDirs: [baseDir],
6757
+ matches,
6758
+ maxResults
6759
+ });
6316
6760
  return matches;
6317
6761
  }
6318
6762
  async function walkDirectory(baseDir, query = "", maxResults = 100) {
@@ -6345,10 +6789,8 @@ async function walkDirectory(baseDir, query = "", maxResults = 100) {
6345
6789
  "node_modules"
6346
6790
  ];
6347
6791
  if (query) args.push(buildFdPathQuery(query));
6348
- for (const command of ["fd", "fdfind"]) {
6349
- const results = await runFdSearch(command, args);
6350
- if (results !== void 0) return results;
6351
- }
6792
+ const results = await runFdSearchCandidates(args);
6793
+ if (results !== void 0) return results;
6352
6794
  return await walkDirectoryWithFallback(baseDir, query, maxResults);
6353
6795
  }
6354
6796
  async function resolveScopedFileReferenceQuery(rawQuery, baseCwd) {
@@ -6394,7 +6836,11 @@ function resolveProjectFilePath(baseCwd, filePath) {
6394
6836
  };
6395
6837
  }
6396
6838
  async function listProjectFileTreePaths(baseCwd) {
6397
- return (await walkDirectory(baseCwd, "", PROJECT_FILE_TREE_LIMIT)).filter((entry) => !entry.isDirectory).map((entry) => displayPath(entry.path).replace(/\/+$/g, "")).filter(Boolean).sort((left, right) => left.localeCompare(right));
6839
+ return (await walkDirectory(baseCwd, "", PROJECT_FILE_TREE_LIMIT)).flatMap((entry) => {
6840
+ if (entry.isDirectory) return [];
6841
+ const path = displayPath(entry.path).replace(/\/+$/g, "");
6842
+ return path ? [path] : [];
6843
+ }).sort((left, right) => left.localeCompare(right));
6398
6844
  }
6399
6845
  async function readProjectFileContent(baseCwd, filePath) {
6400
6846
  const resolved = resolveProjectFilePath(baseCwd, filePath);
@@ -6423,46 +6869,54 @@ function directorySearchScore({ absolutePath, query, root }) {
6423
6869
  if (score === 0) return 0;
6424
6870
  return score - depth * 5;
6425
6871
  }
6872
+ async function searchDirectoriesFallbackLayer({ root, normalizedQuery, currentDirectories, results, maxResults }) {
6873
+ const eligibleDirectories = currentDirectories.filter((current) => current.depth < DIRECTORY_SEARCH_MAX_DEPTH);
6874
+ if (eligibleDirectories.length === 0 || results.length >= maxResults) return;
6875
+ const directoryEntries = await Promise.all(eligibleDirectories.map(async (current) => ({
6876
+ current,
6877
+ entries: await readDirectoryEntries(current.directory)
6878
+ })));
6879
+ const nextDirectories = [];
6880
+ for (const { current, entries } of directoryEntries) for (const entry of entries) {
6881
+ if (results.length >= maxResults) break;
6882
+ if (!entry.isDirectory()) continue;
6883
+ if (DIRECTORY_SEARCH_IGNORE_DIRECTORIES.has(entry.name)) continue;
6884
+ if (!normalizedQuery.startsWith(".") && entry.name.startsWith(".")) continue;
6885
+ const fullPath = join(current.directory, entry.name);
6886
+ const relativePath = `${displayPath(path.relative(root, fullPath))}/`;
6887
+ if (projectPathTextContains(relativePath.toLowerCase(), normalizedQuery)) results.push({
6888
+ path: relativePath,
6889
+ isDirectory: true
6890
+ });
6891
+ nextDirectories.push({
6892
+ directory: fullPath,
6893
+ depth: current.depth + 1
6894
+ });
6895
+ }
6896
+ await searchDirectoriesFallbackLayer({
6897
+ root,
6898
+ normalizedQuery,
6899
+ currentDirectories: nextDirectories,
6900
+ results,
6901
+ maxResults
6902
+ });
6903
+ }
6426
6904
  async function searchDirectoriesWithFallback({ root, query, maxResults }) {
6427
- const normalizedQuery = query.trim().toLowerCase();
6428
6905
  const results = [];
6429
- const queue = [{
6430
- directory: root,
6431
- depth: 0
6432
- }];
6433
- while (queue.length > 0 && results.length < maxResults) {
6434
- const current = queue.shift();
6435
- if (!current || current.depth >= DIRECTORY_SEARCH_MAX_DEPTH) continue;
6436
- let entries;
6437
- try {
6438
- entries = await readdir(current.directory, {
6439
- withFileTypes: true,
6440
- encoding: "utf8"
6441
- });
6442
- } catch {
6443
- continue;
6444
- }
6445
- for (const entry of entries) {
6446
- if (results.length >= maxResults) break;
6447
- if (!entry.isDirectory()) continue;
6448
- if (DIRECTORY_SEARCH_IGNORE_DIRECTORIES.has(entry.name)) continue;
6449
- if (!normalizedQuery.startsWith(".") && entry.name.startsWith(".")) continue;
6450
- const fullPath = join(current.directory, entry.name);
6451
- const relativePath = `${displayPath(path.relative(root, fullPath))}/`;
6452
- if (relativePath.toLowerCase().includes(normalizedQuery)) results.push({
6453
- path: relativePath,
6454
- isDirectory: true
6455
- });
6456
- queue.push({
6457
- directory: fullPath,
6458
- depth: current.depth + 1
6459
- });
6460
- }
6461
- }
6906
+ await searchDirectoriesFallbackLayer({
6907
+ root,
6908
+ normalizedQuery: query.trim().toLowerCase(),
6909
+ currentDirectories: [{
6910
+ directory: root,
6911
+ depth: 0
6912
+ }],
6913
+ results,
6914
+ maxResults
6915
+ });
6462
6916
  return results;
6463
6917
  }
6464
6918
  async function searchDirectoriesInRoot({ root, query, maxResults }) {
6465
- const args = [
6919
+ const results = await runFdSearchCandidates([
6466
6920
  "--base-directory",
6467
6921
  root,
6468
6922
  "--max-depth",
@@ -6498,11 +6952,8 @@ async function searchDirectoriesInRoot({ root, query, maxResults }) {
6498
6952
  "--exclude",
6499
6953
  "node_modules",
6500
6954
  buildFdPathQuery(query)
6501
- ];
6502
- for (const command of ["fd", "fdfind"]) {
6503
- const results = await runFdSearch(command, args);
6504
- if (results !== void 0) return results.filter((entry) => entry.isDirectory);
6505
- }
6955
+ ]);
6956
+ if (results !== void 0) return results.filter((entry) => entry.isDirectory);
6506
6957
  return await searchDirectoriesWithFallback({
6507
6958
  root,
6508
6959
  query,
@@ -6521,37 +6972,40 @@ async function searchDirectoryEntries(query, baseCwd) {
6521
6972
  if (baseCwd && !pathIsInside(baseCwd, homeDirectory)) roots.push(baseCwd);
6522
6973
  const seen = /* @__PURE__ */ new Set();
6523
6974
  const matches = [];
6524
- for (const root of roots) {
6975
+ const rootEntries = await Promise.all(roots.map(async (root) => {
6525
6976
  let rootStats;
6526
6977
  try {
6527
6978
  rootStats = await stat(root);
6528
6979
  } catch {
6529
- continue;
6980
+ return [];
6530
6981
  }
6531
- if (!rootStats.isDirectory()) continue;
6532
- const entries = await searchDirectoriesInRoot({
6982
+ if (!rootStats.isDirectory()) return [];
6983
+ return (await searchDirectoriesInRoot({
6533
6984
  root,
6534
6985
  query: normalizedQuery,
6535
6986
  maxResults: DIRECTORY_SEARCH_LIMIT * 4
6987
+ })).map((entry) => ({
6988
+ entry,
6989
+ root
6990
+ }));
6991
+ }));
6992
+ for (const { entry, root } of rootEntries.flat()) {
6993
+ const relativePath = displayPath(entry.path).replace(/\/+$/g, "");
6994
+ if (!relativePath) continue;
6995
+ const absolutePath = resolve(root, relativePath);
6996
+ if (seen.has(absolutePath)) continue;
6997
+ seen.add(absolutePath);
6998
+ const score = directorySearchScore({
6999
+ absolutePath,
7000
+ query: normalizedQuery,
7001
+ root
7002
+ });
7003
+ if (score <= 0) continue;
7004
+ matches.push({
7005
+ absolutePath,
7006
+ root,
7007
+ score
6536
7008
  });
6537
- for (const entry of entries) {
6538
- const relativePath = displayPath(entry.path).replace(/\/+$/g, "");
6539
- if (!relativePath) continue;
6540
- const absolutePath = resolve(root, relativePath);
6541
- if (seen.has(absolutePath)) continue;
6542
- seen.add(absolutePath);
6543
- const score = directorySearchScore({
6544
- absolutePath,
6545
- query: normalizedQuery,
6546
- root
6547
- });
6548
- if (score <= 0) continue;
6549
- matches.push({
6550
- absolutePath,
6551
- root,
6552
- score
6553
- });
6554
- }
6555
7009
  }
6556
7010
  return matches.sort((left, right) => {
6557
7011
  if (right.score !== left.score) return right.score - left.score;
@@ -6571,10 +7025,13 @@ async function listFileReferenceEntries(query, baseCwd, { isQuotedPrefix = false
6571
7025
  const scopedQuery = await resolveScopedFileReferenceQuery(normalizedQuery, baseCwd);
6572
7026
  const searchBaseDir = scopedQuery?.searchBaseDir ?? baseCwd;
6573
7027
  const searchQuery = scopedQuery?.query ?? normalizedQuery;
6574
- return (await walkDirectory(searchBaseDir, searchQuery, 100)).map((entry) => ({
6575
- ...entry,
6576
- score: scoreFileReferenceEntry(entry.path, searchQuery, entry.isDirectory)
6577
- })).filter((entry) => entry.score > 0).sort((left, right) => right.score - left.score).slice(0, 20).map((entry) => {
7028
+ return (await walkDirectory(searchBaseDir, searchQuery, 100)).flatMap((entry) => {
7029
+ const score = scoreFileReferenceEntry(entry.path, searchQuery, entry.isDirectory);
7030
+ return score > 0 ? [{
7031
+ ...entry,
7032
+ score
7033
+ }] : [];
7034
+ }).sort((left, right) => right.score - left.score).slice(0, 20).map((entry) => {
6578
7035
  const pathWithoutSlash = entry.isDirectory ? entry.path.slice(0, -1) : entry.path;
6579
7036
  const displayValue = scopedQuery ? scopedDisplayPath(scopedQuery.displayBase, pathWithoutSlash) : pathWithoutSlash;
6580
7037
  return {
@@ -6588,7 +7045,7 @@ async function listFileReferenceEntries(query, baseCwd, { isQuotedPrefix = false
6588
7045
  };
6589
7046
  });
6590
7047
  }
6591
- var Route$42 = createFileRoute("/api/path-completions")({ server: { handlers: { POST: async ({ request }) => {
7048
+ var Route$47 = createFileRoute("/api/path-completions")({ server: { handlers: { POST: async ({ request }) => {
6592
7049
  try {
6593
7050
  const body = await readRequestJson(request);
6594
7051
  const { context, activeEntry } = await getPicoRuntime().resolveRequest(request);
@@ -6604,7 +7061,7 @@ var Route$42 = createFileRoute("/api/path-completions")({ server: { handlers: {
6604
7061
  return routeErrorResponse(error, "Failed to list path completions");
6605
7062
  }
6606
7063
  } } } });
6607
- var Route$41 = createFileRoute("/api/model")({ server: { handlers: { POST: async ({ request }) => {
7064
+ var Route$46 = createFileRoute("/api/model")({ server: { handlers: { POST: async ({ request }) => {
6608
7065
  try {
6609
7066
  const body = await readRequestJson(request);
6610
7067
  return jsonResponse(await getPicoRuntime().setModel(request, body));
@@ -6612,7 +7069,7 @@ var Route$41 = createFileRoute("/api/model")({ server: { handlers: { POST: async
6612
7069
  return routeErrorResponse(error, "Failed to update model");
6613
7070
  }
6614
7071
  } } } });
6615
- var Route$40 = createFileRoute("/api/highlight")({ server: { handlers: { POST: async ({ request }) => {
7072
+ var Route$45 = createFileRoute("/api/highlight")({ server: { handlers: { POST: async ({ request }) => {
6616
7073
  try {
6617
7074
  const body = await readRequestJson(request);
6618
7075
  return jsonResponse(await getPicoRuntime().highlightCode(body.code, body.language));
@@ -6620,7 +7077,7 @@ var Route$40 = createFileRoute("/api/highlight")({ server: { handlers: { POST: a
6620
7077
  return routeErrorResponse(error, "Failed to highlight code");
6621
7078
  }
6622
7079
  } } } });
6623
- var Route$39 = createFileRoute("/api/git-status")({ server: { handlers: { GET: async ({ request }) => {
7080
+ var Route$44 = createFileRoute("/api/git-status")({ server: { handlers: { GET: async ({ request }) => {
6624
7081
  const requestedCwd = new URL(request.url).searchParams.get("cwd") || "";
6625
7082
  if (!requestedCwd.trim()) return errorResponse("cwd is required");
6626
7083
  try {
@@ -6635,7 +7092,7 @@ var Route$39 = createFileRoute("/api/git-status")({ server: { handlers: { GET: a
6635
7092
  return routeErrorResponse(error, "Failed to read git status");
6636
7093
  }
6637
7094
  } } } });
6638
- var Route$38 = createFileRoute("/api/git-stage")({ server: { handlers: { POST: async ({ request }) => {
7095
+ var Route$43 = createFileRoute("/api/git-stage")({ server: { handlers: { POST: async ({ request }) => {
6639
7096
  try {
6640
7097
  const body = await readRequestJson(request);
6641
7098
  const requestedCwd = typeof body.cwd === "string" ? body.cwd : "";
@@ -6656,7 +7113,7 @@ var Route$38 = createFileRoute("/api/git-stage")({ server: { handlers: { POST: a
6656
7113
  return routeErrorResponse(error, "Failed to stage changes");
6657
7114
  }
6658
7115
  } } } });
6659
- var Route$37 = createFileRoute("/api/git-review")({ server: { handlers: { GET: async ({ request }) => {
7116
+ var Route$42 = createFileRoute("/api/git-review")({ server: { handlers: { GET: async ({ request }) => {
6660
7117
  const url = new URL(request.url);
6661
7118
  const requestedCwd = url.searchParams.get("cwd") || "";
6662
7119
  const requestedPath = url.searchParams.get("path") || "";
@@ -6679,7 +7136,7 @@ var Route$37 = createFileRoute("/api/git-review")({ server: { handlers: { GET: a
6679
7136
  return routeErrorResponse(error, "Failed to read git review file");
6680
7137
  }
6681
7138
  } } } });
6682
- var Route$36 = createFileRoute("/api/git-push")({ server: { handlers: { POST: async ({ request }) => {
7139
+ var Route$41 = createFileRoute("/api/git-push")({ server: { handlers: { POST: async ({ request }) => {
6683
7140
  try {
6684
7141
  const body = await readRequestJson(request);
6685
7142
  const requestedCwd = typeof body.cwd === "string" ? body.cwd : "";
@@ -6698,7 +7155,7 @@ var Route$36 = createFileRoute("/api/git-push")({ server: { handlers: { POST: as
6698
7155
  return routeErrorResponse(error, "Failed to push changes");
6699
7156
  }
6700
7157
  } } } });
6701
- var Route$35 = createFileRoute("/api/git-pull")({ server: { handlers: { POST: async ({ request }) => {
7158
+ var Route$40 = createFileRoute("/api/git-pull")({ server: { handlers: { POST: async ({ request }) => {
6702
7159
  try {
6703
7160
  const body = await readRequestJson(request);
6704
7161
  const requestedCwd = typeof body.cwd === "string" ? body.cwd : "";
@@ -6716,7 +7173,7 @@ var Route$35 = createFileRoute("/api/git-pull")({ server: { handlers: { POST: as
6716
7173
  return routeErrorResponse(error, "Failed to pull changes");
6717
7174
  }
6718
7175
  } } } });
6719
- var Route$34 = createFileRoute("/api/git-discard")({ server: { handlers: { POST: async ({ request }) => {
7176
+ var Route$39 = createFileRoute("/api/git-discard")({ server: { handlers: { POST: async ({ request }) => {
6720
7177
  try {
6721
7178
  const body = await readRequestJson(request);
6722
7179
  const requestedCwd = typeof body.cwd === "string" ? body.cwd : "";
@@ -6738,7 +7195,7 @@ var Route$34 = createFileRoute("/api/git-discard")({ server: { handlers: { POST:
6738
7195
  return routeErrorResponse(error, "Failed to discard changes");
6739
7196
  }
6740
7197
  } } } });
6741
- var Route$33 = createFileRoute("/api/git-diff")({ server: { handlers: { GET: async ({ request }) => {
7198
+ var Route$38 = createFileRoute("/api/git-diff")({ server: { handlers: { GET: async ({ request }) => {
6742
7199
  const url = new URL(request.url);
6743
7200
  const requestedCwd = url.searchParams.get("cwd") || "";
6744
7201
  const requestedPath = url.searchParams.get("path") || "";
@@ -6758,7 +7215,28 @@ var Route$33 = createFileRoute("/api/git-diff")({ server: { handlers: { GET: asy
6758
7215
  return routeErrorResponse(error, "Failed to read git diff");
6759
7216
  }
6760
7217
  } } } });
6761
- var Route$32 = createFileRoute("/api/git-commit-message")({ server: { handlers: { POST: async ({ request }) => {
7218
+ var Route$37 = createFileRoute("/api/git-commit-remote-url")({ server: { handlers: { GET: async ({ request }) => {
7219
+ try {
7220
+ const url = new URL(request.url);
7221
+ const requestedCwd = url.searchParams.get("cwd") || "";
7222
+ const commit = url.searchParams.get("commit") || "";
7223
+ if (!requestedCwd.trim()) throw new Error("cwd is required");
7224
+ if (!commit.trim()) throw new Error("commit is required");
7225
+ const { context, activeEntry } = await getPicoRuntime().resolveRequest(request);
7226
+ const cwd = await resolveDirectoryPath(requestedCwd, getPicoRuntime().getBaseCwd(activeEntry, context));
7227
+ const result = await readDirectoryGitCommitRemoteUrl(cwd, commit);
7228
+ if (!result?.remoteUrl) throw new Error("No remote URL found");
7229
+ return jsonResponse({
7230
+ ok: true,
7231
+ cwd,
7232
+ commit: result.commit,
7233
+ remoteUrl: result.remoteUrl
7234
+ });
7235
+ } catch (error) {
7236
+ return routeErrorResponse(error, "Failed to read commit remote URL");
7237
+ }
7238
+ } } } });
7239
+ var Route$36 = createFileRoute("/api/git-commit-message")({ server: { handlers: { POST: async ({ request }) => {
6762
7240
  try {
6763
7241
  const body = await readRequestJson(request);
6764
7242
  const requestedCwd = typeof body.cwd === "string" ? body.cwd : "";
@@ -6777,7 +7255,93 @@ var Route$32 = createFileRoute("/api/git-commit-message")({ server: { handlers:
6777
7255
  return routeErrorResponse(error, "Failed to generate commit message");
6778
7256
  }
6779
7257
  } } } });
6780
- var Route$31 = createFileRoute("/api/git-commit")({ server: { handlers: { POST: async ({ request }) => {
7258
+ var Route$35 = createFileRoute("/api/git-commit-files")({ server: { handlers: { GET: async ({ request }) => {
7259
+ try {
7260
+ const url = new URL(request.url);
7261
+ const requestedCwd = url.searchParams.get("cwd") || "";
7262
+ const commit = url.searchParams.get("commit") || "";
7263
+ if (!requestedCwd.trim()) throw new Error("cwd is required");
7264
+ if (!commit.trim()) throw new Error("commit is required");
7265
+ const { context, activeEntry } = await getPicoRuntime().resolveRequest(request);
7266
+ const cwd = await resolveDirectoryPath(requestedCwd, getPicoRuntime().getBaseCwd(activeEntry, context));
7267
+ return jsonResponse({
7268
+ ok: true,
7269
+ cwd,
7270
+ commit,
7271
+ files: await readDirectoryGitCommitFiles(cwd, commit) || []
7272
+ });
7273
+ } catch (error) {
7274
+ return routeErrorResponse(error, "Failed to read commit files");
7275
+ }
7276
+ } } } });
7277
+ function normalizeGitCommitDiffMode(value) {
7278
+ if (value === "head" || value === "previous") return value;
7279
+ return "commit";
7280
+ }
7281
+ var Route$34 = createFileRoute("/api/git-commit-diff")({ server: { handlers: { GET: async ({ request }) => {
7282
+ try {
7283
+ const url = new URL(request.url);
7284
+ const requestedCwd = url.searchParams.get("cwd") || "";
7285
+ const commit = url.searchParams.get("commit") || "";
7286
+ const mode = normalizeGitCommitDiffMode(url.searchParams.get("mode"));
7287
+ const path = url.searchParams.get("path") || void 0;
7288
+ const previousPath = url.searchParams.get("previousPath") || void 0;
7289
+ if (!requestedCwd.trim()) throw new Error("cwd is required");
7290
+ if (!commit.trim()) throw new Error("commit is required");
7291
+ const { context, activeEntry } = await getPicoRuntime().resolveRequest(request);
7292
+ const cwd = await resolveDirectoryPath(requestedCwd, getPicoRuntime().getBaseCwd(activeEntry, context));
7293
+ const result = await readDirectoryGitCommitDiff(cwd, commit, mode, path, previousPath);
7294
+ return jsonResponse({
7295
+ ok: true,
7296
+ cwd,
7297
+ commit: result?.commit || commit,
7298
+ mode,
7299
+ title: result?.title || commit,
7300
+ ...result?.path ? { path: result.path } : {},
7301
+ ...result?.previousPath ? { previousPath: result.previousPath } : {},
7302
+ patch: result?.patch || "No git repository detected."
7303
+ });
7304
+ } catch (error) {
7305
+ return routeErrorResponse(error, "Failed to read commit diff");
7306
+ }
7307
+ } } } });
7308
+ var gitCommitActions = new Set([
7309
+ "checkout",
7310
+ "cherry-pick",
7311
+ "revert",
7312
+ "tag",
7313
+ "reset",
7314
+ "rebase",
7315
+ "drop",
7316
+ "squash"
7317
+ ]);
7318
+ var Route$33 = createFileRoute("/api/git-commit-action")({ server: { handlers: { POST: async ({ request }) => {
7319
+ try {
7320
+ const body = await readRequestJson(request);
7321
+ const requestedCwd = typeof body.cwd === "string" ? body.cwd : "";
7322
+ const action = typeof body.action === "string" ? body.action : "";
7323
+ const commit = typeof body.commit === "string" ? body.commit : "";
7324
+ if (!requestedCwd.trim()) throw new Error("cwd is required");
7325
+ if (!gitCommitActions.has(action)) throw new Error("action is required");
7326
+ if (!commit.trim()) throw new Error("commit is required");
7327
+ const { context, activeEntry } = await getPicoRuntime().resolveRequest(request);
7328
+ const cwd = await resolveDirectoryPath(requestedCwd, getPicoRuntime().getBaseCwd(activeEntry, context));
7329
+ const result = await runDirectoryGitCommitAction(cwd, action, commit, {
7330
+ tagName: typeof body.tagName === "string" ? body.tagName : "",
7331
+ resetMode: typeof body.resetMode === "string" ? body.resetMode : "",
7332
+ message: typeof body.message === "string" ? body.message : ""
7333
+ });
7334
+ return jsonResponse({
7335
+ ok: true,
7336
+ cwd,
7337
+ stdout: result.stdout,
7338
+ stderr: result.stderr
7339
+ });
7340
+ } catch (error) {
7341
+ return routeErrorResponse(error, "Failed to run commit action");
7342
+ }
7343
+ } } } });
7344
+ var Route$32 = createFileRoute("/api/git-commit")({ server: { handlers: { POST: async ({ request }) => {
6781
7345
  try {
6782
7346
  const body = await readRequestJson(request);
6783
7347
  const requestedCwd = typeof body.cwd === "string" ? body.cwd : "";
@@ -6802,7 +7366,7 @@ var Route$31 = createFileRoute("/api/git-commit")({ server: { handlers: { POST:
6802
7366
  return routeErrorResponse(error, "Failed to commit changes");
6803
7367
  }
6804
7368
  } } } });
6805
- var Route$30 = createFileRoute("/api/git-checkout")({ server: { handlers: { POST: async ({ request }) => {
7369
+ var Route$31 = createFileRoute("/api/git-checkout")({ server: { handlers: { POST: async ({ request }) => {
6806
7370
  try {
6807
7371
  const body = await readRequestJson(request);
6808
7372
  const requestedCwd = typeof body.cwd === "string" ? body.cwd : "";
@@ -6852,7 +7416,7 @@ function getRuntimeRequestForGitChanges(request, url) {
6852
7416
  method: request.method
6853
7417
  });
6854
7418
  }
6855
- var Route$29 = createFileRoute("/api/git-changes")({ server: { handlers: { GET: async ({ request }) => {
7419
+ var Route$30 = createFileRoute("/api/git-changes")({ server: { handlers: { GET: async ({ request }) => {
6856
7420
  const url = new URL(request.url);
6857
7421
  const requestedCwd = url.searchParams.get("cwd") || "";
6858
7422
  const gitScope = getGitChangesScope(url);
@@ -6922,7 +7486,7 @@ var Route$29 = createFileRoute("/api/git-changes")({ server: { handlers: { GET:
6922
7486
  return routeErrorResponse(error, "Failed to read git changes");
6923
7487
  }
6924
7488
  } } } });
6925
- var Route$28 = createFileRoute("/api/file-completions")({ server: { handlers: { POST: async ({ request }) => {
7489
+ var Route$29 = createFileRoute("/api/file-completions")({ server: { handlers: { POST: async ({ request }) => {
6926
7490
  try {
6927
7491
  const body = await readRequestJson(request);
6928
7492
  const { context, activeEntry } = await getPicoRuntime().resolveRequest(request);
@@ -6939,7 +7503,7 @@ var Route$28 = createFileRoute("/api/file-completions")({ server: { handlers: {
6939
7503
  return routeErrorResponse(error, "Failed to list file completions");
6940
7504
  }
6941
7505
  } } } });
6942
- var Route$27 = createFileRoute("/api/directory-sessions-indexes")({ server: { handlers: { GET: async ({ request }) => {
7506
+ var Route$28 = createFileRoute("/api/directory-sessions-indexes")({ server: { handlers: { GET: async ({ request }) => {
6943
7507
  const directories = new URL(request.url).searchParams.getAll("directory");
6944
7508
  if (directories.length === 0) return errorResponse("at least one directory is required");
6945
7509
  try {
@@ -6948,7 +7512,7 @@ var Route$27 = createFileRoute("/api/directory-sessions-indexes")({ server: { ha
6948
7512
  return routeErrorResponse(error, "Failed to list directory session indexes");
6949
7513
  }
6950
7514
  } } } });
6951
- var Route$26 = createFileRoute("/api/directory-sessions-index")({ server: { handlers: { GET: async ({ request }) => {
7515
+ var Route$27 = createFileRoute("/api/directory-sessions-index")({ server: { handlers: { GET: async ({ request }) => {
6952
7516
  const directory = new URL(request.url).searchParams.get("directory") || "";
6953
7517
  if (!directory.trim()) return errorResponse("directory is required");
6954
7518
  try {
@@ -6957,7 +7521,7 @@ var Route$26 = createFileRoute("/api/directory-sessions-index")({ server: { hand
6957
7521
  return routeErrorResponse(error, "Failed to list directory session index");
6958
7522
  }
6959
7523
  } } } });
6960
- var Route$25 = createFileRoute("/api/directory-sessions")({ server: { handlers: { GET: async ({ request }) => {
7524
+ var Route$26 = createFileRoute("/api/directory-sessions")({ server: { handlers: { GET: async ({ request }) => {
6961
7525
  const url = new URL(request.url);
6962
7526
  const directory = url.searchParams.get("directory") || "";
6963
7527
  const offset = Number.parseInt(url.searchParams.get("offset") || "0", 10);
@@ -6972,7 +7536,7 @@ var Route$25 = createFileRoute("/api/directory-sessions")({ server: { handlers:
6972
7536
  return routeErrorResponse(error, "Failed to list directory sessions");
6973
7537
  }
6974
7538
  } } } });
6975
- var Route$24 = createFileRoute("/api/directory-search")({ server: { handlers: { POST: async ({ request }) => {
7539
+ var Route$25 = createFileRoute("/api/directory-search")({ server: { handlers: { POST: async ({ request }) => {
6976
7540
  try {
6977
7541
  const body = await readRequestJson(request);
6978
7542
  const { context, activeEntry } = await getPicoRuntime().resolveRequest(request);
@@ -6988,14 +7552,14 @@ var Route$24 = createFileRoute("/api/directory-search")({ server: { handlers: {
6988
7552
  return routeErrorResponse(error, "Failed to search directories");
6989
7553
  }
6990
7554
  } } } });
6991
- var Route$23 = createFileRoute("/api/abort")({ server: { handlers: { POST: async ({ request }) => {
7555
+ var Route$24 = createFileRoute("/api/abort")({ server: { handlers: { POST: async ({ request }) => {
6992
7556
  try {
6993
7557
  return jsonResponse(await getPicoRuntime().abort(request));
6994
7558
  } catch (error) {
6995
7559
  return routeErrorResponse(error, "Failed to abort session");
6996
7560
  }
6997
7561
  } } } });
6998
- var Route$22 = createFileRoute("/api/ui/$id")({ server: { handlers: { POST: async ({ request, params }) => {
7562
+ var Route$23 = createFileRoute("/api/ui/$id")({ server: { handlers: { POST: async ({ request, params }) => {
6999
7563
  try {
7000
7564
  const body = await readRequestJson(request);
7001
7565
  return jsonResponse(await getPicoRuntime().resolveUiRequest(params.id, body));
@@ -7003,7 +7567,7 @@ var Route$22 = createFileRoute("/api/ui/$id")({ server: { handlers: { POST: asyn
7003
7567
  return routeErrorResponse(error, "Failed to resolve UI request");
7004
7568
  }
7005
7569
  } } } });
7006
- var Route$21 = createFileRoute("/api/settings/hide-thinking")({ server: { handlers: { POST: async ({ request }) => {
7570
+ var Route$22 = createFileRoute("/api/settings/hide-thinking")({ server: { handlers: { POST: async ({ request }) => {
7007
7571
  try {
7008
7572
  const body = await readRequestJson(request);
7009
7573
  return jsonResponse(await getPicoRuntime().setHideThinking(body));
@@ -7011,7 +7575,7 @@ var Route$21 = createFileRoute("/api/settings/hide-thinking")({ server: { handle
7011
7575
  return routeErrorResponse(error, "Failed to update hide-thinking setting");
7012
7576
  }
7013
7577
  } } } });
7014
- var Route$20 = createFileRoute("/api/sessions/delete")({ server: { handlers: { POST: async ({ request }) => {
7578
+ var Route$21 = createFileRoute("/api/sessions/delete")({ server: { handlers: { POST: async ({ request }) => {
7015
7579
  try {
7016
7580
  const body = await readRequestJson(request);
7017
7581
  return jsonResponse(await getPicoRuntime().deleteSessions(request, body));
@@ -7019,7 +7583,7 @@ var Route$20 = createFileRoute("/api/sessions/delete")({ server: { handlers: { P
7019
7583
  return routeErrorResponse(error, "Failed to delete sessions");
7020
7584
  }
7021
7585
  } } } });
7022
- var Route$19 = createFileRoute("/api/session/tree")({ server: { handlers: {
7586
+ var Route$20 = createFileRoute("/api/session/tree")({ server: { handlers: {
7023
7587
  GET: async ({ request }) => {
7024
7588
  try {
7025
7589
  return jsonResponse(await getPicoRuntime().getSessionTreeForRequest(request));
@@ -7036,14 +7600,14 @@ var Route$19 = createFileRoute("/api/session/tree")({ server: { handlers: {
7036
7600
  }
7037
7601
  }
7038
7602
  } } });
7039
- var Route$18 = createFileRoute("/api/session/select")({ server: { handlers: { POST: async ({ request }) => {
7603
+ var Route$19 = createFileRoute("/api/session/select")({ server: { handlers: { POST: async ({ request }) => {
7040
7604
  try {
7041
7605
  return jsonResponse(await getPicoRuntime().selectSession(request));
7042
7606
  } catch (error) {
7043
7607
  return routeErrorResponse(error, "Failed to select session");
7044
7608
  }
7045
7609
  } } } });
7046
- var Route$17 = createFileRoute("/api/session/rename")({ server: { handlers: { POST: async ({ request }) => {
7610
+ var Route$18 = createFileRoute("/api/session/rename")({ server: { handlers: { POST: async ({ request }) => {
7047
7611
  try {
7048
7612
  const body = await readRequestJson(request);
7049
7613
  return jsonResponse(await getPicoRuntime().renameSession(body));
@@ -7051,6 +7615,14 @@ var Route$17 = createFileRoute("/api/session/rename")({ server: { handlers: { PO
7051
7615
  return routeErrorResponse(error, "Failed to rename session");
7052
7616
  }
7053
7617
  } } } });
7618
+ var Route$17 = createFileRoute("/api/session/read-state")({ server: { handlers: { POST: async ({ request }) => {
7619
+ try {
7620
+ const body = await readRequestJson(request);
7621
+ return jsonResponse(await getPicoRuntime().setSessionReadState(request, body));
7622
+ } catch (error) {
7623
+ return routeErrorResponse(error, "Failed to update session read state");
7624
+ }
7625
+ } } } });
7054
7626
  var Route$16 = createFileRoute("/api/session/new")({ server: { handlers: { POST: async ({ request }) => {
7055
7627
  try {
7056
7628
  const body = await readRequestJson(request);
@@ -7224,220 +7796,245 @@ var Route = createFileRoute("/api/session/tree/label")({ server: { handlers: { P
7224
7796
  return routeErrorResponse(error, "Failed to update tree label");
7225
7797
  }
7226
7798
  } } } });
7227
- var EventsRoute = Route$47.update({
7799
+ var EventsRoute = Route$52.update({
7228
7800
  id: "/events",
7229
7801
  path: "/events",
7230
- getParentRoute: () => Route$48
7802
+ getParentRoute: () => Route$53
7231
7803
  });
7232
- var IndexRoute = Route$49.update({
7804
+ var IndexRoute = Route$54.update({
7233
7805
  id: "/",
7234
7806
  path: "/",
7235
- getParentRoute: () => Route$48
7807
+ getParentRoute: () => Route$53
7236
7808
  });
7237
- var ApiThinkingRoute = Route$46.update({
7809
+ var ApiThinkingRoute = Route$51.update({
7238
7810
  id: "/api/thinking",
7239
7811
  path: "/api/thinking",
7240
- getParentRoute: () => Route$48
7812
+ getParentRoute: () => Route$53
7241
7813
  });
7242
- var ApiSlashCommandRoute = Route$45.update({
7814
+ var ApiSlashCommandRoute = Route$50.update({
7243
7815
  id: "/api/slash-command",
7244
7816
  path: "/api/slash-command",
7245
- getParentRoute: () => Route$48
7817
+ getParentRoute: () => Route$53
7246
7818
  });
7247
- var ApiProviderUsageRoute = Route$44.update({
7819
+ var ApiProviderUsageRoute = Route$49.update({
7248
7820
  id: "/api/provider-usage",
7249
7821
  path: "/api/provider-usage",
7250
- getParentRoute: () => Route$48
7822
+ getParentRoute: () => Route$53
7251
7823
  });
7252
- var ApiPromptRoute = Route$43.update({
7824
+ var ApiPromptRoute = Route$48.update({
7253
7825
  id: "/api/prompt",
7254
7826
  path: "/api/prompt",
7255
- getParentRoute: () => Route$48
7827
+ getParentRoute: () => Route$53
7256
7828
  });
7257
- var ApiPathCompletionsRoute = Route$42.update({
7829
+ var ApiPathCompletionsRoute = Route$47.update({
7258
7830
  id: "/api/path-completions",
7259
7831
  path: "/api/path-completions",
7260
- getParentRoute: () => Route$48
7832
+ getParentRoute: () => Route$53
7261
7833
  });
7262
- var ApiModelRoute = Route$41.update({
7834
+ var ApiModelRoute = Route$46.update({
7263
7835
  id: "/api/model",
7264
7836
  path: "/api/model",
7265
- getParentRoute: () => Route$48
7837
+ getParentRoute: () => Route$53
7266
7838
  });
7267
- var ApiHighlightRoute = Route$40.update({
7839
+ var ApiHighlightRoute = Route$45.update({
7268
7840
  id: "/api/highlight",
7269
7841
  path: "/api/highlight",
7270
- getParentRoute: () => Route$48
7842
+ getParentRoute: () => Route$53
7271
7843
  });
7272
- var ApiGitStatusRoute = Route$39.update({
7844
+ var ApiGitStatusRoute = Route$44.update({
7273
7845
  id: "/api/git-status",
7274
7846
  path: "/api/git-status",
7275
- getParentRoute: () => Route$48
7847
+ getParentRoute: () => Route$53
7276
7848
  });
7277
- var ApiGitStageRoute = Route$38.update({
7849
+ var ApiGitStageRoute = Route$43.update({
7278
7850
  id: "/api/git-stage",
7279
7851
  path: "/api/git-stage",
7280
- getParentRoute: () => Route$48
7852
+ getParentRoute: () => Route$53
7281
7853
  });
7282
- var ApiGitReviewRoute = Route$37.update({
7854
+ var ApiGitReviewRoute = Route$42.update({
7283
7855
  id: "/api/git-review",
7284
7856
  path: "/api/git-review",
7285
- getParentRoute: () => Route$48
7857
+ getParentRoute: () => Route$53
7286
7858
  });
7287
- var ApiGitPushRoute = Route$36.update({
7859
+ var ApiGitPushRoute = Route$41.update({
7288
7860
  id: "/api/git-push",
7289
7861
  path: "/api/git-push",
7290
- getParentRoute: () => Route$48
7862
+ getParentRoute: () => Route$53
7291
7863
  });
7292
- var ApiGitPullRoute = Route$35.update({
7864
+ var ApiGitPullRoute = Route$40.update({
7293
7865
  id: "/api/git-pull",
7294
7866
  path: "/api/git-pull",
7295
- getParentRoute: () => Route$48
7867
+ getParentRoute: () => Route$53
7296
7868
  });
7297
- var ApiGitDiscardRoute = Route$34.update({
7869
+ var ApiGitDiscardRoute = Route$39.update({
7298
7870
  id: "/api/git-discard",
7299
7871
  path: "/api/git-discard",
7300
- getParentRoute: () => Route$48
7872
+ getParentRoute: () => Route$53
7301
7873
  });
7302
- var ApiGitDiffRoute = Route$33.update({
7874
+ var ApiGitDiffRoute = Route$38.update({
7303
7875
  id: "/api/git-diff",
7304
7876
  path: "/api/git-diff",
7305
- getParentRoute: () => Route$48
7877
+ getParentRoute: () => Route$53
7878
+ });
7879
+ var ApiGitCommitRemoteUrlRoute = Route$37.update({
7880
+ id: "/api/git-commit-remote-url",
7881
+ path: "/api/git-commit-remote-url",
7882
+ getParentRoute: () => Route$53
7306
7883
  });
7307
- var ApiGitCommitMessageRoute = Route$32.update({
7884
+ var ApiGitCommitMessageRoute = Route$36.update({
7308
7885
  id: "/api/git-commit-message",
7309
7886
  path: "/api/git-commit-message",
7310
- getParentRoute: () => Route$48
7887
+ getParentRoute: () => Route$53
7311
7888
  });
7312
- var ApiGitCommitRoute = Route$31.update({
7889
+ var ApiGitCommitFilesRoute = Route$35.update({
7890
+ id: "/api/git-commit-files",
7891
+ path: "/api/git-commit-files",
7892
+ getParentRoute: () => Route$53
7893
+ });
7894
+ var ApiGitCommitDiffRoute = Route$34.update({
7895
+ id: "/api/git-commit-diff",
7896
+ path: "/api/git-commit-diff",
7897
+ getParentRoute: () => Route$53
7898
+ });
7899
+ var ApiGitCommitActionRoute = Route$33.update({
7900
+ id: "/api/git-commit-action",
7901
+ path: "/api/git-commit-action",
7902
+ getParentRoute: () => Route$53
7903
+ });
7904
+ var ApiGitCommitRoute = Route$32.update({
7313
7905
  id: "/api/git-commit",
7314
7906
  path: "/api/git-commit",
7315
- getParentRoute: () => Route$48
7907
+ getParentRoute: () => Route$53
7316
7908
  });
7317
- var ApiGitCheckoutRoute = Route$30.update({
7909
+ var ApiGitCheckoutRoute = Route$31.update({
7318
7910
  id: "/api/git-checkout",
7319
7911
  path: "/api/git-checkout",
7320
- getParentRoute: () => Route$48
7912
+ getParentRoute: () => Route$53
7321
7913
  });
7322
- var ApiGitChangesRoute = Route$29.update({
7914
+ var ApiGitChangesRoute = Route$30.update({
7323
7915
  id: "/api/git-changes",
7324
7916
  path: "/api/git-changes",
7325
- getParentRoute: () => Route$48
7917
+ getParentRoute: () => Route$53
7326
7918
  });
7327
- var ApiFileCompletionsRoute = Route$28.update({
7919
+ var ApiFileCompletionsRoute = Route$29.update({
7328
7920
  id: "/api/file-completions",
7329
7921
  path: "/api/file-completions",
7330
- getParentRoute: () => Route$48
7922
+ getParentRoute: () => Route$53
7331
7923
  });
7332
- var ApiDirectorySessionsIndexesRoute = Route$27.update({
7924
+ var ApiDirectorySessionsIndexesRoute = Route$28.update({
7333
7925
  id: "/api/directory-sessions-indexes",
7334
7926
  path: "/api/directory-sessions-indexes",
7335
- getParentRoute: () => Route$48
7927
+ getParentRoute: () => Route$53
7336
7928
  });
7337
- var ApiDirectorySessionsIndexRoute = Route$26.update({
7929
+ var ApiDirectorySessionsIndexRoute = Route$27.update({
7338
7930
  id: "/api/directory-sessions-index",
7339
7931
  path: "/api/directory-sessions-index",
7340
- getParentRoute: () => Route$48
7932
+ getParentRoute: () => Route$53
7341
7933
  });
7342
- var ApiDirectorySessionsRoute = Route$25.update({
7934
+ var ApiDirectorySessionsRoute = Route$26.update({
7343
7935
  id: "/api/directory-sessions",
7344
7936
  path: "/api/directory-sessions",
7345
- getParentRoute: () => Route$48
7937
+ getParentRoute: () => Route$53
7346
7938
  });
7347
- var ApiDirectorySearchRoute = Route$24.update({
7939
+ var ApiDirectorySearchRoute = Route$25.update({
7348
7940
  id: "/api/directory-search",
7349
7941
  path: "/api/directory-search",
7350
- getParentRoute: () => Route$48
7942
+ getParentRoute: () => Route$53
7351
7943
  });
7352
- var ApiAbortRoute = Route$23.update({
7944
+ var ApiAbortRoute = Route$24.update({
7353
7945
  id: "/api/abort",
7354
7946
  path: "/api/abort",
7355
- getParentRoute: () => Route$48
7947
+ getParentRoute: () => Route$53
7356
7948
  });
7357
- var ApiUiIdRoute = Route$22.update({
7949
+ var ApiUiIdRoute = Route$23.update({
7358
7950
  id: "/api/ui/$id",
7359
7951
  path: "/api/ui/$id",
7360
- getParentRoute: () => Route$48
7952
+ getParentRoute: () => Route$53
7361
7953
  });
7362
- var ApiSettingsHideThinkingRoute = Route$21.update({
7954
+ var ApiSettingsHideThinkingRoute = Route$22.update({
7363
7955
  id: "/api/settings/hide-thinking",
7364
7956
  path: "/api/settings/hide-thinking",
7365
- getParentRoute: () => Route$48
7957
+ getParentRoute: () => Route$53
7366
7958
  });
7367
- var ApiSessionsDeleteRoute = Route$20.update({
7959
+ var ApiSessionsDeleteRoute = Route$21.update({
7368
7960
  id: "/api/sessions/delete",
7369
7961
  path: "/api/sessions/delete",
7370
- getParentRoute: () => Route$48
7962
+ getParentRoute: () => Route$53
7371
7963
  });
7372
- var ApiSessionTreeRoute = Route$19.update({
7964
+ var ApiSessionTreeRoute = Route$20.update({
7373
7965
  id: "/api/session/tree",
7374
7966
  path: "/api/session/tree",
7375
- getParentRoute: () => Route$48
7967
+ getParentRoute: () => Route$53
7376
7968
  });
7377
- var ApiSessionSelectRoute = Route$18.update({
7969
+ var ApiSessionSelectRoute = Route$19.update({
7378
7970
  id: "/api/session/select",
7379
7971
  path: "/api/session/select",
7380
- getParentRoute: () => Route$48
7972
+ getParentRoute: () => Route$53
7381
7973
  });
7382
- var ApiSessionRenameRoute = Route$17.update({
7974
+ var ApiSessionRenameRoute = Route$18.update({
7383
7975
  id: "/api/session/rename",
7384
7976
  path: "/api/session/rename",
7385
- getParentRoute: () => Route$48
7977
+ getParentRoute: () => Route$53
7978
+ });
7979
+ var ApiSessionReadStateRoute = Route$17.update({
7980
+ id: "/api/session/read-state",
7981
+ path: "/api/session/read-state",
7982
+ getParentRoute: () => Route$53
7386
7983
  });
7387
7984
  var ApiSessionNewRoute = Route$16.update({
7388
7985
  id: "/api/session/new",
7389
7986
  path: "/api/session/new",
7390
- getParentRoute: () => Route$48
7987
+ getParentRoute: () => Route$53
7391
7988
  });
7392
7989
  var ApiSessionMoveRoute = Route$15.update({
7393
7990
  id: "/api/session/move",
7394
7991
  path: "/api/session/move",
7395
- getParentRoute: () => Route$48
7992
+ getParentRoute: () => Route$53
7396
7993
  });
7397
7994
  var ApiSessionHistoryRoute = Route$14.update({
7398
7995
  id: "/api/session/history",
7399
7996
  path: "/api/session/history",
7400
- getParentRoute: () => Route$48
7997
+ getParentRoute: () => Route$53
7401
7998
  });
7402
7999
  var ApiSessionForkRoute = Route$13.update({
7403
8000
  id: "/api/session/fork",
7404
8001
  path: "/api/session/fork",
7405
- getParentRoute: () => Route$48
8002
+ getParentRoute: () => Route$53
7406
8003
  });
7407
8004
  var ApiSessionDeleteRoute = Route$12.update({
7408
8005
  id: "/api/session/delete",
7409
8006
  path: "/api/session/delete",
7410
- getParentRoute: () => Route$48
8007
+ getParentRoute: () => Route$53
7411
8008
  });
7412
8009
  var ApiSessionCloneRoute = Route$11.update({
7413
8010
  id: "/api/session/clone",
7414
8011
  path: "/api/session/clone",
7415
- getParentRoute: () => Route$48
8012
+ getParentRoute: () => Route$53
7416
8013
  });
7417
8014
  var ApiPendingMessagesReorderRoute = Route$10.update({
7418
8015
  id: "/api/pending-messages/reorder",
7419
8016
  path: "/api/pending-messages/reorder",
7420
- getParentRoute: () => Route$48
8017
+ getParentRoute: () => Route$53
7421
8018
  });
7422
8019
  var ApiPendingMessageRemoveRoute = Route$9.update({
7423
8020
  id: "/api/pending-message/remove",
7424
8021
  path: "/api/pending-message/remove",
7425
- getParentRoute: () => Route$48
8022
+ getParentRoute: () => Route$53
7426
8023
  });
7427
8024
  var ApiFilesTreeRoute = Route$8.update({
7428
8025
  id: "/api/files/tree",
7429
8026
  path: "/api/files/tree",
7430
- getParentRoute: () => Route$48
8027
+ getParentRoute: () => Route$53
7431
8028
  });
7432
8029
  var ApiFilesReadRoute = Route$7.update({
7433
8030
  id: "/api/files/read",
7434
8031
  path: "/api/files/read",
7435
- getParentRoute: () => Route$48
8032
+ getParentRoute: () => Route$53
7436
8033
  });
7437
8034
  var ApiDirectoryResolveRoute = Route$6.update({
7438
8035
  id: "/api/directory/resolve",
7439
8036
  path: "/api/directory/resolve",
7440
- getParentRoute: () => Route$48
8037
+ getParentRoute: () => Route$53
7441
8038
  });
7442
8039
  var ApiDirectorySessionsCleanupRoute = Route$5.update({
7443
8040
  id: "/cleanup",
@@ -7447,22 +8044,22 @@ var ApiDirectorySessionsCleanupRoute = Route$5.update({
7447
8044
  var ApiAuthProvidersRoute = Route$4.update({
7448
8045
  id: "/api/auth/providers",
7449
8046
  path: "/api/auth/providers",
7450
- getParentRoute: () => Route$48
8047
+ getParentRoute: () => Route$53
7451
8048
  });
7452
8049
  var ApiAuthOauthRoute = Route$3.update({
7453
8050
  id: "/api/auth/oauth",
7454
8051
  path: "/api/auth/oauth",
7455
- getParentRoute: () => Route$48
8052
+ getParentRoute: () => Route$53
7456
8053
  });
7457
8054
  var ApiAuthLogoutRoute = Route$2.update({
7458
8055
  id: "/api/auth/logout",
7459
8056
  path: "/api/auth/logout",
7460
- getParentRoute: () => Route$48
8057
+ getParentRoute: () => Route$53
7461
8058
  });
7462
8059
  var ApiAuthApiKeyRoute = Route$1.update({
7463
8060
  id: "/api/auth/api-key",
7464
8061
  path: "/api/auth/api-key",
7465
- getParentRoute: () => Route$48
8062
+ getParentRoute: () => Route$53
7466
8063
  });
7467
8064
  var ApiSessionTreeLabelRoute = Route.update({
7468
8065
  id: "/label",
@@ -7484,7 +8081,11 @@ var rootRouteChildren = {
7484
8081
  ApiGitChangesRoute,
7485
8082
  ApiGitCheckoutRoute,
7486
8083
  ApiGitCommitRoute,
8084
+ ApiGitCommitActionRoute,
8085
+ ApiGitCommitDiffRoute,
8086
+ ApiGitCommitFilesRoute,
7487
8087
  ApiGitCommitMessageRoute,
8088
+ ApiGitCommitRemoteUrlRoute,
7488
8089
  ApiGitDiffRoute,
7489
8090
  ApiGitDiscardRoute,
7490
8091
  ApiGitPullRoute,
@@ -7514,6 +8115,7 @@ var rootRouteChildren = {
7514
8115
  ApiSessionHistoryRoute,
7515
8116
  ApiSessionMoveRoute,
7516
8117
  ApiSessionNewRoute,
8118
+ ApiSessionReadStateRoute,
7517
8119
  ApiSessionRenameRoute,
7518
8120
  ApiSessionSelectRoute,
7519
8121
  ApiSessionTreeRoute: ApiSessionTreeRoute._addFileChildren(ApiSessionTreeRouteChildren),
@@ -7521,7 +8123,7 @@ var rootRouteChildren = {
7521
8123
  ApiSettingsHideThinkingRoute,
7522
8124
  ApiUiIdRoute
7523
8125
  };
7524
- var routeTree = Route$48._addFileChildren(rootRouteChildren)._addFileTypes();
8126
+ var routeTree = Route$53._addFileChildren(rootRouteChildren)._addFileTypes();
7525
8127
  function getRouter() {
7526
8128
  const queryClient = new QueryClient({ defaultOptions: { queries: {
7527
8129
  retry: 1,