lupacode 1.0.0 → 1.0.1

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 (2) hide show
  1. package/dist/index.js +459 -123
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -85693,6 +85693,12 @@ var toolInputSchemas = {
85693
85693
  command: exports_external.string().describe("Shell command to run"),
85694
85694
  description: exports_external.string().optional().describe("Short description of the command"),
85695
85695
  timeout: exports_external.number().optional().describe("Timeout in milliseconds")
85696
+ }),
85697
+ deleteFile: exports_external.object({
85698
+ path: exports_external.string().describe("Relative path to the file to delete")
85699
+ }),
85700
+ webSearch: exports_external.object({
85701
+ query: exports_external.string().describe("Search query for web search")
85696
85702
  })
85697
85703
  };
85698
85704
  // node_modules/ai/node_modules/@ai-sdk/provider/dist/index.js
@@ -93401,10 +93407,18 @@ var readOnlyToolContracts = {
93401
93407
  grep: tool({
93402
93408
  description: "Search file contents with a regular expression under the current project directory.",
93403
93409
  inputSchema: toolInputSchemas.grep
93410
+ }),
93411
+ webSearch: tool({
93412
+ description: "Search the web for up-to-date information on any topic.",
93413
+ inputSchema: toolInputSchemas.webSearch
93404
93414
  })
93405
93415
  };
