@involvex/super-agent-cli 0.0.49 → 0.0.50

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.js CHANGED
@@ -46,6 +46,9 @@ class SettingsManager {
46
46
  this.userSettingsPath = path.join(os.homedir(), ".super-agent", "settings.json");
47
47
  this.projectSettingsPath = path.join(process.cwd(), ".super-agent", "settings.json");
48
48
  }
49
+ getStorageDirectory() {
50
+ return path.join(os.homedir(), ".super-agent");
51
+ }
49
52
  static getInstance() {
50
53
  if (!SettingsManager.instance) {
51
54
  SettingsManager.instance = new SettingsManager;
@@ -987,7 +990,75 @@ function updateCurrentModel(modelName) {
987
990
 
988
991
  // src/hooks/use-input-handler.ts
989
992
  init_settings_manager();
993
+
994
+ // src/utils/chat-manager.ts
995
+ init_settings_manager();
990
996
  import * as fs3 from "fs-extra";
997
+ import * as path3 from "path";
998
+
999
+ class ChatManager {
1000
+ static instance;
1001
+ chatDirectory;
1002
+ constructor() {
1003
+ const settingsManager = getSettingsManager();
1004
+ this.chatDirectory = path3.join(settingsManager.getStorageDirectory(), "chats");
1005
+ this.ensureDirectoryExists();
1006
+ }
1007
+ static getInstance() {
1008
+ if (!ChatManager.instance) {
1009
+ ChatManager.instance = new ChatManager;
1010
+ }
1011
+ return ChatManager.instance;
1012
+ }
1013
+ ensureDirectoryExists() {
1014
+ if (!fs3.existsSync(this.chatDirectory)) {
1015
+ fs3.mkdirSync(this.chatDirectory, { recursive: true, mode: 448 });
1016
+ }
1017
+ }
1018
+ getChatPath(name) {
1019
+ return path3.join(this.chatDirectory, `${name}.json`);
1020
+ }
1021
+ async saveChat(name, history) {
1022
+ const filePath = this.getChatPath(name);
1023
+ await fs3.writeJson(filePath, {
1024
+ name,
1025
+ updatedAt: new Date().toISOString(),
1026
+ history
1027
+ }, { spaces: 2, mode: 384 });
1028
+ }
1029
+ async loadChat(name) {
1030
+ const filePath = this.getChatPath(name);
1031
+ if (!fs3.existsSync(filePath)) {
1032
+ throw new Error(`Chat session '${name}' not found.`);
1033
+ }
1034
+ const data = await fs3.readJson(filePath);
1035
+ return data.history.map((entry) => ({
1036
+ ...entry,
1037
+ timestamp: new Date(entry.timestamp)
1038
+ }));
1039
+ }
1040
+ async listChats() {
1041
+ if (!fs3.existsSync(this.chatDirectory)) {
1042
+ return [];
1043
+ }
1044
+ const files = await fs3.readdir(this.chatDirectory);
1045
+ return files.filter((file) => file.endsWith(".json")).map((file) => file.replace(".json", ""));
1046
+ }
1047
+ async deleteChat(name) {
1048
+ const filePath = this.getChatPath(name);
1049
+ if (fs3.existsSync(filePath)) {
1050
+ await fs3.unlink(filePath);
1051
+ } else {
1052
+ throw new Error(`Chat session '${name}' not found.`);
1053
+ }
1054
+ }
1055
+ }
1056
+ function getChatManager() {
1057
+ return ChatManager.getInstance();
1058
+ }
1059
+
1060
+ // src/hooks/use-input-handler.ts
1061
+ import * as fs4 from "fs-extra";
991
1062
  function useInputHandler({
992
1063
  agent,
993
1064
  chatHistory,
@@ -1328,6 +1399,10 @@ function useInputHandler({
1328
1399
  { command: "/models", description: "Switch Super Agent Model" },
1329
1400
  { command: "/config", description: "View or edit configuration" },
1330
1401
  { command: "/provider", description: "Manage AI providers" },
1402
+ { command: "/chat save <name>", description: "Save current chat" },
1403
+ { command: "/chat load <name>", description: "Load a saved chat" },
1404
+ { command: "/chat list", description: "List saved chats" },
1405
+ { command: "/chat delete <name>", description: "Delete a saved chat" },
1331
1406
  { command: "/commit-and-push", description: "AI commit & push to remote" },
1332
1407
  { command: "/exit", description: "Exit the application" }
1333
1408
  ];
@@ -1489,6 +1564,91 @@ Available models: ${modelNames.join(", ")}`,
1489
1564
  clearInput();
1490
1565
  return true;
1491
1566
  }
1567
+ if (trimmedInput.startsWith("/chat ")) {
1568
+ const args = trimmedInput.replace("/chat ", "").split(" ");
1569
+ const action = args[0];
1570
+ const name = args.slice(1).join(" ");
1571
+ const chatManager = getChatManager();
1572
+ try {
1573
+ if (action === "save") {
1574
+ if (!name) {
1575
+ throw new Error("Chat name is required.");
1576
+ }
1577
+ await chatManager.saveChat(name, chatHistory);
1578
+ setChatHistory((prev) => [
1579
+ ...prev,
1580
+ {
1581
+ type: "assistant",
1582
+ content: `✓ Chat saved as '${name}'.`,
1583
+ timestamp: new Date
1584
+ }
1585
+ ]);
1586
+ } else if (action === "load") {
1587
+ if (!name) {
1588
+ throw new Error("Chat name is required.");
1589
+ }
1590
+ const history = await chatManager.loadChat(name);
1591
+ setChatHistory(history);
1592
+ setChatHistory((prev) => [
1593
+ ...prev,
1594
+ {
1595
+ type: "assistant",
1596
+ content: `✓ Chat '${name}' loaded.`,
1597
+ timestamp: new Date
1598
+ }
1599
+ ]);
1600
+ } else if (action === "list") {
1601
+ const chats = await chatManager.listChats();
1602
+ setChatHistory((prev) => [
1603
+ ...prev,
1604
+ {
1605
+ type: "assistant",
1606
+ content: `Saved Chats:
1607
+ ${chats.length ? chats.map((c) => `- ${c}`).join(`
1608
+ `) : "No saved chats."}`,
1609
+ timestamp: new Date
1610
+ }
1611
+ ]);
1612
+ } else if (action === "delete") {
1613
+ if (!name) {
1614
+ throw new Error("Chat name is required.");
1615
+ }
1616
+ await chatManager.deleteChat(name);
1617
+ setChatHistory((prev) => [
1618
+ ...prev,
1619
+ {
1620
+ type: "assistant",
1621
+ content: `✓ Chat '${name}' deleted.`,
1622
+ timestamp: new Date
1623
+ }
1624
+ ]);
1625
+ } else if (action === "clear") {
1626
+ setChatHistory([]);
1627
+ setIsProcessing(false);
1628
+ setIsStreaming(false);
1629
+ setTokenCount(0);
1630
+ setProcessingTime(0);
1631
+ processingStartTime.current = 0;
1632
+ ConfirmationService.getInstance().resetSession();
1633
+ clearInput();
1634
+ resetHistory();
1635
+ return true;
1636
+ } else {
1637
+ throw new Error(`Unknown chat action: ${action}`);
1638
+ }
1639
+ } catch (error) {
1640
+ setChatHistory((prev) => [
1641
+ ...prev,
1642
+ {
1643
+ type: "assistant",
1644
+ content: `❌ Error: ${error.message}`,
1645
+ timestamp: new Date
1646
+ }
1647
+ ]);
1648
+ }
1649
+ clearInput();
1650
+ return true;
1651
+ }
1492
1652
  if (trimmedInput === "/commit-and-push") {
1493
1653
  const userEntry = {
1494
1654
  type: "user",
@@ -1740,9 +1900,9 @@ ${commitMessage}`
1740
1900
  for (const mention of mentionMatches) {
1741
1901
  const filePath = mention.slice(1);
1742
1902
  try {
1743
- const stats = await fs3.stat(filePath);
1903
+ const stats = await fs4.stat(filePath);
1744
1904
  if (stats.isFile()) {
1745
- const content = await fs3.readFile(filePath, "utf-8");
1905
+ const content = await fs4.readFile(filePath, "utf-8");
1746
1906
  resolvedInput = resolvedInput.replace(mention, `
1747
1907
 
1748
1908
  --- FILE: ${filePath} ---
@@ -3308,8 +3468,8 @@ class ConfirmationTool {
3308
3468
  }
3309
3469
  }
3310
3470
  // src/tools/morph-editor.ts
3311
- import * as path3 from "path";
3312
- import fs4 from "fs-extra";
3471
+ import * as path4 from "path";
3472
+ import fs5 from "fs-extra";
3313
3473
  import axios from "axios";
3314
3474
 
3315
3475
  class MorphEditorTool {
@@ -3324,8 +3484,8 @@ class MorphEditorTool {
3324
3484
  }
3325
3485
  async editFile(targetFile, instructions, codeEdit) {
3326
3486
  try {
3327
- const resolvedPath = path3.resolve(targetFile);
3328
- if (!await fs4.pathExists(resolvedPath)) {
3487
+ const resolvedPath = path4.resolve(targetFile);
3488
+ if (!await fs5.pathExists(resolvedPath)) {
3329
3489
  return {
3330
3490
  success: false,
3331
3491
  error: `File not found: ${targetFile}`
@@ -3337,7 +3497,7 @@ class MorphEditorTool {
3337
3497
  error: "MORPH_API_KEY not configured. Please set your Morph API key."
3338
3498
  };
3339
3499
  }
3340
- const initialCode = await fs4.readFile(resolvedPath, "utf-8");
3500
+ const initialCode = await fs5.readFile(resolvedPath, "utf-8");
3341
3501
  const sessionFlags = this.confirmationService.getSessionFlags();
3342
3502
  if (!sessionFlags.fileOperations && !sessionFlags.allOperations) {
3343
3503
  const confirmationResult = await this.confirmationService.requestConfirmation({
@@ -3357,7 +3517,7 @@ ${codeEdit}`
3357
3517
  }
3358
3518
  }
3359
3519
  const mergedCode = await this.callMorphApply(instructions, initialCode, codeEdit);
3360
- await fs4.writeFile(resolvedPath, mergedCode, "utf-8");
3520
+ await fs5.writeFile(resolvedPath, mergedCode, "utf-8");
3361
3521
  const oldLines = initialCode.split(`
3362
3522
  `);
3363
3523
  const newLines = mergedCode.split(`
@@ -3540,11 +3700,11 @@ ${codeEdit}`
3540
3700
  }
3541
3701
  async view(filePath, viewRange) {
3542
3702
  try {
3543
- const resolvedPath = path3.resolve(filePath);
3544
- if (await fs4.pathExists(resolvedPath)) {
3545
- const stats = await fs4.stat(resolvedPath);
3703
+ const resolvedPath = path4.resolve(filePath);
3704
+ if (await fs5.pathExists(resolvedPath)) {
3705
+ const stats = await fs5.stat(resolvedPath);
3546
3706
  if (stats.isDirectory()) {
3547
- const files = await fs4.readdir(resolvedPath);
3707
+ const files = await fs5.readdir(resolvedPath);
3548
3708
  return {
3549
3709
  success: true,
3550
3710
  output: `Directory contents of ${filePath}:
@@ -3552,7 +3712,7 @@ ${files.join(`
3552
3712
  `)}`
3553
3713
  };
3554
3714
  }
3555
- const content = await fs4.readFile(resolvedPath, "utf-8");
3715
+ const content = await fs5.readFile(resolvedPath, "utf-8");
3556
3716
  const lines = content.split(`
3557
3717
  `);
3558
3718
  if (viewRange) {
@@ -3598,8 +3758,8 @@ ${numberedLines}${additionalLinesMessage}`
3598
3758
  }
3599
3759
  }
3600
3760
  // src/tools/project-map.ts
3601
- import * as path4 from "path";
3602
- import fs5 from "fs-extra";
3761
+ import * as path5 from "path";
3762
+ import fs6 from "fs-extra";
3603
3763
 
3604
3764
  class ProjectMapTool {
3605
3765
  currentDirectory = process.cwd();
@@ -3633,7 +3793,7 @@ Important Files:
3633
3793
  }
3634
3794
  let result = "";
3635
3795
  try {
3636
- const entries = await fs5.readdir(dir, { withFileTypes: true });
3796
+ const entries = await fs6.readdir(dir, { withFileTypes: true });
3637
3797
  const sortedEntries = entries.sort((a, b) => {
3638
3798
  if (a.isDirectory() && !b.isDirectory()) {
3639
3799
  return -1;
@@ -3661,7 +3821,7 @@ Important Files:
3661
3821
  if (entry.isDirectory()) {
3662
3822
  result += `${indent}\uD83D\uDCC1 ${entry.name}/
3663
3823
  `;
3664
- result += await this.generateTree(path4.join(dir, entry.name), maxDepth, currentDepth + 1);
3824
+ result += await this.generateTree(path5.join(dir, entry.name), maxDepth, currentDepth + 1);
3665
3825
  } else {
3666
3826
  result += `${indent}\uD83D\uDCC4 ${entry.name}
3667
3827
  `;
@@ -3683,8 +3843,8 @@ Important Files:
3683
3843
  ];
3684
3844
  const found = [];
3685
3845
  for (const pattern of importantPatterns) {
3686
- const fullPath = path4.join(this.currentDirectory, pattern);
3687
- if (await fs5.pathExists(fullPath)) {
3846
+ const fullPath = path5.join(this.currentDirectory, pattern);
3847
+ if (await fs6.pathExists(fullPath)) {
3688
3848
  found.push(pattern);
3689
3849
  }
3690
3850
  }
@@ -3696,8 +3856,8 @@ Important Files:
3696
3856
  }
3697
3857
  // src/tools/search.ts
3698
3858
  import { spawn } from "child_process";
3699
- import * as path5 from "path";
3700
- import fs6 from "fs-extra";
3859
+ import * as path6 from "path";
3860
+ import fs7 from "fs-extra";
3701
3861
 
3702
3862
  class SearchTool {
3703
3863
  confirmationService = ConfirmationService.getInstance();
@@ -3837,13 +3997,13 @@ class SearchTool {
3837
3997
  return;
3838
3998
  }
3839
3999
  try {
3840
- const entries = await fs6.readdir(dir, { withFileTypes: true });
4000
+ const entries = await fs7.readdir(dir, { withFileTypes: true });
3841
4001
  for (const entry of entries) {
3842
4002
  if (files.length >= maxResults) {
3843
4003
  break;
3844
4004
  }
3845
- const fullPath = path5.join(dir, entry.name);
3846
- const relativePath = path5.relative(this.currentDirectory, fullPath);
4005
+ const fullPath = path6.join(dir, entry.name);
4006
+ const relativePath = path6.relative(this.currentDirectory, fullPath);
3847
4007
  if (!options.includeHidden && entry.name.startsWith(".")) {
3848
4008
  continue;
3849
4009
  }
@@ -3942,19 +4102,19 @@ class SearchTool {
3942
4102
  }
3943
4103
  // src/tools/text-editor.ts
3944
4104
  import { writeFile as writeFilePromise } from "fs/promises";
3945
- import * as path6 from "path";
3946
- import fs7 from "fs-extra";
4105
+ import * as path7 from "path";
4106
+ import fs8 from "fs-extra";
3947
4107
 
3948
4108
  class TextEditorTool {
3949
4109
  editHistory = [];
3950
4110
  confirmationService = ConfirmationService.getInstance();
3951
4111
  async view(filePath, viewRange) {
3952
4112
  try {
3953
- const resolvedPath = path6.resolve(filePath);
3954
- if (await fs7.pathExists(resolvedPath)) {
3955
- const stats = await fs7.stat(resolvedPath);
4113
+ const resolvedPath = path7.resolve(filePath);
4114
+ if (await fs8.pathExists(resolvedPath)) {
4115
+ const stats = await fs8.stat(resolvedPath);
3956
4116
  if (stats.isDirectory()) {
3957
- const files = await fs7.readdir(resolvedPath);
4117
+ const files = await fs8.readdir(resolvedPath);
3958
4118
  return {
3959
4119
  success: true,
3960
4120
  output: `Directory contents of ${filePath}:
@@ -3962,7 +4122,7 @@ ${files.join(`
3962
4122
  `)}`
3963
4123
  };
3964
4124
  }
3965
- const content = await fs7.readFile(resolvedPath, "utf-8");
4125
+ const content = await fs8.readFile(resolvedPath, "utf-8");
3966
4126
  const lines = content.split(`
3967
4127
  `);
3968
4128
  if (viewRange) {
@@ -4002,14 +4162,14 @@ ${numberedLines}${additionalLinesMessage}`
4002
4162
  }
4003
4163
  async strReplace(filePath, oldStr, newStr, replaceAll = false) {
4004
4164
  try {
4005
- const resolvedPath = path6.resolve(filePath);
4006
- if (!await fs7.pathExists(resolvedPath)) {
4165
+ const resolvedPath = path7.resolve(filePath);
4166
+ if (!await fs8.pathExists(resolvedPath)) {
4007
4167
  return {
4008
4168
  success: false,
4009
4169
  error: `File not found: ${filePath}`
4010
4170
  };
4011
4171
  }
4012
- const content = await fs7.readFile(resolvedPath, "utf-8");
4172
+ const content = await fs8.readFile(resolvedPath, "utf-8");
4013
4173
  if (!content.includes(oldStr)) {
4014
4174
  if (oldStr.includes(`
4015
4175
  `)) {
@@ -4077,7 +4237,7 @@ ${numberedLines}${additionalLinesMessage}`
4077
4237
  }
4078
4238
  async create(filePath, content) {
4079
4239
  try {
4080
- const resolvedPath = path6.resolve(filePath);
4240
+ const resolvedPath = path7.resolve(filePath);
4081
4241
  const sessionFlags = this.confirmationService.getSessionFlags();
4082
4242
  if (!sessionFlags.fileOperations && !sessionFlags.allOperations) {
4083
4243
  const contentLines = content.split(`
@@ -4103,8 +4263,8 @@ ${numberedLines}${additionalLinesMessage}`
4103
4263
  };
4104
4264
  }
4105
4265
  }
4106
- const dir = path6.dirname(resolvedPath);
4107
- await fs7.ensureDir(dir);
4266
+ const dir = path7.dirname(resolvedPath);
4267
+ await fs8.ensureDir(dir);
4108
4268
  await writeFilePromise(resolvedPath, content, "utf-8");
4109
4269
  this.editHistory.push({
4110
4270
  command: "create",
@@ -4128,14 +4288,14 @@ ${numberedLines}${additionalLinesMessage}`
4128
4288
  }
4129
4289
  async replaceLines(filePath, startLine, endLine, newContent) {
4130
4290
  try {
4131
- const resolvedPath = path6.resolve(filePath);
4132
- if (!await fs7.pathExists(resolvedPath)) {
4291
+ const resolvedPath = path7.resolve(filePath);
4292
+ if (!await fs8.pathExists(resolvedPath)) {
4133
4293
  return {
4134
4294
  success: false,
4135
4295
  error: `File not found: ${filePath}`
4136
4296
  };
4137
4297
  }
4138
- const fileContent = await fs7.readFile(resolvedPath, "utf-8");
4298
+ const fileContent = await fs8.readFile(resolvedPath, "utf-8");
4139
4299
  const lines = fileContent.split(`
4140
4300
  `);
4141
4301
  if (startLine < 1 || startLine > lines.length) {
@@ -4198,14 +4358,14 @@ ${numberedLines}${additionalLinesMessage}`
4198
4358
  }
4199
4359
  async insert(filePath, insertLine, content) {
4200
4360
  try {
4201
- const resolvedPath = path6.resolve(filePath);
4202
- if (!await fs7.pathExists(resolvedPath)) {
4361
+ const resolvedPath = path7.resolve(filePath);
4362
+ if (!await fs8.pathExists(resolvedPath)) {
4203
4363
  return {
4204
4364
  success: false,
4205
4365
  error: `File not found: ${filePath}`
4206
4366
  };
4207
4367
  }
4208
- const fileContent = await fs7.readFile(resolvedPath, "utf-8");
4368
+ const fileContent = await fs8.readFile(resolvedPath, "utf-8");
4209
4369
  const lines = fileContent.split(`
4210
4370
  `);
4211
4371
  lines.splice(insertLine - 1, 0, content);
@@ -4241,19 +4401,19 @@ ${numberedLines}${additionalLinesMessage}`
4241
4401
  switch (lastEdit.command) {
4242
4402
  case "str_replace":
4243
4403
  if (lastEdit.path && lastEdit.old_str && lastEdit.new_str) {
4244
- const content = await fs7.readFile(lastEdit.path, "utf-8");
4404
+ const content = await fs8.readFile(lastEdit.path, "utf-8");
4245
4405
  const revertedContent = content.replace(lastEdit.new_str, lastEdit.old_str);
4246
4406
  await writeFilePromise(lastEdit.path, revertedContent, "utf-8");
4247
4407
  }
4248
4408
  break;
4249
4409
  case "create":
4250
4410
  if (lastEdit.path) {
4251
- await fs7.remove(lastEdit.path);
4411
+ await fs8.remove(lastEdit.path);
4252
4412
  }
4253
4413
  break;
4254
4414
  case "insert":
4255
4415
  if (lastEdit.path && lastEdit.insert_line) {
4256
- const content = await fs7.readFile(lastEdit.path, "utf-8");
4416
+ const content = await fs8.readFile(lastEdit.path, "utf-8");
4257
4417
  const lines = content.split(`
4258
4418
  `);
4259
4419
  lines.splice(lastEdit.insert_line - 1, 1);
@@ -5384,19 +5544,19 @@ class OpenAICompatibleProvider {
5384
5544
  }
5385
5545
 
5386
5546
  // src/utils/custom-instructions.ts
5387
- import * as path7 from "path";
5547
+ import * as path8 from "path";
5388
5548
  import * as os2 from "os";
5389
- import * as fs8 from "fs";
5549
+ import * as fs9 from "fs";
5390
5550
  function loadCustomInstructions(workingDirectory = process.cwd()) {
5391
5551
  try {
5392
- let instructionsPath = path7.join(workingDirectory, ".super-agent", "SUPER_AGENT.md");
5393
- if (fs8.existsSync(instructionsPath)) {
5394
- const customInstructions = fs8.readFileSync(instructionsPath, "utf-8");
5552
+ let instructionsPath = path8.join(workingDirectory, ".super-agent", "SUPER_AGENT.md");
5553
+ if (fs9.existsSync(instructionsPath)) {
5554
+ const customInstructions = fs9.readFileSync(instructionsPath, "utf-8");
5395
5555
  return customInstructions.trim();
5396
5556
  }
5397
- instructionsPath = path7.join(os2.homedir(), ".super-agent", "SUPER_AGENT.md");
5398
- if (fs8.existsSync(instructionsPath)) {
5399
- const customInstructions = fs8.readFileSync(instructionsPath, "utf-8");
5557
+ instructionsPath = path8.join(os2.homedir(), ".super-agent", "SUPER_AGENT.md");
5558
+ if (fs9.existsSync(instructionsPath)) {
5559
+ const customInstructions = fs9.readFileSync(instructionsPath, "utf-8");
5400
5560
  return customInstructions.trim();
5401
5561
  }
5402
5562
  return null;
@@ -7293,7 +7453,7 @@ import { program } from "commander";
7293
7453
  // package.json
7294
7454
  var package_default = {
7295
7455
  name: "@involvex/super-agent-cli",
7296
- version: "0.0.49",
7456
+ version: "0.0.50",
7297
7457
  description: "An open-source AI agent that brings the power of Super Agent directly into your terminal.",
7298
7458
  keywords: [
7299
7459
  "cli",
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@involvex/super-agent-cli",
3
- "version": "0.0.49",
3
+ "version": "0.0.50",
4
4
  "description": "An open-source AI agent that brings the power of Super Agent directly into your terminal.",
5
5
  "keywords": [
6
6
  "cli",