@ridit/lens 0.3.4 → 0.3.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -258398,6 +258398,12 @@ var require_asciichart = __commonJS((exports) => {
258398
258398
  });
258399
258399
 
258400
258400
  // src/utils/tools/registry.ts
258401
+ var INTENT_ALLOWED = {
258402
+ readonly: ["read", "net"],
258403
+ mutating: ["read", "net", "write", "delete", "shell"],
258404
+ any: ["read", "net", "write", "delete", "shell"]
258405
+ };
258406
+
258401
258407
  class ToolRegistry {
258402
258408
  tools = new Map;
258403
258409
  register(tool) {
@@ -258418,13 +258424,34 @@ class ToolRegistry {
258418
258424
  names() {
258419
258425
  return Array.from(this.tools.keys());
258420
258426
  }
258421
- buildSystemPromptSection() {
258427
+ namesForIntent(intent) {
258428
+ const allowed = new Set(INTENT_ALLOWED[intent]);
258429
+ return Array.from(this.tools.values()).filter((t) => {
258430
+ const tag = t.tag;
258431
+ if (!tag)
258432
+ return true;
258433
+ return allowed.has(tag);
258434
+ }).map((t) => t.name);
258435
+ }
258436
+ buildSystemPromptSection(intent = "any") {
258437
+ const allowed = new Set(INTENT_ALLOWED[intent]);
258438
+ const visible = Array.from(this.tools.values()).filter((t) => {
258439
+ const tag = t.tag;
258440
+ if (!tag)
258441
+ return true;
258442
+ return allowed.has(tag);
258443
+ });
258422
258444
  const lines = [`## TOOLS
258423
258445
  `];
258424
- lines.push("You have exactly " + this.tools.size + ` tools. To use a tool you MUST wrap it in the exact XML tags shown below — no other format will work.
258446
+ if (intent === "readonly") {
258447
+ lines.push(`You have ${visible.length} tools available for this read-only request. ` + `Do NOT attempt to write, delete, or run shell commands — ` + `those tools are not available right now.
258448
+ `);
258449
+ } else {
258450
+ lines.push(`You have exactly ${visible.length} tools. To use a tool you MUST wrap it ` + `in the exact XML tags shown below — no other format will work.
258425
258451
  `);
258452
+ }
258426
258453
  let i = 1;
258427
- for (const tool of this.tools.values()) {
258454
+ for (const tool of visible) {
258428
258455
  lines.push(tool.systemPromptEntry(i++));
258429
258456
  }
258430
258457
  return lines.join(`
@@ -268627,25 +268654,25 @@ ${f.content.slice(0, 2000)}
268627
268654
  `);
268628
268655
  const tools = toolsSection ?? BUILTIN_TOOLS_SECTION;
268629
268656
  return `You are an expert software engineer assistant with access to the user's codebase and tools.
268630
-
268657
+
268631
268658
  ${tools}
268632
-
268659
+
268633
268660
  ## MEMORY OPERATIONS
268634
-
268661
+
268635
268662
  You can save and delete memories at any time by emitting these tags alongside your normal response.
268636
268663
  They are stripped before display — the user will not see the raw tags.
268637
-
268664
+
268638
268665
  ### memory-add — save something important to long-term memory for this repo
268639
268666
  <memory-add>User prefers TypeScript strict mode in all new files</memory-add>
268640
-
268667
+
268641
268668
  ### memory-delete — delete a memory by its ID (shown in brackets like [abc123])
268642
268669
  <memory-delete>abc123</memory-delete>
268643
-
268670
+
268644
268671
  Use memory-add when the user asks you to remember something, or when you learn something project-specific that would be useful in future sessions.
268645
268672
  Use memory-delete when the user asks you to forget something or a memory is outdated.
268646
-
268673
+
268647
268674
  ## RULES
268648
-
268675
+
268649
268676
  1. ONE tool per response — emit the XML tag, then stop. Never chain tools in one response except when scaffolding (see below).
268650
268677
  2. NEVER call a tool more than once for the same path in a session. If write-file or shell returned a result, it succeeded. Move on immediately.
268651
268678
  3. NEVER write the same file twice in one session. One write per file, period. If you already wrote it, it is done.
@@ -268663,15 +268690,15 @@ Use memory-delete when the user asks you to forget something or a memory is outd
268663
268690
  15. When explaining how to use a tool in text, use [tag] bracket notation — NEVER emit a real XML tool tag as part of an explanation.
268664
268691
  16. NEVER use markdown formatting in plain text responses — no bold, no headings, no bullet points. Only use fenced code blocks when showing actual code.
268665
268692
  17. When scaffolding multiple files, emit ONE write-file tag per response and wait for the result before writing the next file.
268666
-
268693
+
268667
268694
  ## ADDON FORMAT
268668
-
268695
+
268669
268696
  All addons use defineTool from @ridit/lens-sdk. The ONLY correct format is:
268670
-
268697
+
268671
268698
  \`\`\`js
268672
268699
  const { defineTool } = require("@ridit/lens-sdk");
268673
268700
  const { execSync } = require("child_process");
268674
-
268701
+
268675
268702
  defineTool({
268676
268703
  name: "tool-name",
268677
268704
  description: "what it does",
@@ -268687,23 +268714,23 @@ defineTool({
268687
268714
  },
268688
268715
  });
268689
268716
  \`\`\`
268690
-
268717
+
268691
268718
  NEVER use module.exports, registerTool, ctx.tools.shell, or any other format. See addons/run-tests.js for a full working example.
268692
-
268719
+
268693
268720
  ## SCAFFOLDING
268694
-
268721
+
268695
268722
  When creating multiple files, emit ONE write-file per response and wait for each result:
268696
-
268723
+
268697
268724
  <write-file>
268698
268725
  {"path": "myapp/package.json", "content": "..."}
268699
268726
  </write-file>
268700
-
268727
+
268701
268728
  Wait for result, then emit the next file. Never chain write-file tags when content is complex.
268702
-
268729
+
268703
268730
  ## CODEBASE
268704
-
268731
+
268705
268732
  ${fileList.length > 0 ? fileList : "(no files indexed)"}
268706
-
268733
+
268707
268734
  ${memorySummary}`;
268708
268735
  }
268709
268736
  var BUILTIN_TOOLS_SECTION = `## TOOLS
@@ -272580,31 +272607,121 @@ import { existsSync as existsSync14 } from "fs";
272580
272607
  import path19 from "path";
272581
272608
 
272582
272609
  // src/components/chat/ChatRunner.tsx
272583
- var import_react48 = __toESM(require_react(), 1);
272584
- var import_react49 = __toESM(require_react(), 1);
272610
+ var import_react51 = __toESM(require_react(), 1);
272585
272611
  import path18 from "path";
272586
272612
  import os8 from "os";
272587
272613
 
272614
+ // src/utils/memory.ts
272615
+ import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync11, writeFileSync as writeFileSync8 } from "fs";
272616
+ import path16 from "path";
272617
+ import os6 from "os";
272618
+ var LENS_DIR = path16.join(os6.homedir(), ".lens");
272619
+ var MEMORY_PATH = path16.join(LENS_DIR, "memory.json");
272620
+ function loadMemoryFile() {
272621
+ if (!existsSync12(MEMORY_PATH))
272622
+ return { entries: [], memories: [] };
272623
+ try {
272624
+ const data = JSON.parse(readFileSync11(MEMORY_PATH, "utf-8"));
272625
+ return {
272626
+ entries: data.entries ?? [],
272627
+ memories: data.memories ?? []
272628
+ };
272629
+ } catch {
272630
+ return { entries: [], memories: [] };
272631
+ }
272632
+ }
272633
+ function saveMemoryFile(m) {
272634
+ if (!existsSync12(LENS_DIR))
272635
+ mkdirSync6(LENS_DIR, { recursive: true });
272636
+ writeFileSync8(MEMORY_PATH, JSON.stringify(m, null, 2), "utf-8");
272637
+ }
272638
+ function appendMemory(entry) {
272639
+ const m = loadMemoryFile();
272640
+ m.entries.push({ ...entry, timestamp: new Date().toISOString() });
272641
+ if (m.entries.length > 500)
272642
+ m.entries = m.entries.slice(-500);
272643
+ saveMemoryFile(m);
272644
+ }
272645
+ function buildMemorySummary(repoPath) {
272646
+ const m = loadMemoryFile();
272647
+ const relevant = m.entries.slice(-50);
272648
+ const memories = m.memories;
272649
+ const parts = [];
272650
+ if (memories.length > 0) {
272651
+ parts.push(`## MEMORIES ABOUT THIS REPO
272652
+
272653
+ ${memories.map((mem) => `- [${mem.id}] ${mem.content}`).join(`
272654
+ `)}`);
272655
+ }
272656
+ if (relevant.length > 0) {
272657
+ const lines = relevant.map((e) => {
272658
+ const ts = new Date(e.timestamp).toLocaleString();
272659
+ return `[${ts}] ${e.kind}: ${e.detail} — ${e.summary}`;
272660
+ });
272661
+ parts.push(`## WHAT YOU HAVE ALREADY DONE IN THIS REPO
272662
+
272663
+ The following actions have already been completed. Do NOT repeat them unless the user explicitly asks you to redo something:
272664
+
272665
+ ${lines.join(`
272666
+ `)}`);
272667
+ }
272668
+ return parts.join(`
272669
+
272670
+ `);
272671
+ }
272672
+ function clearRepoMemory(repoPath) {
272673
+ const m = loadMemoryFile();
272674
+ m.entries = m.entries = [];
272675
+ m.memories = m.memories = [];
272676
+ saveMemoryFile(m);
272677
+ }
272678
+ function generateId() {
272679
+ return Math.random().toString(36).slice(2, 8);
272680
+ }
272681
+ function addMemory(content, repoPath) {
272682
+ const m = loadMemoryFile();
272683
+ const memory = {
272684
+ id: generateId(),
272685
+ content,
272686
+ timestamp: new Date().toISOString()
272687
+ };
272688
+ m.memories.push(memory);
272689
+ saveMemoryFile(m);
272690
+ return memory;
272691
+ }
272692
+ function deleteMemory(id, repoPath) {
272693
+ const m = loadMemoryFile();
272694
+ const before2 = m.memories.length;
272695
+ m.memories = m.memories.filter((mem) => !(mem.id === id));
272696
+ if (m.memories.length === before2)
272697
+ return false;
272698
+ saveMemoryFile(m);
272699
+ return true;
272700
+ }
272701
+ function listMemories(repoPath) {
272702
+ return loadMemoryFile().memories;
272703
+ }
272704
+
272588
272705
  // src/utils/chatHistory.ts
272589
272706
  import {
272590
- existsSync as existsSync12,
272591
- mkdirSync as mkdirSync6,
272592
- readFileSync as readFileSync11,
272707
+ existsSync as existsSync13,
272708
+ mkdirSync as mkdirSync7,
272709
+ readFileSync as readFileSync12,
272593
272710
  readdirSync as readdirSync4,
272594
- writeFileSync as writeFileSync8,
272711
+ writeFileSync as writeFileSync9,
272595
272712
  unlinkSync
272596
272713
  } from "fs";
272597
- import path16 from "path";
272598
- import os6 from "os";
272599
- var LENS_DIR = path16.join(os6.homedir(), ".lens");
272600
- var CHATS_DIR = path16.join(LENS_DIR, "chats");
272714
+ import path17 from "path";
272715
+ import os7 from "os";
272716
+ var LENS_DIR2 = path17.join(os7.homedir(), ".lens");
272717
+ var CHATS_DIR = path17.join(LENS_DIR2, "chats");
272601
272718
  function ensureChatsDir() {
272602
- if (!existsSync12(CHATS_DIR))
272603
- mkdirSync6(CHATS_DIR, { recursive: true });
272719
+ if (!existsSync13(CHATS_DIR))
272720
+ mkdirSync7(CHATS_DIR, { recursive: true });
272604
272721
  }
272605
272722
  function chatFilePath(name) {
272606
272723
  const safe = name.replace(/[^a-z0-9_-]/gi, "-").toLowerCase();
272607
- return path16.join(CHATS_DIR, `${safe}.json`);
272724
+ return path17.join(CHATS_DIR, `${safe}.json`);
272608
272725
  }
272609
272726
  function saveChat(name, repoPath, messages) {
272610
272727
  ensureChatsDir();
@@ -272615,14 +272732,14 @@ function saveChat(name, repoPath, messages) {
272615
272732
  savedAt: new Date().toISOString(),
272616
272733
  userMessageCount: messages.filter((m) => m.role === "user").length
272617
272734
  };
272618
- writeFileSync8(chatFilePath(name), JSON.stringify(data, null, 2), "utf-8");
272735
+ writeFileSync9(chatFilePath(name), JSON.stringify(data, null, 2), "utf-8");
272619
272736
  }
272620
272737
  function loadChat(name) {
272621
272738
  const filePath = chatFilePath(name);
272622
- if (!existsSync12(filePath))
272739
+ if (!existsSync13(filePath))
272623
272740
  return null;
272624
272741
  try {
272625
- return JSON.parse(readFileSync11(filePath, "utf-8"));
272742
+ return JSON.parse(readFileSync12(filePath, "utf-8"));
272626
272743
  } catch {
272627
272744
  return null;
272628
272745
  }
@@ -272633,7 +272750,7 @@ function listChats(repoPath) {
272633
272750
  const chats = [];
272634
272751
  for (const file of files) {
272635
272752
  try {
272636
- const data = JSON.parse(readFileSync11(path16.join(CHATS_DIR, file), "utf-8"));
272753
+ const data = JSON.parse(readFileSync12(path17.join(CHATS_DIR, file), "utf-8"));
272637
272754
  if (!repoPath || data.repoPath === repoPath)
272638
272755
  chats.push(data);
272639
272756
  } catch {}
@@ -272642,7 +272759,7 @@ function listChats(repoPath) {
272642
272759
  }
272643
272760
  function deleteChat(name) {
272644
272761
  const filePath = chatFilePath(name);
272645
- if (!existsSync12(filePath))
272762
+ if (!existsSync13(filePath))
272646
272763
  return false;
272647
272764
  try {
272648
272765
  unlinkSync(filePath);
@@ -272818,6 +272935,7 @@ function parseArgs(body) {
272818
272935
  var gitStatusTool = {
272819
272936
  name: "git-status",
272820
272937
  description: "show working tree status",
272938
+ tag: "git",
272821
272939
  safe: true,
272822
272940
  permissionLabel: "git status",
272823
272941
  systemPromptEntry: (i) => `### ${i}. git-status — show working tree status (staged, unstaged, untracked)
@@ -272835,6 +272953,7 @@ var gitStatusTool = {
272835
272953
  var gitLogTool = {
272836
272954
  name: "git-log",
272837
272955
  description: "show commit log",
272956
+ tag: "git",
272838
272957
  safe: true,
272839
272958
  permissionLabel: "git log",
272840
272959
  systemPromptEntry: (i) => `### ${i}. git-log — show commit log with optional flags
@@ -272851,6 +272970,7 @@ var gitLogTool = {
272851
272970
  var gitDiffTool = {
272852
272971
  name: "git-diff",
272853
272972
  description: "show changes between commits, working tree, or staged files",
272973
+ tag: "git",
272854
272974
  safe: true,
272855
272975
  permissionLabel: "git diff",
272856
272976
  systemPromptEntry: (i) => `### ${i}. git-diff — show changes
@@ -272868,6 +272988,7 @@ var gitDiffTool = {
272868
272988
  var gitShowTool = {
272869
272989
  name: "git-show",
272870
272990
  description: "show a commit's details and stat",
272991
+ tag: "git",
272871
272992
  safe: true,
272872
272993
  permissionLabel: "git show",
272873
272994
  systemPromptEntry: (i) => `### ${i}. git-show — show a commit's details
@@ -272883,6 +273004,7 @@ var gitShowTool = {
272883
273004
  var gitBranchTool = {
272884
273005
  name: "git-branch",
272885
273006
  description: "list branches",
273007
+ tag: "git",
272886
273008
  safe: true,
272887
273009
  permissionLabel: "git branch",
272888
273010
  systemPromptEntry: (i) => `### ${i}. git-branch — list branches
@@ -272899,6 +273021,7 @@ var gitBranchTool = {
272899
273021
  var gitRemoteTool = {
272900
273022
  name: "git-remote",
272901
273023
  description: "list or inspect remotes",
273024
+ tag: "git",
272902
273025
  safe: true,
272903
273026
  permissionLabel: "git remote",
272904
273027
  systemPromptEntry: (i) => `### ${i}. git-remote — list remotes
@@ -272913,6 +273036,7 @@ var gitRemoteTool = {
272913
273036
  var gitTagTool = {
272914
273037
  name: "git-tag",
272915
273038
  description: "list tags",
273039
+ tag: "git",
272916
273040
  safe: true,
272917
273041
  permissionLabel: "git tag",
272918
273042
  systemPromptEntry: (i) => `### ${i}. git-tag — list tags
@@ -272928,6 +273052,7 @@ var gitTagTool = {
272928
273052
  var gitBlameTool = {
272929
273053
  name: "git-blame",
272930
273054
  description: "show who last modified each line of a file",
273055
+ tag: "git",
272931
273056
  safe: true,
272932
273057
  permissionLabel: "git blame",
272933
273058
  systemPromptEntry: (i) => `### ${i}. git-blame — show per-line authorship
@@ -272963,6 +273088,7 @@ var gitBlameTool = {
272963
273088
  var gitStashListTool = {
272964
273089
  name: "git-stash-list",
272965
273090
  description: "list stashed changes",
273091
+ tag: "git",
272966
273092
  safe: true,
272967
273093
  permissionLabel: "git stash list",
272968
273094
  systemPromptEntry: (i) => `### ${i}. git-stash-list — list stashes
@@ -272977,6 +273103,7 @@ var gitStashListTool = {
272977
273103
  var gitAddTool = {
272978
273104
  name: "git-add",
272979
273105
  description: "stage files for commit",
273106
+ tag: "git",
272980
273107
  safe: false,
272981
273108
  permissionLabel: "git add",
272982
273109
  systemPromptEntry: (i) => `### ${i}. git-add — stage files
@@ -272997,6 +273124,7 @@ var gitAddTool = {
272997
273124
  var gitCommitTool = {
272998
273125
  name: "git-commit",
272999
273126
  description: "commit staged changes with a message",
273127
+ tag: "git",
273000
273128
  safe: false,
273001
273129
  permissionLabel: "git commit",
273002
273130
  systemPromptEntry: (i) => `### ${i}. git-commit — commit staged changes (stage with git-add first)
@@ -273017,6 +273145,7 @@ var gitCommitTool = {
273017
273145
  var gitCommitAmendTool = {
273018
273146
  name: "git-commit-amend",
273019
273147
  description: "amend the last commit message",
273148
+ tag: "git",
273020
273149
  safe: false,
273021
273150
  permissionLabel: "git commit --amend",
273022
273151
  systemPromptEntry: (i) => `### ${i}. git-commit-amend — amend the last commit message
@@ -273037,6 +273166,7 @@ var gitCommitAmendTool = {
273037
273166
  var gitRevertTool = {
273038
273167
  name: "git-revert",
273039
273168
  description: "revert a commit by hash (creates a new revert commit, history preserved)",
273169
+ tag: "git",
273040
273170
  safe: false,
273041
273171
  permissionLabel: "git revert",
273042
273172
  systemPromptEntry: (i) => `### ${i}. git-revert — revert a commit (safe, creates new commit)
@@ -273056,6 +273186,7 @@ var gitRevertTool = {
273056
273186
  var gitResetTool = {
273057
273187
  name: "git-reset",
273058
273188
  description: "reset HEAD or unstage files",
273189
+ tag: "git",
273059
273190
  safe: false,
273060
273191
  permissionLabel: "git reset",
273061
273192
  systemPromptEntry: (i) => `### ${i}. git-reset — reset HEAD or unstage files
@@ -273076,6 +273207,7 @@ var gitResetTool = {
273076
273207
  var gitCheckoutTool = {
273077
273208
  name: "git-checkout",
273078
273209
  description: "switch branches or restore files",
273210
+ tag: "git",
273079
273211
  safe: false,
273080
273212
  permissionLabel: "git checkout",
273081
273213
  systemPromptEntry: (i) => `### ${i}. git-checkout — switch branch or restore file
@@ -273096,6 +273228,7 @@ var gitCheckoutTool = {
273096
273228
  var gitSwitchTool = {
273097
273229
  name: "git-switch",
273098
273230
  description: "switch or create branches",
273231
+ tag: "git",
273099
273232
  safe: false,
273100
273233
  permissionLabel: "git switch",
273101
273234
  systemPromptEntry: (i) => `### ${i}. git-switch — switch or create branches
@@ -273116,6 +273249,7 @@ var gitSwitchTool = {
273116
273249
  var gitMergeTool = {
273117
273250
  name: "git-merge",
273118
273251
  description: "merge a branch into the current branch",
273252
+ tag: "git",
273119
273253
  safe: false,
273120
273254
  permissionLabel: "git merge",
273121
273255
  systemPromptEntry: (i) => `### ${i}. git-merge — merge a branch into HEAD
@@ -273135,6 +273269,7 @@ var gitMergeTool = {
273135
273269
  var gitPullTool = {
273136
273270
  name: "git-pull",
273137
273271
  description: "pull from remote",
273272
+ tag: "git",
273138
273273
  safe: false,
273139
273274
  permissionLabel: "git pull",
273140
273275
  systemPromptEntry: (i) => `### ${i}. git-pull — pull from remote
@@ -273153,6 +273288,7 @@ var gitPullTool = {
273153
273288
  var gitPushTool = {
273154
273289
  name: "git-push",
273155
273290
  description: "push commits to remote",
273291
+ tag: "git",
273156
273292
  safe: false,
273157
273293
  permissionLabel: "git push",
273158
273294
  systemPromptEntry: (i) => `### ${i}. git-push — push to remote
@@ -273172,6 +273308,7 @@ var gitPushTool = {
273172
273308
  var gitStashTool = {
273173
273309
  name: "git-stash",
273174
273310
  description: "stash or apply stashed changes",
273311
+ tag: "git",
273175
273312
  safe: false,
273176
273313
  permissionLabel: "git stash",
273177
273314
  systemPromptEntry: (i) => `### ${i}. git-stash — stash/apply/pop/drop changes
@@ -273193,6 +273330,7 @@ var gitStashTool = {
273193
273330
  var gitBranchCreateTool = {
273194
273331
  name: "git-branch-create",
273195
273332
  description: "create a new branch without switching to it",
273333
+ tag: "git",
273196
273334
  safe: false,
273197
273335
  permissionLabel: "git branch (create)",
273198
273336
  systemPromptEntry: (i) => `### ${i}. git-branch-create — create a branch
@@ -273212,6 +273350,7 @@ var gitBranchCreateTool = {
273212
273350
  var gitBranchDeleteTool = {
273213
273351
  name: "git-branch-delete",
273214
273352
  description: "delete a branch",
273353
+ tag: "git",
273215
273354
  safe: false,
273216
273355
  permissionLabel: "git branch -d",
273217
273356
  systemPromptEntry: (i) => `### ${i}. git-branch-delete — delete a branch
@@ -273235,6 +273374,7 @@ var gitBranchDeleteTool = {
273235
273374
  var gitCherryPickTool = {
273236
273375
  name: "git-cherry-pick",
273237
273376
  description: "apply a specific commit from another branch",
273377
+ tag: "git",
273238
273378
  safe: false,
273239
273379
  permissionLabel: "git cherry-pick",
273240
273380
  systemPromptEntry: (i) => `### ${i}. git-cherry-pick — apply a commit by hash
@@ -273254,6 +273394,7 @@ var gitCherryPickTool = {
273254
273394
  var gitTagCreateTool = {
273255
273395
  name: "git-tag-create",
273256
273396
  description: "create a lightweight or annotated tag",
273397
+ tag: "git",
273257
273398
  safe: false,
273258
273399
  permissionLabel: "git tag (create)",
273259
273400
  systemPromptEntry: (i) => `### ${i}. git-tag-create — create a tag
@@ -273274,6 +273415,7 @@ var gitTagCreateTool = {
273274
273415
  var gitRestoreTool = {
273275
273416
  name: "git-restore",
273276
273417
  description: "discard working directory changes for a file (cannot be undone)",
273418
+ tag: "git",
273277
273419
  safe: false,
273278
273420
  permissionLabel: "git restore",
273279
273421
  systemPromptEntry: (i) => `### ${i}. git-restore — discard changes in a file (irreversible)
@@ -273293,6 +273435,7 @@ var gitRestoreTool = {
273293
273435
  var gitCleanTool = {
273294
273436
  name: "git-clean",
273295
273437
  description: "remove untracked files (cannot be undone)",
273438
+ tag: "git",
273296
273439
  safe: false,
273297
273440
  permissionLabel: "git clean",
273298
273441
  systemPromptEntry: (i) => `### ${i}. git-clean — remove untracked files (irreversible)
@@ -274643,324 +274786,82 @@ function TimelineRunner({
274643
274786
  }, undefined, true, undefined, this);
274644
274787
  }
274645
274788
 
274646
- // src/utils/memory.ts
274647
- import { existsSync as existsSync13, mkdirSync as mkdirSync7, readFileSync as readFileSync12, writeFileSync as writeFileSync9 } from "fs";
274648
- import path17 from "path";
274649
- import os7 from "os";
274650
- var LENS_DIR2 = path17.join(os7.homedir(), ".lens");
274651
- var MEMORY_PATH = path17.join(LENS_DIR2, "memory.json");
274652
- function loadMemoryFile() {
274653
- if (!existsSync13(MEMORY_PATH))
274654
- return { entries: [], memories: [] };
274655
- try {
274656
- const data = JSON.parse(readFileSync12(MEMORY_PATH, "utf-8"));
274657
- return {
274658
- entries: data.entries ?? [],
274659
- memories: data.memories ?? []
274660
- };
274661
- } catch {
274662
- return { entries: [], memories: [] };
274663
- }
274664
- }
274665
- function saveMemoryFile(m) {
274666
- if (!existsSync13(LENS_DIR2))
274667
- mkdirSync7(LENS_DIR2, { recursive: true });
274668
- writeFileSync9(MEMORY_PATH, JSON.stringify(m, null, 2), "utf-8");
274669
- }
274670
- function appendMemory(entry) {
274671
- const m = loadMemoryFile();
274672
- m.entries.push({ ...entry, timestamp: new Date().toISOString() });
274673
- if (m.entries.length > 500)
274674
- m.entries = m.entries.slice(-500);
274675
- saveMemoryFile(m);
274676
- }
274677
- function buildMemorySummary(repoPath) {
274678
- const m = loadMemoryFile();
274679
- const relevant = m.entries.slice(-50);
274680
- const memories = m.memories;
274681
- const parts = [];
274682
- if (memories.length > 0) {
274683
- parts.push(`## MEMORIES ABOUT THIS REPO
274684
-
274685
- ${memories.map((mem) => `- [${mem.id}] ${mem.content}`).join(`
274686
- `)}`);
274687
- }
274688
- if (relevant.length > 0) {
274689
- const lines = relevant.map((e) => {
274690
- const ts = new Date(e.timestamp).toLocaleString();
274691
- return `[${ts}] ${e.kind}: ${e.detail} — ${e.summary}`;
274692
- });
274693
- parts.push(`## WHAT YOU HAVE ALREADY DONE IN THIS REPO
274694
-
274695
- The following actions have already been completed. Do NOT repeat them unless the user explicitly asks you to redo something:
274696
-
274697
- ${lines.join(`
274698
- `)}`);
274699
- }
274700
- return parts.join(`
274789
+ // src/components/chat/hooks/useChat.ts
274790
+ var import_react48 = __toESM(require_react(), 1);
274791
+ var import_react49 = __toESM(require_react(), 1);
274701
274792
 
274702
- `);
274703
- }
274704
- function clearRepoMemory(repoPath) {
274705
- const m = loadMemoryFile();
274706
- m.entries = m.entries = [];
274707
- m.memories = m.memories = [];
274708
- saveMemoryFile(m);
274709
- }
274710
- function generateId() {
274711
- return Math.random().toString(36).slice(2, 8);
274712
- }
274713
- function addMemory(content, repoPath) {
274714
- const m = loadMemoryFile();
274715
- const memory = {
274716
- id: generateId(),
274717
- content,
274718
- timestamp: new Date().toISOString()
274719
- };
274720
- m.memories.push(memory);
274721
- saveMemoryFile(m);
274722
- return memory;
274723
- }
274724
- function deleteMemory(id, repoPath) {
274725
- const m = loadMemoryFile();
274726
- const before2 = m.memories.length;
274727
- m.memories = m.memories.filter((mem) => !(mem.id === id));
274728
- if (m.memories.length === before2)
274729
- return false;
274730
- saveMemoryFile(m);
274731
- return true;
274732
- }
274733
- function listMemories(repoPath) {
274734
- return loadMemoryFile().memories;
274793
+ // src/utils/intentClassifier.ts
274794
+ var READONLY_PATTERNS = [
274795
+ /\b(list|ls|dir|show|display|print|dump)\b/i,
274796
+ /\bwhat(('?s| is| are| does)\b| files| folder)/i,
274797
+ /\b(folder|directory|file) (structure|tree|layout|contents?)\b/i,
274798
+ /\bexplore\b/i,
274799
+ /\b(read|open|view|look at|check out|inspect|peek)\b/i,
274800
+ /\b(explain|describe|summarize|summarise|tell me about|walk me through)\b/i,
274801
+ /\bhow does\b/i,
274802
+ /\bwhat('?s| is) (in|inside|this|that|the)\b/i,
274803
+ /\b(find|search|grep|locate|where is|where are)\b/i,
274804
+ /\b(look for|scan|trace)\b/i,
274805
+ /\bunderstand\b/i,
274806
+ /\bshow me (how|what|where|why)\b/i
274807
+ ];
274808
+ var MUTATING_PATTERNS = [
274809
+ /\b(write|create|make|generate|add|build|scaffold|init|initialize|setup|set up)\b/i,
274810
+ /\b(new file|new folder|new component|new page|new route)\b/i,
274811
+ /\b(edit|modify|update|change|refactor|rename|move|migrate)\b/i,
274812
+ /\b(fix|patch|resolve|correct|debug|repair)\b/i,
274813
+ /\b(implement|add .+ to|insert|inject|append|prepend)\b/i,
274814
+ /\b(delete|remove|drop|clean ?up|purge|wipe)\b/i,
274815
+ /\b(run|execute|install|deploy|build|test|start|launch|compile|lint|format)\b/i
274816
+ ];
274817
+ function classifyIntent(userMessage) {
274818
+ const text = userMessage.trim();
274819
+ const mutatingScore = MUTATING_PATTERNS.filter((p) => p.test(text)).length;
274820
+ const readonlyScore = READONLY_PATTERNS.filter((p) => p.test(text)).length;
274821
+ if (mutatingScore === 0 && readonlyScore > 0)
274822
+ return "readonly";
274823
+ if (mutatingScore > 0)
274824
+ return "mutating";
274825
+ return "any";
274735
274826
  }
274736
274827
 
274737
- // src/components/chat/ChatRunner.tsx
274738
- var jsx_dev_runtime22 = __toESM(require_jsx_dev_runtime(), 1);
274739
- var COMMANDS = [
274740
- { cmd: "/timeline", desc: "browse commit history" },
274741
- { cmd: "/clear history", desc: "wipe session memory for this repo" },
274742
- { cmd: "/review", desc: "review current codebase" },
274743
- { cmd: "/auto", desc: "toggle auto-approve for read/search tools" },
274744
- {
274745
- cmd: "/auto --force-all",
274746
- desc: "auto-approve ALL tools including shell and writes (⚠ dangerous)"
274747
- },
274748
- { cmd: "/chat", desc: "chat history commands" },
274749
- { cmd: "/chat list", desc: "list saved chats for this repo" },
274750
- { cmd: "/chat load", desc: "load a saved chat by name" },
274751
- { cmd: "/chat rename", desc: "rename the current chat" },
274752
- { cmd: "/chat delete", desc: "delete a saved chat by name" },
274753
- { cmd: "/memory", desc: "memory commands" },
274754
- { cmd: "/memory list", desc: "list all memories for this repo" },
274755
- { cmd: "/memory add", desc: "add a memory" },
274756
- { cmd: "/memory delete", desc: "delete a memory by id" },
274757
- { cmd: "/memory clear", desc: "clear all memories for this repo" }
274758
- ];
274759
- function CommandPalette({
274760
- query,
274761
- onSelect,
274762
- recentChats
274763
- }) {
274764
- const q = query.toLowerCase();
274765
- const isChatLoad = q.startsWith("/chat load") || q.startsWith("/chat delete");
274766
- const chatFilter = isChatLoad ? q.startsWith("/chat load") ? q.slice("/chat load".length).trim() : q.slice("/chat delete".length).trim() : "";
274767
- const filteredChats = chatFilter ? recentChats.filter((n) => n.toLowerCase().includes(chatFilter)) : recentChats;
274768
- const matches2 = COMMANDS.filter((c) => c.cmd.startsWith(q));
274769
- if (!matches2.length && !isChatLoad)
274770
- return null;
274771
- if (!matches2.length && isChatLoad && filteredChats.length === 0)
274772
- return null;
274773
- return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
274774
- flexDirection: "column",
274775
- marginBottom: 1,
274776
- marginLeft: 2,
274777
- children: [
274778
- matches2.map((c, i) => {
274779
- const isExact = c.cmd === query;
274780
- return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
274781
- gap: 2,
274782
- children: [
274783
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
274784
- color: isExact ? ACCENT : "white",
274785
- bold: isExact,
274786
- children: c.cmd
274787
- }, undefined, false, undefined, this),
274788
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
274789
- color: "gray",
274790
- dimColor: true,
274791
- children: c.desc
274792
- }, undefined, false, undefined, this)
274793
- ]
274794
- }, i, true, undefined, this);
274795
- }),
274796
- isChatLoad && filteredChats.length > 0 && /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
274797
- flexDirection: "column",
274798
- marginTop: matches2.length ? 1 : 0,
274799
- children: [
274800
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
274801
- color: "gray",
274802
- dimColor: true,
274803
- children: chatFilter ? `matching "${chatFilter}":` : "recent chats:"
274804
- }, undefined, false, undefined, this),
274805
- filteredChats.map((name, i) => /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
274806
- gap: 1,
274807
- marginLeft: 2,
274808
- children: [
274809
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
274810
- color: ACCENT,
274811
- children: "·"
274812
- }, undefined, false, undefined, this),
274813
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
274814
- color: "white",
274815
- children: name
274816
- }, undefined, false, undefined, this)
274817
- ]
274818
- }, i, true, undefined, this))
274819
- ]
274820
- }, undefined, true, undefined, this)
274821
- ]
274822
- }, undefined, true, undefined, this);
274823
- }
274824
- function ForceAllWarning({
274825
- onConfirm
274826
- }) {
274827
- const [input, setInput] = import_react49.useState("");
274828
- return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
274829
- flexDirection: "column",
274830
- marginY: 1,
274831
- gap: 1,
274832
- children: [
274833
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
274834
- gap: 1,
274835
- children: /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
274836
- color: "red",
274837
- bold: true,
274838
- children: "⚠ WARNING"
274839
- }, undefined, false, undefined, this)
274840
- }, undefined, false, undefined, this),
274841
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
274842
- flexDirection: "column",
274843
- marginLeft: 2,
274844
- gap: 1,
274845
- children: [
274846
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
274847
- color: "yellow",
274848
- children: "Force-all mode auto-approves EVERY tool without asking — including:"
274849
- }, undefined, false, undefined, this),
274850
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
274851
- color: "red",
274852
- dimColor: true,
274853
- children: [
274854
- " ",
274855
- "· shell commands (rm, git, npm, anything)"
274856
- ]
274857
- }, undefined, true, undefined, this),
274858
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
274859
- color: "red",
274860
- dimColor: true,
274861
- children: [
274862
- " ",
274863
- "· file writes and deletes"
274864
- ]
274865
- }, undefined, true, undefined, this),
274866
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
274867
- color: "red",
274868
- dimColor: true,
274869
- children: [
274870
- " ",
274871
- "· folder deletes"
274872
- ]
274873
- }, undefined, true, undefined, this),
274874
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
274875
- color: "red",
274876
- dimColor: true,
274877
- children: [
274878
- " ",
274879
- "· external fetches and URL opens"
274880
- ]
274881
- }, undefined, true, undefined, this),
274882
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
274883
- color: "yellow",
274884
- dimColor: true,
274885
- children: "The AI can modify or delete files without any confirmation."
274886
- }, undefined, false, undefined, this),
274887
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
274888
- color: "yellow",
274889
- dimColor: true,
274890
- children: "Only use this in throwaway environments or when you fully trust the task."
274891
- }, undefined, false, undefined, this)
274892
- ]
274893
- }, undefined, true, undefined, this),
274894
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
274895
- gap: 1,
274896
- marginTop: 1,
274897
- children: [
274898
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
274899
- color: "gray",
274900
- children: "Type "
274901
- }, undefined, false, undefined, this),
274902
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
274903
- color: "white",
274904
- bold: true,
274905
- children: "yes"
274906
- }, undefined, false, undefined, this),
274907
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
274908
- color: "gray",
274909
- children: " to enable, or press "
274910
- }, undefined, false, undefined, this),
274911
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
274912
- color: "white",
274913
- bold: true,
274914
- children: "esc"
274915
- }, undefined, false, undefined, this),
274916
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
274917
- color: "gray",
274918
- children: " to cancel: "
274919
- }, undefined, false, undefined, this),
274920
- /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(build_default2, {
274921
- value: input,
274922
- onChange: setInput,
274923
- onSubmit: (v) => onConfirm(v.trim().toLowerCase() === "yes"),
274924
- placeholder: "yes / esc to cancel"
274925
- }, undefined, false, undefined, this)
274926
- ]
274927
- }, undefined, true, undefined, this)
274928
- ]
274929
- }, undefined, true, undefined, this);
274930
- }
274931
- var ChatRunner = ({ repoPath }) => {
274932
- const [stage, setStage] = import_react49.useState({ type: "picking-provider" });
274933
- const [committed, setCommitted] = import_react49.useState([]);
274934
- const [provider, setProvider] = import_react49.useState(null);
274935
- const [systemPrompt, setSystemPrompt] = import_react49.useState("");
274936
- const [inputValue, setInputValue] = import_react49.useState("");
274937
- const [pendingMsgIndex, setPendingMsgIndex] = import_react49.useState(null);
274938
- const [allMessages, setAllMessages] = import_react49.useState([]);
274939
- const [clonedUrls, setClonedUrls] = import_react49.useState(new Set);
274940
- const [showTimeline, setShowTimeline] = import_react49.useState(false);
274941
- const [showReview, setShowReview] = import_react49.useState(false);
274942
- const [autoApprove, setAutoApprove] = import_react49.useState(false);
274943
- const [forceApprove, setForceApprove] = import_react49.useState(false);
274944
- const [showForceWarning, setShowForceWarning] = import_react49.useState(false);
274945
- const [chatName, setChatName] = import_react49.useState(null);
274946
- const chatNameRef = import_react49.useRef(null);
274947
- const [recentChats, setRecentChats] = import_react49.useState([]);
274948
- const inputHistoryRef = import_react49.useRef([]);
274949
- const historyIndexRef = import_react49.useRef(-1);
274950
- const [inputKey, setInputKey] = import_react49.useState(0);
274828
+ // src/components/chat/hooks/useChat.ts
274829
+ function useChat(repoPath) {
274830
+ const [stage, setStage] = import_react48.useState({ type: "picking-provider" });
274831
+ const [committed, setCommitted] = import_react48.useState([]);
274832
+ const [provider, setProvider] = import_react48.useState(null);
274833
+ const [systemPrompt, setSystemPrompt] = import_react48.useState("");
274834
+ const [pendingMsgIndex, setPendingMsgIndex] = import_react48.useState(null);
274835
+ const [allMessages, setAllMessages] = import_react48.useState([]);
274836
+ const [clonedUrls, setClonedUrls] = import_react48.useState(new Set);
274837
+ const [showTimeline, setShowTimeline] = import_react48.useState(false);
274838
+ const [showReview, setShowReview] = import_react48.useState(false);
274839
+ const [autoApprove, setAutoApprove] = import_react48.useState(false);
274840
+ const [forceApprove, setForceApprove] = import_react48.useState(false);
274841
+ const [showForceWarning, setShowForceWarning] = import_react48.useState(false);
274842
+ const [chatName, setChatName] = import_react48.useState(null);
274843
+ const [recentChats, setRecentChats] = import_react48.useState([]);
274844
+ const chatNameRef = import_react48.useRef(null);
274845
+ const providerRef = import_react48.useRef(null);
274846
+ const systemPromptRef = import_react48.useRef("");
274847
+ const abortControllerRef = import_react48.useRef(null);
274848
+ const toolResultCache = import_react48.useRef(new Map);
274849
+ const batchApprovedRef = import_react48.useRef(false);
274951
274850
  const updateChatName = (name) => {
274952
274851
  chatNameRef.current = name;
274953
274852
  setChatName(name);
274954
274853
  };
274955
- const abortControllerRef = import_react49.useRef(null);
274956
- const toolResultCache = import_react49.useRef(new Map);
274957
- const batchApprovedRef = import_react49.useRef(false);
274958
- const thinkingPhrase = useThinkingPhrase(stage.type === "thinking");
274959
- import_react48.default.useEffect(() => {
274854
+ import_react49.default.useEffect(() => {
274855
+ providerRef.current = provider;
274856
+ }, [provider]);
274857
+ import_react49.default.useEffect(() => {
274858
+ systemPromptRef.current = systemPrompt;
274859
+ }, [systemPrompt]);
274860
+ import_react49.default.useEffect(() => {
274960
274861
  const chats = listChats(repoPath);
274961
274862
  setRecentChats(chats.slice(0, 10).map((c) => c.name));
274962
274863
  }, [repoPath]);
274963
- import_react48.default.useEffect(() => {
274864
+ import_react49.default.useEffect(() => {
274964
274865
  if (chatNameRef.current && allMessages.length > 1) {
274965
274866
  saveChat(chatNameRef.current, repoPath, allMessages);
274966
274867
  }
@@ -275135,6 +275036,13 @@ var ChatRunner = ({ repoPath }) => {
275135
275036
  if (approved && remainder) {
275136
275037
  batchApprovedRef.current = true;
275137
275038
  }
275039
+ const currentProvider = providerRef.current;
275040
+ const currentSystemPrompt = systemPromptRef.current;
275041
+ if (!currentProvider) {
275042
+ batchApprovedRef.current = false;
275043
+ setStage({ type: "idle" });
275044
+ return;
275045
+ }
275138
275046
  let result2 = "(denied by user)";
275139
275047
  if (approved) {
275140
275048
  const cacheKey = isSafe ? `${parsed.toolName}:${parsed.rawInput}` : null;
@@ -275186,7 +275094,22 @@ var ChatRunner = ({ repoPath }) => {
275186
275094
  const nextAbort = new AbortController;
275187
275095
  abortControllerRef.current = nextAbort;
275188
275096
  setStage({ type: "thinking" });
275189
- callChat(provider, systemPrompt, withTool, nextAbort.signal).then((r) => processResponse(r, withTool, nextAbort.signal)).catch(handleError(withTool));
275097
+ callChat(currentProvider, currentSystemPrompt, withTool, nextAbort.signal).then((r) => {
275098
+ if (nextAbort.signal.aborted)
275099
+ return;
275100
+ if (!r.trim()) {
275101
+ const nudged = [
275102
+ ...withTool,
275103
+ { role: "user", content: "Please continue.", type: "text" }
275104
+ ];
275105
+ return callChat(currentProvider, currentSystemPrompt, nudged, nextAbort.signal);
275106
+ }
275107
+ return r;
275108
+ }).then((r) => {
275109
+ if (nextAbort.signal.aborted)
275110
+ return;
275111
+ processResponse(r ?? "", withTool, nextAbort.signal);
275112
+ }).catch(handleError(withTool));
275190
275113
  };
275191
275114
  if (forceApprove || autoApprove && isSafe || batchApprovedRef.current) {
275192
275115
  executeAndContinue(true);
@@ -275205,291 +275128,332 @@ var ChatRunner = ({ repoPath }) => {
275205
275128
  resolve: executeAndContinue
275206
275129
  });
275207
275130
  };
275208
- const sendMessage = (text) => {
275209
- if (!provider)
275210
- return;
275211
- if (text.trim().toLowerCase() === "/timeline") {
275212
- setShowTimeline(true);
275213
- return;
275214
- }
275215
- if (text.trim().toLowerCase() === "/review") {
275216
- setShowReview(true);
275217
- return;
275218
- }
275219
- if (text.trim().toLowerCase() === "/auto --force-all") {
275220
- if (forceApprove) {
275221
- setForceApprove(false);
275222
- setAutoApprove(false);
275223
- const msg = {
275224
- role: "assistant",
275225
- content: "Force-all mode OFF — tools will ask for permission again.",
275226
- type: "text"
275227
- };
275228
- setCommitted((prev) => [...prev, msg]);
275229
- setAllMessages((prev) => [...prev, msg]);
275230
- } else {
275231
- setShowForceWarning(true);
275232
- }
275233
- return;
275131
+ const sendMessage = (text, currentProvider, currentSystemPrompt, currentAllMessages) => {
275132
+ const userMsg = { role: "user", content: text, type: "text" };
275133
+ const nextAll = [...currentAllMessages, userMsg];
275134
+ setCommitted((prev) => [...prev, userMsg]);
275135
+ setAllMessages(nextAll);
275136
+ batchApprovedRef.current = false;
275137
+ if (!chatName) {
275138
+ const name = getChatNameSuggestions(nextAll)[0] ?? `chat-${new Date().toISOString().slice(0, 10)}`;
275139
+ updateChatName(name);
275140
+ setRecentChats((prev) => [name, ...prev.filter((n) => n !== name)].slice(0, 10));
275141
+ saveChat(name, repoPath, nextAll);
275234
275142
  }
275235
- if (text.trim().toLowerCase() === "/auto") {
275236
- if (forceApprove) {
275237
- setForceApprove(false);
275238
- setAutoApprove(true);
275239
- const msg2 = {
275240
- role: "assistant",
275241
- content: "Force-all mode OFF — switched to normal auto-approve (safe tools only).",
275242
- type: "text"
275243
- };
275244
- setCommitted((prev) => [...prev, msg2]);
275245
- setAllMessages((prev) => [...prev, msg2]);
275246
- return;
275247
- }
275248
- const next = !autoApprove;
275249
- setAutoApprove(next);
275250
- const msg = {
275143
+ const abort = new AbortController;
275144
+ abortControllerRef.current = abort;
275145
+ const intent = classifyIntent(text);
275146
+ const scopedToolsSection = registry.buildSystemPromptSection(intent);
275147
+ const scopedSystemPrompt = currentSystemPrompt.replace(/## TOOLS[\s\S]*?(?=\n## (?!TOOLS))/, scopedToolsSection + `
275148
+
275149
+ `);
275150
+ setStage({ type: "thinking" });
275151
+ callChat(currentProvider, scopedSystemPrompt, nextAll, abort.signal).then((raw) => processResponse(raw, nextAll, abort.signal)).catch(handleError(nextAll));
275152
+ };
275153
+ const handleProviderDone = (p) => {
275154
+ setProvider(p);
275155
+ providerRef.current = p;
275156
+ setStage({ type: "loading" });
275157
+ fetchFileTree(repoPath).catch(() => walkDir(repoPath)).then((fileTree) => {
275158
+ const importantFiles = readImportantFiles(repoPath, fileTree);
275159
+ const historySummary = buildMemorySummary(repoPath);
275160
+ const lensFile = readLensFile(repoPath);
275161
+ const lensContext = lensFile ? `
275162
+
275163
+ ## LENS.md (previous analysis)
275164
+ ${lensFile.overview}
275165
+
275166
+ Important folders: ${lensFile.importantFolders.join(", ")}
275167
+ Suggestions: ${lensFile.suggestions.slice(0, 3).join("; ")}` : "";
275168
+ const toolsSection = registry.buildSystemPromptSection();
275169
+ const prompt = buildSystemPrompt(importantFiles, historySummary, toolsSection) + lensContext;
275170
+ setSystemPrompt(prompt);
275171
+ systemPromptRef.current = prompt;
275172
+ const greeting = {
275251
275173
  role: "assistant",
275252
- content: next ? "Auto-approve ON — safe tools (read, search, fetch) will run without asking." : "Auto-approve OFF — all tools will ask for permission.",
275174
+ content: `Welcome to Lens
275175
+ Codebase loaded — ${importantFiles.length} files indexed.${historySummary ? `
275176
+
275177
+ I have memory of previous actions in this repo.` : ""}${lensFile ? `
275178
+
275179
+ Found LENS.md — I have context from a previous analysis of this repo.` : ""}
275180
+ Ask me anything, tell me what to build, share a URL, or ask me to read/write files.
275181
+
275182
+ Tip: type /timeline to browse commit history.
275183
+ Tip: ⭐ Star Lens on GitHub — github.com/ridit-jangra/Lens`,
275253
275184
  type: "text"
275254
275185
  };
275255
- setCommitted((prev) => [...prev, msg]);
275256
- setAllMessages((prev) => [...prev, msg]);
275257
- return;
275186
+ setCommitted([greeting]);
275187
+ setAllMessages([greeting]);
275188
+ setStage({ type: "idle" });
275189
+ }).catch(() => setStage({ type: "idle" }));
275190
+ };
275191
+ const abortThinking = () => {
275192
+ abortControllerRef.current?.abort();
275193
+ abortControllerRef.current = null;
275194
+ batchApprovedRef.current = false;
275195
+ setStage({ type: "idle" });
275196
+ };
275197
+ const applyPatchesAndContinue = (patches) => {
275198
+ try {
275199
+ applyPatches2(repoPath, patches);
275200
+ appendMemory({
275201
+ kind: "code-applied",
275202
+ detail: patches.map((p) => p.path).join(", "),
275203
+ summary: `Applied changes to ${patches.length} file(s)`
275204
+ });
275205
+ } catch {}
275206
+ };
275207
+ const skipPatches = (patches) => {
275208
+ appendMemory({
275209
+ kind: "code-skipped",
275210
+ detail: patches.map((p) => p.path).join(", "),
275211
+ summary: `Skipped changes to ${patches.length} file(s)`
275212
+ });
275213
+ };
275214
+ return {
275215
+ stage,
275216
+ setStage,
275217
+ committed,
275218
+ setCommitted,
275219
+ provider,
275220
+ setProvider,
275221
+ systemPrompt,
275222
+ allMessages,
275223
+ setAllMessages,
275224
+ clonedUrls,
275225
+ setClonedUrls,
275226
+ showTimeline,
275227
+ setShowTimeline,
275228
+ showReview,
275229
+ setShowReview,
275230
+ autoApprove,
275231
+ setAutoApprove,
275232
+ forceApprove,
275233
+ setForceApprove,
275234
+ showForceWarning,
275235
+ setShowForceWarning,
275236
+ chatName,
275237
+ setChatName,
275238
+ recentChats,
275239
+ setRecentChats,
275240
+ pendingMsgIndex,
275241
+ setPendingMsgIndex,
275242
+ chatNameRef,
275243
+ providerRef,
275244
+ batchApprovedRef,
275245
+ updateChatName,
275246
+ sendMessage,
275247
+ handleProviderDone,
275248
+ abortThinking,
275249
+ applyPatchesAndContinue,
275250
+ skipPatches,
275251
+ processResponse,
275252
+ handleError
275253
+ };
275254
+ }
275255
+
275256
+ // src/components/chat/hooks/useChatInput.ts
275257
+ var import_react50 = __toESM(require_react(), 1);
275258
+
275259
+ // src/components/chat/hooks/useCommandHandlers.ts
275260
+ var COMMANDS = [
275261
+ { cmd: "/timeline", desc: "browse commit history" },
275262
+ { cmd: "/clear history", desc: "wipe session memory for this repo" },
275263
+ { cmd: "/review", desc: "review current codebase" },
275264
+ { cmd: "/auto", desc: "toggle auto-approve for read/search tools" },
275265
+ {
275266
+ cmd: "/auto --force-all",
275267
+ desc: "auto-approve ALL tools including shell and writes (⚠ dangerous)"
275268
+ },
275269
+ { cmd: "/chat", desc: "chat history commands" },
275270
+ { cmd: "/chat list", desc: "list saved chats for this repo" },
275271
+ { cmd: "/chat load", desc: "load a saved chat by name" },
275272
+ { cmd: "/chat rename", desc: "rename the current chat" },
275273
+ { cmd: "/chat delete", desc: "delete a saved chat by name" },
275274
+ { cmd: "/memory", desc: "memory commands" },
275275
+ { cmd: "/memory list", desc: "list all memories for this repo" },
275276
+ { cmd: "/memory add", desc: "add a memory" },
275277
+ { cmd: "/memory delete", desc: "delete a memory by id" },
275278
+ { cmd: "/memory clear", desc: "clear all memories for this repo" }
275279
+ ];
275280
+ function pushMsg(msg, setCommitted, setAllMessages) {
275281
+ setCommitted((prev) => [...prev, msg]);
275282
+ setAllMessages((prev) => [...prev, msg]);
275283
+ }
275284
+ function makeMsg(content) {
275285
+ return { role: "assistant", content, type: "text" };
275286
+ }
275287
+ function handleCommand(text, ctx) {
275288
+ const t = text.trim().toLowerCase();
275289
+ if (t === "/timeline") {
275290
+ ctx.setShowTimeline(true);
275291
+ return true;
275292
+ }
275293
+ if (t === "/review") {
275294
+ ctx.setShowReview(true);
275295
+ return true;
275296
+ }
275297
+ if (t === "/auto --force-all") {
275298
+ if (ctx.forceApprove) {
275299
+ ctx.setForceApprove(false);
275300
+ ctx.setAutoApprove(false);
275301
+ pushMsg(makeMsg("Force-all mode OFF — tools will ask for permission again."), ctx.setCommitted, ctx.setAllMessages);
275302
+ } else {
275303
+ ctx.setShowForceWarning(true);
275258
275304
  }
275259
- if (text.trim().toLowerCase() === "/clear history") {
275260
- clearRepoMemory(repoPath);
275261
- const msg = {
275262
- role: "assistant",
275263
- content: "History cleared for this repo.",
275264
- type: "text"
275265
- };
275266
- setCommitted((prev) => [...prev, msg]);
275267
- setAllMessages((prev) => [...prev, msg]);
275268
- return;
275305
+ return true;
275306
+ }
275307
+ if (t === "/auto") {
275308
+ if (ctx.forceApprove) {
275309
+ ctx.setForceApprove(false);
275310
+ ctx.setAutoApprove(true);
275311
+ pushMsg(makeMsg("Force-all mode OFF — switched to normal auto-approve (safe tools only)."), ctx.setCommitted, ctx.setAllMessages);
275312
+ return true;
275269
275313
  }
275270
- if (text.trim().toLowerCase() === "/chat") {
275271
- const msg = {
275272
- role: "assistant",
275273
- content: "Chat commands: `/chat list` · `/chat load <n>` · `/chat rename <n>` · `/chat delete <n>`",
275274
- type: "text"
275275
- };
275276
- setCommitted((prev) => [...prev, msg]);
275277
- setAllMessages((prev) => [...prev, msg]);
275278
- return;
275314
+ const next = !ctx.autoApprove;
275315
+ ctx.setAutoApprove(next);
275316
+ pushMsg(makeMsg(next ? "Auto-approve ON — safe tools (read, search, fetch) will run without asking." : "Auto-approve OFF — all tools will ask for permission."), ctx.setCommitted, ctx.setAllMessages);
275317
+ return true;
275318
+ }
275319
+ if (t === "/clear history") {
275320
+ clearRepoMemory(ctx.repoPath);
275321
+ pushMsg(makeMsg("History cleared for this repo."), ctx.setCommitted, ctx.setAllMessages);
275322
+ return true;
275323
+ }
275324
+ if (t === "/chat") {
275325
+ pushMsg(makeMsg("Chat commands: `/chat list` · `/chat load <n>` · `/chat rename <n>` · `/chat delete <n>`"), ctx.setCommitted, ctx.setAllMessages);
275326
+ return true;
275327
+ }
275328
+ if (t.startsWith("/chat rename")) {
275329
+ const parts = text.trim().split(/\s+/);
275330
+ const newName = parts.slice(2).join("-");
275331
+ if (!newName) {
275332
+ pushMsg(makeMsg("Usage: `/chat rename <new-name>`"), ctx.setCommitted, ctx.setAllMessages);
275333
+ return true;
275279
275334
  }
275280
- if (text.trim().toLowerCase().startsWith("/chat rename")) {
275281
- const parts = text.trim().split(/\s+/);
275282
- const newName = parts.slice(2).join("-");
275283
- if (!newName) {
275284
- const msg2 = {
275285
- role: "assistant",
275286
- content: "Usage: `/chat rename <new-name>`",
275287
- type: "text"
275288
- };
275289
- setCommitted((prev) => [...prev, msg2]);
275290
- setAllMessages((prev) => [...prev, msg2]);
275291
- return;
275292
- }
275293
- const oldName = chatNameRef.current;
275294
- if (oldName)
275295
- deleteChat(oldName);
275296
- updateChatName(newName);
275297
- saveChat(newName, repoPath, allMessages);
275298
- setRecentChats((prev) => [newName, ...prev.filter((n) => n !== newName && n !== oldName)].slice(0, 10));
275299
- const msg = {
275300
- role: "assistant",
275301
- content: `Chat renamed to **${newName}**.`,
275302
- type: "text"
275303
- };
275304
- setCommitted((prev) => [...prev, msg]);
275305
- setAllMessages((prev) => [...prev, msg]);
275306
- return;
275335
+ const oldName = ctx.chatNameRef.current;
275336
+ if (oldName)
275337
+ deleteChat(oldName);
275338
+ ctx.updateChatName(newName);
275339
+ saveChat(newName, ctx.repoPath, ctx.allMessages);
275340
+ ctx.setRecentChats((prev) => [newName, ...prev.filter((n) => n !== newName && n !== oldName)].slice(0, 10));
275341
+ pushMsg(makeMsg(`Chat renamed to **${newName}**.`), ctx.setCommitted, ctx.setAllMessages);
275342
+ return true;
275343
+ }
275344
+ if (t.startsWith("/chat delete")) {
275345
+ const parts = text.trim().split(/\s+/);
275346
+ const name = parts.slice(2).join("-");
275347
+ if (!name) {
275348
+ pushMsg(makeMsg("Usage: `/chat delete <n>`"), ctx.setCommitted, ctx.setAllMessages);
275349
+ return true;
275307
275350
  }
275308
- if (text.trim().toLowerCase().startsWith("/chat delete")) {
275309
- const parts = text.trim().split(/\s+/);
275310
- const name = parts.slice(2).join("-");
275311
- if (!name) {
275312
- const msg2 = {
275313
- role: "assistant",
275314
- content: "Usage: `/chat delete <n>`",
275315
- type: "text"
275316
- };
275317
- setCommitted((prev) => [...prev, msg2]);
275318
- setAllMessages((prev) => [...prev, msg2]);
275319
- return;
275320
- }
275321
- const deleted = deleteChat(name);
275322
- if (!deleted) {
275323
- const msg2 = {
275324
- role: "assistant",
275325
- content: `Chat **${name}** not found.`,
275326
- type: "text"
275327
- };
275328
- setCommitted((prev) => [...prev, msg2]);
275329
- setAllMessages((prev) => [...prev, msg2]);
275330
- return;
275331
- }
275332
- if (chatNameRef.current === name) {
275333
- chatNameRef.current = null;
275334
- setChatName(null);
275335
- }
275336
- setRecentChats((prev) => prev.filter((n) => n !== name));
275337
- const msg = {
275338
- role: "assistant",
275339
- content: `Chat **${name}** deleted.`,
275340
- type: "text"
275341
- };
275342
- setCommitted((prev) => [...prev, msg]);
275343
- setAllMessages((prev) => [...prev, msg]);
275344
- return;
275351
+ const deleted = deleteChat(name);
275352
+ if (!deleted) {
275353
+ pushMsg(makeMsg(`Chat **${name}** not found.`), ctx.setCommitted, ctx.setAllMessages);
275354
+ return true;
275355
+ }
275356
+ if (ctx.chatNameRef.current === name) {
275357
+ ctx.chatNameRef.current = null;
275358
+ ctx.updateChatName("");
275345
275359
  }
275346
- if (text.trim().toLowerCase() === "/chat list") {
275347
- const chats = listChats(repoPath);
275348
- const content = chats.length === 0 ? "No saved chats for this repo yet." : `Saved chats:
275360
+ ctx.setRecentChats((prev) => prev.filter((n) => n !== name));
275361
+ pushMsg(makeMsg(`Chat **${name}** deleted.`), ctx.setCommitted, ctx.setAllMessages);
275362
+ return true;
275363
+ }
275364
+ if (t === "/chat list") {
275365
+ const chats = listChats(ctx.repoPath);
275366
+ const content = chats.length === 0 ? "No saved chats for this repo yet." : `Saved chats:
275349
275367
 
275350
275368
  ${chats.map((c) => `- **${c.name}** · ${c.userMessageCount} messages · ${new Date(c.savedAt).toLocaleString()}`).join(`
275351
275369
  `)}`;
275352
- const msg = { role: "assistant", content, type: "text" };
275353
- setCommitted((prev) => [...prev, msg]);
275354
- setAllMessages((prev) => [...prev, msg]);
275355
- return;
275356
- }
275357
- if (text.trim().toLowerCase().startsWith("/chat load")) {
275358
- const parts = text.trim().split(/\s+/);
275359
- const name = parts.slice(2).join("-");
275360
- if (!name) {
275361
- const chats = listChats(repoPath);
275362
- const content = chats.length === 0 ? "No saved chats found." : `Specify a chat name. Recent chats:
275370
+ pushMsg(makeMsg(content), ctx.setCommitted, ctx.setAllMessages);
275371
+ return true;
275372
+ }
275373
+ if (t.startsWith("/chat load")) {
275374
+ const parts = text.trim().split(/\s+/);
275375
+ const name = parts.slice(2).join("-");
275376
+ if (!name) {
275377
+ const chats = listChats(ctx.repoPath);
275378
+ const content = chats.length === 0 ? "No saved chats found." : `Specify a chat name. Recent chats:
275363
275379
 
275364
275380
  ${chats.slice(0, 10).map((c) => `- **${c.name}**`).join(`
275365
275381
  `)}`;
275366
- const msg = { role: "assistant", content, type: "text" };
275367
- setCommitted((prev) => [...prev, msg]);
275368
- setAllMessages((prev) => [...prev, msg]);
275369
- return;
275370
- }
275371
- const saved = loadChat(name);
275372
- if (!saved) {
275373
- const msg = {
275374
- role: "assistant",
275375
- content: `Chat **${name}** not found. Use \`/chat list\` to see saved chats.`,
275376
- type: "text"
275377
- };
275378
- setCommitted((prev) => [...prev, msg]);
275379
- setAllMessages((prev) => [...prev, msg]);
275380
- return;
275381
- }
275382
- updateChatName(name);
275383
- setAllMessages(saved.messages);
275384
- setCommitted(saved.messages);
275385
- const notice = {
275386
- role: "assistant",
275387
- content: `Loaded chat **${name}** · ${saved.userMessageCount} messages · saved ${new Date(saved.savedAt).toLocaleString()}`,
275388
- type: "text"
275389
- };
275390
- setCommitted((prev) => [...prev, notice]);
275391
- setAllMessages((prev) => [...prev, notice]);
275392
- return;
275382
+ pushMsg(makeMsg(content), ctx.setCommitted, ctx.setAllMessages);
275383
+ return true;
275384
+ }
275385
+ const saved = loadChat(name);
275386
+ if (!saved) {
275387
+ pushMsg(makeMsg(`Chat **${name}** not found. Use \`/chat list\` to see saved chats.`), ctx.setCommitted, ctx.setAllMessages);
275388
+ return true;
275393
275389
  }
275394
- if (text.trim().toLowerCase() === "/memory list" || text.trim().toLowerCase() === "/memory") {
275395
- const mems = listMemories(repoPath);
275396
- const content = mems.length === 0 ? "No memories stored for this repo yet." : `Memories for this repo:
275390
+ ctx.updateChatName(name);
275391
+ ctx.setAllMessages(() => saved.messages);
275392
+ ctx.setCommitted(() => saved.messages);
275393
+ const notice = makeMsg(`Loaded chat **${name}** · ${saved.userMessageCount} messages · saved ${new Date(saved.savedAt).toLocaleString()}`);
275394
+ ctx.setCommitted((prev) => [...prev, notice]);
275395
+ ctx.setAllMessages((prev) => [...prev, notice]);
275396
+ return true;
275397
+ }
275398
+ if (t === "/memory list" || t === "/memory") {
275399
+ const mems = listMemories(ctx.repoPath);
275400
+ const content = mems.length === 0 ? "No memories stored for this repo yet." : `Memories for this repo:
275397
275401
 
275398
275402
  ${mems.map((m) => `- [${m.id}] ${m.content}`).join(`
275399
275403
  `)}`;
275400
- const msg = { role: "assistant", content, type: "text" };
275401
- setCommitted((prev) => [...prev, msg]);
275402
- setAllMessages((prev) => [...prev, msg]);
275403
- return;
275404
- }
275405
- if (text.trim().toLowerCase().startsWith("/memory add")) {
275406
- const content = text.trim().slice("/memory add".length).trim();
275407
- if (!content) {
275408
- const msg2 = {
275409
- role: "assistant",
275410
- content: "Usage: `/memory add <content>`",
275411
- type: "text"
275412
- };
275413
- setCommitted((prev) => [...prev, msg2]);
275414
- setAllMessages((prev) => [...prev, msg2]);
275415
- return;
275416
- }
275417
- const mem = addMemory(content, repoPath);
275418
- const msg = {
275419
- role: "assistant",
275420
- content: `Memory saved **[${mem.id}]**: ${mem.content}`,
275421
- type: "text"
275422
- };
275423
- setCommitted((prev) => [...prev, msg]);
275424
- setAllMessages((prev) => [...prev, msg]);
275425
- return;
275426
- }
275427
- if (text.trim().toLowerCase().startsWith("/memory delete")) {
275428
- const id = text.trim().split(/\s+/)[2];
275429
- if (!id) {
275430
- const msg2 = {
275431
- role: "assistant",
275432
- content: "Usage: `/memory delete <id>`",
275433
- type: "text"
275434
- };
275435
- setCommitted((prev) => [...prev, msg2]);
275436
- setAllMessages((prev) => [...prev, msg2]);
275437
- return;
275438
- }
275439
- const deleted = deleteMemory(id, repoPath);
275440
- const msg = {
275441
- role: "assistant",
275442
- content: deleted ? `Memory **[${id}]** deleted.` : `Memory **[${id}]** not found.`,
275443
- type: "text"
275444
- };
275445
- setCommitted((prev) => [...prev, msg]);
275446
- setAllMessages((prev) => [...prev, msg]);
275447
- return;
275404
+ pushMsg(makeMsg(content), ctx.setCommitted, ctx.setAllMessages);
275405
+ return true;
275406
+ }
275407
+ if (t.startsWith("/memory add")) {
275408
+ const content = text.trim().slice("/memory add".length).trim();
275409
+ if (!content) {
275410
+ pushMsg(makeMsg("Usage: `/memory add <content>`"), ctx.setCommitted, ctx.setAllMessages);
275411
+ return true;
275448
275412
  }
275449
- if (text.trim().toLowerCase() === "/memory clear") {
275450
- clearRepoMemory(repoPath);
275451
- const msg = {
275452
- role: "assistant",
275453
- content: "All memories cleared for this repo.",
275454
- type: "text"
275455
- };
275456
- setCommitted((prev) => [...prev, msg]);
275457
- setAllMessages((prev) => [...prev, msg]);
275458
- return;
275413
+ const mem = addMemory(content, ctx.repoPath);
275414
+ pushMsg(makeMsg(`Memory saved **[${mem.id}]**: ${mem.content}`), ctx.setCommitted, ctx.setAllMessages);
275415
+ return true;
275416
+ }
275417
+ if (t.startsWith("/memory delete")) {
275418
+ const id = text.trim().split(/\s+/)[2];
275419
+ if (!id) {
275420
+ pushMsg(makeMsg("Usage: `/memory delete <id>`"), ctx.setCommitted, ctx.setAllMessages);
275421
+ return true;
275459
275422
  }
275460
- const userMsg = { role: "user", content: text, type: "text" };
275461
- const nextAll = [...allMessages, userMsg];
275462
- setCommitted((prev) => [...prev, userMsg]);
275463
- setAllMessages(nextAll);
275464
- batchApprovedRef.current = false;
275423
+ const deleted = deleteMemory(id, ctx.repoPath);
275424
+ pushMsg(makeMsg(deleted ? `Memory **[${id}]** deleted.` : `Memory **[${id}]** not found.`), ctx.setCommitted, ctx.setAllMessages);
275425
+ return true;
275426
+ }
275427
+ if (t === "/memory clear") {
275428
+ clearRepoMemory(ctx.repoPath);
275429
+ pushMsg(makeMsg("All memories cleared for this repo."), ctx.setCommitted, ctx.setAllMessages);
275430
+ return true;
275431
+ }
275432
+ return false;
275433
+ }
275434
+
275435
+ // src/components/chat/hooks/useChatInput.ts
275436
+ function useChatInput(stage, showTimeline, showForceWarning, onAbortThinking, onStageKeyInput) {
275437
+ const [inputValue, setInputValue] = import_react50.useState("");
275438
+ const [inputKey, setInputKey] = import_react50.useState(0);
275439
+ const inputHistoryRef = import_react50.useRef([]);
275440
+ const historyIndexRef = import_react50.useRef(-1);
275441
+ const pushHistory = (text) => {
275465
275442
  inputHistoryRef.current = [
275466
275443
  text,
275467
275444
  ...inputHistoryRef.current.filter((m) => m !== text)
275468
275445
  ].slice(0, 50);
275469
275446
  historyIndexRef.current = -1;
275470
- if (!chatName) {
275471
- const name = getChatNameSuggestions(nextAll)[0] ?? `chat-${new Date().toISOString().slice(0, 10)}`;
275472
- updateChatName(name);
275473
- setRecentChats((prev) => [name, ...prev.filter((n) => n !== name)].slice(0, 10));
275474
- saveChat(name, repoPath, nextAll);
275475
- }
275476
- const abort = new AbortController;
275477
- abortControllerRef.current = abort;
275478
- setStage({ type: "thinking" });
275479
- callChat(provider, systemPrompt, nextAll, abort.signal).then((raw) => processResponse(raw, nextAll, abort.signal)).catch(handleError(nextAll));
275480
275447
  };
275481
275448
  use_input_default((input, key) => {
275482
275449
  if (showTimeline)
275483
275450
  return;
275484
275451
  if (showForceWarning && key.escape) {
275485
- setShowForceWarning(false);
275452
+ onStageKeyInput(input, key);
275486
275453
  return;
275487
275454
  }
275488
275455
  if (stage.type === "thinking" && key.escape) {
275489
- abortControllerRef.current?.abort();
275490
- abortControllerRef.current = null;
275491
- batchApprovedRef.current = false;
275492
- setStage({ type: "idle" });
275456
+ onAbortThinking();
275493
275457
  return;
275494
275458
  }
275495
275459
  if (stage.type === "idle") {
@@ -275520,12 +275484,204 @@ ${mems.map((m) => `- [${m.id}] ${m.content}`).join(`
275520
275484
  }
275521
275485
  return;
275522
275486
  }
275523
- if (stage.type === "clone-offer") {
275487
+ onStageKeyInput(input, key);
275488
+ });
275489
+ return {
275490
+ inputValue,
275491
+ setInputValue,
275492
+ inputKey,
275493
+ pushHistory
275494
+ };
275495
+ }
275496
+
275497
+ // src/components/chat/ChatRunner.tsx
275498
+ var jsx_dev_runtime22 = __toESM(require_jsx_dev_runtime(), 1);
275499
+ function CommandPalette({
275500
+ query,
275501
+ recentChats
275502
+ }) {
275503
+ const q = query.toLowerCase();
275504
+ const isChatLoad = q.startsWith("/chat load") || q.startsWith("/chat delete");
275505
+ const chatFilter = isChatLoad ? q.startsWith("/chat load") ? q.slice("/chat load".length).trim() : q.slice("/chat delete".length).trim() : "";
275506
+ const filteredChats = chatFilter ? recentChats.filter((n) => n.toLowerCase().includes(chatFilter)) : recentChats;
275507
+ const matches2 = COMMANDS.filter((c) => c.cmd.startsWith(q));
275508
+ if (!matches2.length && !isChatLoad)
275509
+ return null;
275510
+ if (!matches2.length && isChatLoad && filteredChats.length === 0)
275511
+ return null;
275512
+ return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
275513
+ flexDirection: "column",
275514
+ marginBottom: 1,
275515
+ marginLeft: 2,
275516
+ children: [
275517
+ matches2.map((c, i) => {
275518
+ const isExact = c.cmd === query;
275519
+ return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
275520
+ gap: 2,
275521
+ children: [
275522
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
275523
+ color: isExact ? ACCENT : "white",
275524
+ bold: isExact,
275525
+ children: c.cmd
275526
+ }, undefined, false, undefined, this),
275527
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
275528
+ color: "gray",
275529
+ dimColor: true,
275530
+ children: c.desc
275531
+ }, undefined, false, undefined, this)
275532
+ ]
275533
+ }, i, true, undefined, this);
275534
+ }),
275535
+ isChatLoad && filteredChats.length > 0 && /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
275536
+ flexDirection: "column",
275537
+ marginTop: matches2.length ? 1 : 0,
275538
+ children: [
275539
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
275540
+ color: "gray",
275541
+ dimColor: true,
275542
+ children: chatFilter ? `matching "${chatFilter}":` : "recent chats:"
275543
+ }, undefined, false, undefined, this),
275544
+ filteredChats.map((name, i) => /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
275545
+ gap: 1,
275546
+ marginLeft: 2,
275547
+ children: [
275548
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
275549
+ color: ACCENT,
275550
+ children: "·"
275551
+ }, undefined, false, undefined, this),
275552
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
275553
+ color: "white",
275554
+ children: name
275555
+ }, undefined, false, undefined, this)
275556
+ ]
275557
+ }, i, true, undefined, this))
275558
+ ]
275559
+ }, undefined, true, undefined, this)
275560
+ ]
275561
+ }, undefined, true, undefined, this);
275562
+ }
275563
+ function ForceAllWarning({
275564
+ onConfirm
275565
+ }) {
275566
+ const [input, setInput] = import_react51.useState("");
275567
+ return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
275568
+ flexDirection: "column",
275569
+ marginY: 1,
275570
+ gap: 1,
275571
+ children: [
275572
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
275573
+ gap: 1,
275574
+ children: /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
275575
+ color: "red",
275576
+ bold: true,
275577
+ children: "⚠ WARNING"
275578
+ }, undefined, false, undefined, this)
275579
+ }, undefined, false, undefined, this),
275580
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
275581
+ flexDirection: "column",
275582
+ marginLeft: 2,
275583
+ gap: 1,
275584
+ children: [
275585
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
275586
+ color: "yellow",
275587
+ children: "Force-all mode auto-approves EVERY tool without asking — including:"
275588
+ }, undefined, false, undefined, this),
275589
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
275590
+ color: "red",
275591
+ dimColor: true,
275592
+ children: [
275593
+ " ",
275594
+ "· shell commands (rm, git, npm, anything)"
275595
+ ]
275596
+ }, undefined, true, undefined, this),
275597
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
275598
+ color: "red",
275599
+ dimColor: true,
275600
+ children: [
275601
+ " ",
275602
+ "· file writes and deletes"
275603
+ ]
275604
+ }, undefined, true, undefined, this),
275605
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
275606
+ color: "red",
275607
+ dimColor: true,
275608
+ children: [
275609
+ " ",
275610
+ "· folder deletes"
275611
+ ]
275612
+ }, undefined, true, undefined, this),
275613
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
275614
+ color: "red",
275615
+ dimColor: true,
275616
+ children: [
275617
+ " ",
275618
+ "· external fetches and URL opens"
275619
+ ]
275620
+ }, undefined, true, undefined, this),
275621
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
275622
+ color: "yellow",
275623
+ dimColor: true,
275624
+ children: "The AI can modify or delete files without any confirmation."
275625
+ }, undefined, false, undefined, this),
275626
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
275627
+ color: "yellow",
275628
+ dimColor: true,
275629
+ children: "Only use this in throwaway environments or when you fully trust the task."
275630
+ }, undefined, false, undefined, this)
275631
+ ]
275632
+ }, undefined, true, undefined, this),
275633
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
275634
+ gap: 1,
275635
+ marginTop: 1,
275636
+ children: [
275637
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
275638
+ color: "gray",
275639
+ children: "Type "
275640
+ }, undefined, false, undefined, this),
275641
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
275642
+ color: "white",
275643
+ bold: true,
275644
+ children: "yes"
275645
+ }, undefined, false, undefined, this),
275646
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
275647
+ color: "gray",
275648
+ children: " to enable, or press "
275649
+ }, undefined, false, undefined, this),
275650
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
275651
+ color: "white",
275652
+ bold: true,
275653
+ children: "esc"
275654
+ }, undefined, false, undefined, this),
275655
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
275656
+ color: "gray",
275657
+ children: " to cancel: "
275658
+ }, undefined, false, undefined, this),
275659
+ /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(build_default2, {
275660
+ value: input,
275661
+ onChange: setInput,
275662
+ onSubmit: (v) => onConfirm(v.trim().toLowerCase() === "yes"),
275663
+ placeholder: "yes / esc to cancel"
275664
+ }, undefined, false, undefined, this)
275665
+ ]
275666
+ }, undefined, true, undefined, this)
275667
+ ]
275668
+ }, undefined, true, undefined, this);
275669
+ }
275670
+ var ChatRunner = ({ repoPath }) => {
275671
+ const chat = useChat(repoPath);
275672
+ const thinkingPhrase = useThinkingPhrase(chat.stage.type === "thinking");
275673
+ const handleStageKey = (input, key) => {
275674
+ const { stage: stage2 } = chat;
275675
+ if (chat.showForceWarning && key.escape) {
275676
+ chat.setShowForceWarning(false);
275677
+ return;
275678
+ }
275679
+ if (stage2.type === "clone-offer") {
275524
275680
  if (input === "y" || input === "Y" || key.return) {
275525
- const { repoUrl } = stage;
275526
- const launch = stage.launchAnalysis ?? false;
275681
+ const { repoUrl } = stage2;
275682
+ const launch = stage2.launchAnalysis ?? false;
275527
275683
  const cloneUrl = toCloneUrl(repoUrl);
275528
- setStage({ type: "cloning", repoUrl });
275684
+ chat.setStage({ type: "cloning", repoUrl });
275529
275685
  startCloneRepo(cloneUrl).then((result2) => {
275530
275686
  if (result2.done) {
275531
275687
  const repoName = cloneUrl.split("/").pop()?.replace(/\.git$/, "") ?? "repo";
@@ -275536,8 +275692,8 @@ ${mems.map((m) => `- [${m.id}] ${m.content}`).join(`
275536
275692
  detail: repoUrl,
275537
275693
  summary: `Cloned ${repoName} — ${fileCount} files`
275538
275694
  });
275539
- setClonedUrls((prev) => new Set([...prev, repoUrl]));
275540
- setStage({
275695
+ chat.setClonedUrls((prev) => new Set([...prev, repoUrl]));
275696
+ chat.setStage({
275541
275697
  type: "clone-done",
275542
275698
  repoUrl,
275543
275699
  destPath,
@@ -275545,13 +275701,13 @@ ${mems.map((m) => `- [${m.id}] ${m.content}`).join(`
275545
275701
  launchAnalysis: launch
275546
275702
  });
275547
275703
  } else if (result2.folderExists && result2.repoPath) {
275548
- setStage({
275704
+ chat.setStage({
275549
275705
  type: "clone-exists",
275550
275706
  repoUrl,
275551
275707
  repoPath: result2.repoPath
275552
275708
  });
275553
275709
  } else {
275554
- setStage({
275710
+ chat.setStage({
275555
275711
  type: "clone-error",
275556
275712
  message: !result2.folderExists && result2.error ? result2.error : "Clone failed"
275557
275713
  });
@@ -275560,23 +275716,23 @@ ${mems.map((m) => `- [${m.id}] ${m.content}`).join(`
275560
275716
  return;
275561
275717
  }
275562
275718
  if (input === "n" || input === "N" || key.escape)
275563
- setStage({ type: "idle" });
275719
+ chat.setStage({ type: "idle" });
275564
275720
  return;
275565
275721
  }
275566
- if (stage.type === "clone-exists") {
275722
+ if (stage2.type === "clone-exists") {
275567
275723
  if (input === "y" || input === "Y") {
275568
- const { repoUrl, repoPath: existingPath } = stage;
275569
- setStage({ type: "cloning", repoUrl });
275724
+ const { repoUrl, repoPath: existingPath } = stage2;
275725
+ chat.setStage({ type: "cloning", repoUrl });
275570
275726
  startCloneRepo(toCloneUrl(repoUrl), { forceReclone: true }).then((result2) => {
275571
275727
  if (result2.done) {
275572
- setStage({
275728
+ chat.setStage({
275573
275729
  type: "clone-done",
275574
275730
  repoUrl,
275575
275731
  destPath: existingPath,
275576
275732
  fileCount: walkDir(existingPath).length
275577
275733
  });
275578
275734
  } else {
275579
- setStage({
275735
+ chat.setStage({
275580
275736
  type: "clone-error",
275581
275737
  message: !result2.folderExists && result2.error ? result2.error : "Clone failed"
275582
275738
  });
@@ -275585,8 +275741,8 @@ ${mems.map((m) => `- [${m.id}] ${m.content}`).join(`
275585
275741
  return;
275586
275742
  }
275587
275743
  if (input === "n" || input === "N") {
275588
- const { repoUrl, repoPath: existingPath } = stage;
275589
- setStage({
275744
+ const { repoUrl, repoPath: existingPath } = stage2;
275745
+ chat.setStage({
275590
275746
  type: "clone-done",
275591
275747
  repoUrl,
275592
275748
  destPath: existingPath,
@@ -275596,14 +275752,14 @@ ${mems.map((m) => `- [${m.id}] ${m.content}`).join(`
275596
275752
  }
275597
275753
  return;
275598
275754
  }
275599
- if (stage.type === "clone-done" || stage.type === "clone-error") {
275755
+ if (stage2.type === "clone-done" || stage2.type === "clone-error") {
275600
275756
  if (key.return || key.escape) {
275601
- if (stage.type === "clone-done") {
275602
- const repoName = stage.repoUrl.split("/").pop() ?? "repo";
275757
+ if (stage2.type === "clone-done") {
275758
+ const repoName = stage2.repoUrl.split("/").pop() ?? "repo";
275603
275759
  const summaryMsg = {
275604
275760
  role: "assistant",
275605
275761
  type: "text",
275606
- content: `Cloned **${repoName}** (${stage.fileCount} files) to \`${stage.destPath}\`.
275762
+ content: `Cloned **${repoName}** (${stage2.fileCount} files) to \`${stage2.destPath}\`.
275607
275763
 
275608
275764
  Ask me anything about it — I can read files, explain how it works, or suggest improvements.`
275609
275765
  };
@@ -275611,139 +275767,128 @@ Ask me anything about it — I can read files, explain how it works, or suggest
275611
275767
  role: "assistant",
275612
275768
  type: "tool",
275613
275769
  toolName: "fetch",
275614
- content: stage.repoUrl,
275615
- result: `Clone complete. Repo: ${repoName}. Local path: ${stage.destPath}. ${stage.fileCount} files.`,
275770
+ content: stage2.repoUrl,
275771
+ result: `Clone complete. Repo: ${repoName}. Local path: ${stage2.destPath}. ${stage2.fileCount} files.`,
275616
275772
  approved: true
275617
275773
  };
275618
- const withClone = [...allMessages, contextMsg, summaryMsg];
275619
- setAllMessages(withClone);
275620
- setCommitted((prev) => [...prev, summaryMsg]);
275621
- setStage({ type: "idle" });
275774
+ chat.setAllMessages([...chat.allMessages, contextMsg, summaryMsg]);
275775
+ chat.setCommitted((prev) => [...prev, summaryMsg]);
275776
+ chat.setStage({ type: "idle" });
275622
275777
  } else {
275623
- setStage({ type: "idle" });
275778
+ chat.setStage({ type: "idle" });
275624
275779
  }
275625
275780
  }
275626
275781
  return;
275627
275782
  }
275628
- if (stage.type === "cloning")
275783
+ if (stage2.type === "cloning")
275629
275784
  return;
275630
- if (stage.type === "permission") {
275785
+ if (stage2.type === "permission") {
275631
275786
  if (input === "y" || input === "Y" || key.return) {
275632
- stage.resolve(true);
275787
+ stage2.resolve(true);
275633
275788
  return;
275634
275789
  }
275635
275790
  if (input === "n" || input === "N" || key.escape) {
275636
- batchApprovedRef.current = false;
275637
- stage.resolve(false);
275791
+ chat.batchApprovedRef.current = false;
275792
+ stage2.resolve(false);
275638
275793
  return;
275639
275794
  }
275640
275795
  return;
275641
275796
  }
275642
- if (stage.type === "preview") {
275797
+ if (stage2.type === "preview") {
275643
275798
  if (key.upArrow) {
275644
- setStage({
275645
- ...stage,
275646
- scrollOffset: Math.max(0, stage.scrollOffset - 1)
275799
+ chat.setStage({
275800
+ ...stage2,
275801
+ scrollOffset: Math.max(0, stage2.scrollOffset - 1)
275647
275802
  });
275648
275803
  return;
275649
275804
  }
275650
275805
  if (key.downArrow) {
275651
- setStage({ ...stage, scrollOffset: stage.scrollOffset + 1 });
275806
+ chat.setStage({ ...stage2, scrollOffset: stage2.scrollOffset + 1 });
275652
275807
  return;
275653
275808
  }
275654
275809
  if (key.escape || input === "s" || input === "S") {
275655
- if (pendingMsgIndex !== null) {
275656
- const msg = allMessages[pendingMsgIndex];
275810
+ if (chat.pendingMsgIndex !== null) {
275811
+ const msg = chat.allMessages[chat.pendingMsgIndex];
275657
275812
  if (msg?.type === "plan") {
275658
- setCommitted((prev) => [...prev, { ...msg, applied: false }]);
275659
- appendMemory({
275660
- kind: "code-skipped",
275661
- detail: msg.patches.map((p) => p.path).join(", "),
275662
- summary: `Skipped changes to ${msg.patches.length} file(s)`
275663
- });
275813
+ chat.setCommitted((prev) => [...prev, { ...msg, applied: false }]);
275814
+ chat.skipPatches(msg.patches);
275664
275815
  }
275665
275816
  }
275666
- setPendingMsgIndex(null);
275667
- setStage({ type: "idle" });
275817
+ chat.setPendingMsgIndex(null);
275818
+ chat.setStage({ type: "idle" });
275668
275819
  return;
275669
275820
  }
275670
275821
  if (key.return || input === "a" || input === "A") {
275671
- try {
275672
- applyPatches2(repoPath, stage.patches);
275673
- appendMemory({
275674
- kind: "code-applied",
275675
- detail: stage.patches.map((p) => p.path).join(", "),
275676
- summary: `Applied changes to ${stage.patches.length} file(s)`
275677
- });
275678
- } catch {}
275679
- if (pendingMsgIndex !== null) {
275680
- const msg = allMessages[pendingMsgIndex];
275822
+ if (chat.pendingMsgIndex !== null) {
275823
+ const msg = chat.allMessages[chat.pendingMsgIndex];
275681
275824
  if (msg?.type === "plan") {
275825
+ chat.applyPatchesAndContinue(msg.patches);
275682
275826
  const applied = { ...msg, applied: true };
275683
- setAllMessages((prev) => prev.map((m, i) => i === pendingMsgIndex ? applied : m));
275684
- setCommitted((prev) => [...prev, applied]);
275827
+ chat.setAllMessages((prev) => prev.map((m, i) => i === chat.pendingMsgIndex ? applied : m));
275828
+ chat.setCommitted((prev) => [...prev, applied]);
275685
275829
  }
275686
275830
  }
275687
- setPendingMsgIndex(null);
275688
- setStage({ type: "idle" });
275831
+ chat.setPendingMsgIndex(null);
275832
+ chat.setStage({ type: "idle" });
275689
275833
  return;
275690
275834
  }
275691
275835
  }
275692
- if (stage.type === "viewing-file") {
275836
+ if (stage2.type === "viewing-file") {
275693
275837
  if (key.upArrow) {
275694
- setStage({
275695
- ...stage,
275696
- scrollOffset: Math.max(0, stage.scrollOffset - 1)
275838
+ chat.setStage({
275839
+ ...stage2,
275840
+ scrollOffset: Math.max(0, stage2.scrollOffset - 1)
275697
275841
  });
275698
275842
  return;
275699
275843
  }
275700
275844
  if (key.downArrow) {
275701
- setStage({ ...stage, scrollOffset: stage.scrollOffset + 1 });
275845
+ chat.setStage({ ...stage2, scrollOffset: stage2.scrollOffset + 1 });
275702
275846
  return;
275703
275847
  }
275704
275848
  if (key.escape || key.return) {
275705
- setStage({ type: "idle" });
275849
+ chat.setStage({ type: "idle" });
275706
275850
  return;
275707
275851
  }
275708
275852
  }
275709
- });
275710
- const handleProviderDone = (p) => {
275711
- setProvider(p);
275712
- setStage({ type: "loading" });
275713
- fetchFileTree(repoPath).catch(() => walkDir(repoPath)).then((fileTree) => {
275714
- const importantFiles = readImportantFiles(repoPath, fileTree);
275715
- const historySummary = buildMemorySummary(repoPath);
275716
- const lensFile = readLensFile(repoPath);
275717
- const lensContext = lensFile ? `
275718
-
275719
- ## LENS.md (previous analysis)
275720
- ${lensFile.overview}
275721
-
275722
- Important folders: ${lensFile.importantFolders.join(", ")}
275723
- Suggestions: ${lensFile.suggestions.slice(0, 3).join("; ")}` : "";
275724
- const toolsSection = registry.buildSystemPromptSection();
275725
- setSystemPrompt(buildSystemPrompt(importantFiles, historySummary, toolsSection) + lensContext);
275726
- const greeting = {
275727
- role: "assistant",
275728
- content: `Welcome to Lens
275729
- Codebase loaded — ${importantFiles.length} files indexed.${historySummary ? `
275730
-
275731
- I have memory of previous actions in this repo.` : ""}${lensFile ? `
275732
-
275733
- Found LENS.md — I have context from a previous analysis of this repo.` : ""}
275734
- Ask me anything, tell me what to build, share a URL, or ask me to read/write files.
275735
-
275736
- Tip: type /timeline to browse commit history.`,
275737
- type: "text"
275738
- };
275739
- setCommitted([greeting]);
275740
- setAllMessages([greeting]);
275741
- setStage({ type: "idle" });
275742
- }).catch(() => setStage({ type: "idle" }));
275743
275853
  };
275854
+ const chatInput = useChatInput(chat.stage, chat.showTimeline, chat.showForceWarning, chat.abortThinking, handleStageKey);
275855
+ const sendMessage = (text) => {
275856
+ if (!chat.provider)
275857
+ return;
275858
+ const handled = handleCommand(text, {
275859
+ repoPath,
275860
+ allMessages: chat.allMessages,
275861
+ autoApprove: chat.autoApprove,
275862
+ forceApprove: chat.forceApprove,
275863
+ chatName: chat.chatName,
275864
+ chatNameRef: chat.chatNameRef,
275865
+ setShowTimeline: chat.setShowTimeline,
275866
+ setShowReview: chat.setShowReview,
275867
+ setShowForceWarning: chat.setShowForceWarning,
275868
+ setForceApprove: chat.setForceApprove,
275869
+ setAutoApprove: chat.setAutoApprove,
275870
+ setAllMessages: chat.setAllMessages,
275871
+ setCommitted: chat.setCommitted,
275872
+ setRecentChats: chat.setRecentChats,
275873
+ updateChatName: chat.updateChatName
275874
+ });
275875
+ if (handled)
275876
+ return;
275877
+ chatInput.pushHistory(text);
275878
+ chat.sendMessage(text, chat.provider, chat.systemPrompt, chat.allMessages);
275879
+ if (!chat.chatName) {
275880
+ const name = getChatNameSuggestions([
275881
+ ...chat.allMessages,
275882
+ { role: "user", content: text, type: "text" }
275883
+ ])[0] ?? `chat-${new Date().toISOString().slice(0, 10)}`;
275884
+ chat.updateChatName(name);
275885
+ chat.setRecentChats((prev) => [name, ...prev.filter((n) => n !== name)].slice(0, 10));
275886
+ }
275887
+ };
275888
+ const { stage } = chat;
275744
275889
  if (stage.type === "picking-provider")
275745
275890
  return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(ProviderPicker, {
275746
- onDone: handleProviderDone
275891
+ onDone: chat.handleProviderDone
275747
275892
  }, undefined, false, undefined, this);
275748
275893
  if (stage.type === "loading")
275749
275894
  return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
@@ -275765,85 +275910,85 @@ Tip: type /timeline to browse commit history.`,
275765
275910
  }, undefined, false, undefined, this)
275766
275911
  ]
275767
275912
  }, undefined, true, undefined, this);
275768
- if (showTimeline)
275913
+ if (chat.showTimeline)
275769
275914
  return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(TimelineRunner, {
275770
275915
  repoPath,
275771
- onExit: () => setShowTimeline(false)
275916
+ onExit: () => chat.setShowTimeline(false)
275772
275917
  }, undefined, false, undefined, this);
275773
- if (showReview)
275918
+ if (chat.showReview)
275774
275919
  return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(ReviewCommand, {
275775
275920
  path: repoPath,
275776
- onExit: () => setShowReview(false)
275921
+ onExit: () => chat.setShowReview(false)
275777
275922
  }, undefined, false, undefined, this);
275778
275923
  if (stage.type === "clone-offer")
275779
275924
  return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(CloneOfferView, {
275780
275925
  stage,
275781
- committed
275926
+ committed: chat.committed
275782
275927
  }, undefined, false, undefined, this);
275783
275928
  if (stage.type === "cloning")
275784
275929
  return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(CloningView, {
275785
275930
  stage,
275786
- committed
275931
+ committed: chat.committed
275787
275932
  }, undefined, false, undefined, this);
275788
275933
  if (stage.type === "clone-exists")
275789
275934
  return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(CloneExistsView, {
275790
275935
  stage,
275791
- committed
275936
+ committed: chat.committed
275792
275937
  }, undefined, false, undefined, this);
275793
275938
  if (stage.type === "clone-done")
275794
275939
  return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(CloneDoneView, {
275795
275940
  stage,
275796
- committed
275941
+ committed: chat.committed
275797
275942
  }, undefined, false, undefined, this);
275798
275943
  if (stage.type === "clone-error")
275799
275944
  return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(CloneErrorView, {
275800
275945
  stage,
275801
- committed
275946
+ committed: chat.committed
275802
275947
  }, undefined, false, undefined, this);
275803
275948
  if (stage.type === "preview")
275804
275949
  return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(PreviewView, {
275805
275950
  stage,
275806
- committed
275951
+ committed: chat.committed
275807
275952
  }, undefined, false, undefined, this);
275808
275953
  if (stage.type === "viewing-file")
275809
275954
  return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(ViewingFileView, {
275810
275955
  stage,
275811
- committed
275956
+ committed: chat.committed
275812
275957
  }, undefined, false, undefined, this);
275813
275958
  return /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
275814
275959
  flexDirection: "column",
275815
275960
  children: [
275816
275961
  /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Static, {
275817
- items: committed,
275962
+ items: chat.committed,
275818
275963
  children: (msg, i) => /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(StaticMessage, {
275819
275964
  msg
275820
275965
  }, i, false, undefined, this)
275821
275966
  }, undefined, false, undefined, this),
275822
- showForceWarning && /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(ForceAllWarning, {
275967
+ chat.showForceWarning && /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(ForceAllWarning, {
275823
275968
  onConfirm: (confirmed) => {
275824
- setShowForceWarning(false);
275969
+ chat.setShowForceWarning(false);
275825
275970
  if (confirmed) {
275826
- setForceApprove(true);
275827
- setAutoApprove(true);
275971
+ chat.setForceApprove(true);
275972
+ chat.setAutoApprove(true);
275828
275973
  const msg = {
275829
275974
  role: "assistant",
275830
275975
  content: "⚡⚡ Force-all mode ON — ALL tools auto-approved including shell and writes. Type /auto --force-all again to disable.",
275831
275976
  type: "text"
275832
275977
  };
275833
- setCommitted((prev) => [...prev, msg]);
275834
- setAllMessages((prev) => [...prev, msg]);
275978
+ chat.setCommitted((prev) => [...prev, msg]);
275979
+ chat.setAllMessages((prev) => [...prev, msg]);
275835
275980
  } else {
275836
275981
  const msg = {
275837
275982
  role: "assistant",
275838
275983
  content: "Force-all cancelled.",
275839
275984
  type: "text"
275840
275985
  };
275841
- setCommitted((prev) => [...prev, msg]);
275842
- setAllMessages((prev) => [...prev, msg]);
275986
+ chat.setCommitted((prev) => [...prev, msg]);
275987
+ chat.setAllMessages((prev) => [...prev, msg]);
275843
275988
  }
275844
275989
  }
275845
275990
  }, undefined, false, undefined, this),
275846
- !showForceWarning && stage.type === "thinking" && /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
275991
+ !chat.showForceWarning && stage.type === "thinking" && /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
275847
275992
  gap: 1,
275848
275993
  children: [
275849
275994
  /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Text, {
@@ -275860,34 +276005,30 @@ Tip: type /timeline to browse commit history.`,
275860
276005
  }, undefined, false, undefined, this)
275861
276006
  ]
275862
276007
  }, undefined, true, undefined, this),
275863
- !showForceWarning && stage.type === "permission" && /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(PermissionPrompt, {
276008
+ !chat.showForceWarning && stage.type === "permission" && /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(PermissionPrompt, {
275864
276009
  tool: stage.tool,
275865
276010
  onDecide: stage.resolve
275866
276011
  }, undefined, false, undefined, this),
275867
- !showForceWarning && stage.type === "idle" && /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
276012
+ !chat.showForceWarning && stage.type === "idle" && /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(Box_default, {
275868
276013
  flexDirection: "column",
275869
276014
  children: [
275870
- inputValue.startsWith("/") && /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(CommandPalette, {
275871
- query: inputValue,
275872
- onSelect: (cmd) => setInputValue(cmd),
275873
- recentChats
276015
+ chatInput.inputValue.startsWith("/") && /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(CommandPalette, {
276016
+ query: chatInput.inputValue,
276017
+ recentChats: chat.recentChats
275874
276018
  }, undefined, false, undefined, this),
275875
276019
  /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(InputBox, {
275876
- value: inputValue,
275877
- onChange: (v) => {
275878
- historyIndexRef.current = -1;
275879
- setInputValue(v);
275880
- },
276020
+ value: chatInput.inputValue,
276021
+ onChange: (v) => chatInput.setInputValue(v),
275881
276022
  onSubmit: (val) => {
275882
276023
  if (val.trim())
275883
276024
  sendMessage(val.trim());
275884
- setInputValue("");
276025
+ chatInput.setInputValue("");
275885
276026
  },
275886
- inputKey
276027
+ inputKey: chatInput.inputKey
275887
276028
  }, undefined, false, undefined, this),
275888
276029
  /* @__PURE__ */ jsx_dev_runtime22.jsxDEV(ShortcutBar, {
275889
- autoApprove,
275890
- forceApprove
276030
+ autoApprove: chat.autoApprove,
276031
+ forceApprove: chat.forceApprove
275891
276032
  }, undefined, false, undefined, this)
275892
276033
  ]
275893
276034
  }, undefined, true, undefined, this)
@@ -275917,12 +276058,12 @@ var ChatCommand = ({ path: inputPath }) => {
275917
276058
  }, undefined, false, undefined, this);
275918
276059
  };
275919
276060
 
275920
- // src/commands/watch.tsx
276061
+ // src/commands/run.tsx
275921
276062
  import path21 from "path";
275922
276063
  import { existsSync as existsSync16 } from "fs";
275923
276064
 
275924
- // src/components/watch/WatchRunner.tsx
275925
- var import_react50 = __toESM(require_react(), 1);
276065
+ // src/components/watch/RunRunner.tsx
276066
+ var import_react52 = __toESM(require_react(), 1);
275926
276067
 
275927
276068
  // src/utils/watch.ts
275928
276069
  import { spawn as spawn2 } from "child_process";
@@ -276102,7 +276243,7 @@ function readPackageJson(repoPath) {
276102
276243
  }
276103
276244
  }
276104
276245
 
276105
- // src/components/watch/WatchRunner.tsx
276246
+ // src/components/watch/RunRunner.tsx
276106
276247
  var jsx_dev_runtime24 = __toESM(require_jsx_dev_runtime(), 1);
276107
276248
  var MAX_LOGS2 = 120;
276108
276249
  var MAX_SUGGESTIONS = 8;
@@ -276180,7 +276321,7 @@ function SuggestionCard({
276180
276321
  }) {
276181
276322
  const w = process.stdout.columns ?? 80;
276182
276323
  const divider = "─".repeat(Math.min(w - 4, 60));
276183
- const [patchState, setPatchState] = import_react50.useState(fixAll && suggestion.patch ? "applied" : null);
276324
+ const [patchState, setPatchState] = import_react52.useState(fixAll && suggestion.patch ? "applied" : null);
276184
276325
  use_input_default((input) => {
276185
276326
  if (!isNew || !suggestion.patch || patchState !== null || fixAll)
276186
276327
  return;
@@ -276372,8 +276513,8 @@ function ThinkingCard({
276372
276513
  toolLog,
276373
276514
  startTime
276374
276515
  }) {
276375
- const [elapsed, setElapsed] = import_react50.useState(0);
276376
- import_react50.useEffect(() => {
276516
+ const [elapsed, setElapsed] = import_react52.useState(0);
276517
+ import_react52.useEffect(() => {
276377
276518
  const t = setInterval(() => setElapsed(Math.floor((Date.now() - startTime) / 1000)), 1000);
276378
276519
  return () => clearInterval(t);
276379
276520
  }, [startTime]);
@@ -276558,7 +276699,7 @@ function InputCard({ prompt, value }) {
276558
276699
  ]
276559
276700
  }, undefined, true, undefined, this);
276560
276701
  }
276561
- function WatchRunner({
276702
+ function RunRunner({
276562
276703
  cmd,
276563
276704
  repoPath,
276564
276705
  clean,
@@ -276566,22 +276707,22 @@ function WatchRunner({
276566
276707
  autoRestart,
276567
276708
  extraPrompt
276568
276709
  }) {
276569
- const [stage, setStage] = import_react50.useState({ type: "picking-provider" });
276570
- const [logs, setLogs] = import_react50.useState([]);
276571
- const [suggestions, setSuggestions] = import_react50.useState([]);
276572
- const [active, setActive] = import_react50.useState([]);
276573
- const [lensLoaded, setLensLoaded] = import_react50.useState(false);
276574
- const [pendingQueue, setPendingQueue] = import_react50.useState([]);
276575
- const [fixedCount, setFixedCount] = import_react50.useState(0);
276576
- const [inputRequest, setInputRequest] = import_react50.useState(null);
276577
- const [inputValue, setInputValue] = import_react50.useState("");
276578
- const processRef = import_react50.useRef(null);
276579
- const providerRef = import_react50.useRef(null);
276580
- const systemPromptRef = import_react50.useRef("");
276581
- const activeCountRef = import_react50.useRef(0);
276582
- const pendingExitCode = import_react50.useRef(undefined);
276583
- const abortControllersRef = import_react50.useRef(new Map);
276584
- const patchedThisRunRef = import_react50.useRef(0);
276710
+ const [stage, setStage] = import_react52.useState({ type: "picking-provider" });
276711
+ const [logs, setLogs] = import_react52.useState([]);
276712
+ const [suggestions, setSuggestions] = import_react52.useState([]);
276713
+ const [active, setActive] = import_react52.useState([]);
276714
+ const [lensLoaded, setLensLoaded] = import_react52.useState(false);
276715
+ const [pendingQueue, setPendingQueue] = import_react52.useState([]);
276716
+ const [fixedCount, setFixedCount] = import_react52.useState(0);
276717
+ const [inputRequest, setInputRequest] = import_react52.useState(null);
276718
+ const [inputValue, setInputValue] = import_react52.useState("");
276719
+ const processRef = import_react52.useRef(null);
276720
+ const providerRef = import_react52.useRef(null);
276721
+ const systemPromptRef = import_react52.useRef("");
276722
+ const activeCountRef = import_react52.useRef(0);
276723
+ const pendingExitCode = import_react52.useRef(undefined);
276724
+ const abortControllersRef = import_react52.useRef(new Map);
276725
+ const patchedThisRunRef = import_react52.useRef(0);
276585
276726
  const { stdout } = use_stdout_default();
276586
276727
  const currentPending = pendingQueue[0] ?? null;
276587
276728
  const handleRestart = () => {
@@ -276649,10 +276790,6 @@ function WatchRunner({
276649
276790
  lensContext = `Overview: ${lensFile.overview}
276650
276791
 
276651
276792
  Important folders: ${lensFile.importantFolders.join(", ")}
276652
- ${lensFile.securityIssues.length > 0 ? `
276653
- Known security issues:
276654
- ${lensFile.securityIssues.map((s) => `- ${s}`).join(`
276655
- `)}` : ""}
276656
276793
  ${lensFile.suggestions.length > 0 ? `
276657
276794
  Project suggestions:
276658
276795
  ${lensFile.suggestions.map((s) => `- ${s}`).join(`
@@ -276723,13 +276860,13 @@ ${lensFile.suggestions.map((s) => `- ${s}`).join(`
276723
276860
  ];
276724
276861
  runInvestigation(id, chunk2, initialMessages, abort.signal, t);
276725
276862
  };
276726
- import_react50.useEffect(() => {
276863
+ import_react52.useEffect(() => {
276727
276864
  return () => {
276728
276865
  processRef.current?.kill();
276729
276866
  abortControllersRef.current.forEach((a) => a.abort());
276730
276867
  };
276731
276868
  }, []);
276732
- import_react50.useEffect(() => {
276869
+ import_react52.useEffect(() => {
276733
276870
  if (autoRestart && stage.type === "crashed") {
276734
276871
  const t = setTimeout(() => handleRestart(), 1500);
276735
276872
  return () => clearTimeout(t);
@@ -277133,9 +277270,9 @@ ${result2}` : `Tool <${parsed.toolName}> was denied.`,
277133
277270
  }, undefined, true, undefined, this);
277134
277271
  }
277135
277272
 
277136
- // src/commands/watch.tsx
277273
+ // src/commands/run.tsx
277137
277274
  var jsx_dev_runtime25 = __toESM(require_jsx_dev_runtime(), 1);
277138
- function WatchCommand({
277275
+ function RunCommand({
277139
277276
  cmd,
277140
277277
  path: inputPath,
277141
277278
  clean,
@@ -277169,7 +277306,7 @@ function WatchCommand({
277169
277306
  }, undefined, true, undefined, this)
277170
277307
  }, undefined, false, undefined, this);
277171
277308
  }
277172
- return /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(WatchRunner, {
277309
+ return /* @__PURE__ */ jsx_dev_runtime25.jsxDEV(RunRunner, {
277173
277310
  cmd,
277174
277311
  repoPath,
277175
277312
  clean,
@@ -277204,7 +277341,7 @@ var TimelineCommand = ({ path: inputPath }) => {
277204
277341
  };
277205
277342
 
277206
277343
  // src/commands/commit.tsx
277207
- var import_react51 = __toESM(require_react(), 1);
277344
+ var import_react53 = __toESM(require_react(), 1);
277208
277345
  import { execSync as execSync5 } from "child_process";
277209
277346
  import { existsSync as existsSync18 } from "fs";
277210
277347
  import path23 from "path";
@@ -277359,9 +277496,9 @@ function CommitRunner({
277359
277496
  push,
277360
277497
  confirm
277361
277498
  }) {
277362
- const [phase, setPhase] = import_react51.useState({ type: "checking" });
277499
+ const [phase, setPhase] = import_react53.useState({ type: "checking" });
277363
277500
  const phraseText = useThinkingPhrase(phase.type === "generating", "commit", 2800);
277364
- import_react51.useEffect(() => {
277501
+ import_react53.useEffect(() => {
277365
277502
  (async () => {
277366
277503
  if (!gitRun3("git rev-parse --git-dir", cwd2).ok) {
277367
277504
  setPhase({ type: "error", message: "not a git repository" });
@@ -277929,7 +278066,7 @@ function CommitCommand({
277929
278066
  confirm
277930
278067
  }) {
277931
278068
  const cwd2 = path23.resolve(inputPath);
277932
- const [provider, setProvider] = import_react51.useState(null);
278069
+ const [provider, setProvider] = import_react53.useState(null);
277933
278070
  if (!existsSync18(cwd2)) {
277934
278071
  return /* @__PURE__ */ jsx_dev_runtime27.jsxDEV(Box_default, {
277935
278072
  marginTop: 1,
@@ -277958,6 +278095,17 @@ function CommitCommand({
277958
278095
  confirm
277959
278096
  }, undefined, false, undefined, this);
277960
278097
  }
278098
+
278099
+ // node_modules/@ridit/lens-sdk/dist/index.mjs
278100
+ var TOOL_TAGS = {
278101
+ read: "read",
278102
+ net: "net",
278103
+ write: "write",
278104
+ delete: "delete",
278105
+ shell: "shell",
278106
+ git: "git",
278107
+ find: "find"
278108
+ };
277961
278109
  // src/tools/view-image.ts
277962
278110
  import path26 from "path";
277963
278111
  import { existsSync as existsSync20, readFileSync as readFileSync14 } from "fs";
@@ -278529,6 +278677,7 @@ var fetchTool = {
278529
278677
  name: "fetch",
278530
278678
  description: "load a URL",
278531
278679
  safe: true,
278680
+ tag: TOOL_TAGS.net,
278532
278681
  permissionLabel: "fetch",
278533
278682
  systemPromptEntry: (i) => `### ${i}. fetch — load a URL
278534
278683
  <fetch>https://example.com</fetch>`,
@@ -278550,6 +278699,7 @@ var shellTool = {
278550
278699
  name: "shell",
278551
278700
  description: "run a terminal command",
278552
278701
  safe: false,
278702
+ tag: TOOL_TAGS.shell,
278553
278703
  permissionLabel: "run",
278554
278704
  systemPromptEntry: (i) => `### ${i}. shell — run a terminal command
278555
278705
  <shell>node -v</shell>`,
@@ -278564,6 +278714,7 @@ var readFileTool = {
278564
278714
  name: "read-file",
278565
278715
  description: "read a file from the repo",
278566
278716
  safe: true,
278717
+ tag: TOOL_TAGS.read,
278567
278718
  permissionLabel: "read",
278568
278719
  systemPromptEntry: (i) => `### ${i}. read-file — read a file from the repo
278569
278720
  <read-file>src/foo.ts</read-file>`,
@@ -278577,6 +278728,7 @@ var readFileTool = {
278577
278728
  var readFolderTool = {
278578
278729
  name: "read-folder",
278579
278730
  description: "list contents of a folder (files + subfolders, one level deep)",
278731
+ tag: TOOL_TAGS.read,
278580
278732
  safe: true,
278581
278733
  permissionLabel: "folder",
278582
278734
  systemPromptEntry: (i) => `### ${i}. read-folder — list contents of a folder (files + subfolders, one level deep)
@@ -278591,6 +278743,7 @@ var readFolderTool = {
278591
278743
  var grepTool = {
278592
278744
  name: "grep",
278593
278745
  description: "search for a pattern across files in the repo",
278746
+ tag: TOOL_TAGS.find,
278594
278747
  safe: true,
278595
278748
  permissionLabel: "grep",
278596
278749
  systemPromptEntry: (i) => `### ${i}. grep — search for a pattern across files in the repo (cross-platform, no shell needed)
@@ -278614,6 +278767,7 @@ var grepTool = {
278614
278767
  var writeFileTool = {
278615
278768
  name: "write-file",
278616
278769
  description: "create or overwrite a file",
278770
+ tag: TOOL_TAGS.write,
278617
278771
  safe: false,
278618
278772
  permissionLabel: "write",
278619
278773
  systemPromptEntry: (i) => `### ${i}. write-file — create or overwrite a file
@@ -278639,6 +278793,7 @@ var writeFileTool = {
278639
278793
  var deleteFileTool = {
278640
278794
  name: "delete-file",
278641
278795
  description: "permanently delete a single file",
278796
+ tag: TOOL_TAGS.delete,
278642
278797
  safe: false,
278643
278798
  permissionLabel: "delete",
278644
278799
  systemPromptEntry: (i) => `### ${i}. delete-file — permanently delete a single file
@@ -278653,6 +278808,7 @@ var deleteFileTool = {
278653
278808
  var deleteFolderTool = {
278654
278809
  name: "delete-folder",
278655
278810
  description: "permanently delete a folder and all its contents",
278811
+ tag: TOOL_TAGS.delete,
278656
278812
  safe: false,
278657
278813
  permissionLabel: "delete folder",
278658
278814
  systemPromptEntry: (i) => `### ${i}. delete-folder — permanently delete a folder and all its contents
@@ -278667,6 +278823,7 @@ var deleteFolderTool = {
278667
278823
  var openUrlTool = {
278668
278824
  name: "open-url",
278669
278825
  description: "open a URL in the user's default browser",
278826
+ tag: TOOL_TAGS.net,
278670
278827
  safe: true,
278671
278828
  permissionLabel: "open",
278672
278829
  systemPromptEntry: (i) => `### ${i}. open-url — open a URL in the user's default browser
@@ -278678,6 +278835,7 @@ var openUrlTool = {
278678
278835
  var generatePdfTool = {
278679
278836
  name: "generate-pdf",
278680
278837
  description: "generate a PDF file from markdown-style content",
278838
+ tag: TOOL_TAGS.write,
278681
278839
  safe: false,
278682
278840
  permissionLabel: "pdf",
278683
278841
  systemPromptEntry: (i) => `### ${i}. generate-pdf — generate a PDF file from markdown-style content
@@ -278703,6 +278861,7 @@ var generatePdfTool = {
278703
278861
  };
278704
278862
  var searchTool = {
278705
278863
  name: "search",
278864
+ tag: TOOL_TAGS.net,
278706
278865
  description: "search the internet for anything you are unsure about",
278707
278866
  safe: true,
278708
278867
  permissionLabel: "search",
@@ -278725,6 +278884,7 @@ var searchTool = {
278725
278884
  var cloneTool = {
278726
278885
  name: "clone",
278727
278886
  description: "clone a GitHub repo so you can explore and discuss it",
278887
+ tag: TOOL_TAGS.write,
278728
278888
  safe: false,
278729
278889
  permissionLabel: "clone",
278730
278890
  systemPromptEntry: (i) => `### ${i}. clone — clone a GitHub repo so you can explore and discuss it
@@ -278739,6 +278899,7 @@ var cloneTool = {
278739
278899
  var changesTool = {
278740
278900
  name: "changes",
278741
278901
  description: "propose code edits (shown as a diff for user approval)",
278902
+ tag: TOOL_TAGS.write,
278742
278903
  safe: false,
278743
278904
  permissionLabel: "changes",
278744
278905
  systemPromptEntry: (i) => `### ${i}. changes — propose code edits (shown as a diff for user approval)
@@ -278761,6 +278922,7 @@ var changesTool = {
278761
278922
  var readFilesTool = {
278762
278923
  name: "read-files",
278763
278924
  description: "read multiple files from the repo at once",
278925
+ tag: TOOL_TAGS.read,
278764
278926
  safe: true,
278765
278927
  permissionLabel: "read",
278766
278928
  systemPromptEntry: (i) => `### ${i}. read-files — read multiple files from the repo at once
@@ -278840,7 +279002,7 @@ var jsx_dev_runtime28 = __toESM(require_jsx_dev_runtime(), 1);
278840
279002
  registerBuiltins();
278841
279003
  await loadAddons();
278842
279004
  var program2 = new Command;
278843
- program2.command("stalk <url>").alias("repo").description("Analyze a remote repository").action((url) => {
279005
+ program2.command("repo <url>").description("Analyze a remote repository").action((url) => {
278844
279006
  render_default(/* @__PURE__ */ jsx_dev_runtime28.jsxDEV(RepoCommand, {
278845
279007
  url
278846
279008
  }, undefined, false, undefined, this));
@@ -278848,28 +279010,28 @@ program2.command("stalk <url>").alias("repo").description("Analyze a remote repo
278848
279010
  program2.command("provider").description("Configure AI providers").action(() => {
278849
279011
  render_default(/* @__PURE__ */ jsx_dev_runtime28.jsxDEV(InitCommand, {}, undefined, false, undefined, this));
278850
279012
  });
278851
- program2.command("judge [path]").alias("review").description("Review a local codebase").action((inputPath) => {
279013
+ program2.command("review [path]").description("Review a local codebase").action((inputPath) => {
278852
279014
  render_default(/* @__PURE__ */ jsx_dev_runtime28.jsxDEV(ReviewCommand, {
278853
279015
  path: inputPath ?? "."
278854
279016
  }, undefined, false, undefined, this));
278855
279017
  });
278856
- program2.command("cook <text>").alias("task").description("Apply a natural language change to the codebase").option("-p, --path <path>", "Path to the repo", ".").action((text, opts) => {
279018
+ program2.command("task <text>").description("Apply a natural language change to the codebase").option("-p, --path <path>", "Path to the repo", ".").action((text, opts) => {
278857
279019
  render_default(/* @__PURE__ */ jsx_dev_runtime28.jsxDEV(TaskCommand, {
278858
279020
  prompt: text,
278859
279021
  path: opts.path
278860
279022
  }, undefined, false, undefined, this));
278861
279023
  });
278862
- program2.command("vibe").alias("chat").description("Chat with your codebase — ask questions or make changes").option("-p, --path <path>", "Path to the repo", ".").action((opts) => {
279024
+ program2.command("chat").description("Chat with your codebase — ask questions or make changes").option("-p, --path <path>", "Path to the repo", ".").action((opts) => {
278863
279025
  render_default(/* @__PURE__ */ jsx_dev_runtime28.jsxDEV(ChatCommand, {
278864
279026
  path: opts.path
278865
279027
  }, undefined, false, undefined, this));
278866
279028
  });
278867
- program2.command("history").alias("timeline").description("Explore your code history — see commits, changes, and evolution").option("-p, --path <path>", "Path to the repo", ".").action((opts) => {
279029
+ program2.command("timeline").description("Explore your code history — see commits, changes, and evolution").option("-p, --path <path>", "Path to the repo", ".").action((opts) => {
278868
279030
  render_default(/* @__PURE__ */ jsx_dev_runtime28.jsxDEV(TimelineCommand, {
278869
279031
  path: opts.path
278870
279032
  }, undefined, false, undefined, this));
278871
279033
  });
278872
- program2.command("crimes [files...]").alias("commit").description("Generate a smart conventional commit message from staged changes or specific files").option("-p, --path <path>", "Path to the repo", ".").option("--auto", "Stage all changes (or the given files) and commit without confirmation").option("--confirm", "Show preview before committing even when using --auto").option("--preview", "Show the generated message without committing").option("--push", "Push to remote after committing").action((files, opts) => {
279034
+ program2.command("commit [files...]").description("Generate a smart conventional commit message from staged changes or specific files").option("-p, --path <path>", "Path to the repo", ".").option("--auto", "Stage all changes (or the given files) and commit without confirmation").option("--confirm", "Show preview before committing even when using --auto").option("--preview", "Show the generated message without committing").option("--push", "Push to remote after committing").action((files, opts) => {
278873
279035
  render_default(/* @__PURE__ */ jsx_dev_runtime28.jsxDEV(CommitCommand, {
278874
279036
  path: opts.path,
278875
279037
  files: files ?? [],
@@ -278879,8 +279041,8 @@ program2.command("crimes [files...]").alias("commit").description("Generate a sm
278879
279041
  push: opts.push ?? false
278880
279042
  }, undefined, false, undefined, this));
278881
279043
  });
278882
- program2.command("watch <cmd>").alias("spy").description("Watch a dev command and get AI suggestions for errors").option("-p, --path <path>", "Path to the repo", ".").option("--clean", "Only show AI suggestions, hide raw logs").option("--fix-all", "Auto-apply fixes as errors are detected").option("--auto-restart", "Automatically re-run the command after a crash").option("--prompt <text>", "Extra context for the AI about your project").action((cmd, opts) => {
278883
- render_default(/* @__PURE__ */ jsx_dev_runtime28.jsxDEV(WatchCommand, {
279044
+ program2.command("run <cmd>").description("Run your dev server. Lens detects and fixes errors automatically").option("-p, --path <path>", "Path to the repo", ".").option("--clean", "Only show AI suggestions, hide raw logs").option("--fix-all", "Auto-apply fixes as errors are detected").option("--auto-restart", "Automatically re-run the command after a crash").option("--prompt <text>", "Extra context for the AI about your project").action((cmd, opts) => {
279045
+ render_default(/* @__PURE__ */ jsx_dev_runtime28.jsxDEV(RunCommand, {
278884
279046
  cmd,
278885
279047
  path: opts.path,
278886
279048
  clean: opts.clean ?? false,