93406
93416
  var buildToolContracts = {
93407
93417
  ...readOnlyToolContracts,
93418
+ deleteFile: tool({
93419
+ description: "Delete a file under the current project directory.",
93420
+ inputSchema: toolInputSchemas.deleteFile
93421
+ }),
93408
93422
  writeFile: tool({
93409
93423
  description: "Create or overwrite a file under the current project directory.",
93410
93424
  inputSchema: toolInputSchemas.writeFile
@@ -93421,7 +93435,7 @@ var buildToolContracts = {
93421
93435
  // src/lib/shared/models.ts
93422
93436
  var SUPPORTED_CHAT_MODELS = [
93423
93437
  {
93424
- id: "claude-sonnet-4-20250514",
93438
+ id: "claude-sonnet-5",
93425
93439
  provider: "anthropic",
93426
93440
  pricing: {
93427
93441
  inputUsdPerMillionTokens: 3,
@@ -93429,7 +93443,7 @@ var SUPPORTED_CHAT_MODELS = [
93429
93443
  }
93430
93444
  },
93431
93445
  {
93432
- id: "claude-3-5-haiku-latest",
93446
+ id: "claude-haiku-4-5",
93433
93447
  provider: "anthropic",
93434
93448
  pricing: {
93435
93449
  inputUsdPerMillionTokens: 1,
@@ -93437,7 +93451,7 @@ var SUPPORTED_CHAT_MODELS = [
93437
93451
  }
93438
93452
  },
93439
93453
  {
93440
- id: "claude-opus-4-20250514",
93454
+ id: "claude-opus-4-8",
93441
93455
  provider: "anthropic",
93442
93456
  pricing: {
93443
93457
  inputUsdPerMillionTokens: 5,
@@ -93445,7 +93459,7 @@ var SUPPORTED_CHAT_MODELS = [
93445
93459
  }
93446
93460
  },
93447
93461
  {
93448
- id: "gpt-4.1",
93462
+ id: "gpt-5.5",
93449
93463
  provider: "openai",
93450
93464
  pricing: {
93451
93465
  inputUsdPerMillionTokens: 2.5,
@@ -93453,7 +93467,7 @@ var SUPPORTED_CHAT_MODELS = [
93453
93467
  }
93454
93468
  },
93455
93469
  {
93456
- id: "gpt-4.1-mini",
93470
+ id: "gpt-5.4-mini",
93457
93471
  provider: "openai",
93458
93472
  pricing: {
93459
93473
  inputUsdPerMillionTokens: 0.75,
@@ -93461,7 +93475,7 @@ var SUPPORTED_CHAT_MODELS = [
93461
93475
  }
93462
93476
  },
93463
93477
  {
93464
- id: "gpt-4.1-nano",
93478
+ id: "gpt-5.4-nano",
93465
93479
  provider: "openai",
93466
93480
  pricing: {
93467
93481
  inputUsdPerMillionTokens: 0.2,
@@ -93469,19 +93483,19 @@ var SUPPORTED_CHAT_MODELS = [
93469
93483
  }
93470
93484
  },
93471
93485
  {
93472
- id: "qwen/qwen3-coder",
93486
+ id: "cohere/north-mini-code:free",
93473
93487
  provider: "openrouter",
93474
93488
  pricing: {
93475
- inputUsdPerMillionTokens: 0.3,
93476
- outputUsdPerMillionTokens: 1.2
93489
+ inputUsdPerMillionTokens: 0,
93490
+ outputUsdPerMillionTokens: 0
93477
93491
  }
93478
93492
  },
93479
93493
  {
93480
- id: "qwen/qwen3-32b",
93481
- provider: "groq",
93494
+ id: "deepseek/deepseek-chat-v3",
93495
+ provider: "openrouter",
93482
93496
  pricing: {
93483
- inputUsdPerMillionTokens: 0.29,
93484
- outputUsdPerMillionTokens: 0.59
93497
+ inputUsdPerMillionTokens: 0.27,
93498
+ outputUsdPerMillionTokens: 1.1
93485
93499
  }
93486
93500
  },
93487
93501
  {
@@ -93493,11 +93507,67 @@ var SUPPORTED_CHAT_MODELS = [
93493
93507
  }
93494
93508
  },
93495
93509
  {
93496
- id: "deepseek/deepseek-chat-v3",
93510
+ id: "deepseek/deepseek-v3.2",
93497
93511
  provider: "openrouter",
93498
93512
  pricing: {
93499
- inputUsdPerMillionTokens: 0.27,
93500
- outputUsdPerMillionTokens: 1.1
93513
+ inputUsdPerMillionTokens: 0.2288,
93514
+ outputUsdPerMillionTokens: 0.3432
93515
+ }
93516
+ },
93517
+ {
93518
+ id: "deepseek/deepseek-v4-flash",
93519
+ provider: "openrouter",
93520
+ pricing: {
93521
+ inputUsdPerMillionTokens: 0.1,
93522
+ outputUsdPerMillionTokens: 0.2
93523
+ }
93524
+ },
93525
+ {
93526
+ id: "deepseek/deepseek-v4-pro",
93527
+ provider: "openrouter",
93528
+ pricing: {
93529
+ inputUsdPerMillionTokens: 0.435,
93530
+ outputUsdPerMillionTokens: 0.87
93531
+ }
93532
+ },
93533
+ {
93534
+ id: "nvidia/nemotron-3-super-120b-a12b:free",
93535
+ provider: "openrouter",
93536
+ pricing: {
93537
+ inputUsdPerMillionTokens: 0,
93538
+ outputUsdPerMillionTokens: 0
93539
+ }
93540
+ },
93541
+ {
93542
+ id: "nvidia/nemotron-3-ultra-550b-a55b:free",
93543
+ provider: "openrouter",
93544
+ pricing: {
93545
+ inputUsdPerMillionTokens: 0,
93546
+ outputUsdPerMillionTokens: 0
93547
+ }
93548
+ },
93549
+ {
93550
+ id: "poolside/laguna-m.1:free",
93551
+ provider: "openrouter",
93552
+ pricing: {
93553
+ inputUsdPerMillionTokens: 0,
93554
+ outputUsdPerMillionTokens: 0
93555
+ }
93556
+ },
93557
+ {
93558
+ id: "qwen/qwen3-coder",
93559
+ provider: "openrouter",
93560
+ pricing: {
93561
+ inputUsdPerMillionTokens: 0.3,
93562
+ outputUsdPerMillionTokens: 1.2
93563
+ }
93564
+ },
93565
+ {
93566
+ id: "qwen/qwen3-coder-next",
93567
+ provider: "openrouter",
93568
+ pricing: {
93569
+ inputUsdPerMillionTokens: 0.11,
93570
+ outputUsdPerMillionTokens: 0.8
93501
93571
  }
93502
93572
  },
93503
93573
  {
@@ -93508,6 +93578,22 @@ var SUPPORTED_CHAT_MODELS = [
93508
93578
  outputUsdPerMillionTokens: 0
93509
93579
  }
93510
93580
  },
93581
+ {
93582
+ id: "gemini-3-flash-lite",
93583
+ provider: "google",
93584
+ pricing: {
93585
+ inputUsdPerMillionTokens: 0.25,
93586
+ outputUsdPerMillionTokens: 1.5
93587
+ }
93588
+ },
93589
+ {
93590
+ id: "gemini-3-flash-preview",
93591
+ provider: "google",
93592
+ pricing: {
93593
+ inputUsdPerMillionTokens: 0.5,
93594
+ outputUsdPerMillionTokens: 3
93595
+ }
93596
+ },
93511
93597
  {
93512
93598
  id: "llama-3.3-70b-versatile",
93513
93599
  provider: "groq",
@@ -93555,7 +93641,7 @@ function findSupportedChatModel(modelId) {
93555
93641
  function isFreeModel(model) {
93556
93642
  return model.pricing.inputUsdPerMillionTokens === 0 && model.pricing.outputUsdPerMillionTokens === 0;
93557
93643
  }
93558
- var DEFAULT_CHAT_MODEL_ID = "qwen/qwen3-32b";
93644
+ var DEFAULT_CHAT_MODEL_ID = "deepseek/deepseek-v4-flash";
93559
93645
  // src/lib/shared/domains.ts
93560
93646
  var DOMAINS = [
93561
93647
  {
@@ -93823,11 +93909,8 @@ function DialogProvider({ children }) {
93823
93909
  const [dialogStack, setDialogStack] = import_react24.useState([]);
93824
93910
  const { push, pop } = useKeyboardLayer();
93825
93911
  const close = import_react24.useCallback(() => {
93826
- setDialogStack((prev) => {
93827
- const next = prev.slice(0, -1);
93828
- pop("dialog");
93829
- return next;
93830
- });
93912
+ setDialogStack((prev) => prev.slice(0, -1));
93913
+ pop("dialog");
93831
93914
  }, [pop]);
93832
93915
  const open = import_react24.useCallback((config2) => {
93833
93916
  setDialogStack((prev) => [...prev, config2]);
@@ -93994,7 +94077,7 @@ function RootLayout() {
93994
94077
  }
93995
94078
 
93996
94079
  // src/screens/home.tsx
93997
- var import_react41 = __toESM(require_react(), 1);
94080
+ var import_react42 = __toESM(require_react(), 1);
93998
94081
 
93999
94082
  // src/components/header.tsx
94000
94083
  function Header() {
@@ -94022,7 +94105,7 @@ function Header() {
94022
94105
  }
94023
94106
 
94024
94107
  // src/components/input-bar.tsx
94025
- var import_react39 = __toESM(require_react(), 1);
94108
+ var import_react40 = __toESM(require_react(), 1);
94026
94109
  import { readdir } from "fs/promises";
94027
94110
  import { isAbsolute as isAbsolute3, relative, resolve as resolve5 } from "path";
94028
94111
 
@@ -96333,7 +96416,7 @@ var import_react35 = __toESM(require_react(), 1);
96333
96416
  // package.json
96334
96417
  var package_default2 = {
96335
96418
  name: "lupacode",
96336
- version: "1.0.0",
96419
+ version: "1.0.1",
96337
96420
  description: "AI-powered terminal coding assistant",
96338
96421
  type: "module",
96339
96422
  bin: {
@@ -96415,7 +96498,7 @@ async function checkForUpdate(currentVersion) {
96415
96498
  const cache = readCache();
96416
96499
  if (cache && Date.now() - cache.checkedAt < CHECK_INTERVAL_MS) {
96417
96500
  cachedLatest = cache.latest;
96418
- return cache.latest && cache.latest !== currentVersion ? cache.latest : null;
96501
+ return isNewer(cache.latest, currentVersion) ? cache.latest : null;
96419
96502
  }
96420
96503
  try {
96421
96504
  const res = await fetch("https://registry.npmjs.org/lupacode/latest");
@@ -96426,13 +96509,32 @@ async function checkForUpdate(currentVersion) {
96426
96509
  const result = { latest, checkedAt: Date.now() };
96427
96510
  writeCache(result);
96428
96511
  cachedLatest = latest;
96429
- return latest !== currentVersion ? latest : null;
96512
+ return isNewer(latest, currentVersion) ? latest : null;
96430
96513
  } catch {
96431
96514
  return null;
96432
96515
  }
96433
96516
  }
96517
+ function isNewer(latest, current) {
96518
+ if (!latest)
96519
+ return false;
96520
+ const a = parseSemver(latest);
96521
+ const b2 = parseSemver(current);
96522
+ if (!a || !b2)
96523
+ return false;
96524
+ if (a.major !== b2.major)
96525
+ return a.major > b2.major;
96526
+ if (a.minor !== b2.minor)
96527
+ return a.minor > b2.minor;
96528
+ return a.patch > b2.patch;
96529
+ }
96530
+ function parseSemver(v2) {
96531
+ const m2 = /^v?(\d+)\.(\d+)\.(\d+)/.exec(v2.trim());
96532
+ if (!m2 || m2[1] == null || m2[2] == null || m2[3] == null)
96533
+ return null;
96534
+ return { major: Number(m2[1]), minor: Number(m2[2]), patch: Number(m2[3]) };
96535
+ }
96434
96536
  function hasUpdate() {
96435
- return cachedLatest !== null && cachedLatest !== cachedCurrent;
96537
+ return isNewer(cachedLatest, cachedCurrent);
96436
96538
  }
96437
96539
 
96438
96540
  // src/components/dialogs/settings-dialog.tsx
@@ -96460,7 +96562,7 @@ var SettingsDialogContent = () => {
96460
96562
  break;
96461
96563
  case "model":
96462
96564
  dialog.open({ title: "Select Model", children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ModelsDialogContent, {
96463
- models: SUPPORTED_CHAT_MODELS,
96565
+ models: [...SUPPORTED_CHAT_MODELS],
96464
96566
  onSelectModel: setModel
96465
96567
  }, undefined, false, undefined, this) });
96466
96568
  break;
@@ -96549,7 +96651,7 @@ var shortcuts = [
96549
96651
  { key: "ctrl+d", description: "Switch domain" },
96550
96652
  { key: "ctrl+s", description: "Open settings" },
96551
96653
  { key: "ctrl+r", description: "Regenerate last assistant response" },
96552
- { key: "e", description: "Edit last user message" },
96654
+ { key: "ctrl+e", description: "Edit last user message" },
96553
96655
  { key: "escape", description: "Interrupt response / Cancel / Close dialog" }
96554
96656
  ];
96555
96657
  var KeyboardHelpDialogContent = () => {
@@ -96616,6 +96718,9 @@ function StatusBar() {
96616
96718
  }, undefined, true, undefined, this);
96617
96719
  }
96618
96720
 
96721
+ // src/components/command-menu/commands.tsx
96722
+ var import_react37 = __toESM(require_react(), 1);
96723
+
96619
96724
  // ../../node_modules/open/index.js
96620
96725
  import process9 from "process";
96621
96726
  import path4 from "path";
@@ -97440,6 +97545,85 @@ var COMMANDS = [
97440
97545
  }
97441
97546
  }
97442
97547
  },
97548
+ {
97549
+ name: "rename",
97550
+ description: "Rename the current session",
97551
+ value: "/rename",
97552
+ action: (ctx) => {
97553
+ if (!ctx.sessionId) {
97554
+ ctx.toast.show({ variant: "error", message: "No active session" });
97555
+ return;
97556
+ }
97557
+ const RenameDialog = () => {
97558
+ const [text2, setText] = import_react37.useState("");
97559
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
97560
+ flexDirection: "column",
97561
+ gap: 1,
97562
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("input", {
97563
+ focused: true,
97564
+ placeholder: "New session name",
97565
+ onContentChange: (event) => setText(String(event.value ?? event)),
97566
+ onSubmit: () => {
97567
+ const name23 = text2.trim();
97568
+ if (!name23)
97569
+ return;
97570
+ const baseUrl = process.env.API_URL ?? "https://lupacodeserver-production.up.railway.app";
97571
+ const token = getAuth()?.token ?? "";
97572
+ fetch(`${baseUrl}/sessions/${ctx.sessionId}`, {
97573
+ method: "PATCH",
97574
+ headers: {
97575
+ "Content-Type": "application/json",
97576
+ ...token ? { Authorization: `Bearer ${token}` } : {}
97577
+ },
97578
+ body: JSON.stringify({ title: name23 })
97579
+ }).then((res) => {
97580
+ if (!res.ok)
97581
+ throw new Error("Failed to rename");
97582
+ ctx.toast.show({ variant: "success", message: `Renamed to "${name23}"` });
97583
+ }).catch(() => {
97584
+ ctx.toast.show({ variant: "error", message: "Failed to rename session" });
97585
+ });
97586
+ ctx.dialog.close();
97587
+ }
97588
+ }, undefined, false, undefined, this)
97589
+ }, undefined, false, undefined, this);
97590
+ };
97591
+ ctx.dialog.open({ title: "Rename Session", children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(RenameDialog, {}, undefined, false, undefined, this) });
97592
+ }
97593
+ },
97594
+ {
97595
+ name: "export",
97596
+ description: "Export conversation as markdown",
97597
+ value: "/export",
97598
+ action: (ctx) => {
97599
+ if (!ctx.messages || ctx.messages.length === 0) {
97600
+ ctx.toast.show({ variant: "error", message: "No messages to export" });
97601
+ return;
97602
+ }
97603
+ const lines = [];
97604
+ lines.push("# Chat Export");
97605
+ lines.push("");
97606
+ for (const msg of ctx.messages) {
97607
+ const role = msg.role === "user" ? "User" : "Assistant";
97608
+ const text2 = msg.parts.filter((p) => p.type === "text").map((p) => p.text).join("");
97609
+ if (!text2)
97610
+ continue;
97611
+ lines.push(`**${role}:**`);
97612
+ lines.push("");
97613
+ lines.push(text2);
97614
+ lines.push("");
97615
+ }
97616
+ const content = lines.join(`
97617
+ `);
97618
+ const filename = `chat-export-${Date.now()}.md`;
97619
+ try {
97620
+ Bun.write(filename, content);
97621
+ ctx.toast.show({ variant: "success", message: `Exported to ${filename}` });
97622
+ } catch {
97623
+ ctx.toast.show({ variant: "error", message: "Failed to write export file" });
97624
+ }
97625
+ }
97626
+ },
97443
97627
  {
97444
97628
  name: "exit",
97445
97629
  description: "Quit the application",
@@ -97520,15 +97704,15 @@ function CommandMenu({
97520
97704
  }
97521
97705
 
97522
97706
  // src/components/command-menu/use-command-menu.ts
97523
- var import_react37 = __toESM(require_react(), 1);
97707
+ var import_react38 = __toESM(require_react(), 1);
97524
97708
  function useCommandMenu() {
97525
- const [textValue, setTextValue] = import_react37.useState("");
97526
- const [selectedIndex, setSelectedIndex] = import_react37.useState(0);
97527
- const [showCommandMenu, setShowCommandMenu] = import_react37.useState(false);
97528
- const scrollRef = import_react37.useRef(null);
97709
+ const [textValue, setTextValue] = import_react38.useState("");
97710
+ const [selectedIndex, setSelectedIndex] = import_react38.useState(0);
97711
+ const [showCommandMenu, setShowCommandMenu] = import_react38.useState(false);
97712
+ const scrollRef = import_react38.useRef(null);
97529
97713
  const { push, pop, isTopLayer } = useKeyboardLayer();
97530
97714
  const commandQuery = showCommandMenu && textValue.startsWith("/") ? textValue.slice(1) : "";
97531
- const filteredCommands = import_react37.useMemo(() => getFilteredCommands(commandQuery), [commandQuery]);
97715
+ const filteredCommands = import_react38.useMemo(() => getFilteredCommands(commandQuery), [commandQuery]);
97532
97716
  const close = () => {
97533
97717
  setShowCommandMenu(false);
97534
97718
  pop("command");
@@ -97785,21 +97969,21 @@ var TEXTAREA_KEY_BINDINGS = [
97785
97969
  { name: "return", shift: true, action: "newline" },
97786
97970
  { name: "enter", shift: true, action: "newline" }
97787
97971
  ];
97788
- function InputBar({ onSubmit, disabled = false }) {
97972
+ function InputBar({ onSubmit, disabled = false, sessionId, messages }) {
97789
97973
  const { mode, toggleMode, setMode, setModel, domain: domain2, setDomain } = usePromptConfig();
97790
- const textareaRef = import_react39.useRef(null);
97791
- const onSubmitRef = import_react39.useRef(() => {});
97792
- const activeMentionRef = import_react39.useRef(null);
97793
- const mentionScrollRef = import_react39.useRef(null);
97974
+ const textareaRef = import_react40.useRef(null);
97975
+ const onSubmitRef = import_react40.useRef(() => {});
97976
+ const activeMentionRef = import_react40.useRef(null);
97977
+ const mentionScrollRef = import_react40.useRef(null);
97794
97978
  const renderer = useRenderer();
97795
97979
  const toast = useToast();
97796
97980
  const navigate = useNavigate();
97797
97981
  const dialog = useDialog();
97798
97982
  const { colors } = useTheme();
97799
97983
  const { isTopLayer, setResponder, push, pop } = useKeyboardLayer();
97800
- const [activeMention, setActiveMention] = import_react39.useState(null);
97801
- const [mentionCandidates, setMentionCandidates] = import_react39.useState([]);
97802
- const [mentionSelectedIndex, setMentionSelectedIndex] = import_react39.useState(0);
97984
+ const [activeMention, setActiveMention] = import_react40.useState(null);
97985
+ const [mentionCandidates, setMentionCandidates] = import_react40.useState([]);
97986
+ const [mentionSelectedIndex, setMentionSelectedIndex] = import_react40.useState(0);
97803
97987
  const {
97804
97988
  showCommandMenu,
97805
97989
  commandQuery,
@@ -97810,13 +97994,13 @@ function InputBar({ onSubmit, disabled = false }) {
97810
97994
  setSelectedIndex
97811
97995
  } = useCommandMenu();
97812
97996
  const showMentionMenu = activeMention !== null;
97813
- const closeMentionMenu = import_react39.useCallback(() => {
97997
+ const closeMentionMenu = import_react40.useCallback(() => {
97814
97998
  activeMentionRef.current = null;
97815
97999
  setActiveMention(null);
97816
98000
  setMentionCandidates([]);
97817
98001
  pop("mention");
97818
98002
  }, [pop]);
97819
- const syncMentionMenu = import_react39.useCallback((text2, cursorOffset) => {
98003
+ const syncMentionMenu = import_react40.useCallback((text2, cursorOffset) => {
97820
98004
  const nextMention = findActiveMention(text2, cursorOffset);
97821
98005
  const previousMention = activeMentionRef.current;
97822
98006
  const mentionChanged = previousMention?.start !== nextMention?.start || previousMention?.end !== nextMention?.end || previousMention?.query !== nextMention?.query;
@@ -97839,7 +98023,7 @@ function InputBar({ onSubmit, disabled = false }) {
97839
98023
  mentionScrollRef.current?.scrollTo(0);
97840
98024
  }
97841
98025
  }, [closeMentionMenu, push]);
97842
- const handleTextareaContentChange = import_react39.useCallback(() => {
98026
+ const handleTextareaContentChange = import_react40.useCallback(() => {
97843
98027
  const textarea = textareaRef.current;
97844
98028
  if (!textarea)
97845
98029
  return;
@@ -97847,7 +98031,7 @@ function InputBar({ onSubmit, disabled = false }) {
97847
98031
  handleContentChange(textarea.plainText);
97848
98032
  syncMentionMenu(text2, textarea.cursorOffset);
97849
98033
  }, [handleContentChange, syncMentionMenu]);
97850
- const handleSubmit = import_react39.useCallback(() => {
98034
+ const handleSubmit = import_react40.useCallback(() => {
97851
98035
  if (disabled)
97852
98036
  return;
97853
98037
  const textarea = textareaRef.current;
@@ -97859,7 +98043,7 @@ function InputBar({ onSubmit, disabled = false }) {
97859
98043
  onSubmit(text2);
97860
98044
  textarea.setText("");
97861
98045
  }, [disabled, onSubmit]);
97862
- const handleMentionExecute = import_react39.useCallback((index) => {
98046
+ const handleMentionExecute = import_react40.useCallback((index) => {
97863
98047
  const textarea = textareaRef.current;
97864
98048
  const mention = activeMentionRef.current;
97865
98049
  const candidate = mentionCandidates[index];
@@ -97871,13 +98055,13 @@ function InputBar({ onSubmit, disabled = false }) {
97871
98055
  textarea.cursorOffset = mention.start + insertion.length + 1;
97872
98056
  syncMentionMenu(nextText, textarea.cursorOffset);
97873
98057
  }, [mentionCandidates, syncMentionMenu]);
97874
- const handleTextareaCursorChange = import_react39.useCallback(() => {
98058
+ const handleTextareaCursorChange = import_react40.useCallback(() => {
97875
98059
  const textarea = textareaRef.current;
97876
98060
  if (!textarea)
97877
98061
  return;
97878
98062
  syncMentionMenu(textarea.plainText, textarea.cursorOffset);
97879
98063
  }, [syncMentionMenu]);
97880
- const handleCommand = import_react39.useCallback((command) => {
98064
+ const handleCommand = import_react40.useCallback((command) => {
97881
98065
  const textarea = textareaRef.current;
97882
98066
  if (!textarea || !command)
97883
98067
  return;
@@ -97891,17 +98075,19 @@ function InputBar({ onSubmit, disabled = false }) {
97891
98075
  mode,
97892
98076
  setMode,
97893
98077
  setModel,
97894
- setDomain
98078
+ setDomain,
98079
+ sessionId,
98080
+ messages
97895
98081
  });
97896
98082
  } else {
97897
98083
  textarea.insertText(command.value + " ");
97898
98084
  }
97899
98085
  }, [renderer, toast, dialog, navigate, mode, setMode, setModel, setDomain]);
97900
- const handleCommandExecute = import_react39.useCallback((index) => {
98086
+ const handleCommandExecute = import_react40.useCallback((index) => {
97901
98087
  const command = resolveCommand(index);
97902
98088
  handleCommand(command);
97903
98089
  }, [resolveCommand, handleCommand]);
97904
- import_react39.useEffect(() => {
98090
+ import_react40.useEffect(() => {
97905
98091
  if (!activeMention) {
97906
98092
  setMentionCandidates([]);
97907
98093
  return;
@@ -97924,7 +98110,7 @@ function InputBar({ onSubmit, disabled = false }) {
97924
98110
  ignore = true;
97925
98111
  };
97926
98112
  }, [activeMention]);
97927
- import_react39.useEffect(() => {
98113
+ import_react40.useEffect(() => {
97928
98114
  const textare = textareaRef.current;
97929
98115
  if (!textare)
97930
98116
  return;
@@ -97982,7 +98168,7 @@ function InputBar({ onSubmit, disabled = false }) {
97982
98168
  });
97983
98169
  }
97984
98170
  });
97985
- import_react39.useEffect(() => {
98171
+ import_react40.useEffect(() => {
97986
98172
  setResponder("base", () => {
97987
98173
  if (disabled)
97988
98174
  return false;
@@ -98100,7 +98286,7 @@ function InputBar({ onSubmit, disabled = false }) {
98100
98286
  function Home() {
98101
98287
  const navigate = useNavigate();
98102
98288
  const { mode, model, domain: domain2 } = usePromptConfig();
98103
- const handleSubmit = import_react41.useCallback((text2) => {
98289
+ const handleSubmit = import_react42.useCallback((text2) => {
98104
98290
  navigate("/sessions/new", { state: { message: text2, mode, model, domain: domain2 } });
98105
98291
  }, [navigate, mode, model, domain2]);
98106
98292
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
@@ -98178,7 +98364,7 @@ function Home() {
98178
98364
  }
98179
98365
 
98180
98366
  // src/screens/new-session.tsx
98181
- var import_react44 = __toESM(require_react(), 1);
98367
+ var import_react45 = __toESM(require_react(), 1);
98182
98368
 
98183
98369
  // src/components/messages/error-message.tsx
98184
98370
  function ErrorMessage({ message: message2 }) {
@@ -98369,7 +98555,45 @@ function prettyMilliseconds(milliseconds, options) {
98369
98555
  }
98370
98556
 
98371
98557
  // src/components/messages/bot-message.tsx
98372
- var globalSyntaxStyle = SyntaxStyle.create();
98558
+ var globalSyntaxStyle = SyntaxStyle.fromStyles({
98559
+ default: { fg: "#D4D4D4" },
98560
+ keyword: { fg: "#569CD6" },
98561
+ "keyword.control": { fg: "#C586C0" },
98562
+ "keyword.import": { fg: "#C586C0" },
98563
+ "keyword.function": { fg: "#DCDCAA" },
98564
+ string: { fg: "#CE9178" },
98565
+ "string.special": { fg: "#CE9178" },
98566
+ number: { fg: "#B5CEA8" },
98567
+ "number.float": { fg: "#B5CEA8" },
98568
+ comment: { fg: "#6A9955", italic: true },
98569
+ function: { fg: "#DCDCAA" },
98570
+ "function.call": { fg: "#DCDCAA" },
98571
+ "function.method": { fg: "#DCDCAA" },
98572
+ type: { fg: "#4EC9B0" },
98573
+ "type.builtin": { fg: "#4EC9B0" },
98574
+ variable: { fg: "#9CDCFE" },
98575
+ "variable.parameter": { fg: "#9CDCFE" },
98576
+ "variable.builtin": { fg: "#9CDCFE" },
98577
+ constant: { fg: "#4FC1FF" },
98578
+ "constant.builtin": { fg: "#569CD6" },
98579
+ property: { fg: "#9CDCFE" },
98580
+ operator: { fg: "#D4D4D4" },
98581
+ "punctuation.delimiter": { fg: "#D4D4D4" },
98582
+ "punctuation.bracket": { fg: "#D4D4D4" },
98583
+ boolean: { fg: "#569CD6" },
98584
+ label: { fg: "#DCDCAA" },
98585
+ "markup.heading": { fg: "#569CD6", bold: true },
98586
+ "markup.italic": { italic: true },
98587
+ "markup.strong": { fg: "#DCDCAA", bold: true },
98588
+ "markup.strikethrough": { fg: "#888888", italic: true, dim: true },
98589
+ "markup.raw": { fg: "#CE9178" },
98590
+ "markup.link": { fg: "#569CD6", underline: true },
98591
+ "markup.link.label": { fg: "#569CD6", underline: true },
98592
+ "markup.link.url": { fg: "#4FC1FF" },
98593
+ "markup.list": { fg: "#569CD6" },
98594
+ "markup.quote": { fg: "#6A9955", italic: true },
98595
+ conceal: { fg: "#555555" }
98596
+ });
98373
98597
  function formatToolName(name23) {
98374
98598
  return name23.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/^./, (c) => c.toUpperCase());
98375
98599
  }
@@ -98383,6 +98607,79 @@ function formatToolArgs(tc) {
98383
98607
  return String(tc.input);
98384
98608
  return Object.values(tc.input).map(String).join(" ");
98385
98609
  }
98610
+ function isBashTool(tc) {
98611
+ const name23 = tc.type === "dynamic-tool" ? tc.toolName : tc.type.slice("tool-".length);
98612
+ return name23 === "bash";
98613
+ }
98614
+ function isToolRunning(tc) {
98615
+ return tc.state !== "output-available" && tc.state !== "output-error";
98616
+ }
98617
+ function renderToolCall(tc, colors, j2, renderKey) {
98618
+ const toolName = tc.type === "dynamic-tool" ? tc.toolName : tc.type.slice("tool-".length);
98619
+ const running = isToolRunning(tc);
98620
+ const done = tc.state === "output-available";
98621
+ if (isBashTool(tc)) {
98622
+ const command = typeof tc.input === "object" && tc.input != null ? String(tc.input.command ?? "") : "";
98623
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98624
+ width: "100%",
98625
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98626
+ attributes: TextAttributes.DIM,
98627
+ children: [
98628
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("em", {
98629
+ fg: colors.success,
98630
+ attributes: TextAttributes.BOLD,
98631
+ children: "$"
98632
+ }, undefined, false, undefined, this),
98633
+ " ",
98634
+ command,
98635
+ running ? "" : "",
98636
+ tc.state === "output-error" ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("em", {
98637
+ fg: colors.error,
98638
+ children: [
98639
+ " ",
98640
+ "\u2716",
98641
+ " ",
98642
+ tc.errorText
98643
+ ]
98644
+ }, undefined, true, undefined, this) : null
98645
+ ]
98646
+ }, undefined, true, undefined, this)
98647
+ }, renderKey, false, undefined, this);
98648
+ }
98649
+ return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98650
+ width: "100%",
98651
+ children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98652
+ attributes: TextAttributes.DIM,
98653
+ children: [
98654
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("em", {
98655
+ fg: colors.info,
98656
+ children: [
98657
+ formatToolName(toolName),
98658
+ ":"
98659
+ ]
98660
+ }, undefined, true, undefined, this),
98661
+ " ",
98662
+ formatToolArgs(tc),
98663
+ running ? "..." : done ? " \u2713" : "",
98664
+ tc.state === "output-error" ? /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("em", {
98665
+ fg: colors.error,
98666
+ children: [
98667
+ " ",
98668
+ "\u2716",
98669
+ " ",
98670
+ tc.errorText
98671
+ ]
98672
+ }, undefined, true, undefined, this) : null
98673
+ ]
98674
+ }, undefined, true, undefined, this)
98675
+ }, renderKey, false, undefined, this);
98676
+ }
98677
+ function formatTokens(usage) {
98678
+ const total = usage.totalTokens ?? usage.inputTokens ?? usage.outputTokens;
98679
+ if (total == null)
98680
+ return "";
98681
+ return `${total.toLocaleString()} tok`;
98682
+ }
98386
98683
  function mergeReasoningParts(parts) {
98387
98684
  const reasoningParts = parts.filter((p) => p.type === "reasoning");
98388
98685
  if (reasoningParts.length <= 1)
@@ -98420,6 +98717,7 @@ function BotMessage({
98420
98717
  model,
98421
98718
  mode,
98422
98719
  durationMs,
98720
+ usage,
98423
98721
  streaming = false
98424
98722
  }) {
98425
98723
  const { colors } = useTheme();
@@ -98445,22 +98743,7 @@ function BotMessage({
98445
98743
  flexDirection: "column",
98446
98744
  children: group.parts.map((part, j2) => {
98447
98745
  const tc = part;
98448
- const toolName = tc.type === "dynamic-tool" ? tc.toolName : tc.type.slice("tool-".length);
98449
- return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98450
- attributes: TextAttributes.DIM,
98451
- children: [
98452
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("em", {
98453
- fg: colors.info,
98454
- children: [
98455
- formatToolName(toolName),
98456
- ":"
98457
- ]
98458
- }, undefined, true, undefined, this),
98459
- formatToolArgs(tc),
98460
- tc.state !== "output-available" && tc.state !== "output-error" ? "..." : "",
98461
- tc.state === "output-error" ? ` ${tc.errorText}` : ""
98462
- ]
98463
- }, tc.toolCallId, true, undefined, this);
98746
+ return renderToolCall(tc, colors, j2, tc.toolCallId);
98464
98747
  })
98465
98748
  }, undefined, false, undefined, this)
98466
98749
  }, group.key, false, undefined, this);
@@ -98493,7 +98776,6 @@ function BotMessage({
98493
98776
  }, `reasoning-${j2}`, false, undefined, this);
98494
98777
  }
98495
98778
  if (isToolPart(part)) {
98496
- const toolName = part.type === "dynamic-tool" ? part.toolName : part.type.slice("tool-".length);
98497
98779
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
98498
98780
  border: ["left"],
98499
98781
  borderColor: colors.thinkingBorder,
@@ -98503,21 +98785,7 @@ function BotMessage({
98503
98785
  },
98504
98786
  width: "100%",
98505
98787
  paddingX: 2,
98506
- children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98507
- attributes: TextAttributes.DIM,
98508
- children: [
98509
- /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("em", {
98510
- fg: colors.info,
98511
- children: [
98512
- formatToolName(toolName),
98513
- ":"
98514
- ]
98515
- }, undefined, true, undefined, this),
98516
- formatToolArgs(part),
98517
- part.state !== "output-available" && part.state !== "output-error" ? "..." : "",
98518
- part.state === "output-error" ? ` ${part.errorText}` : ""
98519
- ]
98520
- }, undefined, true, undefined, this)
98788
+ children: renderToolCall(part, colors, j2, part.toolCallId)
98521
98789
  }, part.toolCallId, false, undefined, this);
98522
98790
  }
98523
98791
  if (part.type === "text") {
@@ -98527,7 +98795,17 @@ function BotMessage({
98527
98795
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("markdown", {
98528
98796
  content: part.text,
98529
98797
  syntaxStyle: globalSyntaxStyle,
98530
- conceal: true
98798
+ conceal: true,
98799
+ concealCode: true,
98800
+ streaming,
98801
+ tableOptions: {
98802
+ style: "grid",
98803
+ borders: true,
98804
+ outerBorder: true,
98805
+ borderStyle: "rounded",
98806
+ cellPadding: 1,
98807
+ borderColor: "#555555"
98808
+ }
98531
98809
  }, undefined, false, undefined, this)
98532
98810
  }, `text-${j2}`, false, undefined, this);
98533
98811
  }
@@ -98576,6 +98854,19 @@ function BotMessage({
98576
98854
  children: prettyMilliseconds(durationMs)
98577
98855
  }, undefined, false, undefined, this)
98578
98856
  ]
98857
+ }, undefined, true, undefined, this),
98858
+ usage && formatTokens(usage) && /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(import_jsx_dev_runtime2.Fragment, {
98859
+ children: [
98860
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98861
+ attributes: TextAttributes.DIM,
98862
+ fg: colors.dimSeparator,
98863
+ children: ">"
98864
+ }, undefined, false, undefined, this),
98865
+ /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("text", {
98866
+ attributes: TextAttributes.DIM,
98867
+ children: formatTokens(usage)
98868
+ }, undefined, false, undefined, this)
98869
+ ]
98579
98870
  }, undefined, true, undefined, this)
98580
98871
  ]
98581
98872
  }, undefined, true, undefined, this)
@@ -100570,7 +100861,9 @@ function SessionShell({
100570
100861
  onSubmit,
100571
100862
  inputDisabled = false,
100572
100863
  loading = false,
100573
- interruptible = false
100864
+ interruptible = false,
100865
+ sessionId,
100866
+ messages
100574
100867
  }) {
100575
100868
  const { mode } = usePromptConfig();
100576
100869
  return /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
@@ -100595,7 +100888,9 @@ function SessionShell({
100595
100888
  flexShrink: 0,
100596
100889
  children: /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(InputBar, {
100597
100890
  onSubmit,
100598
- disabled: inputDisabled
100891
+ disabled: inputDisabled,
100892
+ sessionId,
100893
+ messages
100599
100894
  }, undefined, false, undefined, this)
100600
100895
  }, undefined, false, undefined, this),
100601
100896
  /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV("box", {
@@ -100684,17 +100979,17 @@ function NewSession() {
100684
100979
  const navigate = useNavigate();
100685
100980
  const location = useLocation();
100686
100981
  const toast = useToast();
100687
- const hasStartedRef = import_react44.useRef(false);
100688
- const state = import_react44.useMemo(() => {
100982
+ const hasStartedRef = import_react45.useRef(false);
100983
+ const state = import_react45.useMemo(() => {
100689
100984
  const parsed = newSessionStateSchema.safeParse(location.state);
100690
100985
  return parsed.success ? parsed.data : null;
100691
100986
  }, [location.state]);
100692
- import_react44.useEffect(() => {
100987
+ import_react45.useEffect(() => {
100693
100988
  if (!state?.message) {
100694
100989
  navigate("/", { replace: true });
100695
100990
  }
100696
100991
  }, [state, navigate]);
100697
- import_react44.useEffect(() => {
100992
+ import_react45.useEffect(() => {
100698
100993
  if (!state || hasStartedRef.current)
100699
100994
  return;
100700
100995
  hasStartedRef.current = true;
@@ -100742,13 +101037,13 @@ function NewSession() {
100742
101037
  }
100743
101038
 
100744
101039
  // src/screens/sessions.tsx
100745
- var import_react53 = __toESM(require_react(), 1);
101040
+ var import_react54 = __toESM(require_react(), 1);
100746
101041
 
100747
101042
  // src/hooks/use-chat.ts
100748
- var import_react51 = __toESM(require_react(), 1);
101043
+ var import_react52 = __toESM(require_react(), 1);
100749
101044
 
100750
101045
  // ../../node_modules/@ai-sdk/react/dist/index.js
100751
- var import_react45 = __toESM(require_react(), 1);
101046
+ var import_react46 = __toESM(require_react(), 1);
100752
101047
 
100753
101048
  // ../../node_modules/@ai-sdk/react/node_modules/@ai-sdk/provider/dist/index.js
100754
101049
  var marker23 = "vercel.ai.error";
@@ -105501,11 +105796,11 @@ var AbstractChat = class {
105501
105796
 
105502
105797
  // ../../node_modules/@ai-sdk/react/dist/index.js
105503
105798
  var import_throttleit = __toESM(require_throttleit(), 1);
105504
- var import_react46 = __toESM(require_react(), 1);
105505
105799
  var import_react47 = __toESM(require_react(), 1);
105506
105800
  var import_react48 = __toESM(require_react(), 1);
105507
105801
  var import_react49 = __toESM(require_react(), 1);
105508
105802
  var import_react50 = __toESM(require_react(), 1);
105803
+ var import_react51 = __toESM(require_react(), 1);
105509
105804
  var import_jsx_runtime = __toESM(require_jsx_runtime(), 1);
105510
105805
  var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1);
105511
105806
  var __accessCheck = (obj, member, msg) => {
@@ -105642,7 +105937,7 @@ function useChat({
105642
105937
  resume = false,
105643
105938
  ...options
105644
105939
  } = {}) {
105645
- const callbacksRef = import_react45.useRef(!("chat" in options) ? {
105940
+ const callbacksRef = import_react46.useRef(!("chat" in options) ? {
105646
105941
  onToolCall: options.onToolCall,
105647
105942
  onData: options.onData,
105648
105943
  onFinish: options.onFinish,
@@ -105681,22 +105976,22 @@ function useChat({
105681
105976
  return (_c = (_b17 = (_a29 = callbacksRef.current).sendAutomaticallyWhen) == null ? undefined : _b17.call(_a29, arg)) != null ? _c : false;
105682
105977
  }
105683
105978
  };
105684
- const chatRef = import_react45.useRef("chat" in options ? options.chat : new Chat(optionsWithCallbacks));
105979
+ const chatRef = import_react46.useRef("chat" in options ? options.chat : new Chat(optionsWithCallbacks));
105685
105980
  const shouldRecreateChat = "chat" in options && options.chat !== chatRef.current || "id" in options && chatRef.current.id !== options.id;
105686
105981
  if (shouldRecreateChat) {
105687
105982
  chatRef.current = "chat" in options ? options.chat : new Chat(optionsWithCallbacks);
105688
105983
  }
105689
- const subscribeToMessages = import_react45.useCallback((update) => chatRef.current["~registerMessagesCallback"](update, throttleWaitMs), [throttleWaitMs, chatRef.current.id]);
105690
- const messages = import_react45.useSyncExternalStore(subscribeToMessages, () => chatRef.current.messages, () => chatRef.current.messages);
105691
- const status = import_react45.useSyncExternalStore(chatRef.current["~registerStatusCallback"], () => chatRef.current.status, () => chatRef.current.status);
105692
- const error51 = import_react45.useSyncExternalStore(chatRef.current["~registerErrorCallback"], () => chatRef.current.error, () => chatRef.current.error);
105693
- const setMessages = import_react45.useCallback((messagesParam) => {
105984
+ const subscribeToMessages = import_react46.useCallback((update) => chatRef.current["~registerMessagesCallback"](update, throttleWaitMs), [throttleWaitMs, chatRef.current.id]);
105985
+ const messages = import_react46.useSyncExternalStore(subscribeToMessages, () => chatRef.current.messages, () => chatRef.current.messages);
105986
+ const status = import_react46.useSyncExternalStore(chatRef.current["~registerStatusCallback"], () => chatRef.current.status, () => chatRef.current.status);
105987
+ const error51 = import_react46.useSyncExternalStore(chatRef.current["~registerErrorCallback"], () => chatRef.current.error, () => chatRef.current.error);
105988
+ const setMessages = import_react46.useCallback((messagesParam) => {
105694
105989
  if (typeof messagesParam === "function") {
105695
105990
  messagesParam = messagesParam(chatRef.current.messages);
105696
105991
  }
105697
105992
  chatRef.current.messages = messagesParam;
105698
105993
  }, [chatRef]);
105699
- import_react45.useEffect(() => {
105994
+ import_react46.useEffect(() => {
105700
105995
  if (resume) {
105701
105996
  chatRef.current.resumeStream();
105702
105997
  }
@@ -105719,7 +106014,7 @@ function useChat({
105719
106014
  }
105720
106015
 
105721
106016
  // src/lib/local-tools.ts
105722
- import { mkdir as mkdir2, readFile as readFile2, readdir as readdir2, stat, writeFile as writeFile2 } from "fs/promises";
106017
+ import { mkdir as mkdir2, readFile as readFile2, readdir as readdir2, stat, writeFile as writeFile2, unlink as unlink2 } from "fs/promises";
105723
106018
  import { dirname as dirname2, isAbsolute as isAbsolute5, join as join5, relative as relative2, resolve as resolve7 } from "path";
105724
106019
  var MAX_FILE_SIZE = 1e4;
105725
106020
  var MAX_RESULTS = 200;
@@ -105739,7 +106034,7 @@ function truncate(value, limit) {
105739
106034
  return value.length > limit ? `${value.slice(0, limit)}n... (truncated, ${value.length} total chars)` : value;
105740
106035
  }
105741
106036
  async function executeLocalTool(toolName, input, mode) {
105742
- if (mode === Mode.PLAN && !["readFile", "listDirectory", "glob", "grep"].includes(toolName)) {
106037
+ if (mode === Mode.PLAN && !["readFile", "listDirectory", "glob", "grep", "webSearch"].includes(toolName)) {
105743
106038
  throw new Error(`Tool ${toolName} is not available in PLAN mode`);
105744
106039
  }
105745
106040
  switch (toolName) {
@@ -105849,11 +106144,15 @@ async function executeLocalTool(toolName, input, mode) {
105849
106144
  }
105850
106145
  case "bash": {
105851
106146
  const { command, timeout = DEFAULT_TIMEOUT } = toolInputSchemas.bash.parse(input);
105852
- const proc = Bun.spawn(["bash", "-c", command], {
106147
+ const isWindows = process.platform === "win32";
106148
+ const shell = isWindows ? "cmd.exe" : "bash";
106149
+ const shellFlag = isWindows ? "/c" : "-c";
106150
+ const env2 = isWindows ? { ...process.env } : { ...process.env, TERM: "dumb" };
106151
+ const proc = Bun.spawn([shell, shellFlag, command], {
105853
106152
  cwd: resolveInsideCwd(".").resolved,
105854
106153
  stdout: "pipe",
105855
106154
  stderr: "pipe",
105856
- env: { ...process.env, TERM: "dumb" }
106155
+ env: env2
105857
106156
  });
105858
106157
  const timer = setTimeout(() => proc.kill(), timeout);
105859
106158
  const [stdout, stderr] = await Promise.all([
@@ -105868,6 +106167,40 @@ async function executeLocalTool(toolName, input, mode) {
105868
106167
  exitCode
105869
106168
  };
105870
106169
  }
106170
+ case "deleteFile": {
106171
+ const { path: path5 } = toolInputSchemas.deleteFile.parse(input);
106172
+ const { cwd, resolved } = resolveInsideCwd(path5);
106173
+ await unlink2(resolved);
106174
+ return { success: true, path: relative2(cwd, resolved) };
106175
+ }
106176
+ case "webSearch": {
106177
+ const { query } = toolInputSchemas.webSearch.parse(input);
106178
+ const apiKey = process.env.TAVILY_API_KEY;
106179
+ if (!apiKey)
106180
+ throw new Error("TAVILY_API_KEY is not set");
106181
+ const res = await fetch("https://api.tavily.com/search", {
106182
+ method: "POST",
106183
+ headers: { "Content-Type": "application/json" },
106184
+ body: JSON.stringify({
106185
+ api_key: apiKey,
106186
+ query,
106187
+ search_depth: "advanced",
106188
+ include_answer: true,
106189
+ max_results: 5
106190
+ })
106191
+ });
106192
+ if (!res.ok)
106193
+ throw new Error(`Web search failed: ${res.status} ${res.statusText}`);
106194
+ const data2 = await res.json();
106195
+ return {
106196
+ results: data2.results.map((r) => ({
106197
+ title: r.title,
106198
+ url: r.url,
106199
+ content: r.content
106200
+ })),
106201
+ answer: data2.answer
106202
+ };
106203
+ }
105871
106204
  default:
105872
106205
  throw new Error(`Unknown tool ${toolName}`);
105873
106206
  }
@@ -105875,7 +106208,7 @@ async function executeLocalTool(toolName, input, mode) {
105875
106208
 
105876
106209
  // src/hooks/use-chat.ts
105877
106210
  function useChat2(sessionId, initialMessages) {
105878
- const transport = import_react51.useMemo(() => {
106211
+ const transport = import_react52.useMemo(() => {
105879
106212
  return new DefaultChatTransport({
105880
106213
  api: apiClient.chat.$url().toString(),
105881
106214
  headers() {
@@ -105963,6 +106296,7 @@ function ChatMessage({ msg }) {
105963
106296
  model: msg.metadata?.model ?? "unknown",
105964
106297
  mode: msg.metadata?.mode ?? "BUILD",
105965
106298
  durationMs: msg.metadata?.durationMs,
106299
+ usage: msg.metadata?.usage,
105966
106300
  streaming: false
105967
106301
  }, undefined, false, undefined, this);
105968
106302
  }
@@ -105986,14 +106320,14 @@ function SessionChat({
105986
106320
  session,
105987
106321
  initialPrompt
105988
106322
  }) {
105989
- const [initialMessages] = import_react53.useState(() => session.messages);
106323
+ const [initialMessages] = import_react54.useState(() => session.messages);
105990
106324
  const { mode, model, domain: domain2 } = usePromptConfig();
105991
106325
  const { isTopLayer } = useKeyboardLayer();
105992
106326
  const { messages, status, submit, setMessages, reload, abort, interrupt, error: error51 } = useChat2(session.id, initialMessages);
105993
- const hasSubmittedInitialPromptRef = import_react53.useRef(false);
106327
+ const hasSubmittedInitialPromptRef = import_react54.useRef(false);
105994
106328
  const toast = useToast();
105995
106329
  const dialog = useDialog();
105996
- import_react53.useEffect(() => {
106330
+ import_react54.useEffect(() => {
105997
106331
  return () => {
105998
106332
  abort();
105999
106333
  };
@@ -106014,7 +106348,7 @@ function SessionChat({
106014
106348
  }
106015
106349
  });
106016
106350
  useKeyboard((key) => {
106017
- if (key.name === "e" && !key.ctrl && isTopLayer("base") && status !== "streaming" && status !== "submitted") {
106351
+ if (key.name === "e" && key.ctrl && isTopLayer("base") && status !== "streaming" && status !== "submitted") {
106018
106352
  const lastUserMsg = messages.findLast((m2) => m2.role === "user");
106019
106353
  if (!lastUserMsg)
106020
106354
  return;
@@ -106052,7 +106386,7 @@ function SessionChat({
106052
106386
  });
106053
106387
  }
106054
106388
  });
106055
- import_react53.useEffect(() => {
106389
+ import_react54.useEffect(() => {
106056
106390
  if (!initialPrompt || hasSubmittedInitialPromptRef.current)
106057
106391
  return;
106058
106392
  hasSubmittedInitialPromptRef.current = true;
@@ -106066,6 +106400,8 @@ function SessionChat({
106066
106400
  onSubmit: (text3) => submit({ userText: text3, mode, model, domain: domain2 }),
106067
106401
  loading: status === "submitted" || status === "streaming",
106068
106402
  interruptible: status === "submitted" || status === "streaming",
106403
+ sessionId: session.id,
106404
+ messages,
106069
106405
  children: [
106070
106406
  messages.map((msg) => /* @__PURE__ */ import_jsx_dev_runtime2.jsxDEV(ChatMessage, {
106071
106407
  msg
@@ -106081,12 +106417,12 @@ function Session() {
106081
106417
  const location = useLocation();
106082
106418
  const navigate = useNavigate();
106083
106419
  const toast = useToast();
106084
- const prefetched = import_react53.useMemo(() => {
106420
+ const prefetched = import_react54.useMemo(() => {
106085
106421
  const parsed = sessionLocationSchema.safeParse(location.state);
106086
106422
  return parsed.success ? parsed.data : null;
106087
106423
  }, [location.state]);
106088
- const [session, setSession] = import_react53.useState(prefetched?.session ?? null);
106089
- import_react53.useEffect(() => {
106424
+ const [session, setSession] = import_react54.useState(prefetched?.session ?? null);
106425
+ import_react54.useEffect(() => {
106090
106426
  if (prefetched?.session)
106091
106427
  return;
106092
106428
  setSession(null);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lupacode",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "AI-powered terminal coding assistant",
5
5
  "type": "module",
6
6
  "bin": {