@involvex/super-agent-cli 0.0.61 → 0.0.63
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 +2018 -1015
- package/dist/super-agent-cli.exe +0 -0
- package/package.json +8 -2
package/dist/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from "node:module";
|
|
2
3
|
var __create = Object.create;
|
|
3
4
|
var __getProtoOf = Object.getPrototypeOf;
|
|
4
5
|
var __defProp = Object.defineProperty;
|
|
@@ -41,12 +42,14 @@ var __export = (target, all) => {
|
|
|
41
42
|
});
|
|
42
43
|
};
|
|
43
44
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
45
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
44
46
|
|
|
45
47
|
// src/utils/settings-manager.ts
|
|
46
48
|
var exports_settings_manager = {};
|
|
47
49
|
__export(exports_settings_manager, {
|
|
48
50
|
getSettingsManager: () => getSettingsManager,
|
|
49
|
-
SettingsManager: () => SettingsManager
|
|
51
|
+
SettingsManager: () => SettingsManager,
|
|
52
|
+
PROVIDER_MODELS: () => PROVIDER_MODELS
|
|
50
53
|
});
|
|
51
54
|
import * as path from "path";
|
|
52
55
|
import * as os from "os";
|
|
@@ -87,7 +90,20 @@ class SettingsManager {
|
|
|
87
90
|
}
|
|
88
91
|
const content = fs.readFileSync(this.userSettingsPath, "utf-8");
|
|
89
92
|
const settings = JSON.parse(content);
|
|
90
|
-
|
|
93
|
+
const mergedProviders = { ...DEFAULT_USER_SETTINGS.providers };
|
|
94
|
+
if (settings.providers) {
|
|
95
|
+
for (const [key, value] of Object.entries(settings.providers)) {
|
|
96
|
+
mergedProviders[key] = {
|
|
97
|
+
...mergedProviders[key] || {},
|
|
98
|
+
...value
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
...DEFAULT_USER_SETTINGS,
|
|
104
|
+
...settings,
|
|
105
|
+
providers: mergedProviders
|
|
106
|
+
};
|
|
91
107
|
} catch (error) {
|
|
92
108
|
console.warn("Failed to load user settings:", error);
|
|
93
109
|
return { ...DEFAULT_USER_SETTINGS };
|
|
@@ -175,6 +191,12 @@ class SettingsManager {
|
|
|
175
191
|
if (models) {
|
|
176
192
|
return models;
|
|
177
193
|
}
|
|
194
|
+
if (activeProvider) {
|
|
195
|
+
const config = this.getEffectiveSettings().providers[activeProvider];
|
|
196
|
+
if (config && config.model) {
|
|
197
|
+
return [config.model];
|
|
198
|
+
}
|
|
199
|
+
}
|
|
178
200
|
return [
|
|
179
201
|
"grok-beta",
|
|
180
202
|
"grok-vision-beta",
|
|
@@ -336,6 +358,94 @@ var init_settings_manager = __esm(() => {
|
|
|
336
358
|
DEFAULT_PROJECT_SETTINGS = {};
|
|
337
359
|
});
|
|
338
360
|
|
|
361
|
+
// src/utils/file-utils.ts
|
|
362
|
+
var exports_file_utils = {};
|
|
363
|
+
__export(exports_file_utils, {
|
|
364
|
+
resolveSourcePath: () => resolveSourcePath,
|
|
365
|
+
listFilesRecursive: () => listFilesRecursive,
|
|
366
|
+
filterFileEntries: () => filterFileEntries,
|
|
367
|
+
expandHome: () => expandHome
|
|
368
|
+
});
|
|
369
|
+
import * as fs2 from "fs-extra";
|
|
370
|
+
import * as path2 from "path";
|
|
371
|
+
import * as os2 from "os";
|
|
372
|
+
function expandHome(filepath) {
|
|
373
|
+
if (filepath.startsWith("~")) {
|
|
374
|
+
return path2.join(os2.homedir(), filepath.slice(1));
|
|
375
|
+
}
|
|
376
|
+
return filepath;
|
|
377
|
+
}
|
|
378
|
+
function resolveSourcePath(source) {
|
|
379
|
+
const defaults = {
|
|
380
|
+
gemini: "~/.gemini",
|
|
381
|
+
claude: "~/.claude",
|
|
382
|
+
kilo: "~/.kilocode"
|
|
383
|
+
};
|
|
384
|
+
const rawPath = defaults[source.toLowerCase()] || source;
|
|
385
|
+
return expandHome(rawPath);
|
|
386
|
+
}
|
|
387
|
+
async function listFilesRecursive(dir, baseDir = dir, maxDepth = 3) {
|
|
388
|
+
const result = [];
|
|
389
|
+
try {
|
|
390
|
+
const entries = await fs2.readdir(dir, { withFileTypes: true });
|
|
391
|
+
for (const entry of entries) {
|
|
392
|
+
const fullPath = path2.join(dir, entry.name);
|
|
393
|
+
const relativePath = path2.relative(baseDir, fullPath);
|
|
394
|
+
const isIgnored = [
|
|
395
|
+
"node_modules",
|
|
396
|
+
".git",
|
|
397
|
+
"dist",
|
|
398
|
+
"build",
|
|
399
|
+
".next",
|
|
400
|
+
"target",
|
|
401
|
+
"vendor"
|
|
402
|
+
].includes(entry.name);
|
|
403
|
+
if (isIgnored) {
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
if (entry.name.startsWith(".") && entry.name !== ".env") {
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
result.push({
|
|
410
|
+
name: entry.name,
|
|
411
|
+
path: relativePath,
|
|
412
|
+
isDirectory: entry.isDirectory()
|
|
413
|
+
});
|
|
414
|
+
if (entry.isDirectory() && maxDepth > 0) {
|
|
415
|
+
const subFiles = await listFilesRecursive(fullPath, baseDir, maxDepth - 1);
|
|
416
|
+
result.push(...subFiles);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
} catch (error) {}
|
|
420
|
+
return result;
|
|
421
|
+
}
|
|
422
|
+
function filterFileEntries(entries, query) {
|
|
423
|
+
if (!query) {
|
|
424
|
+
return entries.slice(0, 20);
|
|
425
|
+
}
|
|
426
|
+
const lowerQuery = query.toLowerCase();
|
|
427
|
+
return entries.filter((e) => e.path.toLowerCase().includes(lowerQuery)).sort((a, b) => {
|
|
428
|
+
const aLower = a.name.toLowerCase();
|
|
429
|
+
const bLower = b.name.toLowerCase();
|
|
430
|
+
if (aLower === lowerQuery && bLower !== lowerQuery) {
|
|
431
|
+
return -1;
|
|
432
|
+
}
|
|
433
|
+
if (bLower === lowerQuery && aLower !== lowerQuery) {
|
|
434
|
+
return 1;
|
|
435
|
+
}
|
|
436
|
+
const aPathLower = a.path.toLowerCase();
|
|
437
|
+
const bPathLower = b.path.toLowerCase();
|
|
438
|
+
if (aPathLower.startsWith(lowerQuery) && !bPathLower.startsWith(lowerQuery)) {
|
|
439
|
+
return -1;
|
|
440
|
+
}
|
|
441
|
+
if (bPathLower.startsWith(lowerQuery) && !aPathLower.startsWith(lowerQuery)) {
|
|
442
|
+
return 1;
|
|
443
|
+
}
|
|
444
|
+
return a.path.length - b.path.length;
|
|
445
|
+
}).slice(0, 20);
|
|
446
|
+
}
|
|
447
|
+
var init_file_utils = () => {};
|
|
448
|
+
|
|
339
449
|
// src/mcp/config.ts
|
|
340
450
|
var exports_config = {};
|
|
341
451
|
__export(exports_config, {
|
|
@@ -412,14 +522,231 @@ var init_config = __esm(() => {
|
|
|
412
522
|
PREDEFINED_SERVERS = {};
|
|
413
523
|
});
|
|
414
524
|
|
|
525
|
+
// src/agents/manager.ts
|
|
526
|
+
var exports_manager = {};
|
|
527
|
+
__export(exports_manager, {
|
|
528
|
+
AgentsManager: () => AgentsManager
|
|
529
|
+
});
|
|
530
|
+
import fs6 from "fs/promises";
|
|
531
|
+
import path6 from "path";
|
|
532
|
+
|
|
533
|
+
class AgentsManager {
|
|
534
|
+
static instance;
|
|
535
|
+
agentsPath;
|
|
536
|
+
constructor() {
|
|
537
|
+
this.agentsPath = path6.join(getSettingsManager().getStorageDirectory(), "agents");
|
|
538
|
+
}
|
|
539
|
+
static getInstance() {
|
|
540
|
+
if (!AgentsManager.instance) {
|
|
541
|
+
AgentsManager.instance = new AgentsManager;
|
|
542
|
+
}
|
|
543
|
+
return AgentsManager.instance;
|
|
544
|
+
}
|
|
545
|
+
async ensureAgentsDirectory() {
|
|
546
|
+
try {
|
|
547
|
+
await fs6.mkdir(this.agentsPath, { recursive: true });
|
|
548
|
+
} catch (error) {}
|
|
549
|
+
}
|
|
550
|
+
async listAgents() {
|
|
551
|
+
await this.ensureAgentsDirectory();
|
|
552
|
+
try {
|
|
553
|
+
const files = await fs6.readdir(this.agentsPath);
|
|
554
|
+
const agents = [];
|
|
555
|
+
for (const file of files) {
|
|
556
|
+
if (file.endsWith(".json")) {
|
|
557
|
+
try {
|
|
558
|
+
const content = await fs6.readFile(path6.join(this.agentsPath, file), "utf-8");
|
|
559
|
+
agents.push(JSON.parse(content));
|
|
560
|
+
} catch (e) {}
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
return agents;
|
|
564
|
+
} catch (error) {
|
|
565
|
+
return [];
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
async getAgent(name) {
|
|
569
|
+
try {
|
|
570
|
+
const content = await fs6.readFile(path6.join(this.agentsPath, `${name}.json`), "utf-8");
|
|
571
|
+
return JSON.parse(content);
|
|
572
|
+
} catch (error) {
|
|
573
|
+
return null;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
async createAgent(config) {
|
|
577
|
+
await this.ensureAgentsDirectory();
|
|
578
|
+
const filePath = path6.join(this.agentsPath, `${config.name}.json`);
|
|
579
|
+
await fs6.writeFile(filePath, JSON.stringify(config, null, 2));
|
|
580
|
+
}
|
|
581
|
+
async generateAgent(name, description, agent) {
|
|
582
|
+
const prompt = `Create a configuration for an AI agent named "${name}" based on this description: "${description}".
|
|
583
|
+
|
|
584
|
+
The configuration should be a JSON object matching this interface:
|
|
585
|
+
interface AgentConfig {
|
|
586
|
+
name: string;
|
|
587
|
+
role: string;
|
|
588
|
+
description: string;
|
|
589
|
+
model?: string; // suggest a model if appropriate, or leave undefined
|
|
590
|
+
tools?: string[]; // suggest relevant tools/skills names
|
|
591
|
+
temperature?: number;
|
|
592
|
+
systemPrompt?: string; // a detailed system prompt for this agent
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
Return ONLY the JSON object.`;
|
|
596
|
+
const response = await agent.processUserMessage(prompt);
|
|
597
|
+
let jsonData = "";
|
|
598
|
+
for (const entry of response) {
|
|
599
|
+
if (entry.type === "assistant") {
|
|
600
|
+
const match = entry.content.match(/```(?:json)?\n([\s\S]*?)```/);
|
|
601
|
+
if (match) {
|
|
602
|
+
jsonData = match[1];
|
|
603
|
+
break;
|
|
604
|
+
} else {
|
|
605
|
+
if (entry.content.trim().startsWith("{")) {
|
|
606
|
+
jsonData = entry.content;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
if (!jsonData) {
|
|
612
|
+
throw new Error("Failed to generate agent configuration");
|
|
613
|
+
}
|
|
614
|
+
try {
|
|
615
|
+
const config = JSON.parse(jsonData);
|
|
616
|
+
config.name = name;
|
|
617
|
+
await this.createAgent(config);
|
|
618
|
+
} catch (e) {
|
|
619
|
+
throw new Error(`Failed to parse generated agent config: ${e.message}`);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
async deleteAgent(name) {
|
|
623
|
+
try {
|
|
624
|
+
const filePath = path6.join(this.agentsPath, `${name}.json`);
|
|
625
|
+
await fs6.unlink(filePath);
|
|
626
|
+
} catch (error) {
|
|
627
|
+
throw new Error(`Failed to delete agent '${name}'`);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
var init_manager = __esm(() => {
|
|
632
|
+
init_settings_manager();
|
|
633
|
+
});
|
|
634
|
+
|
|
635
|
+
// src/skills/manager.ts
|
|
636
|
+
var exports_manager2 = {};
|
|
637
|
+
__export(exports_manager2, {
|
|
638
|
+
SkillsManager: () => SkillsManager
|
|
639
|
+
});
|
|
640
|
+
import fs7 from "fs/promises";
|
|
641
|
+
import path7 from "path";
|
|
642
|
+
|
|
643
|
+
class SkillsManager {
|
|
644
|
+
static instance;
|
|
645
|
+
skillsPath;
|
|
646
|
+
constructor() {
|
|
647
|
+
this.skillsPath = path7.join(getSettingsManager().getStorageDirectory(), "skills");
|
|
648
|
+
}
|
|
649
|
+
static getInstance() {
|
|
650
|
+
if (!SkillsManager.instance) {
|
|
651
|
+
SkillsManager.instance = new SkillsManager;
|
|
652
|
+
}
|
|
653
|
+
return SkillsManager.instance;
|
|
654
|
+
}
|
|
655
|
+
async ensureSkillsDirectory() {
|
|
656
|
+
try {
|
|
657
|
+
await fs7.mkdir(this.skillsPath, { recursive: true });
|
|
658
|
+
} catch (error) {}
|
|
659
|
+
}
|
|
660
|
+
async listSkills() {
|
|
661
|
+
await this.ensureSkillsDirectory();
|
|
662
|
+
try {
|
|
663
|
+
const files = await fs7.readdir(this.skillsPath);
|
|
664
|
+
return files.filter((file) => file.endsWith(".ts") || file.endsWith(".js") || file.endsWith(".json")).map((file) => path7.parse(file).name);
|
|
665
|
+
} catch (error) {
|
|
666
|
+
return [];
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
async getSkillPath(name) {
|
|
670
|
+
const extensions = [".ts", ".js", ".json"];
|
|
671
|
+
for (const ext of extensions) {
|
|
672
|
+
const fullPath = path7.join(this.skillsPath, `${name}${ext}`);
|
|
673
|
+
try {
|
|
674
|
+
await fs7.access(fullPath);
|
|
675
|
+
return fullPath;
|
|
676
|
+
} catch {
|
|
677
|
+
continue;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
throw new Error(`Skill '${name}' not found`);
|
|
681
|
+
}
|
|
682
|
+
async getSkillContent(name) {
|
|
683
|
+
const skillPath = await this.getSkillPath(name);
|
|
684
|
+
return await fs7.readFile(skillPath, "utf-8");
|
|
685
|
+
}
|
|
686
|
+
async createSkill(name, description, agent) {
|
|
687
|
+
await this.ensureSkillsDirectory();
|
|
688
|
+
const prompt = `Create a robust TypeScript skill for the Super Agent CLI named "${name}".
|
|
689
|
+
|
|
690
|
+
Description: ${description}
|
|
691
|
+
|
|
692
|
+
The skill should be a module that exports a default function or class that implements the desired functionality.
|
|
693
|
+
It should valid standalone TypeScript code.
|
|
694
|
+
Include comments explaining how it works.
|
|
695
|
+
|
|
696
|
+
Structure:
|
|
697
|
+
\`\`\`typescript
|
|
698
|
+
// ${name} skill
|
|
699
|
+
export default async function(args: any) {
|
|
700
|
+
// implementation
|
|
701
|
+
}
|
|
702
|
+
\`\`\`
|
|
703
|
+
|
|
704
|
+
Return ONLY the code block.`;
|
|
705
|
+
const response = await agent.processUserMessage(prompt);
|
|
706
|
+
let code = "";
|
|
707
|
+
for (const entry of response) {
|
|
708
|
+
if (entry.type === "assistant") {
|
|
709
|
+
const match = entry.content.match(/```(?:typescript|ts)?\n([\s\S]*?)```/);
|
|
710
|
+
if (match) {
|
|
711
|
+
code = match[1];
|
|
712
|
+
break;
|
|
713
|
+
} else {
|
|
714
|
+
code = entry.content;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
if (!code) {
|
|
719
|
+
throw new Error("Failed to generate skill code");
|
|
720
|
+
}
|
|
721
|
+
const filePath = path7.join(this.skillsPath, `${name}.ts`);
|
|
722
|
+
await fs7.writeFile(filePath, code);
|
|
723
|
+
}
|
|
724
|
+
async deleteSkill(name) {
|
|
725
|
+
try {
|
|
726
|
+
const skillPath = await this.getSkillPath(name);
|
|
727
|
+
await fs7.unlink(skillPath);
|
|
728
|
+
} catch (error) {
|
|
729
|
+
throw new Error(`Failed to delete skill '${name}': ${error.message}`);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
async saveSkill(name, content) {
|
|
733
|
+
await this.ensureSkillsDirectory();
|
|
734
|
+
const filePath = path7.join(this.skillsPath, name.endsWith(".ts") ? name : `${name}.ts`);
|
|
735
|
+
await fs7.writeFile(filePath, content);
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
var init_manager2 = __esm(() => {
|
|
739
|
+
init_settings_manager();
|
|
740
|
+
});
|
|
741
|
+
|
|
415
742
|
// src/indexing/indexer.ts
|
|
416
743
|
var exports_indexer = {};
|
|
417
744
|
__export(exports_indexer, {
|
|
418
745
|
getFileIndexer: () => getFileIndexer,
|
|
419
746
|
FileIndexer: () => FileIndexer
|
|
420
747
|
});
|
|
421
|
-
import * as
|
|
422
|
-
import * as
|
|
748
|
+
import * as fs11 from "fs-extra";
|
|
749
|
+
import * as path10 from "path";
|
|
423
750
|
|
|
424
751
|
class FileIndexer {
|
|
425
752
|
static instance;
|
|
@@ -429,7 +756,7 @@ class FileIndexer {
|
|
|
429
756
|
isScanning = false;
|
|
430
757
|
constructor() {
|
|
431
758
|
const settingsManager = getSettingsManager();
|
|
432
|
-
this.storagePath =
|
|
759
|
+
this.storagePath = path10.join(settingsManager.getStorageDirectory(), INDEX_FILENAME);
|
|
433
760
|
this.rootPath = process.cwd();
|
|
434
761
|
}
|
|
435
762
|
static getInstance() {
|
|
@@ -440,8 +767,8 @@ class FileIndexer {
|
|
|
440
767
|
}
|
|
441
768
|
async loadIndex() {
|
|
442
769
|
try {
|
|
443
|
-
if (
|
|
444
|
-
const content = await
|
|
770
|
+
if (fs11.existsSync(this.storagePath)) {
|
|
771
|
+
const content = await fs11.readFile(this.storagePath, "utf-8");
|
|
445
772
|
this.index = JSON.parse(content);
|
|
446
773
|
if (!this.index || this.index.metadata.version !== INDEX_VERSION || this.index.metadata.rootPath !== this.rootPath) {
|
|
447
774
|
this.index = null;
|
|
@@ -457,7 +784,7 @@ class FileIndexer {
|
|
|
457
784
|
return;
|
|
458
785
|
}
|
|
459
786
|
try {
|
|
460
|
-
await
|
|
787
|
+
await fs11.outputFile(this.storagePath, JSON.stringify(this.index, null, 2));
|
|
461
788
|
} catch (error) {
|
|
462
789
|
console.error("Failed to save file index:", error);
|
|
463
790
|
}
|
|
@@ -483,15 +810,15 @@ class FileIndexer {
|
|
|
483
810
|
];
|
|
484
811
|
const entries = [];
|
|
485
812
|
const scanDir = async (dir) => {
|
|
486
|
-
const files = await
|
|
813
|
+
const files = await fs11.readdir(dir, { withFileTypes: true });
|
|
487
814
|
for (const file of files) {
|
|
488
815
|
if (ignoreList.includes(file.name) || file.name.startsWith(".")) {
|
|
489
816
|
if (file.name !== ".env") {
|
|
490
817
|
continue;
|
|
491
818
|
}
|
|
492
819
|
}
|
|
493
|
-
const fullPath =
|
|
494
|
-
const relativePath =
|
|
820
|
+
const fullPath = path10.join(dir, file.name);
|
|
821
|
+
const relativePath = path10.relative(this.rootPath, fullPath);
|
|
495
822
|
if (file.isDirectory()) {
|
|
496
823
|
entries.push({
|
|
497
824
|
path: relativePath,
|
|
@@ -501,7 +828,7 @@ class FileIndexer {
|
|
|
501
828
|
});
|
|
502
829
|
await scanDir(fullPath);
|
|
503
830
|
} else {
|
|
504
|
-
const stats = await
|
|
831
|
+
const stats = await fs11.stat(fullPath);
|
|
505
832
|
entries.push({
|
|
506
833
|
path: relativePath,
|
|
507
834
|
size: stats.size,
|
|
@@ -536,16 +863,130 @@ var init_indexer = __esm(() => {
|
|
|
536
863
|
init_settings_manager();
|
|
537
864
|
});
|
|
538
865
|
|
|
866
|
+
// src/utils/session-manager.ts
|
|
867
|
+
var exports_session_manager = {};
|
|
868
|
+
__export(exports_session_manager, {
|
|
869
|
+
getSessionManager: () => getSessionManager,
|
|
870
|
+
SessionManager: () => SessionManager
|
|
871
|
+
});
|
|
872
|
+
import * as fs15 from "fs-extra";
|
|
873
|
+
import * as path14 from "path";
|
|
874
|
+
|
|
875
|
+
class SessionManager {
|
|
876
|
+
static instance;
|
|
877
|
+
sessionsDir;
|
|
878
|
+
currentSession = null;
|
|
879
|
+
constructor() {
|
|
880
|
+
const settingsManager = getSettingsManager();
|
|
881
|
+
this.sessionsDir = path14.join(settingsManager.getStorageDirectory(), "sessions");
|
|
882
|
+
fs15.ensureDirSync(this.sessionsDir);
|
|
883
|
+
}
|
|
884
|
+
static getInstance() {
|
|
885
|
+
if (!SessionManager.instance) {
|
|
886
|
+
SessionManager.instance = new SessionManager;
|
|
887
|
+
}
|
|
888
|
+
return SessionManager.instance;
|
|
889
|
+
}
|
|
890
|
+
generateSessionId(workingDir) {
|
|
891
|
+
const normalized = path14.normalize(workingDir).toLowerCase();
|
|
892
|
+
return Buffer.from(normalized).toString("base64").replace(/[/+=]/g, "_");
|
|
893
|
+
}
|
|
894
|
+
getSessionFilePath(sessionId) {
|
|
895
|
+
return path14.join(this.sessionsDir, `${sessionId}.json`);
|
|
896
|
+
}
|
|
897
|
+
async getOrCreateSession(workingDirectory, name) {
|
|
898
|
+
const sessionId = this.generateSessionId(workingDirectory);
|
|
899
|
+
const sessionFile = this.getSessionFilePath(sessionId);
|
|
900
|
+
try {
|
|
901
|
+
if (await fs15.pathExists(sessionFile)) {
|
|
902
|
+
const session = await fs15.readJson(sessionFile);
|
|
903
|
+
session.lastAccessed = Date.now();
|
|
904
|
+
this.currentSession = session;
|
|
905
|
+
await this.saveSession(session);
|
|
906
|
+
return session;
|
|
907
|
+
}
|
|
908
|
+
} catch (error) {}
|
|
909
|
+
const newSession = {
|
|
910
|
+
id: sessionId,
|
|
911
|
+
workingDirectory,
|
|
912
|
+
name: name || path14.basename(workingDirectory),
|
|
913
|
+
messages: [],
|
|
914
|
+
lastAccessed: Date.now(),
|
|
915
|
+
createdAt: Date.now()
|
|
916
|
+
};
|
|
917
|
+
this.currentSession = newSession;
|
|
918
|
+
await this.saveSession(newSession);
|
|
919
|
+
return newSession;
|
|
920
|
+
}
|
|
921
|
+
async saveSession(session) {
|
|
922
|
+
const sessionFile = this.getSessionFilePath(session.id);
|
|
923
|
+
await fs15.outputJson(sessionFile, session, { spaces: 2 });
|
|
924
|
+
}
|
|
925
|
+
async addMessage(message) {
|
|
926
|
+
if (!this.currentSession) {
|
|
927
|
+
throw new Error("No active session");
|
|
928
|
+
}
|
|
929
|
+
this.currentSession.messages.push(message);
|
|
930
|
+
this.currentSession.lastAccessed = Date.now();
|
|
931
|
+
await this.saveSession(this.currentSession);
|
|
932
|
+
}
|
|
933
|
+
async listSessions() {
|
|
934
|
+
const sessionFiles = await fs15.readdir(this.sessionsDir);
|
|
935
|
+
const sessions = [];
|
|
936
|
+
for (const file of sessionFiles) {
|
|
937
|
+
if (file.endsWith(".json")) {
|
|
938
|
+
try {
|
|
939
|
+
const session = await fs15.readJson(path14.join(this.sessionsDir, file));
|
|
940
|
+
sessions.push(session);
|
|
941
|
+
} catch (error) {}
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
sessions.sort((a, b) => b.lastAccessed - a.lastAccessed);
|
|
945
|
+
return sessions;
|
|
946
|
+
}
|
|
947
|
+
async deleteSession(sessionId) {
|
|
948
|
+
const sessionFile = this.getSessionFilePath(sessionId);
|
|
949
|
+
if (await fs15.pathExists(sessionFile)) {
|
|
950
|
+
await fs15.remove(sessionFile);
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
getCurrentSession() {
|
|
954
|
+
return this.currentSession;
|
|
955
|
+
}
|
|
956
|
+
async switchSession(sessionId) {
|
|
957
|
+
const sessionFile = this.getSessionFilePath(sessionId);
|
|
958
|
+
try {
|
|
959
|
+
if (await fs15.pathExists(sessionFile)) {
|
|
960
|
+
const session = await fs15.readJson(sessionFile);
|
|
961
|
+
session.lastAccessed = Date.now();
|
|
962
|
+
this.currentSession = session;
|
|
963
|
+
await this.saveSession(session);
|
|
964
|
+
return session;
|
|
965
|
+
}
|
|
966
|
+
} catch (error) {}
|
|
967
|
+
return null;
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
function getSessionManager() {
|
|
971
|
+
return SessionManager.getInstance();
|
|
972
|
+
}
|
|
973
|
+
var init_session_manager = __esm(() => {
|
|
974
|
+
init_settings_manager();
|
|
975
|
+
});
|
|
976
|
+
|
|
539
977
|
// package.json
|
|
540
978
|
var require_package = __commonJS((exports, module) => {
|
|
541
979
|
module.exports = {
|
|
542
980
|
name: "@involvex/super-agent-cli",
|
|
543
|
-
version: "0.0.
|
|
981
|
+
version: "0.0.63",
|
|
544
982
|
description: "An open-source AI agent that brings the power of Super Agent directly into your terminal.",
|
|
545
983
|
keywords: [
|
|
546
984
|
"cli",
|
|
547
985
|
"agent",
|
|
548
|
-
"
|
|
986
|
+
"cli-agent",
|
|
987
|
+
"ai-cli",
|
|
988
|
+
"coding-cli",
|
|
989
|
+
"ai-coding-cli",
|
|
549
990
|
"ai"
|
|
550
991
|
],
|
|
551
992
|
homepage: "https://involvex.github.io/super-agent-cli/",
|
|
@@ -592,6 +1033,7 @@ var require_package = __commonJS((exports, module) => {
|
|
|
592
1033
|
dependencies: {
|
|
593
1034
|
"@google/generative-ai": "^0.24.1",
|
|
594
1035
|
"@modelcontextprotocol/sdk": "^1.25.3",
|
|
1036
|
+
"@types/mime": "^4.0.0",
|
|
595
1037
|
axios: "^1.13.4",
|
|
596
1038
|
cfonts: "^3.3.1",
|
|
597
1039
|
chalk: "^5.6.2",
|
|
@@ -600,7 +1042,9 @@ var require_package = __commonJS((exports, module) => {
|
|
|
600
1042
|
dotenv: "^17.2.3",
|
|
601
1043
|
enquirer: "^2.4.1",
|
|
602
1044
|
"fs-extra": "^11.3.3",
|
|
1045
|
+
ignore: "^7.0.5",
|
|
603
1046
|
ink: "^6.6.0",
|
|
1047
|
+
inquirer: "^13.2.2",
|
|
604
1048
|
marked: "^17.0.1",
|
|
605
1049
|
"marked-terminal": "^7.3.0",
|
|
606
1050
|
mime: "^4.1.0",
|
|
@@ -638,46 +1082,14 @@ var require_package = __commonJS((exports, module) => {
|
|
|
638
1082
|
};
|
|
639
1083
|
});
|
|
640
1084
|
|
|
641
|
-
// src/utils/banner.ts
|
|
642
|
-
var exports_banner = {};
|
|
643
|
-
__export(exports_banner, {
|
|
644
|
-
HELP_BANNER: () => HELP_BANNER,
|
|
645
|
-
BANNER: () => BANNER
|
|
646
|
-
});
|
|
647
|
-
var BANNER = `
|
|
648
|
-
╔═══════════════════════════════════════════════════════════════╗
|
|
649
|
-
║ ║
|
|
650
|
-
║ ███████╗██╗ ██╗██████╗ ███████╗██████╗ ║
|
|
651
|
-
║ ██╔════╝██║ ██║██╔══██╗██╔════╝██╔══██╗ ║
|
|
652
|
-
║ ███████╗██║ ██║██████╔╝█████╗ ██████╔╝ ║
|
|
653
|
-
║ ╚════██║██║ ██║██╔═══╝ ██╔══╝ ██╔══██╗ ║
|
|
654
|
-
║ ███████║╚██████╔╝██║ ███████╗██║ ██║ ║
|
|
655
|
-
║ ╚══════╝ ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═╝ ║
|
|
656
|
-
║ ║
|
|
657
|
-
║ █████╗ ██████╗ ███████╗███╗ ██╗████████╗ ║
|
|
658
|
-
║ ██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝ ║
|
|
659
|
-
║ ███████║██║ ███╗█████╗ ██╔██╗ ██║ ██║ ║
|
|
660
|
-
║ ██╔══██║██║ ██║██╔══╝ ██║╚██╗██║ ██║ ║
|
|
661
|
-
║ ██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║ ║
|
|
662
|
-
║ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ║
|
|
663
|
-
║ ║
|
|
664
|
-
║ \uD83E\uDD16 AI-Powered Terminal Assistant ║
|
|
665
|
-
║ ║
|
|
666
|
-
╚═══════════════════════════════════════════════════════════════╝
|
|
667
|
-
`, HELP_BANNER = `
|
|
668
|
-
╔═══════════════════════════════════════════╗
|
|
669
|
-
║ \uD83E\uDD16 SUPER AGENT - Help & Usage ║
|
|
670
|
-
╚═══════════════════════════════════════════╝
|
|
671
|
-
`;
|
|
672
|
-
|
|
673
1085
|
// src/utils/update-checker.ts
|
|
674
1086
|
var exports_update_checker = {};
|
|
675
1087
|
__export(exports_update_checker, {
|
|
676
1088
|
getUpdateChecker: () => getUpdateChecker,
|
|
677
1089
|
UpdateChecker: () => UpdateChecker
|
|
678
1090
|
});
|
|
679
|
-
import * as
|
|
680
|
-
import * as
|
|
1091
|
+
import * as fs16 from "fs-extra";
|
|
1092
|
+
import * as path15 from "path";
|
|
681
1093
|
import axios3 from "axios";
|
|
682
1094
|
|
|
683
1095
|
class UpdateChecker {
|
|
@@ -686,7 +1098,7 @@ class UpdateChecker {
|
|
|
686
1098
|
currentVersion;
|
|
687
1099
|
constructor(currentVersion) {
|
|
688
1100
|
const settingsManager = getSettingsManager();
|
|
689
|
-
this.cacheFile =
|
|
1101
|
+
this.cacheFile = path15.join(settingsManager.getStorageDirectory(), "update-cache.json");
|
|
690
1102
|
this.currentVersion = currentVersion;
|
|
691
1103
|
}
|
|
692
1104
|
static getInstance(currentVersion) {
|
|
@@ -697,8 +1109,8 @@ class UpdateChecker {
|
|
|
697
1109
|
}
|
|
698
1110
|
async loadCache() {
|
|
699
1111
|
try {
|
|
700
|
-
if (await
|
|
701
|
-
const cache = await
|
|
1112
|
+
if (await fs16.pathExists(this.cacheFile)) {
|
|
1113
|
+
const cache = await fs16.readJson(this.cacheFile);
|
|
702
1114
|
const now = Date.now();
|
|
703
1115
|
if (cache.lastChecked && now - cache.lastChecked < CACHE_DURATION) {
|
|
704
1116
|
return cache;
|
|
@@ -709,7 +1121,7 @@ class UpdateChecker {
|
|
|
709
1121
|
}
|
|
710
1122
|
async saveCache(info) {
|
|
711
1123
|
try {
|
|
712
|
-
await
|
|
1124
|
+
await fs16.outputJson(this.cacheFile, info);
|
|
713
1125
|
} catch (error) {}
|
|
714
1126
|
}
|
|
715
1127
|
compareVersions(v1, v2) {
|
|
@@ -778,724 +1190,333 @@ var init_update_checker = __esm(() => {
|
|
|
778
1190
|
CACHE_DURATION = 24 * 60 * 60 * 1000;
|
|
779
1191
|
});
|
|
780
1192
|
|
|
781
|
-
// src/utils/
|
|
782
|
-
var
|
|
783
|
-
__export(
|
|
784
|
-
|
|
785
|
-
|
|
1193
|
+
// src/utils/banner.ts
|
|
1194
|
+
var exports_banner = {};
|
|
1195
|
+
__export(exports_banner, {
|
|
1196
|
+
HELP_BANNER: () => HELP_BANNER,
|
|
1197
|
+
BANNER: () => BANNER
|
|
786
1198
|
});
|
|
787
|
-
|
|
788
|
-
|
|
1199
|
+
var BANNER = `
|
|
1200
|
+
╔═══════════════════════════════════════════════════════════════╗
|
|
1201
|
+
║ ║
|
|
1202
|
+
║ ███████╗██╗ ██╗██████╗ ███████╗██████╗ ║
|
|
1203
|
+
║ ██╔════╝██║ ██║██╔══██╗██╔════╝██╔══██╗ ║
|
|
1204
|
+
║ ███████╗██║ ██║██████╔╝█████╗ ██████╔╝ ║
|
|
1205
|
+
║ ╚════██║██║ ██║██╔═══╝ ██╔══╝ ██╔══██╗ ║
|
|
1206
|
+
║ ███████║╚██████╔╝██║ ███████╗██║ ██║ ║
|
|
1207
|
+
║ ╚══════╝ ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═╝ ║
|
|
1208
|
+
║ ║
|
|
1209
|
+
║ █████╗ ██████╗ ███████╗███╗ ██╗████████╗ ║
|
|
1210
|
+
║ ██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝ ║
|
|
1211
|
+
║ ███████║██║ ███╗█████╗ ██╔██╗ ██║ ██║ ║
|
|
1212
|
+
║ ██╔══██║██║ ██║██╔══╝ ██║╚██╗██║ ██║ ║
|
|
1213
|
+
║ ██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║ ║
|
|
1214
|
+
║ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ║
|
|
1215
|
+
║ ║
|
|
1216
|
+
║ \uD83E\uDD16 AI-Powered Terminal Assistant ║
|
|
1217
|
+
║ ║
|
|
1218
|
+
╚═══════════════════════════════════════════════════════════════╝
|
|
1219
|
+
`, HELP_BANNER = `
|
|
1220
|
+
╔═══════════════════════════════════════════╗
|
|
1221
|
+
║ \uD83E\uDD16 SUPER AGENT - Help & Usage ║
|
|
1222
|
+
╚═══════════════════════════════════════════╝
|
|
1223
|
+
`;
|
|
789
1224
|
|
|
790
|
-
|
|
1225
|
+
// src/utils/confirmation-service.ts
|
|
1226
|
+
import { EventEmitter } from "events";
|
|
1227
|
+
import { exec } from "child_process";
|
|
1228
|
+
import { promisify } from "util";
|
|
1229
|
+
var execAsync = promisify(exec);
|
|
1230
|
+
|
|
1231
|
+
class ConfirmationService extends EventEmitter {
|
|
791
1232
|
static instance;
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
1233
|
+
skipConfirmationThisSession = false;
|
|
1234
|
+
pendingConfirmation = null;
|
|
1235
|
+
resolveConfirmation = null;
|
|
1236
|
+
sessionFlags = {
|
|
1237
|
+
fileOperations: false,
|
|
1238
|
+
bashCommands: false,
|
|
1239
|
+
allOperations: false
|
|
1240
|
+
};
|
|
799
1241
|
static getInstance() {
|
|
800
|
-
if (!
|
|
801
|
-
|
|
1242
|
+
if (!ConfirmationService.instance) {
|
|
1243
|
+
ConfirmationService.instance = new ConfirmationService;
|
|
802
1244
|
}
|
|
803
|
-
return
|
|
804
|
-
}
|
|
805
|
-
generateSessionId(workingDir) {
|
|
806
|
-
const normalized = path13.normalize(workingDir).toLowerCase();
|
|
807
|
-
return Buffer.from(normalized).toString("base64").replace(/[/+=]/g, "_");
|
|
1245
|
+
return ConfirmationService.instance;
|
|
808
1246
|
}
|
|
809
|
-
|
|
810
|
-
|
|
1247
|
+
constructor() {
|
|
1248
|
+
super();
|
|
811
1249
|
}
|
|
812
|
-
async
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
return session;
|
|
1250
|
+
async requestConfirmation(options, operationType = "file") {
|
|
1251
|
+
if (this.sessionFlags.allOperations || operationType === "file" && this.sessionFlags.fileOperations || operationType === "bash" && this.sessionFlags.bashCommands) {
|
|
1252
|
+
return { confirmed: true };
|
|
1253
|
+
}
|
|
1254
|
+
if (options.showVSCodeOpen) {
|
|
1255
|
+
try {
|
|
1256
|
+
await this.openInVSCode(options.filename);
|
|
1257
|
+
} catch (error) {
|
|
1258
|
+
options.showVSCodeOpen = false;
|
|
822
1259
|
}
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
1260
|
+
}
|
|
1261
|
+
this.pendingConfirmation = new Promise((resolve) => {
|
|
1262
|
+
this.resolveConfirmation = resolve;
|
|
1263
|
+
});
|
|
1264
|
+
setImmediate(() => {
|
|
1265
|
+
this.emit("confirmation-requested", options);
|
|
1266
|
+
});
|
|
1267
|
+
const result = await this.pendingConfirmation;
|
|
1268
|
+
if (result.dontAskAgain) {
|
|
1269
|
+
if (operationType === "file") {
|
|
1270
|
+
this.sessionFlags.fileOperations = true;
|
|
1271
|
+
} else if (operationType === "bash") {
|
|
1272
|
+
this.sessionFlags.bashCommands = true;
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
return result;
|
|
835
1276
|
}
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
1277
|
+
confirmOperation(confirmed, dontAskAgain) {
|
|
1278
|
+
if (this.resolveConfirmation) {
|
|
1279
|
+
this.resolveConfirmation({ confirmed, dontAskAgain });
|
|
1280
|
+
this.resolveConfirmation = null;
|
|
1281
|
+
this.pendingConfirmation = null;
|
|
1282
|
+
}
|
|
839
1283
|
}
|
|
840
|
-
|
|
841
|
-
if (
|
|
842
|
-
|
|
1284
|
+
rejectOperation(feedback) {
|
|
1285
|
+
if (this.resolveConfirmation) {
|
|
1286
|
+
this.resolveConfirmation({ confirmed: false, feedback });
|
|
1287
|
+
this.resolveConfirmation = null;
|
|
1288
|
+
this.pendingConfirmation = null;
|
|
843
1289
|
}
|
|
844
|
-
this.currentSession.messages.push(message);
|
|
845
|
-
this.currentSession.lastAccessed = Date.now();
|
|
846
|
-
await this.saveSession(this.currentSession);
|
|
847
1290
|
}
|
|
848
|
-
async
|
|
849
|
-
const
|
|
850
|
-
const
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
1291
|
+
async openInVSCode(filename) {
|
|
1292
|
+
const commands = ["code", "code-insiders", "codium"];
|
|
1293
|
+
for (const cmd of commands) {
|
|
1294
|
+
try {
|
|
1295
|
+
await execAsync(`which ${cmd}`);
|
|
1296
|
+
await execAsync(`${cmd} "${filename}"`);
|
|
1297
|
+
return;
|
|
1298
|
+
} catch (error) {
|
|
1299
|
+
continue;
|
|
857
1300
|
}
|
|
858
1301
|
}
|
|
859
|
-
|
|
860
|
-
return sessions;
|
|
1302
|
+
throw new Error("VS Code not found");
|
|
861
1303
|
}
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
if (await fs14.pathExists(sessionFile)) {
|
|
865
|
-
await fs14.remove(sessionFile);
|
|
866
|
-
}
|
|
1304
|
+
isPending() {
|
|
1305
|
+
return this.pendingConfirmation !== null;
|
|
867
1306
|
}
|
|
868
|
-
|
|
869
|
-
|
|
1307
|
+
resetSession() {
|
|
1308
|
+
this.sessionFlags = {
|
|
1309
|
+
fileOperations: false,
|
|
1310
|
+
bashCommands: false,
|
|
1311
|
+
allOperations: false
|
|
1312
|
+
};
|
|
870
1313
|
}
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
session.lastAccessed = Date.now();
|
|
877
|
-
this.currentSession = session;
|
|
878
|
-
await this.saveSession(session);
|
|
879
|
-
return session;
|
|
880
|
-
}
|
|
881
|
-
} catch (error) {}
|
|
882
|
-
return null;
|
|
1314
|
+
getSessionFlags() {
|
|
1315
|
+
return { ...this.sessionFlags };
|
|
1316
|
+
}
|
|
1317
|
+
setSessionFlag(flagType, value) {
|
|
1318
|
+
this.sessionFlags[flagType] = value;
|
|
883
1319
|
}
|
|
884
1320
|
}
|
|
885
|
-
function getSessionManager() {
|
|
886
|
-
return SessionManager.getInstance();
|
|
887
|
-
}
|
|
888
|
-
var init_session_manager = __esm(() => {
|
|
889
|
-
init_settings_manager();
|
|
890
|
-
});
|
|
891
1321
|
|
|
892
|
-
// src/
|
|
893
|
-
|
|
894
|
-
__export(exports_server, {
|
|
895
|
-
WebServer: () => WebServer
|
|
896
|
-
});
|
|
897
|
-
import { createServer } from "http";
|
|
898
|
-
import { WebSocketServer } from "ws";
|
|
899
|
-
import * as fs15 from "fs-extra";
|
|
900
|
-
import * as path14 from "path";
|
|
901
|
-
import open from "open";
|
|
902
|
-
import mime from "mime";
|
|
1322
|
+
// src/index.ts
|
|
1323
|
+
init_settings_manager();
|
|
903
1324
|
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
constructor(options) {
|
|
912
|
-
this.hostname = options.hostname || "localhost";
|
|
913
|
-
this.port = options.port || 3000;
|
|
914
|
-
this.agent = options.agent;
|
|
915
|
-
this.httpServer = createServer((req, res) => {
|
|
916
|
-
this.handleHttpRequest(req, res);
|
|
917
|
-
});
|
|
918
|
-
this.wss = new WebSocketServer({ server: this.httpServer });
|
|
919
|
-
this.wss.on("connection", (ws) => {
|
|
920
|
-
this.handleWebSocketConnection(ws);
|
|
921
|
-
});
|
|
1325
|
+
// src/hooks/use-input-handler.ts
|
|
1326
|
+
init_file_utils();
|
|
1327
|
+
|
|
1328
|
+
// src/utils/text-utils.ts
|
|
1329
|
+
function isWordBoundary(char) {
|
|
1330
|
+
if (!char) {
|
|
1331
|
+
return true;
|
|
922
1332
|
}
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
const absolutePath = path14.resolve(clientDir, sanitizedPath.substring(1));
|
|
929
|
-
if (!absolutePath.startsWith(clientDir)) {
|
|
930
|
-
res.writeHead(403, { "Content-Type": "text/plain" });
|
|
931
|
-
res.end("Forbidden");
|
|
932
|
-
return;
|
|
933
|
-
}
|
|
934
|
-
try {
|
|
935
|
-
if (await fs15.pathExists(absolutePath)) {
|
|
936
|
-
const stat5 = await fs15.stat(absolutePath);
|
|
937
|
-
let filePath = absolutePath;
|
|
938
|
-
if (stat5.isDirectory()) {
|
|
939
|
-
filePath = path14.join(absolutePath, "index.html");
|
|
940
|
-
}
|
|
941
|
-
const content = await fs15.readFile(filePath);
|
|
942
|
-
const mimeType = mime.getType(filePath) || "application/octet-stream";
|
|
943
|
-
res.writeHead(200, { "Content-Type": mimeType });
|
|
944
|
-
res.end(content);
|
|
945
|
-
} else {
|
|
946
|
-
res.writeHead(404);
|
|
947
|
-
res.end("Not Found");
|
|
948
|
-
}
|
|
949
|
-
} catch (error) {
|
|
950
|
-
console.error("Error serving file:", error);
|
|
951
|
-
res.writeHead(500);
|
|
952
|
-
res.end("Internal Server Error");
|
|
953
|
-
}
|
|
1333
|
+
return /\s/.test(char) || /[^\w]/.test(char);
|
|
1334
|
+
}
|
|
1335
|
+
function moveToPreviousWord(text, position) {
|
|
1336
|
+
if (position <= 0) {
|
|
1337
|
+
return 0;
|
|
954
1338
|
}
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
this.checkAndSendUpdateNotification(ws);
|
|
959
|
-
ws.on("message", async (data) => {
|
|
960
|
-
try {
|
|
961
|
-
const message = JSON.parse(data.toString());
|
|
962
|
-
if (message.type === "prompt") {
|
|
963
|
-
await this.handlePrompt(message.content, ws);
|
|
964
|
-
} else if (message.type === "get_file_tree") {
|
|
965
|
-
await this.handleGetFileTree(ws);
|
|
966
|
-
} else if (message.type === "get_file_content") {
|
|
967
|
-
await this.handleGetFileContent(message.path, ws);
|
|
968
|
-
} else if (message.type === "list_sessions") {
|
|
969
|
-
await this.handleListSessions(ws);
|
|
970
|
-
} else if (message.type === "switch_session") {
|
|
971
|
-
await this.handleSwitchSession(message.sessionId, ws);
|
|
972
|
-
}
|
|
973
|
-
} catch (error) {
|
|
974
|
-
console.error("WebSocket message error:", error);
|
|
975
|
-
ws.send(JSON.stringify({ type: "error", content: "Invalid message format" }));
|
|
976
|
-
}
|
|
977
|
-
});
|
|
978
|
-
ws.on("close", () => {
|
|
979
|
-
this.clients.delete(ws);
|
|
980
|
-
console.log(`\uD83D\uDCE1 Web client disconnected (${this.clients.size} remaining)`);
|
|
981
|
-
});
|
|
982
|
-
ws.on("error", (error) => {
|
|
983
|
-
console.error("WebSocket error:", error);
|
|
984
|
-
});
|
|
1339
|
+
let pos = position - 1;
|
|
1340
|
+
while (pos > 0 && isWordBoundary(text[pos])) {
|
|
1341
|
+
pos--;
|
|
985
1342
|
}
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
ws.send(JSON.stringify({ type: "user_message", content: prompt }));
|
|
989
|
-
const entries = await this.agent.processUserMessage(prompt);
|
|
990
|
-
for (const entry of entries) {
|
|
991
|
-
if (entry.type === "assistant") {
|
|
992
|
-
ws.send(JSON.stringify({
|
|
993
|
-
type: "assistant_message",
|
|
994
|
-
content: entry.content
|
|
995
|
-
}));
|
|
996
|
-
} else if (entry.type === "tool_call") {
|
|
997
|
-
ws.send(JSON.stringify({
|
|
998
|
-
type: "tool_call",
|
|
999
|
-
tool: entry.toolCall?.function.name,
|
|
1000
|
-
content: "Executing..."
|
|
1001
|
-
}));
|
|
1002
|
-
} else if (entry.type === "tool_result") {
|
|
1003
|
-
ws.send(JSON.stringify({
|
|
1004
|
-
type: "tool_result",
|
|
1005
|
-
tool: entry.toolCall?.function.name,
|
|
1006
|
-
content: entry.content
|
|
1007
|
-
}));
|
|
1008
|
-
}
|
|
1009
|
-
}
|
|
1010
|
-
ws.send(JSON.stringify({ type: "done" }));
|
|
1011
|
-
} catch (error) {
|
|
1012
|
-
ws.send(JSON.stringify({
|
|
1013
|
-
type: "error",
|
|
1014
|
-
content: error.message
|
|
1015
|
-
}));
|
|
1016
|
-
}
|
|
1343
|
+
while (pos > 0 && !isWordBoundary(text[pos - 1])) {
|
|
1344
|
+
pos--;
|
|
1017
1345
|
}
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
if (!index) {
|
|
1024
|
-
ws.send(JSON.stringify({ type: "file_tree", tree: [] }));
|
|
1025
|
-
return;
|
|
1026
|
-
}
|
|
1027
|
-
const tree = index.entries.filter((e) => !e.path.includes("node_modules") && !e.path.startsWith(".")).map((e) => ({
|
|
1028
|
-
path: e.path,
|
|
1029
|
-
name: path14.basename(e.path),
|
|
1030
|
-
isDirectory: e.isDirectory,
|
|
1031
|
-
size: e.size
|
|
1032
|
-
})).slice(0, 500);
|
|
1033
|
-
ws.send(JSON.stringify({ type: "file_tree", tree }));
|
|
1034
|
-
} catch (error) {
|
|
1035
|
-
ws.send(JSON.stringify({ type: "error", content: error.message }));
|
|
1036
|
-
}
|
|
1346
|
+
return pos;
|
|
1347
|
+
}
|
|
1348
|
+
function moveToNextWord(text, position) {
|
|
1349
|
+
if (position >= text.length) {
|
|
1350
|
+
return text.length;
|
|
1037
1351
|
}
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
if (!fullPath.startsWith(process.cwd())) {
|
|
1042
|
-
throw new Error("Access denied");
|
|
1043
|
-
}
|
|
1044
|
-
const content = await fs15.readFile(fullPath, "utf-8");
|
|
1045
|
-
ws.send(JSON.stringify({
|
|
1046
|
-
type: "file_content",
|
|
1047
|
-
path: filePath,
|
|
1048
|
-
content: content.slice(0, 1e4)
|
|
1049
|
-
}));
|
|
1050
|
-
} catch (error) {
|
|
1051
|
-
ws.send(JSON.stringify({ type: "error", content: error.message }));
|
|
1052
|
-
}
|
|
1352
|
+
let pos = position;
|
|
1353
|
+
while (pos < text.length && !isWordBoundary(text[pos])) {
|
|
1354
|
+
pos++;
|
|
1053
1355
|
}
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
const { getSessionManager: getSessionManager2 } = await Promise.resolve().then(() => (init_session_manager(), exports_session_manager));
|
|
1057
|
-
const sessionManager = getSessionManager2();
|
|
1058
|
-
const sessions = await sessionManager.listSessions();
|
|
1059
|
-
ws.send(JSON.stringify({
|
|
1060
|
-
type: "sessions_list",
|
|
1061
|
-
sessions: sessions.map((s) => ({
|
|
1062
|
-
id: s.id,
|
|
1063
|
-
name: s.name,
|
|
1064
|
-
workingDirectory: s.workingDirectory,
|
|
1065
|
-
messageCount: s.messages.length,
|
|
1066
|
-
lastAccessed: s.lastAccessed
|
|
1067
|
-
}))
|
|
1068
|
-
}));
|
|
1069
|
-
} catch (error) {
|
|
1070
|
-
ws.send(JSON.stringify({ type: "error", content: error.message }));
|
|
1071
|
-
}
|
|
1356
|
+
while (pos < text.length && isWordBoundary(text[pos])) {
|
|
1357
|
+
pos++;
|
|
1072
1358
|
}
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1359
|
+
return pos;
|
|
1360
|
+
}
|
|
1361
|
+
function deleteWordBefore(text, position) {
|
|
1362
|
+
const wordStart = moveToPreviousWord(text, position);
|
|
1363
|
+
const newText = text.slice(0, wordStart) + text.slice(position);
|
|
1364
|
+
return {
|
|
1365
|
+
text: newText,
|
|
1366
|
+
position: wordStart
|
|
1367
|
+
};
|
|
1368
|
+
}
|
|
1369
|
+
function deleteWordAfter(text, position) {
|
|
1370
|
+
const wordEnd = moveToNextWord(text, position);
|
|
1371
|
+
const newText = text.slice(0, position) + text.slice(wordEnd);
|
|
1372
|
+
return {
|
|
1373
|
+
text: newText,
|
|
1374
|
+
position
|
|
1375
|
+
};
|
|
1376
|
+
}
|
|
1377
|
+
function moveToLineStart(text, position) {
|
|
1378
|
+
const beforeCursor = text.slice(0, position);
|
|
1379
|
+
const lastNewlineIndex = beforeCursor.lastIndexOf(`
|
|
1380
|
+
`);
|
|
1381
|
+
return lastNewlineIndex === -1 ? 0 : lastNewlineIndex + 1;
|
|
1382
|
+
}
|
|
1383
|
+
function moveToLineEnd(text, position) {
|
|
1384
|
+
const afterCursor = text.slice(position);
|
|
1385
|
+
const nextNewlineIndex = afterCursor.indexOf(`
|
|
1386
|
+
`);
|
|
1387
|
+
return nextNewlineIndex === -1 ? text.length : position + nextNewlineIndex;
|
|
1388
|
+
}
|
|
1389
|
+
function deleteCharBefore(text, position) {
|
|
1390
|
+
if (position <= 0) {
|
|
1391
|
+
return { text, position };
|
|
1392
|
+
}
|
|
1393
|
+
let deleteCount = 1;
|
|
1394
|
+
const charBefore = text.charAt(position - 1);
|
|
1395
|
+
if (position >= 2) {
|
|
1396
|
+
const charBeforeBefore = text.charAt(position - 2);
|
|
1397
|
+
if (charBeforeBefore >= "\uD800" && charBeforeBefore <= "\uDBFF" && charBefore >= "\uDC00" && charBefore <= "\uDFFF") {
|
|
1398
|
+
deleteCount = 2;
|
|
1093
1399
|
}
|
|
1094
1400
|
}
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
currentVersion: updateInfo.currentVersion,
|
|
1105
|
-
latestVersion: updateInfo.latestVersion
|
|
1106
|
-
}));
|
|
1107
|
-
}
|
|
1108
|
-
} catch (error) {}
|
|
1401
|
+
const newText = text.slice(0, position - deleteCount) + text.slice(position);
|
|
1402
|
+
return {
|
|
1403
|
+
text: newText,
|
|
1404
|
+
position: position - deleteCount
|
|
1405
|
+
};
|
|
1406
|
+
}
|
|
1407
|
+
function deleteCharAfter(text, position) {
|
|
1408
|
+
if (position >= text.length) {
|
|
1409
|
+
return { text, position };
|
|
1109
1410
|
}
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
this.httpServer.on("error", (error) => {
|
|
1118
|
-
reject(error);
|
|
1119
|
-
});
|
|
1120
|
-
});
|
|
1121
|
-
}
|
|
1122
|
-
async openBrowser() {
|
|
1123
|
-
const url = `http://${this.hostname}:${this.port}`;
|
|
1124
|
-
try {
|
|
1125
|
-
await open(url);
|
|
1126
|
-
console.log(`\uD83D\uDE80 Opened browser at ${url}`);
|
|
1127
|
-
} catch (error) {
|
|
1128
|
-
console.warn(`Could not open browser automatically. Please visit ${url}`);
|
|
1129
|
-
}
|
|
1130
|
-
}
|
|
1131
|
-
stop() {
|
|
1132
|
-
this.clients.forEach((client) => {
|
|
1133
|
-
client.close();
|
|
1134
|
-
});
|
|
1135
|
-
this.wss.close();
|
|
1136
|
-
this.httpServer.close();
|
|
1137
|
-
console.log("\uD83D\uDED1 Web server stopped");
|
|
1411
|
+
let deleteCount = 1;
|
|
1412
|
+
const charAfter = text.charAt(position);
|
|
1413
|
+
if (position + 1 < text.length) {
|
|
1414
|
+
const charAfterAfter = text.charAt(position + 1);
|
|
1415
|
+
if (charAfter >= "\uD800" && charAfter <= "\uDBFF" && charAfterAfter >= "\uDC00" && charAfterAfter <= "\uDFFF") {
|
|
1416
|
+
deleteCount = 2;
|
|
1417
|
+
}
|
|
1138
1418
|
}
|
|
1419
|
+
const newText = text.slice(0, position) + text.slice(position + deleteCount);
|
|
1420
|
+
return {
|
|
1421
|
+
text: newText,
|
|
1422
|
+
position
|
|
1423
|
+
};
|
|
1139
1424
|
}
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
import { exec } from "child_process";
|
|
1146
|
-
import { promisify } from "util";
|
|
1147
|
-
var execAsync = promisify(exec);
|
|
1148
|
-
|
|
1149
|
-
class ConfirmationService extends EventEmitter {
|
|
1150
|
-
static instance;
|
|
1151
|
-
skipConfirmationThisSession = false;
|
|
1152
|
-
pendingConfirmation = null;
|
|
1153
|
-
resolveConfirmation = null;
|
|
1154
|
-
sessionFlags = {
|
|
1155
|
-
fileOperations: false,
|
|
1156
|
-
bashCommands: false,
|
|
1157
|
-
allOperations: false
|
|
1425
|
+
function insertText(text, position, insert) {
|
|
1426
|
+
const newText = text.slice(0, position) + insert + text.slice(position);
|
|
1427
|
+
return {
|
|
1428
|
+
text: newText,
|
|
1429
|
+
position: position + insert.length
|
|
1158
1430
|
};
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
// src/hooks/use-input-history.ts
|
|
1434
|
+
import { useState, useCallback } from "react";
|
|
1435
|
+
function useInputHistory() {
|
|
1436
|
+
const [history, setHistory] = useState([]);
|
|
1437
|
+
const [currentIndex, setCurrentIndex] = useState(-1);
|
|
1438
|
+
const [originalInput, setOriginalInput] = useState("");
|
|
1439
|
+
const addToHistory = useCallback((input) => {
|
|
1440
|
+
if (input.trim() && !history.includes(input.trim())) {
|
|
1441
|
+
setHistory((prev) => [...prev, input.trim()]);
|
|
1162
1442
|
}
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
if (this.sessionFlags.allOperations || operationType === "file" && this.sessionFlags.fileOperations || operationType === "bash" && this.sessionFlags.bashCommands) {
|
|
1170
|
-
return { confirmed: true };
|
|
1443
|
+
setCurrentIndex(-1);
|
|
1444
|
+
setOriginalInput("");
|
|
1445
|
+
}, [history]);
|
|
1446
|
+
const navigateHistory = useCallback((direction) => {
|
|
1447
|
+
if (history.length === 0) {
|
|
1448
|
+
return null;
|
|
1171
1449
|
}
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1450
|
+
let newIndex;
|
|
1451
|
+
if (direction === "up") {
|
|
1452
|
+
if (currentIndex === -1) {
|
|
1453
|
+
newIndex = history.length - 1;
|
|
1454
|
+
} else {
|
|
1455
|
+
newIndex = Math.max(0, currentIndex - 1);
|
|
1177
1456
|
}
|
|
1178
|
-
}
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
if (result.dontAskAgain) {
|
|
1187
|
-
if (operationType === "file") {
|
|
1188
|
-
this.sessionFlags.fileOperations = true;
|
|
1189
|
-
} else if (operationType === "bash") {
|
|
1190
|
-
this.sessionFlags.bashCommands = true;
|
|
1457
|
+
} else {
|
|
1458
|
+
if (currentIndex === -1) {
|
|
1459
|
+
return null;
|
|
1460
|
+
} else if (currentIndex === history.length - 1) {
|
|
1461
|
+
newIndex = -1;
|
|
1462
|
+
return originalInput;
|
|
1463
|
+
} else {
|
|
1464
|
+
newIndex = Math.min(history.length - 1, currentIndex + 1);
|
|
1191
1465
|
}
|
|
1192
1466
|
}
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
}
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
this.pendingConfirmation = null;
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
async openInVSCode(filename) {
|
|
1210
|
-
const commands = ["code", "code-insiders", "codium"];
|
|
1211
|
-
for (const cmd of commands) {
|
|
1212
|
-
try {
|
|
1213
|
-
await execAsync(`which ${cmd}`);
|
|
1214
|
-
await execAsync(`${cmd} "${filename}"`);
|
|
1215
|
-
return;
|
|
1216
|
-
} catch (error) {
|
|
1217
|
-
continue;
|
|
1218
|
-
}
|
|
1467
|
+
setCurrentIndex(newIndex);
|
|
1468
|
+
return newIndex === -1 ? originalInput : history[newIndex];
|
|
1469
|
+
}, [history, currentIndex, originalInput]);
|
|
1470
|
+
const getCurrentHistoryIndex = useCallback(() => currentIndex, [currentIndex]);
|
|
1471
|
+
const resetHistory = useCallback(() => {
|
|
1472
|
+
setHistory([]);
|
|
1473
|
+
setCurrentIndex(-1);
|
|
1474
|
+
setOriginalInput("");
|
|
1475
|
+
}, []);
|
|
1476
|
+
const isNavigatingHistory = useCallback(() => currentIndex !== -1, [currentIndex]);
|
|
1477
|
+
const setOriginalInputCallback = useCallback((input) => {
|
|
1478
|
+
if (currentIndex === -1) {
|
|
1479
|
+
setOriginalInput(input);
|
|
1219
1480
|
}
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
allOperations: false
|
|
1230
|
-
};
|
|
1231
|
-
}
|
|
1232
|
-
getSessionFlags() {
|
|
1233
|
-
return { ...this.sessionFlags };
|
|
1234
|
-
}
|
|
1235
|
-
setSessionFlag(flagType, value) {
|
|
1236
|
-
this.sessionFlags[flagType] = value;
|
|
1237
|
-
}
|
|
1481
|
+
}, [currentIndex]);
|
|
1482
|
+
return {
|
|
1483
|
+
addToHistory,
|
|
1484
|
+
navigateHistory,
|
|
1485
|
+
getCurrentHistoryIndex,
|
|
1486
|
+
resetHistory,
|
|
1487
|
+
isNavigatingHistory,
|
|
1488
|
+
setOriginalInput: setOriginalInputCallback
|
|
1489
|
+
};
|
|
1238
1490
|
}
|
|
1239
1491
|
|
|
1240
|
-
// src/
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
if (entry.name.startsWith(".") && entry.name !== ".env") {
|
|
1266
|
-
continue;
|
|
1267
|
-
}
|
|
1268
|
-
result.push({
|
|
1269
|
-
name: entry.name,
|
|
1270
|
-
path: relativePath,
|
|
1271
|
-
isDirectory: entry.isDirectory()
|
|
1272
|
-
});
|
|
1273
|
-
if (entry.isDirectory() && maxDepth > 0) {
|
|
1274
|
-
const subFiles = await listFilesRecursive(fullPath, baseDir, maxDepth - 1);
|
|
1275
|
-
result.push(...subFiles);
|
|
1276
|
-
}
|
|
1277
|
-
}
|
|
1278
|
-
} catch (error) {}
|
|
1279
|
-
return result;
|
|
1280
|
-
}
|
|
1281
|
-
function filterFileEntries(entries, query) {
|
|
1282
|
-
if (!query) {
|
|
1283
|
-
return entries.slice(0, 20);
|
|
1284
|
-
}
|
|
1285
|
-
const lowerQuery = query.toLowerCase();
|
|
1286
|
-
return entries.filter((e) => e.path.toLowerCase().includes(lowerQuery)).sort((a, b) => {
|
|
1287
|
-
const aLower = a.name.toLowerCase();
|
|
1288
|
-
const bLower = b.name.toLowerCase();
|
|
1289
|
-
if (aLower === lowerQuery && bLower !== lowerQuery) {
|
|
1290
|
-
return -1;
|
|
1291
|
-
}
|
|
1292
|
-
if (bLower === lowerQuery && aLower !== lowerQuery) {
|
|
1293
|
-
return 1;
|
|
1294
|
-
}
|
|
1295
|
-
const aPathLower = a.path.toLowerCase();
|
|
1296
|
-
const bPathLower = b.path.toLowerCase();
|
|
1297
|
-
if (aPathLower.startsWith(lowerQuery) && !bPathLower.startsWith(lowerQuery)) {
|
|
1298
|
-
return -1;
|
|
1492
|
+
// src/hooks/use-enhanced-input.ts
|
|
1493
|
+
import { useCallback as useCallback2, useRef, useState as useState2 } from "react";
|
|
1494
|
+
function useEnhancedInput({
|
|
1495
|
+
onSubmit,
|
|
1496
|
+
onEscape,
|
|
1497
|
+
onSpecialKey,
|
|
1498
|
+
disabled = false,
|
|
1499
|
+
multiline = false
|
|
1500
|
+
} = {}) {
|
|
1501
|
+
const [input, setInputState] = useState2("");
|
|
1502
|
+
const [cursorPosition, setCursorPositionState] = useState2(0);
|
|
1503
|
+
const isMultilineRef = useRef(multiline);
|
|
1504
|
+
const {
|
|
1505
|
+
addToHistory,
|
|
1506
|
+
navigateHistory,
|
|
1507
|
+
resetHistory,
|
|
1508
|
+
setOriginalInput,
|
|
1509
|
+
isNavigatingHistory
|
|
1510
|
+
} = useInputHistory();
|
|
1511
|
+
const setInput = useCallback2((text, newCursorPos) => {
|
|
1512
|
+
setInputState(text);
|
|
1513
|
+
if (newCursorPos !== undefined) {
|
|
1514
|
+
setCursorPositionState(Math.max(0, Math.min(text.length, newCursorPos)));
|
|
1515
|
+
} else {
|
|
1516
|
+
setCursorPositionState(Math.min(text.length, cursorPosition));
|
|
1299
1517
|
}
|
|
1300
|
-
if (
|
|
1301
|
-
|
|
1302
|
-
}
|
|
1303
|
-
return a.path.length - b.path.length;
|
|
1304
|
-
}).slice(0, 20);
|
|
1305
|
-
}
|
|
1306
|
-
|
|
1307
|
-
// src/utils/text-utils.ts
|
|
1308
|
-
function isWordBoundary(char) {
|
|
1309
|
-
if (!char) {
|
|
1310
|
-
return true;
|
|
1311
|
-
}
|
|
1312
|
-
return /\s/.test(char) || /[^\w]/.test(char);
|
|
1313
|
-
}
|
|
1314
|
-
function moveToPreviousWord(text, position) {
|
|
1315
|
-
if (position <= 0) {
|
|
1316
|
-
return 0;
|
|
1317
|
-
}
|
|
1318
|
-
let pos = position - 1;
|
|
1319
|
-
while (pos > 0 && isWordBoundary(text[pos])) {
|
|
1320
|
-
pos--;
|
|
1321
|
-
}
|
|
1322
|
-
while (pos > 0 && !isWordBoundary(text[pos - 1])) {
|
|
1323
|
-
pos--;
|
|
1324
|
-
}
|
|
1325
|
-
return pos;
|
|
1326
|
-
}
|
|
1327
|
-
function moveToNextWord(text, position) {
|
|
1328
|
-
if (position >= text.length) {
|
|
1329
|
-
return text.length;
|
|
1330
|
-
}
|
|
1331
|
-
let pos = position;
|
|
1332
|
-
while (pos < text.length && !isWordBoundary(text[pos])) {
|
|
1333
|
-
pos++;
|
|
1334
|
-
}
|
|
1335
|
-
while (pos < text.length && isWordBoundary(text[pos])) {
|
|
1336
|
-
pos++;
|
|
1337
|
-
}
|
|
1338
|
-
return pos;
|
|
1339
|
-
}
|
|
1340
|
-
function deleteWordBefore(text, position) {
|
|
1341
|
-
const wordStart = moveToPreviousWord(text, position);
|
|
1342
|
-
const newText = text.slice(0, wordStart) + text.slice(position);
|
|
1343
|
-
return {
|
|
1344
|
-
text: newText,
|
|
1345
|
-
position: wordStart
|
|
1346
|
-
};
|
|
1347
|
-
}
|
|
1348
|
-
function deleteWordAfter(text, position) {
|
|
1349
|
-
const wordEnd = moveToNextWord(text, position);
|
|
1350
|
-
const newText = text.slice(0, position) + text.slice(wordEnd);
|
|
1351
|
-
return {
|
|
1352
|
-
text: newText,
|
|
1353
|
-
position
|
|
1354
|
-
};
|
|
1355
|
-
}
|
|
1356
|
-
function moveToLineStart(text, position) {
|
|
1357
|
-
const beforeCursor = text.slice(0, position);
|
|
1358
|
-
const lastNewlineIndex = beforeCursor.lastIndexOf(`
|
|
1359
|
-
`);
|
|
1360
|
-
return lastNewlineIndex === -1 ? 0 : lastNewlineIndex + 1;
|
|
1361
|
-
}
|
|
1362
|
-
function moveToLineEnd(text, position) {
|
|
1363
|
-
const afterCursor = text.slice(position);
|
|
1364
|
-
const nextNewlineIndex = afterCursor.indexOf(`
|
|
1365
|
-
`);
|
|
1366
|
-
return nextNewlineIndex === -1 ? text.length : position + nextNewlineIndex;
|
|
1367
|
-
}
|
|
1368
|
-
function deleteCharBefore(text, position) {
|
|
1369
|
-
if (position <= 0) {
|
|
1370
|
-
return { text, position };
|
|
1371
|
-
}
|
|
1372
|
-
let deleteCount = 1;
|
|
1373
|
-
const charBefore = text.charAt(position - 1);
|
|
1374
|
-
if (position >= 2) {
|
|
1375
|
-
const charBeforeBefore = text.charAt(position - 2);
|
|
1376
|
-
if (charBeforeBefore >= "\uD800" && charBeforeBefore <= "\uDBFF" && charBefore >= "\uDC00" && charBefore <= "\uDFFF") {
|
|
1377
|
-
deleteCount = 2;
|
|
1378
|
-
}
|
|
1379
|
-
}
|
|
1380
|
-
const newText = text.slice(0, position - deleteCount) + text.slice(position);
|
|
1381
|
-
return {
|
|
1382
|
-
text: newText,
|
|
1383
|
-
position: position - deleteCount
|
|
1384
|
-
};
|
|
1385
|
-
}
|
|
1386
|
-
function deleteCharAfter(text, position) {
|
|
1387
|
-
if (position >= text.length) {
|
|
1388
|
-
return { text, position };
|
|
1389
|
-
}
|
|
1390
|
-
let deleteCount = 1;
|
|
1391
|
-
const charAfter = text.charAt(position);
|
|
1392
|
-
if (position + 1 < text.length) {
|
|
1393
|
-
const charAfterAfter = text.charAt(position + 1);
|
|
1394
|
-
if (charAfter >= "\uD800" && charAfter <= "\uDBFF" && charAfterAfter >= "\uDC00" && charAfterAfter <= "\uDFFF") {
|
|
1395
|
-
deleteCount = 2;
|
|
1396
|
-
}
|
|
1397
|
-
}
|
|
1398
|
-
const newText = text.slice(0, position) + text.slice(position + deleteCount);
|
|
1399
|
-
return {
|
|
1400
|
-
text: newText,
|
|
1401
|
-
position
|
|
1402
|
-
};
|
|
1403
|
-
}
|
|
1404
|
-
function insertText(text, position, insert) {
|
|
1405
|
-
const newText = text.slice(0, position) + insert + text.slice(position);
|
|
1406
|
-
return {
|
|
1407
|
-
text: newText,
|
|
1408
|
-
position: position + insert.length
|
|
1409
|
-
};
|
|
1410
|
-
}
|
|
1411
|
-
|
|
1412
|
-
// src/hooks/use-input-history.ts
|
|
1413
|
-
import { useState, useCallback } from "react";
|
|
1414
|
-
function useInputHistory() {
|
|
1415
|
-
const [history, setHistory] = useState([]);
|
|
1416
|
-
const [currentIndex, setCurrentIndex] = useState(-1);
|
|
1417
|
-
const [originalInput, setOriginalInput] = useState("");
|
|
1418
|
-
const addToHistory = useCallback((input) => {
|
|
1419
|
-
if (input.trim() && !history.includes(input.trim())) {
|
|
1420
|
-
setHistory((prev) => [...prev, input.trim()]);
|
|
1421
|
-
}
|
|
1422
|
-
setCurrentIndex(-1);
|
|
1423
|
-
setOriginalInput("");
|
|
1424
|
-
}, [history]);
|
|
1425
|
-
const navigateHistory = useCallback((direction) => {
|
|
1426
|
-
if (history.length === 0) {
|
|
1427
|
-
return null;
|
|
1428
|
-
}
|
|
1429
|
-
let newIndex;
|
|
1430
|
-
if (direction === "up") {
|
|
1431
|
-
if (currentIndex === -1) {
|
|
1432
|
-
newIndex = history.length - 1;
|
|
1433
|
-
} else {
|
|
1434
|
-
newIndex = Math.max(0, currentIndex - 1);
|
|
1435
|
-
}
|
|
1436
|
-
} else {
|
|
1437
|
-
if (currentIndex === -1) {
|
|
1438
|
-
return null;
|
|
1439
|
-
} else if (currentIndex === history.length - 1) {
|
|
1440
|
-
newIndex = -1;
|
|
1441
|
-
return originalInput;
|
|
1442
|
-
} else {
|
|
1443
|
-
newIndex = Math.min(history.length - 1, currentIndex + 1);
|
|
1444
|
-
}
|
|
1445
|
-
}
|
|
1446
|
-
setCurrentIndex(newIndex);
|
|
1447
|
-
return newIndex === -1 ? originalInput : history[newIndex];
|
|
1448
|
-
}, [history, currentIndex, originalInput]);
|
|
1449
|
-
const getCurrentHistoryIndex = useCallback(() => currentIndex, [currentIndex]);
|
|
1450
|
-
const resetHistory = useCallback(() => {
|
|
1451
|
-
setHistory([]);
|
|
1452
|
-
setCurrentIndex(-1);
|
|
1453
|
-
setOriginalInput("");
|
|
1454
|
-
}, []);
|
|
1455
|
-
const isNavigatingHistory = useCallback(() => currentIndex !== -1, [currentIndex]);
|
|
1456
|
-
const setOriginalInputCallback = useCallback((input) => {
|
|
1457
|
-
if (currentIndex === -1) {
|
|
1458
|
-
setOriginalInput(input);
|
|
1459
|
-
}
|
|
1460
|
-
}, [currentIndex]);
|
|
1461
|
-
return {
|
|
1462
|
-
addToHistory,
|
|
1463
|
-
navigateHistory,
|
|
1464
|
-
getCurrentHistoryIndex,
|
|
1465
|
-
resetHistory,
|
|
1466
|
-
isNavigatingHistory,
|
|
1467
|
-
setOriginalInput: setOriginalInputCallback
|
|
1468
|
-
};
|
|
1469
|
-
}
|
|
1470
|
-
|
|
1471
|
-
// src/hooks/use-enhanced-input.ts
|
|
1472
|
-
import { useCallback as useCallback2, useRef, useState as useState2 } from "react";
|
|
1473
|
-
function useEnhancedInput({
|
|
1474
|
-
onSubmit,
|
|
1475
|
-
onEscape,
|
|
1476
|
-
onSpecialKey,
|
|
1477
|
-
disabled = false,
|
|
1478
|
-
multiline = false
|
|
1479
|
-
} = {}) {
|
|
1480
|
-
const [input, setInputState] = useState2("");
|
|
1481
|
-
const [cursorPosition, setCursorPositionState] = useState2(0);
|
|
1482
|
-
const isMultilineRef = useRef(multiline);
|
|
1483
|
-
const {
|
|
1484
|
-
addToHistory,
|
|
1485
|
-
navigateHistory,
|
|
1486
|
-
resetHistory,
|
|
1487
|
-
setOriginalInput,
|
|
1488
|
-
isNavigatingHistory
|
|
1489
|
-
} = useInputHistory();
|
|
1490
|
-
const setInput = useCallback2((text, newCursorPos) => {
|
|
1491
|
-
setInputState(text);
|
|
1492
|
-
if (newCursorPos !== undefined) {
|
|
1493
|
-
setCursorPositionState(Math.max(0, Math.min(text.length, newCursorPos)));
|
|
1494
|
-
} else {
|
|
1495
|
-
setCursorPositionState(Math.min(text.length, cursorPosition));
|
|
1496
|
-
}
|
|
1497
|
-
if (!isNavigatingHistory()) {
|
|
1498
|
-
setOriginalInput(text);
|
|
1518
|
+
if (!isNavigatingHistory()) {
|
|
1519
|
+
setOriginalInput(text);
|
|
1499
1520
|
}
|
|
1500
1521
|
}, [cursorPosition, isNavigatingHistory, setOriginalInput]);
|
|
1501
1522
|
const setCursorPosition = useCallback2((position) => {
|
|
@@ -1747,9 +1768,9 @@ function CommandSuggestions({
|
|
|
1747
1768
|
|
|
1748
1769
|
// src/utils/model-config.ts
|
|
1749
1770
|
init_settings_manager();
|
|
1750
|
-
function loadModelConfig() {
|
|
1771
|
+
function loadModelConfig(providerId) {
|
|
1751
1772
|
const manager = getSettingsManager();
|
|
1752
|
-
const models = manager.getAvailableModels();
|
|
1773
|
+
const models = manager.getAvailableModels(providerId);
|
|
1753
1774
|
return models.map((model) => ({
|
|
1754
1775
|
model: model.trim()
|
|
1755
1776
|
}));
|
|
@@ -2721,7 +2742,7 @@ function getChatManager() {
|
|
|
2721
2742
|
}
|
|
2722
2743
|
|
|
2723
2744
|
// src/hooks/use-input-handler.ts
|
|
2724
|
-
import * as
|
|
2745
|
+
import * as fs8 from "fs-extra";
|
|
2725
2746
|
function useInputHandler({
|
|
2726
2747
|
agent,
|
|
2727
2748
|
chatHistory,
|
|
@@ -2863,6 +2884,7 @@ function useInputHandler({
|
|
|
2863
2884
|
if (providers.length > 0) {
|
|
2864
2885
|
const selectedProviderId = providers[selectedProviderIndex];
|
|
2865
2886
|
manager.updateUserSetting("active_provider", selectedProviderId);
|
|
2887
|
+
setActiveProvider(selectedProviderId);
|
|
2866
2888
|
setChatHistory((prev) => [
|
|
2867
2889
|
...prev,
|
|
2868
2890
|
{
|
|
@@ -2879,6 +2901,24 @@ function useInputHandler({
|
|
|
2879
2901
|
setShowProviderSelection(false);
|
|
2880
2902
|
return true;
|
|
2881
2903
|
}
|
|
2904
|
+
if (char === "e" || char === "E") {
|
|
2905
|
+
if (providers.length > 0) {
|
|
2906
|
+
const selectedProviderId = providers[selectedProviderIndex];
|
|
2907
|
+
const manager2 = getSettingsManager();
|
|
2908
|
+
const currentKey = manager2.getUserSetting("providers")?.[selectedProviderId]?.api_key || "";
|
|
2909
|
+
setChatHistory((prev) => [
|
|
2910
|
+
...prev,
|
|
2911
|
+
{
|
|
2912
|
+
type: "assistant",
|
|
2913
|
+
content: `\uD83D\uDCDD Editing API key for ${selectedProviderId}. Press Enter after pasting key.`,
|
|
2914
|
+
timestamp: new Date
|
|
2915
|
+
}
|
|
2916
|
+
]);
|
|
2917
|
+
setShowProviderSelection(false);
|
|
2918
|
+
setInput(`/provider set-key ${selectedProviderId} `);
|
|
2919
|
+
}
|
|
2920
|
+
return true;
|
|
2921
|
+
}
|
|
2882
2922
|
return true;
|
|
2883
2923
|
}
|
|
2884
2924
|
if (showConfigViewer) {
|
|
@@ -3074,13 +3114,17 @@ function useInputHandler({
|
|
|
3074
3114
|
description: "Manage plugins (list, install, remove)"
|
|
3075
3115
|
},
|
|
3076
3116
|
{ command: "/commit-and-push", description: "AI commit & push to remote" },
|
|
3117
|
+
{
|
|
3118
|
+
command: "/import <type> <source>",
|
|
3119
|
+
description: "Import resources (agents, skills, hooks)"
|
|
3120
|
+
},
|
|
3077
3121
|
{ command: "/exit", description: "Exit the application" }
|
|
3078
3122
|
];
|
|
3079
3123
|
const [activeProvider, setActiveProvider] = useState3(() => {
|
|
3080
3124
|
return getSettingsManager().loadUserSettings().active_provider;
|
|
3081
3125
|
});
|
|
3082
3126
|
const availableModels = useMemo2(() => {
|
|
3083
|
-
return loadModelConfig();
|
|
3127
|
+
return loadModelConfig(activeProvider);
|
|
3084
3128
|
}, [activeProvider]);
|
|
3085
3129
|
const handleDirectCommand = async (input2) => {
|
|
3086
3130
|
const trimmedInput = input2.trim();
|
|
@@ -3146,6 +3190,64 @@ Config Commands:
|
|
|
3146
3190
|
clearInput();
|
|
3147
3191
|
return true;
|
|
3148
3192
|
}
|
|
3193
|
+
if (trimmedInput === "/provider config") {
|
|
3194
|
+
setChatHistory((prev) => [
|
|
3195
|
+
...prev,
|
|
3196
|
+
{
|
|
3197
|
+
type: "assistant",
|
|
3198
|
+
content: "⚠️ Interactive configuration cannot be run inside the chat session.\n\nPlease run `super-agent provider config` in a separate terminal, or use:\n`/provider set-key <provider> <key>` to set an API key directly.",
|
|
3199
|
+
timestamp: new Date
|
|
3200
|
+
}
|
|
3201
|
+
]);
|
|
3202
|
+
clearInput();
|
|
3203
|
+
return true;
|
|
3204
|
+
}
|
|
3205
|
+
if (trimmedInput.startsWith("/provider set-key ")) {
|
|
3206
|
+
const args = trimmedInput.replace("/provider set-key ", "").trim().split(" ");
|
|
3207
|
+
const providerId = args[0];
|
|
3208
|
+
const key = args.slice(1).join(" ");
|
|
3209
|
+
if (!providerId || !key) {
|
|
3210
|
+
setChatHistory((prev) => [
|
|
3211
|
+
...prev,
|
|
3212
|
+
{
|
|
3213
|
+
type: "assistant",
|
|
3214
|
+
content: "❌ Usage: /provider set-key <provider> <api_key>",
|
|
3215
|
+
timestamp: new Date
|
|
3216
|
+
}
|
|
3217
|
+
]);
|
|
3218
|
+
clearInput();
|
|
3219
|
+
return true;
|
|
3220
|
+
}
|
|
3221
|
+
const manager = getSettingsManager();
|
|
3222
|
+
const settings = manager.loadUserSettings();
|
|
3223
|
+
if (settings.providers && settings.providers[providerId]) {
|
|
3224
|
+
const newProviders = { ...settings.providers };
|
|
3225
|
+
newProviders[providerId] = {
|
|
3226
|
+
...newProviders[providerId],
|
|
3227
|
+
api_key: key
|
|
3228
|
+
};
|
|
3229
|
+
manager.updateUserSetting("providers", newProviders);
|
|
3230
|
+
setChatHistory((prev) => [
|
|
3231
|
+
...prev,
|
|
3232
|
+
{
|
|
3233
|
+
type: "assistant",
|
|
3234
|
+
content: `✅ API Key for ${providerId} updated.`,
|
|
3235
|
+
timestamp: new Date
|
|
3236
|
+
}
|
|
3237
|
+
]);
|
|
3238
|
+
} else {
|
|
3239
|
+
setChatHistory((prev) => [
|
|
3240
|
+
...prev,
|
|
3241
|
+
{
|
|
3242
|
+
type: "assistant",
|
|
3243
|
+
content: `❌ Provider '${providerId}' not found.`,
|
|
3244
|
+
timestamp: new Date
|
|
3245
|
+
}
|
|
3246
|
+
]);
|
|
3247
|
+
}
|
|
3248
|
+
clearInput();
|
|
3249
|
+
return true;
|
|
3250
|
+
}
|
|
3149
3251
|
if (trimmedInput.startsWith("/provider use ")) {
|
|
3150
3252
|
const providerId = trimmedInput.replace("/provider use ", "").trim();
|
|
3151
3253
|
const manager = getSettingsManager();
|
|
@@ -3319,10 +3421,153 @@ ${chats.length ? chats.map((c) => `- ${c}`).join(`
|
|
|
3319
3421
|
clearInput();
|
|
3320
3422
|
return true;
|
|
3321
3423
|
}
|
|
3322
|
-
if (trimmedInput.startsWith("/
|
|
3323
|
-
const args = trimmedInput.replace("/
|
|
3324
|
-
const
|
|
3325
|
-
const
|
|
3424
|
+
if (trimmedInput.startsWith("/import ")) {
|
|
3425
|
+
const args = trimmedInput.replace("/import ", "").split(" ");
|
|
3426
|
+
const type = args[0];
|
|
3427
|
+
const source = args[1];
|
|
3428
|
+
if (!type || !source) {
|
|
3429
|
+
setChatHistory((prev) => [
|
|
3430
|
+
...prev,
|
|
3431
|
+
{
|
|
3432
|
+
type: "assistant",
|
|
3433
|
+
content: `❌ Usage: /import <type> <source>
|
|
3434
|
+
Types: agents, skills, hooks
|
|
3435
|
+
Sources: gemini, claude, kilo, or path`,
|
|
3436
|
+
timestamp: new Date
|
|
3437
|
+
}
|
|
3438
|
+
]);
|
|
3439
|
+
clearInput();
|
|
3440
|
+
return true;
|
|
3441
|
+
}
|
|
3442
|
+
setIsProcessing(true);
|
|
3443
|
+
setChatHistory((prev) => [
|
|
3444
|
+
...prev,
|
|
3445
|
+
{
|
|
3446
|
+
type: "assistant",
|
|
3447
|
+
content: `Importing ${type} from ${source}...`,
|
|
3448
|
+
timestamp: new Date
|
|
3449
|
+
}
|
|
3450
|
+
]);
|
|
3451
|
+
try {
|
|
3452
|
+
const { resolveSourcePath: resolveSourcePath2 } = await Promise.resolve().then(() => (init_file_utils(), exports_file_utils));
|
|
3453
|
+
const { AgentsManager: AgentsManager2 } = await Promise.resolve().then(() => (init_manager(), exports_manager));
|
|
3454
|
+
const { SkillsManager: SkillsManager2 } = await Promise.resolve().then(() => (init_manager2(), exports_manager2));
|
|
3455
|
+
const { getSettingsManager: getSettingsManager2 } = await Promise.resolve().then(() => (init_settings_manager(), exports_settings_manager));
|
|
3456
|
+
const fs9 = await import("fs-extra");
|
|
3457
|
+
const path8 = await import("path");
|
|
3458
|
+
const sourcePath = resolveSourcePath2(source);
|
|
3459
|
+
if (type === "agents") {
|
|
3460
|
+
const agentsDir = path8.join(sourcePath, "agents");
|
|
3461
|
+
if (!await fs9.pathExists(agentsDir)) {
|
|
3462
|
+
throw new Error(`Agents directory not found at ${agentsDir}`);
|
|
3463
|
+
}
|
|
3464
|
+
const files = await fs9.readdir(agentsDir);
|
|
3465
|
+
const manager = AgentsManager2.getInstance();
|
|
3466
|
+
let count = 0;
|
|
3467
|
+
for (const file of files) {
|
|
3468
|
+
if (file.endsWith(".json")) {
|
|
3469
|
+
try {
|
|
3470
|
+
const content = await fs9.readJson(path8.join(agentsDir, file));
|
|
3471
|
+
const agentConfig = {
|
|
3472
|
+
name: content.name || path8.parse(file).name,
|
|
3473
|
+
role: content.role || "Assistant",
|
|
3474
|
+
description: content.description || "Imported agent",
|
|
3475
|
+
model: content.model,
|
|
3476
|
+
tools: content.tools,
|
|
3477
|
+
temperature: content.temperature,
|
|
3478
|
+
systemPrompt: content.systemPrompt || content.system_prompt || content.prompt
|
|
3479
|
+
};
|
|
3480
|
+
await manager.createAgent(agentConfig);
|
|
3481
|
+
count++;
|
|
3482
|
+
} catch (e) {}
|
|
3483
|
+
}
|
|
3484
|
+
}
|
|
3485
|
+
setChatHistory((prev) => [
|
|
3486
|
+
...prev,
|
|
3487
|
+
{
|
|
3488
|
+
type: "assistant",
|
|
3489
|
+
content: `✅ Imported ${count} agents.`,
|
|
3490
|
+
timestamp: new Date
|
|
3491
|
+
}
|
|
3492
|
+
]);
|
|
3493
|
+
} else if (type === "skills") {
|
|
3494
|
+
const skillsDir = path8.join(sourcePath, "skills");
|
|
3495
|
+
if (!await fs9.pathExists(skillsDir)) {
|
|
3496
|
+
throw new Error(`Skills directory not found at ${skillsDir}`);
|
|
3497
|
+
}
|
|
3498
|
+
const files = await fs9.readdir(skillsDir);
|
|
3499
|
+
const manager = SkillsManager2.getInstance();
|
|
3500
|
+
let count = 0;
|
|
3501
|
+
for (const file of files) {
|
|
3502
|
+
if (file.endsWith(".ts") || file.endsWith(".js")) {
|
|
3503
|
+
try {
|
|
3504
|
+
const content = await fs9.readFile(path8.join(skillsDir, file), "utf-8");
|
|
3505
|
+
const name = path8.parse(file).name;
|
|
3506
|
+
await manager.saveSkill(name, content);
|
|
3507
|
+
count++;
|
|
3508
|
+
} catch (e) {}
|
|
3509
|
+
}
|
|
3510
|
+
}
|
|
3511
|
+
setChatHistory((prev) => [
|
|
3512
|
+
...prev,
|
|
3513
|
+
{
|
|
3514
|
+
type: "assistant",
|
|
3515
|
+
content: `✅ Imported ${count} skills.`,
|
|
3516
|
+
timestamp: new Date
|
|
3517
|
+
}
|
|
3518
|
+
]);
|
|
3519
|
+
} else if (type === "hooks") {
|
|
3520
|
+
const settingsFile = source.toLowerCase() === "claude" ? "settings.local.json" : "settings.json";
|
|
3521
|
+
const fullPath = path8.join(sourcePath, settingsFile);
|
|
3522
|
+
if (!await fs9.pathExists(fullPath)) {
|
|
3523
|
+
throw new Error(`Settings file not found at ${fullPath}`);
|
|
3524
|
+
}
|
|
3525
|
+
const settings = await fs9.readJson(fullPath);
|
|
3526
|
+
if (settings.hooks) {
|
|
3527
|
+
const manager = getSettingsManager2();
|
|
3528
|
+
const currentHooks = manager.getUserSetting("hooks") || {};
|
|
3529
|
+
const mergedHooks = { ...currentHooks, ...settings.hooks };
|
|
3530
|
+
manager.updateUserSetting("hooks", mergedHooks);
|
|
3531
|
+
setChatHistory((prev) => [
|
|
3532
|
+
...prev,
|
|
3533
|
+
{
|
|
3534
|
+
type: "assistant",
|
|
3535
|
+
content: `✅ Imported ${Object.keys(settings.hooks).length} hooks.`,
|
|
3536
|
+
timestamp: new Date
|
|
3537
|
+
}
|
|
3538
|
+
]);
|
|
3539
|
+
} else {
|
|
3540
|
+
setChatHistory((prev) => [
|
|
3541
|
+
...prev,
|
|
3542
|
+
{
|
|
3543
|
+
type: "assistant",
|
|
3544
|
+
content: "⚠️ No hooks found in settings file.",
|
|
3545
|
+
timestamp: new Date
|
|
3546
|
+
}
|
|
3547
|
+
]);
|
|
3548
|
+
}
|
|
3549
|
+
} else {
|
|
3550
|
+
throw new Error(`Unknown import type: ${type}`);
|
|
3551
|
+
}
|
|
3552
|
+
} catch (error) {
|
|
3553
|
+
setChatHistory((prev) => [
|
|
3554
|
+
...prev,
|
|
3555
|
+
{
|
|
3556
|
+
type: "assistant",
|
|
3557
|
+
content: `❌ Import failed: ${error.message}`,
|
|
3558
|
+
timestamp: new Date
|
|
3559
|
+
}
|
|
3560
|
+
]);
|
|
3561
|
+
} finally {
|
|
3562
|
+
setIsProcessing(false);
|
|
3563
|
+
}
|
|
3564
|
+
clearInput();
|
|
3565
|
+
return true;
|
|
3566
|
+
}
|
|
3567
|
+
if (trimmedInput.startsWith("/plugin ")) {
|
|
3568
|
+
const args = trimmedInput.replace("/plugin ", "").split(" ");
|
|
3569
|
+
const action = args[0];
|
|
3570
|
+
const pluginManager = getPluginManager();
|
|
3326
3571
|
try {
|
|
3327
3572
|
if (action === "list") {
|
|
3328
3573
|
const plugins = pluginManager.getPlugins();
|
|
@@ -3735,9 +3980,9 @@ ${commitMessage}`
|
|
|
3735
3980
|
for (const mention of mentionMatches) {
|
|
3736
3981
|
const filePath = mention.slice(1);
|
|
3737
3982
|
try {
|
|
3738
|
-
const stats = await
|
|
3983
|
+
const stats = await fs8.stat(filePath);
|
|
3739
3984
|
if (stats.isFile()) {
|
|
3740
|
-
const content = await
|
|
3985
|
+
const content = await fs8.readFile(filePath, "utf-8");
|
|
3741
3986
|
resolvedInput = resolvedInput.replace(mention, `
|
|
3742
3987
|
|
|
3743
3988
|
--- FILE: ${filePath} ---
|
|
@@ -3888,6 +4133,7 @@ ${structure}
|
|
|
3888
4133
|
}
|
|
3889
4134
|
|
|
3890
4135
|
// src/ui/components/mention-suggestions.tsx
|
|
4136
|
+
init_file_utils();
|
|
3891
4137
|
import { useMemo as useMemo3 } from "react";
|
|
3892
4138
|
import { Box as Box2, Text as Text2 } from "ink";
|
|
3893
4139
|
import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
|
|
@@ -4665,6 +4911,7 @@ function LoadingSpinner({
|
|
|
4665
4911
|
}
|
|
4666
4912
|
|
|
4667
4913
|
// src/ui/components/command-palette.tsx
|
|
4914
|
+
init_file_utils();
|
|
4668
4915
|
import { useMemo as useMemo4 } from "react";
|
|
4669
4916
|
import { Box as Box9, Text as Text8 } from "ink";
|
|
4670
4917
|
import { jsxDEV as jsxDEV9 } from "react/jsx-dev-runtime";
|
|
@@ -5303,8 +5550,8 @@ class ConfirmationTool {
|
|
|
5303
5550
|
}
|
|
5304
5551
|
}
|
|
5305
5552
|
// src/tools/morph-editor.ts
|
|
5306
|
-
import * as
|
|
5307
|
-
import
|
|
5553
|
+
import * as path8 from "path";
|
|
5554
|
+
import fs9 from "fs-extra";
|
|
5308
5555
|
import axios2 from "axios";
|
|
5309
5556
|
|
|
5310
5557
|
class MorphEditorTool {
|
|
@@ -5319,8 +5566,8 @@ class MorphEditorTool {
|
|
|
5319
5566
|
}
|
|
5320
5567
|
async editFile(targetFile, instructions, codeEdit) {
|
|
5321
5568
|
try {
|
|
5322
|
-
const resolvedPath =
|
|
5323
|
-
if (!await
|
|
5569
|
+
const resolvedPath = path8.resolve(targetFile);
|
|
5570
|
+
if (!await fs9.pathExists(resolvedPath)) {
|
|
5324
5571
|
return {
|
|
5325
5572
|
success: false,
|
|
5326
5573
|
error: `File not found: ${targetFile}`
|
|
@@ -5332,7 +5579,7 @@ class MorphEditorTool {
|
|
|
5332
5579
|
error: "MORPH_API_KEY not configured. Please set your Morph API key."
|
|
5333
5580
|
};
|
|
5334
5581
|
}
|
|
5335
|
-
const initialCode = await
|
|
5582
|
+
const initialCode = await fs9.readFile(resolvedPath, "utf-8");
|
|
5336
5583
|
const sessionFlags = this.confirmationService.getSessionFlags();
|
|
5337
5584
|
if (!sessionFlags.fileOperations && !sessionFlags.allOperations) {
|
|
5338
5585
|
const confirmationResult = await this.confirmationService.requestConfirmation({
|
|
@@ -5352,7 +5599,7 @@ ${codeEdit}`
|
|
|
5352
5599
|
}
|
|
5353
5600
|
}
|
|
5354
5601
|
const mergedCode = await this.callMorphApply(instructions, initialCode, codeEdit);
|
|
5355
|
-
await
|
|
5602
|
+
await fs9.writeFile(resolvedPath, mergedCode, "utf-8");
|
|
5356
5603
|
const oldLines = initialCode.split(`
|
|
5357
5604
|
`);
|
|
5358
5605
|
const newLines = mergedCode.split(`
|
|
@@ -5535,11 +5782,11 @@ ${codeEdit}`
|
|
|
5535
5782
|
}
|
|
5536
5783
|
async view(filePath, viewRange) {
|
|
5537
5784
|
try {
|
|
5538
|
-
const resolvedPath =
|
|
5539
|
-
if (await
|
|
5540
|
-
const stats = await
|
|
5785
|
+
const resolvedPath = path8.resolve(filePath);
|
|
5786
|
+
if (await fs9.pathExists(resolvedPath)) {
|
|
5787
|
+
const stats = await fs9.stat(resolvedPath);
|
|
5541
5788
|
if (stats.isDirectory()) {
|
|
5542
|
-
const files = await
|
|
5789
|
+
const files = await fs9.readdir(resolvedPath);
|
|
5543
5790
|
return {
|
|
5544
5791
|
success: true,
|
|
5545
5792
|
output: `Directory contents of ${filePath}:
|
|
@@ -5547,7 +5794,7 @@ ${files.join(`
|
|
|
5547
5794
|
`)}`
|
|
5548
5795
|
};
|
|
5549
5796
|
}
|
|
5550
|
-
const content = await
|
|
5797
|
+
const content = await fs9.readFile(resolvedPath, "utf-8");
|
|
5551
5798
|
const lines = content.split(`
|
|
5552
5799
|
`);
|
|
5553
5800
|
if (viewRange) {
|
|
@@ -5593,8 +5840,8 @@ ${numberedLines}${additionalLinesMessage}`
|
|
|
5593
5840
|
}
|
|
5594
5841
|
}
|
|
5595
5842
|
// src/tools/project-map.ts
|
|
5596
|
-
import * as
|
|
5597
|
-
import
|
|
5843
|
+
import * as path9 from "path";
|
|
5844
|
+
import fs10 from "fs-extra";
|
|
5598
5845
|
|
|
5599
5846
|
class ProjectMapTool {
|
|
5600
5847
|
currentDirectory = process.cwd();
|
|
@@ -5628,7 +5875,7 @@ Important Files:
|
|
|
5628
5875
|
}
|
|
5629
5876
|
let result = "";
|
|
5630
5877
|
try {
|
|
5631
|
-
const entries = await
|
|
5878
|
+
const entries = await fs10.readdir(dir, { withFileTypes: true });
|
|
5632
5879
|
const sortedEntries = entries.sort((a, b) => {
|
|
5633
5880
|
if (a.isDirectory() && !b.isDirectory()) {
|
|
5634
5881
|
return -1;
|
|
@@ -5656,7 +5903,7 @@ Important Files:
|
|
|
5656
5903
|
if (entry.isDirectory()) {
|
|
5657
5904
|
result += `${indent}\uD83D\uDCC1 ${entry.name}/
|
|
5658
5905
|
`;
|
|
5659
|
-
result += await this.generateTree(
|
|
5906
|
+
result += await this.generateTree(path9.join(dir, entry.name), maxDepth, currentDepth + 1);
|
|
5660
5907
|
} else {
|
|
5661
5908
|
result += `${indent}\uD83D\uDCC4 ${entry.name}
|
|
5662
5909
|
`;
|
|
@@ -5678,8 +5925,8 @@ Important Files:
|
|
|
5678
5925
|
];
|
|
5679
5926
|
const found = [];
|
|
5680
5927
|
for (const pattern of importantPatterns) {
|
|
5681
|
-
const fullPath =
|
|
5682
|
-
if (await
|
|
5928
|
+
const fullPath = path9.join(this.currentDirectory, pattern);
|
|
5929
|
+
if (await fs10.pathExists(fullPath)) {
|
|
5683
5930
|
found.push(pattern);
|
|
5684
5931
|
}
|
|
5685
5932
|
}
|
|
@@ -5692,8 +5939,8 @@ Important Files:
|
|
|
5692
5939
|
// src/tools/search.ts
|
|
5693
5940
|
init_indexer();
|
|
5694
5941
|
import { spawn } from "child_process";
|
|
5695
|
-
import * as
|
|
5696
|
-
import
|
|
5942
|
+
import * as path11 from "path";
|
|
5943
|
+
import fs12 from "fs-extra";
|
|
5697
5944
|
|
|
5698
5945
|
class SearchTool {
|
|
5699
5946
|
confirmationService = ConfirmationService.getInstance();
|
|
@@ -5722,7 +5969,7 @@ class SearchTool {
|
|
|
5722
5969
|
const searchPattern = query.toLowerCase();
|
|
5723
5970
|
fileResults = entries.filter((e) => e.path.toLowerCase().includes(searchPattern)).map((e) => ({
|
|
5724
5971
|
path: e.path,
|
|
5725
|
-
name:
|
|
5972
|
+
name: path11.basename(e.path),
|
|
5726
5973
|
score: 10
|
|
5727
5974
|
}));
|
|
5728
5975
|
} else {
|
|
@@ -5846,13 +6093,13 @@ class SearchTool {
|
|
|
5846
6093
|
return;
|
|
5847
6094
|
}
|
|
5848
6095
|
try {
|
|
5849
|
-
const entries = await
|
|
6096
|
+
const entries = await fs12.readdir(dir, { withFileTypes: true });
|
|
5850
6097
|
for (const entry of entries) {
|
|
5851
6098
|
if (files.length >= maxResults) {
|
|
5852
6099
|
break;
|
|
5853
6100
|
}
|
|
5854
|
-
const fullPath =
|
|
5855
|
-
const relativePath =
|
|
6101
|
+
const fullPath = path11.join(dir, entry.name);
|
|
6102
|
+
const relativePath = path11.relative(this.currentDirectory, fullPath);
|
|
5856
6103
|
if (!options.includeHidden && entry.name.startsWith(".")) {
|
|
5857
6104
|
continue;
|
|
5858
6105
|
}
|
|
@@ -5951,19 +6198,19 @@ class SearchTool {
|
|
|
5951
6198
|
}
|
|
5952
6199
|
// src/tools/text-editor.ts
|
|
5953
6200
|
import { writeFile as writeFilePromise } from "fs/promises";
|
|
5954
|
-
import * as
|
|
5955
|
-
import
|
|
6201
|
+
import * as path12 from "path";
|
|
6202
|
+
import fs13 from "fs-extra";
|
|
5956
6203
|
|
|
5957
6204
|
class TextEditorTool {
|
|
5958
6205
|
editHistory = [];
|
|
5959
6206
|
confirmationService = ConfirmationService.getInstance();
|
|
5960
6207
|
async view(filePath, viewRange) {
|
|
5961
6208
|
try {
|
|
5962
|
-
const resolvedPath =
|
|
5963
|
-
if (await
|
|
5964
|
-
const stats = await
|
|
6209
|
+
const resolvedPath = path12.resolve(filePath);
|
|
6210
|
+
if (await fs13.pathExists(resolvedPath)) {
|
|
6211
|
+
const stats = await fs13.stat(resolvedPath);
|
|
5965
6212
|
if (stats.isDirectory()) {
|
|
5966
|
-
const files = await
|
|
6213
|
+
const files = await fs13.readdir(resolvedPath);
|
|
5967
6214
|
return {
|
|
5968
6215
|
success: true,
|
|
5969
6216
|
output: `Directory contents of ${filePath}:
|
|
@@ -5971,7 +6218,7 @@ ${files.join(`
|
|
|
5971
6218
|
`)}`
|
|
5972
6219
|
};
|
|
5973
6220
|
}
|
|
5974
|
-
const content = await
|
|
6221
|
+
const content = await fs13.readFile(resolvedPath, "utf-8");
|
|
5975
6222
|
const lines = content.split(`
|
|
5976
6223
|
`);
|
|
5977
6224
|
if (viewRange) {
|
|
@@ -6011,14 +6258,14 @@ ${numberedLines}${additionalLinesMessage}`
|
|
|
6011
6258
|
}
|
|
6012
6259
|
async strReplace(filePath, oldStr, newStr, replaceAll = false) {
|
|
6013
6260
|
try {
|
|
6014
|
-
const resolvedPath =
|
|
6015
|
-
if (!await
|
|
6261
|
+
const resolvedPath = path12.resolve(filePath);
|
|
6262
|
+
if (!await fs13.pathExists(resolvedPath)) {
|
|
6016
6263
|
return {
|
|
6017
6264
|
success: false,
|
|
6018
6265
|
error: `File not found: ${filePath}`
|
|
6019
6266
|
};
|
|
6020
6267
|
}
|
|
6021
|
-
const content = await
|
|
6268
|
+
const content = await fs13.readFile(resolvedPath, "utf-8");
|
|
6022
6269
|
if (!content.includes(oldStr)) {
|
|
6023
6270
|
if (oldStr.includes(`
|
|
6024
6271
|
`)) {
|
|
@@ -6086,7 +6333,7 @@ ${numberedLines}${additionalLinesMessage}`
|
|
|
6086
6333
|
}
|
|
6087
6334
|
async create(filePath, content) {
|
|
6088
6335
|
try {
|
|
6089
|
-
const resolvedPath =
|
|
6336
|
+
const resolvedPath = path12.resolve(filePath);
|
|
6090
6337
|
const sessionFlags = this.confirmationService.getSessionFlags();
|
|
6091
6338
|
if (!sessionFlags.fileOperations && !sessionFlags.allOperations) {
|
|
6092
6339
|
const contentLines = content.split(`
|
|
@@ -6112,8 +6359,8 @@ ${numberedLines}${additionalLinesMessage}`
|
|
|
6112
6359
|
};
|
|
6113
6360
|
}
|
|
6114
6361
|
}
|
|
6115
|
-
const dir =
|
|
6116
|
-
await
|
|
6362
|
+
const dir = path12.dirname(resolvedPath);
|
|
6363
|
+
await fs13.ensureDir(dir);
|
|
6117
6364
|
await writeFilePromise(resolvedPath, content, "utf-8");
|
|
6118
6365
|
this.editHistory.push({
|
|
6119
6366
|
command: "create",
|
|
@@ -6137,14 +6384,14 @@ ${numberedLines}${additionalLinesMessage}`
|
|
|
6137
6384
|
}
|
|
6138
6385
|
async replaceLines(filePath, startLine, endLine, newContent) {
|
|
6139
6386
|
try {
|
|
6140
|
-
const resolvedPath =
|
|
6141
|
-
if (!await
|
|
6387
|
+
const resolvedPath = path12.resolve(filePath);
|
|
6388
|
+
if (!await fs13.pathExists(resolvedPath)) {
|
|
6142
6389
|
return {
|
|
6143
6390
|
success: false,
|
|
6144
6391
|
error: `File not found: ${filePath}`
|
|
6145
6392
|
};
|
|
6146
6393
|
}
|
|
6147
|
-
const fileContent = await
|
|
6394
|
+
const fileContent = await fs13.readFile(resolvedPath, "utf-8");
|
|
6148
6395
|
const lines = fileContent.split(`
|
|
6149
6396
|
`);
|
|
6150
6397
|
if (startLine < 1 || startLine > lines.length) {
|
|
@@ -6207,14 +6454,14 @@ ${numberedLines}${additionalLinesMessage}`
|
|
|
6207
6454
|
}
|
|
6208
6455
|
async insert(filePath, insertLine, content) {
|
|
6209
6456
|
try {
|
|
6210
|
-
const resolvedPath =
|
|
6211
|
-
if (!await
|
|
6457
|
+
const resolvedPath = path12.resolve(filePath);
|
|
6458
|
+
if (!await fs13.pathExists(resolvedPath)) {
|
|
6212
6459
|
return {
|
|
6213
6460
|
success: false,
|
|
6214
6461
|
error: `File not found: ${filePath}`
|
|
6215
6462
|
};
|
|
6216
6463
|
}
|
|
6217
|
-
const fileContent = await
|
|
6464
|
+
const fileContent = await fs13.readFile(resolvedPath, "utf-8");
|
|
6218
6465
|
const lines = fileContent.split(`
|
|
6219
6466
|
`);
|
|
6220
6467
|
lines.splice(insertLine - 1, 0, content);
|
|
@@ -6250,19 +6497,19 @@ ${numberedLines}${additionalLinesMessage}`
|
|
|
6250
6497
|
switch (lastEdit.command) {
|
|
6251
6498
|
case "str_replace":
|
|
6252
6499
|
if (lastEdit.path && lastEdit.old_str && lastEdit.new_str) {
|
|
6253
|
-
const content = await
|
|
6500
|
+
const content = await fs13.readFile(lastEdit.path, "utf-8");
|
|
6254
6501
|
const revertedContent = content.replace(lastEdit.new_str, lastEdit.old_str);
|
|
6255
6502
|
await writeFilePromise(lastEdit.path, revertedContent, "utf-8");
|
|
6256
6503
|
}
|
|
6257
6504
|
break;
|
|
6258
6505
|
case "create":
|
|
6259
6506
|
if (lastEdit.path) {
|
|
6260
|
-
await
|
|
6507
|
+
await fs13.remove(lastEdit.path);
|
|
6261
6508
|
}
|
|
6262
6509
|
break;
|
|
6263
6510
|
case "insert":
|
|
6264
6511
|
if (lastEdit.path && lastEdit.insert_line) {
|
|
6265
|
-
const content = await
|
|
6512
|
+
const content = await fs13.readFile(lastEdit.path, "utf-8");
|
|
6266
6513
|
const lines = content.split(`
|
|
6267
6514
|
`);
|
|
6268
6515
|
lines.splice(lastEdit.insert_line - 1, 1);
|
|
@@ -6707,19 +6954,19 @@ class OpenAICompatibleProvider {
|
|
|
6707
6954
|
}
|
|
6708
6955
|
|
|
6709
6956
|
// src/utils/custom-instructions.ts
|
|
6710
|
-
import * as
|
|
6711
|
-
import * as
|
|
6712
|
-
import * as
|
|
6957
|
+
import * as path13 from "path";
|
|
6958
|
+
import * as os3 from "os";
|
|
6959
|
+
import * as fs14 from "fs";
|
|
6713
6960
|
function loadCustomInstructions(workingDirectory = process.cwd()) {
|
|
6714
6961
|
try {
|
|
6715
|
-
let instructionsPath =
|
|
6716
|
-
if (
|
|
6717
|
-
const customInstructions =
|
|
6962
|
+
let instructionsPath = path13.join(workingDirectory, ".super-agent", "SUPER_AGENT.md");
|
|
6963
|
+
if (fs14.existsSync(instructionsPath)) {
|
|
6964
|
+
const customInstructions = fs14.readFileSync(instructionsPath, "utf-8");
|
|
6718
6965
|
return customInstructions.trim();
|
|
6719
6966
|
}
|
|
6720
|
-
instructionsPath =
|
|
6721
|
-
if (
|
|
6722
|
-
const customInstructions =
|
|
6967
|
+
instructionsPath = path13.join(os3.homedir(), ".super-agent", "SUPER_AGENT.md");
|
|
6968
|
+
if (fs14.existsSync(instructionsPath)) {
|
|
6969
|
+
const customInstructions = fs14.readFileSync(instructionsPath, "utf-8");
|
|
6723
6970
|
return customInstructions.trim();
|
|
6724
6971
|
}
|
|
6725
6972
|
return null;
|
|
@@ -8422,39 +8669,852 @@ function ChatInterface({
|
|
|
8422
8669
|
}, undefined, false, undefined, this);
|
|
8423
8670
|
}
|
|
8424
8671
|
|
|
8672
|
+
// src/commands/web.ts
|
|
8673
|
+
init_settings_manager();
|
|
8674
|
+
|
|
8675
|
+
// src/web/server.ts
|
|
8676
|
+
import { createServer } from "http";
|
|
8677
|
+
import { WebSocketServer } from "ws";
|
|
8678
|
+
import * as fs17 from "fs-extra";
|
|
8679
|
+
import * as path16 from "path";
|
|
8680
|
+
import open from "open";
|
|
8681
|
+
import mime from "mime";
|
|
8682
|
+
var __dirname = "/home/runner/work/super-agent-cli/super-agent-cli/src/web";
|
|
8683
|
+
|
|
8684
|
+
class WebServer {
|
|
8685
|
+
httpServer;
|
|
8686
|
+
wss;
|
|
8687
|
+
agent;
|
|
8688
|
+
hostname;
|
|
8689
|
+
port;
|
|
8690
|
+
clients = new Set;
|
|
8691
|
+
constructor(options) {
|
|
8692
|
+
this.hostname = options.hostname || "localhost";
|
|
8693
|
+
this.port = options.port || 3000;
|
|
8694
|
+
this.agent = options.agent;
|
|
8695
|
+
this.httpServer = createServer((req, res) => {
|
|
8696
|
+
this.handleHttpRequest(req, res);
|
|
8697
|
+
});
|
|
8698
|
+
this.wss = new WebSocketServer({ server: this.httpServer });
|
|
8699
|
+
this.wss.on("connection", (ws) => {
|
|
8700
|
+
this.handleWebSocketConnection(ws);
|
|
8701
|
+
});
|
|
8702
|
+
}
|
|
8703
|
+
async handleHttpRequest(req, res) {
|
|
8704
|
+
const url = req.url || "/";
|
|
8705
|
+
const requestedPath = url === "/" ? "index.html" : url;
|
|
8706
|
+
const sanitizedPath = requestedPath.split("?")[0].split("#")[0];
|
|
8707
|
+
const clientDir = path16.join(__dirname, "../web/client");
|
|
8708
|
+
const absolutePath = path16.resolve(clientDir, sanitizedPath.substring(1));
|
|
8709
|
+
if (!absolutePath.startsWith(clientDir)) {
|
|
8710
|
+
res.writeHead(403, { "Content-Type": "text/plain" });
|
|
8711
|
+
res.end("Forbidden");
|
|
8712
|
+
return;
|
|
8713
|
+
}
|
|
8714
|
+
try {
|
|
8715
|
+
if (await fs17.pathExists(absolutePath)) {
|
|
8716
|
+
const stat5 = await fs17.stat(absolutePath);
|
|
8717
|
+
let filePath = absolutePath;
|
|
8718
|
+
if (stat5.isDirectory()) {
|
|
8719
|
+
filePath = path16.join(absolutePath, "index.html");
|
|
8720
|
+
}
|
|
8721
|
+
const content = await fs17.readFile(filePath);
|
|
8722
|
+
const mimeType = mime.getType(filePath) || "application/octet-stream";
|
|
8723
|
+
res.writeHead(200, { "Content-Type": mimeType });
|
|
8724
|
+
res.end(content);
|
|
8725
|
+
} else {
|
|
8726
|
+
res.writeHead(404);
|
|
8727
|
+
res.end("Not Found");
|
|
8728
|
+
}
|
|
8729
|
+
} catch (error) {
|
|
8730
|
+
console.error("Error serving file:", error);
|
|
8731
|
+
res.writeHead(500);
|
|
8732
|
+
res.end("Internal Server Error");
|
|
8733
|
+
}
|
|
8734
|
+
}
|
|
8735
|
+
handleWebSocketConnection(ws) {
|
|
8736
|
+
this.clients.add(ws);
|
|
8737
|
+
console.log(`\uD83D\uDCE1 Web client connected (${this.clients.size} total)`);
|
|
8738
|
+
this.checkAndSendUpdateNotification(ws);
|
|
8739
|
+
ws.on("message", async (data) => {
|
|
8740
|
+
try {
|
|
8741
|
+
const message = JSON.parse(data.toString());
|
|
8742
|
+
if (message.type === "prompt") {
|
|
8743
|
+
await this.handlePrompt(message.content, ws);
|
|
8744
|
+
} else if (message.type === "get_file_tree") {
|
|
8745
|
+
await this.handleGetFileTree(ws);
|
|
8746
|
+
} else if (message.type === "get_file_content") {
|
|
8747
|
+
await this.handleGetFileContent(message.path, ws);
|
|
8748
|
+
} else if (message.type === "list_sessions") {
|
|
8749
|
+
await this.handleListSessions(ws);
|
|
8750
|
+
} else if (message.type === "switch_session") {
|
|
8751
|
+
await this.handleSwitchSession(message.sessionId, ws);
|
|
8752
|
+
}
|
|
8753
|
+
} catch (error) {
|
|
8754
|
+
console.error("WebSocket message error:", error);
|
|
8755
|
+
ws.send(JSON.stringify({ type: "error", content: "Invalid message format" }));
|
|
8756
|
+
}
|
|
8757
|
+
});
|
|
8758
|
+
ws.on("close", () => {
|
|
8759
|
+
this.clients.delete(ws);
|
|
8760
|
+
console.log(`\uD83D\uDCE1 Web client disconnected (${this.clients.size} remaining)`);
|
|
8761
|
+
});
|
|
8762
|
+
ws.on("error", (error) => {
|
|
8763
|
+
console.error("WebSocket error:", error);
|
|
8764
|
+
});
|
|
8765
|
+
}
|
|
8766
|
+
async handlePrompt(prompt, ws) {
|
|
8767
|
+
try {
|
|
8768
|
+
ws.send(JSON.stringify({ type: "user_message", content: prompt }));
|
|
8769
|
+
const entries = await this.agent.processUserMessage(prompt);
|
|
8770
|
+
for (const entry of entries) {
|
|
8771
|
+
if (entry.type === "assistant") {
|
|
8772
|
+
ws.send(JSON.stringify({
|
|
8773
|
+
type: "assistant_message",
|
|
8774
|
+
content: entry.content
|
|
8775
|
+
}));
|
|
8776
|
+
} else if (entry.type === "tool_call") {
|
|
8777
|
+
ws.send(JSON.stringify({
|
|
8778
|
+
type: "tool_call",
|
|
8779
|
+
tool: entry.toolCall?.function.name,
|
|
8780
|
+
content: "Executing..."
|
|
8781
|
+
}));
|
|
8782
|
+
} else if (entry.type === "tool_result") {
|
|
8783
|
+
ws.send(JSON.stringify({
|
|
8784
|
+
type: "tool_result",
|
|
8785
|
+
tool: entry.toolCall?.function.name,
|
|
8786
|
+
content: entry.content
|
|
8787
|
+
}));
|
|
8788
|
+
}
|
|
8789
|
+
}
|
|
8790
|
+
ws.send(JSON.stringify({ type: "done" }));
|
|
8791
|
+
} catch (error) {
|
|
8792
|
+
ws.send(JSON.stringify({
|
|
8793
|
+
type: "error",
|
|
8794
|
+
content: error.message
|
|
8795
|
+
}));
|
|
8796
|
+
}
|
|
8797
|
+
}
|
|
8798
|
+
async handleGetFileTree(ws) {
|
|
8799
|
+
try {
|
|
8800
|
+
const { getFileIndexer: getFileIndexer2 } = await Promise.resolve().then(() => (init_indexer(), exports_indexer));
|
|
8801
|
+
const indexer = getFileIndexer2();
|
|
8802
|
+
const index = indexer.getIndex();
|
|
8803
|
+
if (!index) {
|
|
8804
|
+
ws.send(JSON.stringify({ type: "file_tree", tree: [] }));
|
|
8805
|
+
return;
|
|
8806
|
+
}
|
|
8807
|
+
const tree = index.entries.filter((e) => !e.path.includes("node_modules") && !e.path.startsWith(".")).map((e) => ({
|
|
8808
|
+
path: e.path,
|
|
8809
|
+
name: path16.basename(e.path),
|
|
8810
|
+
isDirectory: e.isDirectory,
|
|
8811
|
+
size: e.size
|
|
8812
|
+
})).slice(0, 500);
|
|
8813
|
+
ws.send(JSON.stringify({ type: "file_tree", tree }));
|
|
8814
|
+
} catch (error) {
|
|
8815
|
+
ws.send(JSON.stringify({ type: "error", content: error.message }));
|
|
8816
|
+
}
|
|
8817
|
+
}
|
|
8818
|
+
async handleGetFileContent(filePath, ws) {
|
|
8819
|
+
try {
|
|
8820
|
+
const fullPath = path16.join(process.cwd(), filePath);
|
|
8821
|
+
if (!fullPath.startsWith(process.cwd())) {
|
|
8822
|
+
throw new Error("Access denied");
|
|
8823
|
+
}
|
|
8824
|
+
const content = await fs17.readFile(fullPath, "utf-8");
|
|
8825
|
+
ws.send(JSON.stringify({
|
|
8826
|
+
type: "file_content",
|
|
8827
|
+
path: filePath,
|
|
8828
|
+
content: content.slice(0, 1e4)
|
|
8829
|
+
}));
|
|
8830
|
+
} catch (error) {
|
|
8831
|
+
ws.send(JSON.stringify({ type: "error", content: error.message }));
|
|
8832
|
+
}
|
|
8833
|
+
}
|
|
8834
|
+
async handleListSessions(ws) {
|
|
8835
|
+
try {
|
|
8836
|
+
const { getSessionManager: getSessionManager2 } = await Promise.resolve().then(() => (init_session_manager(), exports_session_manager));
|
|
8837
|
+
const sessionManager = getSessionManager2();
|
|
8838
|
+
const sessions = await sessionManager.listSessions();
|
|
8839
|
+
ws.send(JSON.stringify({
|
|
8840
|
+
type: "sessions_list",
|
|
8841
|
+
sessions: sessions.map((s) => ({
|
|
8842
|
+
id: s.id,
|
|
8843
|
+
name: s.name,
|
|
8844
|
+
workingDirectory: s.workingDirectory,
|
|
8845
|
+
messageCount: s.messages.length,
|
|
8846
|
+
lastAccessed: s.lastAccessed
|
|
8847
|
+
}))
|
|
8848
|
+
}));
|
|
8849
|
+
} catch (error) {
|
|
8850
|
+
ws.send(JSON.stringify({ type: "error", content: error.message }));
|
|
8851
|
+
}
|
|
8852
|
+
}
|
|
8853
|
+
async handleSwitchSession(sessionId, ws) {
|
|
8854
|
+
try {
|
|
8855
|
+
const { getSessionManager: getSessionManager2 } = await Promise.resolve().then(() => (init_session_manager(), exports_session_manager));
|
|
8856
|
+
const sessionManager = getSessionManager2();
|
|
8857
|
+
const session = await sessionManager.switchSession(sessionId);
|
|
8858
|
+
if (session) {
|
|
8859
|
+
ws.send(JSON.stringify({
|
|
8860
|
+
type: "session_switched",
|
|
8861
|
+
session: {
|
|
8862
|
+
id: session.id,
|
|
8863
|
+
name: session.name,
|
|
8864
|
+
workingDirectory: session.workingDirectory,
|
|
8865
|
+
messages: session.messages
|
|
8866
|
+
}
|
|
8867
|
+
}));
|
|
8868
|
+
} else {
|
|
8869
|
+
throw new Error("Session not found");
|
|
8870
|
+
}
|
|
8871
|
+
} catch (error) {
|
|
8872
|
+
ws.send(JSON.stringify({ type: "error", content: error.message }));
|
|
8873
|
+
}
|
|
8874
|
+
}
|
|
8875
|
+
async checkAndSendUpdateNotification(ws) {
|
|
8876
|
+
try {
|
|
8877
|
+
const pkg = await Promise.resolve().then(() => __toESM(require_package(), 1));
|
|
8878
|
+
const { getUpdateChecker: getUpdateChecker2 } = await Promise.resolve().then(() => (init_update_checker(), exports_update_checker));
|
|
8879
|
+
const updateChecker = getUpdateChecker2(pkg.version);
|
|
8880
|
+
const updateInfo = await updateChecker.checkForUpdates();
|
|
8881
|
+
if (updateInfo?.updateAvailable) {
|
|
8882
|
+
ws.send(JSON.stringify({
|
|
8883
|
+
type: "update_available",
|
|
8884
|
+
currentVersion: updateInfo.currentVersion,
|
|
8885
|
+
latestVersion: updateInfo.latestVersion
|
|
8886
|
+
}));
|
|
8887
|
+
}
|
|
8888
|
+
} catch (error) {}
|
|
8889
|
+
}
|
|
8890
|
+
async start() {
|
|
8891
|
+
return new Promise((resolve5, reject) => {
|
|
8892
|
+
this.httpServer.listen(this.port, this.hostname, () => {
|
|
8893
|
+
const url = `http://${this.hostname}:${this.port}`;
|
|
8894
|
+
console.log(`\uD83C\uDF10 Web interface available at ${url}`);
|
|
8895
|
+
resolve5();
|
|
8896
|
+
});
|
|
8897
|
+
this.httpServer.on("error", (error) => {
|
|
8898
|
+
reject(error);
|
|
8899
|
+
});
|
|
8900
|
+
});
|
|
8901
|
+
}
|
|
8902
|
+
async openBrowser() {
|
|
8903
|
+
const url = `http://${this.hostname}:${this.port}`;
|
|
8904
|
+
try {
|
|
8905
|
+
await open(url);
|
|
8906
|
+
console.log(`\uD83D\uDE80 Opened browser at ${url}`);
|
|
8907
|
+
} catch (error) {
|
|
8908
|
+
console.warn(`Could not open browser automatically. Please visit ${url}`);
|
|
8909
|
+
}
|
|
8910
|
+
}
|
|
8911
|
+
stop() {
|
|
8912
|
+
this.clients.forEach((client) => {
|
|
8913
|
+
client.close();
|
|
8914
|
+
});
|
|
8915
|
+
this.wss.close();
|
|
8916
|
+
this.httpServer.close();
|
|
8917
|
+
console.log("\uD83D\uDED1 Web server stopped");
|
|
8918
|
+
}
|
|
8919
|
+
}
|
|
8920
|
+
|
|
8921
|
+
// src/commands/web.ts
|
|
8922
|
+
import { Command } from "commander";
|
|
8923
|
+
import chalk from "chalk";
|
|
8924
|
+
function createWebCommand() {
|
|
8925
|
+
const webCommand = new Command("web").description("Start the web interface").option("-p, --port <number>", "Port to run server on", "3000").option("--no-browser", "Do not open browser automatically").action(async (options) => {
|
|
8926
|
+
const port = parseInt(options.port);
|
|
8927
|
+
const settingsManager = getSettingsManager();
|
|
8928
|
+
const apiKey = settingsManager.getApiKey();
|
|
8929
|
+
const baseURL = settingsManager.getBaseURL() || "https://api.openai.com/v1";
|
|
8930
|
+
const model = settingsManager.getCurrentModel();
|
|
8931
|
+
if (!apiKey) {
|
|
8932
|
+
console.error(chalk.red("API Key not found. Please configure it first."));
|
|
8933
|
+
process.exit(1);
|
|
8934
|
+
}
|
|
8935
|
+
console.log(chalk.blue(`Starting web server on port ${port}...`));
|
|
8936
|
+
const agent = new SuperAgent(apiKey, baseURL, model);
|
|
8937
|
+
const server = new WebServer({
|
|
8938
|
+
port,
|
|
8939
|
+
agent,
|
|
8940
|
+
openBrowser: options.browser
|
|
8941
|
+
});
|
|
8942
|
+
try {
|
|
8943
|
+
await server.start();
|
|
8944
|
+
if (options.browser) {
|
|
8945
|
+
await server.openBrowser();
|
|
8946
|
+
}
|
|
8947
|
+
process.on("SIGINT", () => {
|
|
8948
|
+
console.log(chalk.yellow(`
|
|
8949
|
+
Stopping server...`));
|
|
8950
|
+
server.stop();
|
|
8951
|
+
process.exit(0);
|
|
8952
|
+
});
|
|
8953
|
+
} catch (error) {
|
|
8954
|
+
console.error(chalk.red(`Failed to start server: ${error.message}`));
|
|
8955
|
+
process.exit(1);
|
|
8956
|
+
}
|
|
8957
|
+
});
|
|
8958
|
+
return webCommand;
|
|
8959
|
+
}
|
|
8960
|
+
function createServeCommand() {
|
|
8961
|
+
const serveCommand = new Command("serve").description("Start the web interface and CLI together").option("-p, --port <number>", "Port to run server on", "3000").action(async (options) => {
|
|
8962
|
+
console.log(chalk.yellow("Serve mode is currently an alias for 'web' mode with background persistence capabilities."));
|
|
8963
|
+
const port = parseInt(options.port);
|
|
8964
|
+
const settingsManager = getSettingsManager();
|
|
8965
|
+
const apiKey = settingsManager.getApiKey();
|
|
8966
|
+
if (!apiKey) {
|
|
8967
|
+
console.error(chalk.red("API Key not found."));
|
|
8968
|
+
process.exit(1);
|
|
8969
|
+
}
|
|
8970
|
+
const agent = new SuperAgent(apiKey, settingsManager.getBaseURL() || "", settingsManager.getCurrentModel());
|
|
8971
|
+
const server = new WebServer({ port, agent, openBrowser: true });
|
|
8972
|
+
await server.start();
|
|
8973
|
+
await server.openBrowser();
|
|
8974
|
+
});
|
|
8975
|
+
return serveCommand;
|
|
8976
|
+
}
|
|
8977
|
+
|
|
8978
|
+
// src/commands/provider.ts
|
|
8979
|
+
init_settings_manager();
|
|
8980
|
+
import { Command as Command2 } from "commander";
|
|
8981
|
+
import inquirer from "inquirer";
|
|
8982
|
+
import chalk2 from "chalk";
|
|
8983
|
+
function createProviderCommand() {
|
|
8984
|
+
const cmd = new Command2("provider").description("Manage LLM provider configuration");
|
|
8985
|
+
cmd.command("config").description("Interactive provider configuration").action(async () => {
|
|
8986
|
+
const manager = getSettingsManager();
|
|
8987
|
+
const settings = manager.loadUserSettings();
|
|
8988
|
+
const providers = Object.keys(settings.providers);
|
|
8989
|
+
const { selectedProvider } = await inquirer.prompt([
|
|
8990
|
+
{
|
|
8991
|
+
type: "list",
|
|
8992
|
+
name: "selectedProvider",
|
|
8993
|
+
message: "Select a provider to configure:",
|
|
8994
|
+
choices: providers,
|
|
8995
|
+
default: settings.active_provider
|
|
8996
|
+
}
|
|
8997
|
+
]);
|
|
8998
|
+
const currentConfig = settings.providers[selectedProvider];
|
|
8999
|
+
if (!currentConfig) {
|
|
9000
|
+
console.error(chalk2.red(`Configuration for ${selectedProvider} not found.`));
|
|
9001
|
+
return;
|
|
9002
|
+
}
|
|
9003
|
+
const models = PROVIDER_MODELS[currentConfig.provider] || [];
|
|
9004
|
+
const { apiKey } = await inquirer.prompt([
|
|
9005
|
+
{
|
|
9006
|
+
type: "password",
|
|
9007
|
+
name: "apiKey",
|
|
9008
|
+
message: `Enter API Key for ${selectedProvider} (leave empty to keep current):`,
|
|
9009
|
+
mask: "*"
|
|
9010
|
+
}
|
|
9011
|
+
]);
|
|
9012
|
+
let selectedModel = currentConfig.model;
|
|
9013
|
+
if (models.length > 0) {
|
|
9014
|
+
const { model } = await inquirer.prompt([
|
|
9015
|
+
{
|
|
9016
|
+
type: "list",
|
|
9017
|
+
name: "model",
|
|
9018
|
+
message: "Select default model:",
|
|
9019
|
+
choices: [...models, "Custom..."],
|
|
9020
|
+
default: currentConfig.model
|
|
9021
|
+
}
|
|
9022
|
+
]);
|
|
9023
|
+
selectedModel = model;
|
|
9024
|
+
}
|
|
9025
|
+
if (selectedModel === "Custom..." || models.length === 0) {
|
|
9026
|
+
const { customModel } = await inquirer.prompt([
|
|
9027
|
+
{
|
|
9028
|
+
type: "input",
|
|
9029
|
+
name: "customModel",
|
|
9030
|
+
message: "Enter model ID:",
|
|
9031
|
+
default: currentConfig.model
|
|
9032
|
+
}
|
|
9033
|
+
]);
|
|
9034
|
+
selectedModel = customModel;
|
|
9035
|
+
}
|
|
9036
|
+
const { baseURL } = await inquirer.prompt([
|
|
9037
|
+
{
|
|
9038
|
+
type: "input",
|
|
9039
|
+
name: "baseURL",
|
|
9040
|
+
message: "Enter Base URL (optional, leave empty for default):",
|
|
9041
|
+
default: currentConfig.base_url
|
|
9042
|
+
}
|
|
9043
|
+
]);
|
|
9044
|
+
console.log(chalk2.blue(`
|
|
9045
|
+
New Configuration:`));
|
|
9046
|
+
console.log(`Provider: ${chalk2.bold(selectedProvider)}`);
|
|
9047
|
+
console.log(`Model: ${chalk2.bold(selectedModel)}`);
|
|
9048
|
+
console.log(`Base URL: ${baseURL || "Default"}`);
|
|
9049
|
+
const { confirm } = await inquirer.prompt([
|
|
9050
|
+
{
|
|
9051
|
+
type: "confirm",
|
|
9052
|
+
name: "confirm",
|
|
9053
|
+
message: "Save these settings?",
|
|
9054
|
+
default: true
|
|
9055
|
+
}
|
|
9056
|
+
]);
|
|
9057
|
+
if (confirm) {
|
|
9058
|
+
const newProviders = { ...settings.providers };
|
|
9059
|
+
newProviders[selectedProvider] = {
|
|
9060
|
+
...currentConfig,
|
|
9061
|
+
model: selectedModel,
|
|
9062
|
+
base_url: baseURL || currentConfig.base_url
|
|
9063
|
+
};
|
|
9064
|
+
if (apiKey) {
|
|
9065
|
+
newProviders[selectedProvider].api_key = apiKey;
|
|
9066
|
+
}
|
|
9067
|
+
if (baseURL !== undefined && baseURL !== currentConfig.base_url) {
|
|
9068
|
+
newProviders[selectedProvider].base_url = baseURL;
|
|
9069
|
+
}
|
|
9070
|
+
manager.updateUserSetting("providers", newProviders);
|
|
9071
|
+
if (settings.active_provider !== selectedProvider) {
|
|
9072
|
+
const { makeActive } = await inquirer.prompt([
|
|
9073
|
+
{
|
|
9074
|
+
type: "confirm",
|
|
9075
|
+
name: "makeActive",
|
|
9076
|
+
message: `Set ${selectedProvider} as active provider?`,
|
|
9077
|
+
default: true
|
|
9078
|
+
}
|
|
9079
|
+
]);
|
|
9080
|
+
if (makeActive) {
|
|
9081
|
+
manager.updateUserSetting("active_provider", selectedProvider);
|
|
9082
|
+
console.log(chalk2.green(`
|
|
9083
|
+
✅ Settings saved and ${selectedProvider} is now active.`));
|
|
9084
|
+
} else {
|
|
9085
|
+
console.log(chalk2.green(`
|
|
9086
|
+
✅ Settings saved.`));
|
|
9087
|
+
}
|
|
9088
|
+
} else {
|
|
9089
|
+
console.log(chalk2.green(`
|
|
9090
|
+
✅ Settings saved.`));
|
|
9091
|
+
}
|
|
9092
|
+
} else {
|
|
9093
|
+
console.log(chalk2.yellow("Configuration cancelled."));
|
|
9094
|
+
}
|
|
9095
|
+
});
|
|
9096
|
+
return cmd;
|
|
9097
|
+
}
|
|
9098
|
+
|
|
9099
|
+
// src/commands/index-cmd.ts
|
|
9100
|
+
import { Command as Command3 } from "commander";
|
|
9101
|
+
import fs18 from "fs/promises";
|
|
9102
|
+
import ignore from "ignore";
|
|
9103
|
+
import chalk3 from "chalk";
|
|
9104
|
+
import path17 from "path";
|
|
9105
|
+
var DEFAULT_IGNORES = [
|
|
9106
|
+
"node_modules",
|
|
9107
|
+
".git",
|
|
9108
|
+
"dist",
|
|
9109
|
+
"build",
|
|
9110
|
+
"coverage",
|
|
9111
|
+
".env",
|
|
9112
|
+
"*.log",
|
|
9113
|
+
".DS_Store",
|
|
9114
|
+
"Thumbs.db"
|
|
9115
|
+
];
|
|
9116
|
+
function createIndexCommand() {
|
|
9117
|
+
const indexCommand = new Command3("index").description(" recursively index a directory and save to a file").argument("[directory]", "Directory to index", ".").option("-o, --output <file>", "Output file path (default: index.md)").option("--no-ignore", "Disable .gitignore respecting").option("-d, --depth <depth>", "Max depth to traverse", "10").action(async (directory, options) => {
|
|
9118
|
+
try {
|
|
9119
|
+
const rootDir = path17.resolve(directory);
|
|
9120
|
+
const outputFile2 = options.output ? path17.resolve(options.output) : path17.join(rootDir, "index.md");
|
|
9121
|
+
const maxDepth = parseInt(options.depth);
|
|
9122
|
+
console.log(chalk3.blue(`Indexing directory: ${rootDir}`));
|
|
9123
|
+
const ig = ignore().add(DEFAULT_IGNORES);
|
|
9124
|
+
if (options.ignore !== false) {
|
|
9125
|
+
try {
|
|
9126
|
+
const gitignorePath = path17.join(rootDir, ".gitignore");
|
|
9127
|
+
const gitignoreContent = await fs18.readFile(gitignorePath, "utf-8");
|
|
9128
|
+
ig.add(gitignoreContent);
|
|
9129
|
+
} catch (e) {}
|
|
9130
|
+
}
|
|
9131
|
+
let outputContent = `# Directory Index
|
|
9132
|
+
|
|
9133
|
+
Generated for: ${rootDir}
|
|
9134
|
+
Date: ${new Date().toISOString()}
|
|
9135
|
+
|
|
9136
|
+
`;
|
|
9137
|
+
outputContent += "## File Structure\n\n```\n";
|
|
9138
|
+
async function buildTree(currentPath, depth, prefix = "") {
|
|
9139
|
+
if (depth > maxDepth) {
|
|
9140
|
+
return;
|
|
9141
|
+
}
|
|
9142
|
+
const relativePath = path17.relative(rootDir, currentPath);
|
|
9143
|
+
if (relativePath && ig.ignores(relativePath)) {
|
|
9144
|
+
return;
|
|
9145
|
+
}
|
|
9146
|
+
const stats = await fs18.stat(currentPath);
|
|
9147
|
+
const isDir = stats.isDirectory();
|
|
9148
|
+
const name = path17.basename(currentPath);
|
|
9149
|
+
if (isDir) {
|
|
9150
|
+
if (relativePath) {
|
|
9151
|
+
outputContent += `${prefix}${name}/
|
|
9152
|
+
`;
|
|
9153
|
+
}
|
|
9154
|
+
const entries = await fs18.readdir(currentPath, {
|
|
9155
|
+
withFileTypes: true
|
|
9156
|
+
});
|
|
9157
|
+
const sortedEntries = entries.sort((a, b) => {
|
|
9158
|
+
if (a.isDirectory() && !b.isDirectory()) {
|
|
9159
|
+
return -1;
|
|
9160
|
+
}
|
|
9161
|
+
if (!a.isDirectory() && b.isDirectory()) {
|
|
9162
|
+
return 1;
|
|
9163
|
+
}
|
|
9164
|
+
return a.name.localeCompare(b.name);
|
|
9165
|
+
});
|
|
9166
|
+
for (let i = 0;i < sortedEntries.length; i++) {
|
|
9167
|
+
const entry = sortedEntries[i];
|
|
9168
|
+
const isLast = i === sortedEntries.length - 1;
|
|
9169
|
+
const newPrefix = relativePath ? prefix + " " : "";
|
|
9170
|
+
await buildTree(path17.join(currentPath, entry.name), depth + 1, newPrefix);
|
|
9171
|
+
}
|
|
9172
|
+
} else {
|
|
9173
|
+
outputContent += `${prefix}${name}
|
|
9174
|
+
`;
|
|
9175
|
+
}
|
|
9176
|
+
}
|
|
9177
|
+
const files = [];
|
|
9178
|
+
async function walk(dir, currentDepth) {
|
|
9179
|
+
if (currentDepth > maxDepth) {
|
|
9180
|
+
return;
|
|
9181
|
+
}
|
|
9182
|
+
const entries = await fs18.readdir(dir, { withFileTypes: true });
|
|
9183
|
+
for (const entry of entries) {
|
|
9184
|
+
const fullPath = path17.join(dir, entry.name);
|
|
9185
|
+
const relPath = path17.relative(rootDir, fullPath);
|
|
9186
|
+
if (ig.ignores(relPath)) {
|
|
9187
|
+
continue;
|
|
9188
|
+
}
|
|
9189
|
+
if (entry.isDirectory()) {
|
|
9190
|
+
await walk(fullPath, currentDepth + 1);
|
|
9191
|
+
} else {
|
|
9192
|
+
files.push(relPath);
|
|
9193
|
+
}
|
|
9194
|
+
}
|
|
9195
|
+
}
|
|
9196
|
+
await walk(rootDir, 0);
|
|
9197
|
+
console.log(chalk3.blue(`Found ${files.length} files.`));
|
|
9198
|
+
outputContent = `# Project Index: ${path17.basename(rootDir)}
|
|
9199
|
+
|
|
9200
|
+
`;
|
|
9201
|
+
outputContent += `Total Files: ${files.length}
|
|
9202
|
+
|
|
9203
|
+
`;
|
|
9204
|
+
outputContent += `## Files
|
|
9205
|
+
|
|
9206
|
+
`;
|
|
9207
|
+
for (const file of files) {
|
|
9208
|
+
outputContent += `### ${file}
|
|
9209
|
+
`;
|
|
9210
|
+
const stats = await fs18.stat(path17.join(rootDir, file));
|
|
9211
|
+
outputContent += `- Size: ${stats.size} bytes
|
|
9212
|
+
`;
|
|
9213
|
+
outputContent += `- Modified: ${stats.mtime.toISOString()}
|
|
9214
|
+
|
|
9215
|
+
`;
|
|
9216
|
+
}
|
|
9217
|
+
await fs18.writeFile(outputFile2, outputContent);
|
|
9218
|
+
console.log(chalk3.green(`✓ Index generated at: ${outputFile2}`));
|
|
9219
|
+
} catch (error) {
|
|
9220
|
+
console.error(chalk3.red(`Error indexing directory: ${error.message}`));
|
|
9221
|
+
process.exit(1);
|
|
9222
|
+
}
|
|
9223
|
+
});
|
|
9224
|
+
return indexCommand;
|
|
9225
|
+
}
|
|
9226
|
+
|
|
9227
|
+
// src/commands/plugins.ts
|
|
9228
|
+
init_settings_manager();
|
|
9229
|
+
import { Command as Command4 } from "commander";
|
|
9230
|
+
function createPluginsCommand() {
|
|
9231
|
+
const pluginsCommand = new Command4("plugins").description("Manage plugins for Super Agent CLI").argument("[action]", "Action to perform (list, install, uninstall)").argument("[target]", "Plugin name or path");
|
|
9232
|
+
pluginsCommand.command("list").description("List installed plugins").action(() => {
|
|
9233
|
+
const manager = getSettingsManager();
|
|
9234
|
+
const settings = manager.loadUserSettings();
|
|
9235
|
+
const plugins = settings.plugins || [];
|
|
9236
|
+
if (plugins.length === 0) {
|
|
9237
|
+
console.log("No plugins installed.");
|
|
9238
|
+
return;
|
|
9239
|
+
}
|
|
9240
|
+
console.log("Installed plugins:");
|
|
9241
|
+
plugins.forEach((p) => console.log(`- ${p}`));
|
|
9242
|
+
});
|
|
9243
|
+
pluginsCommand.command("install <path>").description("Install a plugin from a path, GitHub URL, or registry").action(async (path18) => {
|
|
9244
|
+
try {
|
|
9245
|
+
const manager = PluginManager.getInstance();
|
|
9246
|
+
console.log(`Installing plugin from: ${path18}...`);
|
|
9247
|
+
const installedPath = await manager.installPlugin(path18);
|
|
9248
|
+
console.log(`✅ Plugin installed successfully: ${installedPath}`);
|
|
9249
|
+
} catch (error) {
|
|
9250
|
+
console.error(`❌ Error installing plugin: ${error.message}`);
|
|
9251
|
+
process.exit(1);
|
|
9252
|
+
}
|
|
9253
|
+
});
|
|
9254
|
+
pluginsCommand.command("uninstall <path>").description("Uninstall a plugin").action(async (path18) => {
|
|
9255
|
+
try {
|
|
9256
|
+
const manager = PluginManager.getInstance();
|
|
9257
|
+
await manager.removePlugin(path18);
|
|
9258
|
+
console.log(`✅ Plugin uninstalled: ${path18}`);
|
|
9259
|
+
} catch (error) {
|
|
9260
|
+
console.error(`❌ Error uninstalling plugin: ${error.message}`);
|
|
9261
|
+
process.exit(1);
|
|
9262
|
+
}
|
|
9263
|
+
});
|
|
9264
|
+
return pluginsCommand;
|
|
9265
|
+
}
|
|
9266
|
+
|
|
9267
|
+
// src/commands/skills.ts
|
|
9268
|
+
init_settings_manager();
|
|
9269
|
+
init_manager2();
|
|
9270
|
+
import { Command as Command5 } from "commander";
|
|
9271
|
+
import inquirer2 from "inquirer";
|
|
9272
|
+
import chalk4 from "chalk";
|
|
9273
|
+
function createSkillsCommand() {
|
|
9274
|
+
const skillsCommand = new Command5("skills").description("Manage AI skills");
|
|
9275
|
+
skillsCommand.command("list").description("List available skills").action(async () => {
|
|
9276
|
+
const manager = SkillsManager.getInstance();
|
|
9277
|
+
const skills = await manager.listSkills();
|
|
9278
|
+
if (skills.length === 0) {
|
|
9279
|
+
console.log("No skills found.");
|
|
9280
|
+
} else {
|
|
9281
|
+
console.log("Available skills:");
|
|
9282
|
+
skills.forEach((skill) => console.log(`- ${skill}`));
|
|
9283
|
+
}
|
|
9284
|
+
});
|
|
9285
|
+
skillsCommand.command("create <name>").description("Create a new skill with AI assistance").option("-d, --description <description>", "Description of the skill").action(async (name, options) => {
|
|
9286
|
+
try {
|
|
9287
|
+
const manager = SkillsManager.getInstance();
|
|
9288
|
+
const settingsManager = getSettingsManager();
|
|
9289
|
+
let description = options.description;
|
|
9290
|
+
if (!description) {
|
|
9291
|
+
const answer = await inquirer2.prompt([
|
|
9292
|
+
{
|
|
9293
|
+
type: "input",
|
|
9294
|
+
name: "description",
|
|
9295
|
+
message: "Describe what this skill should do:"
|
|
9296
|
+
}
|
|
9297
|
+
]);
|
|
9298
|
+
description = answer.description;
|
|
9299
|
+
}
|
|
9300
|
+
console.log(chalk4.blue(`Generating skill '${name}' based on description: "${description}"...`));
|
|
9301
|
+
const apiKey = settingsManager.getApiKey();
|
|
9302
|
+
const baseURL = settingsManager.getBaseURL();
|
|
9303
|
+
const model = settingsManager.getCurrentModel();
|
|
9304
|
+
if (!apiKey) {
|
|
9305
|
+
console.error(chalk4.red("API Key not found. Please configure it first."));
|
|
9306
|
+
return;
|
|
9307
|
+
}
|
|
9308
|
+
const agent = new SuperAgent(apiKey, baseURL, model);
|
|
9309
|
+
await manager.createSkill(name, description, agent);
|
|
9310
|
+
console.log(chalk4.green(`✓ Skill '${name}' created successfully.`));
|
|
9311
|
+
} catch (error) {
|
|
9312
|
+
console.error(chalk4.red(`Error creating skill: ${error.message}`));
|
|
9313
|
+
}
|
|
9314
|
+
});
|
|
9315
|
+
skillsCommand.command("delete <name>").description("Delete a skill").action(async (name) => {
|
|
9316
|
+
try {
|
|
9317
|
+
const manager = SkillsManager.getInstance();
|
|
9318
|
+
await manager.deleteSkill(name);
|
|
9319
|
+
console.log(chalk4.green(`✓ Skill '${name}' deleted.`));
|
|
9320
|
+
} catch (error) {
|
|
9321
|
+
console.error(chalk4.red(`Error deleting skill: ${error.message}`));
|
|
9322
|
+
}
|
|
9323
|
+
});
|
|
9324
|
+
return skillsCommand;
|
|
9325
|
+
}
|
|
9326
|
+
|
|
9327
|
+
// src/commands/import.ts
|
|
9328
|
+
init_settings_manager();
|
|
9329
|
+
init_file_utils();
|
|
9330
|
+
init_manager2();
|
|
9331
|
+
init_manager();
|
|
9332
|
+
import { Command as Command6 } from "commander";
|
|
9333
|
+
import fs19 from "fs-extra";
|
|
9334
|
+
import chalk5 from "chalk";
|
|
9335
|
+
import path18 from "path";
|
|
9336
|
+
function createImportCommand() {
|
|
9337
|
+
const cmd = new Command6("import").description("Import resources from other AI assistants");
|
|
9338
|
+
cmd.command("agents <source>").description("Import agents from source (gemini, claude, kilo)").action(async (source) => {
|
|
9339
|
+
const sourcePath = resolveSourcePath(source);
|
|
9340
|
+
const agentsDir = path18.join(sourcePath, "agents");
|
|
9341
|
+
if (!await fs19.pathExists(agentsDir)) {
|
|
9342
|
+
console.error(chalk5.red(`Agents directory not found at ${agentsDir}`));
|
|
9343
|
+
return;
|
|
9344
|
+
}
|
|
9345
|
+
const files = await fs19.readdir(agentsDir);
|
|
9346
|
+
const manager = AgentsManager.getInstance();
|
|
9347
|
+
let count = 0;
|
|
9348
|
+
for (const file of files) {
|
|
9349
|
+
if (file.endsWith(".json")) {
|
|
9350
|
+
try {
|
|
9351
|
+
const content = await fs19.readJson(path18.join(agentsDir, file));
|
|
9352
|
+
const agentConfig = {
|
|
9353
|
+
name: content.name || path18.parse(file).name,
|
|
9354
|
+
role: content.role || "Assistant",
|
|
9355
|
+
description: content.description || "Imported agent",
|
|
9356
|
+
model: content.model,
|
|
9357
|
+
tools: content.tools,
|
|
9358
|
+
temperature: content.temperature,
|
|
9359
|
+
systemPrompt: content.systemPrompt || content.system_prompt || content.prompt
|
|
9360
|
+
};
|
|
9361
|
+
await manager.createAgent(agentConfig);
|
|
9362
|
+
console.log(chalk5.green(`Imported agent: ${agentConfig.name}`));
|
|
9363
|
+
count++;
|
|
9364
|
+
} catch (error) {
|
|
9365
|
+
console.warn(chalk5.yellow(`Failed to import ${file}: ${error.message}`));
|
|
9366
|
+
}
|
|
9367
|
+
}
|
|
9368
|
+
}
|
|
9369
|
+
console.log(chalk5.bold(`Imported ${count} agents.`));
|
|
9370
|
+
});
|
|
9371
|
+
cmd.command("skills <source>").description("Import skills from source (gemini, claude, kilo)").action(async (source) => {
|
|
9372
|
+
const sourcePath = resolveSourcePath(source);
|
|
9373
|
+
const skillsDir = path18.join(sourcePath, "skills");
|
|
9374
|
+
if (!await fs19.pathExists(skillsDir)) {
|
|
9375
|
+
console.error(chalk5.red(`Skills directory not found at ${skillsDir}`));
|
|
9376
|
+
return;
|
|
9377
|
+
}
|
|
9378
|
+
const files = await fs19.readdir(skillsDir);
|
|
9379
|
+
const manager = SkillsManager.getInstance();
|
|
9380
|
+
let count = 0;
|
|
9381
|
+
for (const file of files) {
|
|
9382
|
+
if (file.endsWith(".ts") || file.endsWith(".js")) {
|
|
9383
|
+
try {
|
|
9384
|
+
const content = await fs19.readFile(path18.join(skillsDir, file), "utf-8");
|
|
9385
|
+
const name = path18.parse(file).name;
|
|
9386
|
+
await manager.saveSkill(name, content);
|
|
9387
|
+
console.log(chalk5.green(`Imported skill: ${name}`));
|
|
9388
|
+
count++;
|
|
9389
|
+
} catch (error) {
|
|
9390
|
+
console.warn(chalk5.yellow(`Failed to import ${file}: ${error.message}`));
|
|
9391
|
+
}
|
|
9392
|
+
}
|
|
9393
|
+
}
|
|
9394
|
+
console.log(chalk5.bold(`Imported ${count} skills.`));
|
|
9395
|
+
});
|
|
9396
|
+
cmd.command("hooks <source>").description("Import hooks from source settings").action(async (source) => {
|
|
9397
|
+
const sourcePath = resolveSourcePath(source);
|
|
9398
|
+
const settingsFile = source.toLowerCase() === "claude" ? "settings.local.json" : "settings.json";
|
|
9399
|
+
const fullPath = path18.join(sourcePath, settingsFile);
|
|
9400
|
+
if (!await fs19.pathExists(fullPath)) {
|
|
9401
|
+
console.error(chalk5.red(`Settings file not found at ${fullPath}`));
|
|
9402
|
+
return;
|
|
9403
|
+
}
|
|
9404
|
+
try {
|
|
9405
|
+
const settings = await fs19.readJson(fullPath);
|
|
9406
|
+
if (settings.hooks) {
|
|
9407
|
+
const manager = getSettingsManager();
|
|
9408
|
+
const currentHooks = manager.getUserSetting("hooks") || {};
|
|
9409
|
+
const mergedHooks = { ...currentHooks, ...settings.hooks };
|
|
9410
|
+
manager.updateUserSetting("hooks", mergedHooks);
|
|
9411
|
+
console.log(chalk5.green(`Imported ${Object.keys(settings.hooks).length} hooks.`));
|
|
9412
|
+
} else {
|
|
9413
|
+
console.log(chalk5.yellow("No hooks found in settings file."));
|
|
9414
|
+
}
|
|
9415
|
+
} catch (error) {
|
|
9416
|
+
console.error(chalk5.red(`Failed to import hooks: ${error.message}`));
|
|
9417
|
+
}
|
|
9418
|
+
});
|
|
9419
|
+
return cmd;
|
|
9420
|
+
}
|
|
9421
|
+
|
|
9422
|
+
// src/commands/agents.ts
|
|
9423
|
+
init_settings_manager();
|
|
9424
|
+
init_manager();
|
|
9425
|
+
import { Command as Command7 } from "commander";
|
|
9426
|
+
import inquirer3 from "inquirer";
|
|
9427
|
+
import chalk6 from "chalk";
|
|
9428
|
+
function createAgentsCommand() {
|
|
9429
|
+
const agentsCommand = new Command7("agents").description("Manage AI agents");
|
|
9430
|
+
agentsCommand.command("list").description("List available agents").action(async () => {
|
|
9431
|
+
const manager = AgentsManager.getInstance();
|
|
9432
|
+
const agents = await manager.listAgents();
|
|
9433
|
+
if (agents.length === 0) {
|
|
9434
|
+
console.log("No agents found.");
|
|
9435
|
+
} else {
|
|
9436
|
+
console.log("Available agents:");
|
|
9437
|
+
agents.forEach((agent) => {
|
|
9438
|
+
console.log(`- ${chalk6.bold(agent.name)} (${agent.role})`);
|
|
9439
|
+
console.log(` ${chalk6.dim(agent.description)}`);
|
|
9440
|
+
});
|
|
9441
|
+
}
|
|
9442
|
+
});
|
|
9443
|
+
agentsCommand.command("create <name>").description("Create a new agent with AI assistance").option("-d, --description <description>", "Description of the agent's role and purpose").action(async (name, options) => {
|
|
9444
|
+
try {
|
|
9445
|
+
const manager = AgentsManager.getInstance();
|
|
9446
|
+
const settingsManager = getSettingsManager();
|
|
9447
|
+
let description = options.description;
|
|
9448
|
+
if (!description) {
|
|
9449
|
+
const answer = await inquirer3.prompt([
|
|
9450
|
+
{
|
|
9451
|
+
type: "input",
|
|
9452
|
+
name: "description",
|
|
9453
|
+
message: "Describe the agent's role and purpose:"
|
|
9454
|
+
}
|
|
9455
|
+
]);
|
|
9456
|
+
description = answer.description;
|
|
9457
|
+
}
|
|
9458
|
+
console.log(chalk6.blue(`Generating agent configuration for '${name}'...`));
|
|
9459
|
+
const apiKey = settingsManager.getApiKey();
|
|
9460
|
+
const baseURL = settingsManager.getBaseURL();
|
|
9461
|
+
const model = settingsManager.getCurrentModel();
|
|
9462
|
+
if (!apiKey) {
|
|
9463
|
+
console.error(chalk6.red("API Key not found. Please configure it first."));
|
|
9464
|
+
return;
|
|
9465
|
+
}
|
|
9466
|
+
const agent = new SuperAgent(apiKey, baseURL, model);
|
|
9467
|
+
await manager.generateAgent(name, description, agent);
|
|
9468
|
+
console.log(chalk6.green(`✓ Agent '${name}' created successfully.`));
|
|
9469
|
+
} catch (error) {
|
|
9470
|
+
console.error(chalk6.red(`Error creating agent: ${error.message}`));
|
|
9471
|
+
}
|
|
9472
|
+
});
|
|
9473
|
+
agentsCommand.command("delete <name>").description("Delete an agent").action(async (name) => {
|
|
9474
|
+
try {
|
|
9475
|
+
const manager = AgentsManager.getInstance();
|
|
9476
|
+
await manager.deleteAgent(name);
|
|
9477
|
+
console.log(chalk6.green(`✓ Agent '${name}' deleted.`));
|
|
9478
|
+
} catch (error) {
|
|
9479
|
+
console.error(chalk6.red(`Error deleting agent: ${error.message}`));
|
|
9480
|
+
}
|
|
9481
|
+
});
|
|
9482
|
+
return agentsCommand;
|
|
9483
|
+
}
|
|
9484
|
+
|
|
8425
9485
|
// src/commands/mcp.ts
|
|
8426
9486
|
init_config();
|
|
8427
|
-
import { Command } from "commander";
|
|
8428
|
-
import
|
|
9487
|
+
import { Command as Command8 } from "commander";
|
|
9488
|
+
import chalk7 from "chalk";
|
|
8429
9489
|
function createMCPCommand() {
|
|
8430
|
-
const mcpCommand = new
|
|
9490
|
+
const mcpCommand = new Command8("mcp");
|
|
8431
9491
|
mcpCommand.description("Manage MCP (Model Context Protocol) servers");
|
|
8432
9492
|
mcpCommand.command("add <name>").description("Add an MCP server").option("-t, --transport <type>", "Transport type (stdio, http, sse, streamable_http)", "stdio").option("-c, --command <command>", "Command to run the server (for stdio transport)").option("-a, --args [args...]", "Arguments for the server command (for stdio transport)", []).option("-u, --url <url>", "URL for HTTP/SSE transport").option("-h, --headers [headers...]", "HTTP headers (key=value format)", []).option("-e, --env [env...]", "Environment variables (key=value format)", []).action(async (name, options) => {
|
|
8433
9493
|
try {
|
|
8434
9494
|
if (PREDEFINED_SERVERS[name]) {
|
|
8435
9495
|
const config2 = PREDEFINED_SERVERS[name];
|
|
8436
9496
|
addMCPServer(config2);
|
|
8437
|
-
console.log(
|
|
9497
|
+
console.log(chalk7.green(`✓ Added predefined MCP server: ${name}`));
|
|
8438
9498
|
const manager2 = getMCPManager();
|
|
8439
9499
|
await manager2.addServer(config2);
|
|
8440
|
-
console.log(
|
|
9500
|
+
console.log(chalk7.green(`✓ Connected to MCP server: ${name}`));
|
|
8441
9501
|
const tools2 = manager2.getTools().filter((t) => t.serverName === name);
|
|
8442
|
-
console.log(
|
|
9502
|
+
console.log(chalk7.blue(` Available tools: ${tools2.length}`));
|
|
8443
9503
|
return;
|
|
8444
9504
|
}
|
|
8445
9505
|
const transportType = options.transport.toLowerCase();
|
|
8446
9506
|
if (transportType === "stdio") {
|
|
8447
9507
|
if (!options.command) {
|
|
8448
|
-
console.error(
|
|
9508
|
+
console.error(chalk7.red("Error: --command is required for stdio transport"));
|
|
8449
9509
|
process.exit(1);
|
|
8450
9510
|
}
|
|
8451
9511
|
} else if (transportType === "http" || transportType === "sse" || transportType === "streamable_http") {
|
|
8452
9512
|
if (!options.url) {
|
|
8453
|
-
console.error(
|
|
9513
|
+
console.error(chalk7.red(`Error: --url is required for ${transportType} transport`));
|
|
8454
9514
|
process.exit(1);
|
|
8455
9515
|
}
|
|
8456
9516
|
} else {
|
|
8457
|
-
console.error(
|
|
9517
|
+
console.error(chalk7.red("Error: Transport type must be stdio, http, sse, or streamable_http"));
|
|
8458
9518
|
process.exit(1);
|
|
8459
9519
|
}
|
|
8460
9520
|
const env = {};
|
|
@@ -8483,14 +9543,14 @@ function createMCPCommand() {
|
|
|
8483
9543
|
}
|
|
8484
9544
|
};
|
|
8485
9545
|
addMCPServer(config);
|
|
8486
|
-
console.log(
|
|
9546
|
+
console.log(chalk7.green(`✓ Added MCP server: ${name}`));
|
|
8487
9547
|
const manager = getMCPManager();
|
|
8488
9548
|
await manager.addServer(config);
|
|
8489
|
-
console.log(
|
|
9549
|
+
console.log(chalk7.green(`✓ Connected to MCP server: ${name}`));
|
|
8490
9550
|
const tools = manager.getTools().filter((t) => t.serverName === name);
|
|
8491
|
-
console.log(
|
|
9551
|
+
console.log(chalk7.blue(` Available tools: ${tools.length}`));
|
|
8492
9552
|
} catch (error) {
|
|
8493
|
-
console.error(
|
|
9553
|
+
console.error(chalk7.red(`Error adding MCP server: ${error.message}`));
|
|
8494
9554
|
process.exit(1);
|
|
8495
9555
|
}
|
|
8496
9556
|
});
|
|
@@ -8500,7 +9560,7 @@ function createMCPCommand() {
|
|
|
8500
9560
|
try {
|
|
8501
9561
|
config = JSON.parse(jsonConfig);
|
|
8502
9562
|
} catch (error) {
|
|
8503
|
-
console.error(
|
|
9563
|
+
console.error(chalk7.red("Error: Invalid JSON configuration"));
|
|
8504
9564
|
process.exit(1);
|
|
8505
9565
|
}
|
|
8506
9566
|
const serverConfig = {
|
|
@@ -8525,14 +9585,14 @@ function createMCPCommand() {
|
|
|
8525
9585
|
}
|
|
8526
9586
|
}
|
|
8527
9587
|
addMCPServer(serverConfig);
|
|
8528
|
-
console.log(
|
|
9588
|
+
console.log(chalk7.green(`✓ Added MCP server: ${name}`));
|
|
8529
9589
|
const manager = getMCPManager();
|
|
8530
9590
|
await manager.addServer(serverConfig);
|
|
8531
|
-
console.log(
|
|
9591
|
+
console.log(chalk7.green(`✓ Connected to MCP server: ${name}`));
|
|
8532
9592
|
const tools = manager.getTools().filter((t) => t.serverName === name);
|
|
8533
|
-
console.log(
|
|
9593
|
+
console.log(chalk7.blue(` Available tools: ${tools.length}`));
|
|
8534
9594
|
} catch (error) {
|
|
8535
|
-
console.error(
|
|
9595
|
+
console.error(chalk7.red(`Error adding MCP server: ${error.message}`));
|
|
8536
9596
|
process.exit(1);
|
|
8537
9597
|
}
|
|
8538
9598
|
});
|
|
@@ -8541,9 +9601,9 @@ function createMCPCommand() {
|
|
|
8541
9601
|
const manager = getMCPManager();
|
|
8542
9602
|
await manager.removeServer(name);
|
|
8543
9603
|
removeMCPServer(name);
|
|
8544
|
-
console.log(
|
|
9604
|
+
console.log(chalk7.green(`✓ Removed MCP server: ${name}`));
|
|
8545
9605
|
} catch (error) {
|
|
8546
|
-
console.error(
|
|
9606
|
+
console.error(chalk7.red(`Error removing MCP server: ${error.message}`));
|
|
8547
9607
|
process.exit(1);
|
|
8548
9608
|
}
|
|
8549
9609
|
});
|
|
@@ -8551,15 +9611,15 @@ function createMCPCommand() {
|
|
|
8551
9611
|
const config = loadMCPConfig();
|
|
8552
9612
|
const manager = getMCPManager();
|
|
8553
9613
|
if (config.servers.length === 0) {
|
|
8554
|
-
console.log(
|
|
9614
|
+
console.log(chalk7.yellow("No MCP servers configured"));
|
|
8555
9615
|
return;
|
|
8556
9616
|
}
|
|
8557
|
-
console.log(
|
|
9617
|
+
console.log(chalk7.bold("Configured MCP servers:"));
|
|
8558
9618
|
console.log();
|
|
8559
9619
|
for (const server of config.servers) {
|
|
8560
9620
|
const isConnected = manager.getServers().includes(server.name);
|
|
8561
|
-
const status = isConnected ?
|
|
8562
|
-
console.log(`${
|
|
9621
|
+
const status = isConnected ? chalk7.green("✓ Connected") : chalk7.red("✗ Disconnected");
|
|
9622
|
+
console.log(`${chalk7.bold(server.name)}: ${status}`);
|
|
8563
9623
|
if (server.transport) {
|
|
8564
9624
|
console.log(` Transport: ${server.transport.type}`);
|
|
8565
9625
|
if (server.transport.type === "stdio") {
|
|
@@ -8592,15 +9652,15 @@ function createMCPCommand() {
|
|
|
8592
9652
|
const config = loadMCPConfig();
|
|
8593
9653
|
const serverConfig = config.servers.find((s) => s.name === name);
|
|
8594
9654
|
if (!serverConfig) {
|
|
8595
|
-
console.error(
|
|
9655
|
+
console.error(chalk7.red(`Server ${name} not found`));
|
|
8596
9656
|
process.exit(1);
|
|
8597
9657
|
}
|
|
8598
|
-
console.log(
|
|
9658
|
+
console.log(chalk7.blue(`Testing connection to ${name}...`));
|
|
8599
9659
|
const manager = getMCPManager();
|
|
8600
9660
|
await manager.addServer(serverConfig);
|
|
8601
9661
|
const tools = manager.getTools().filter((t) => t.serverName === name);
|
|
8602
|
-
console.log(
|
|
8603
|
-
console.log(
|
|
9662
|
+
console.log(chalk7.green(`✓ Successfully connected to ${name}`));
|
|
9663
|
+
console.log(chalk7.blue(` Available tools: ${tools.length}`));
|
|
8604
9664
|
if (tools.length > 0) {
|
|
8605
9665
|
console.log(" Tools:");
|
|
8606
9666
|
tools.forEach((tool) => {
|
|
@@ -8609,82 +9669,44 @@ function createMCPCommand() {
|
|
|
8609
9669
|
});
|
|
8610
9670
|
}
|
|
8611
9671
|
} catch (error) {
|
|
8612
|
-
console.error(
|
|
9672
|
+
console.error(chalk7.red(`✗ Failed to connect to ${name}: ${error.message}`));
|
|
8613
9673
|
process.exit(1);
|
|
8614
9674
|
}
|
|
8615
9675
|
});
|
|
8616
9676
|
return mcpCommand;
|
|
8617
9677
|
}
|
|
8618
9678
|
|
|
8619
|
-
// src/
|
|
8620
|
-
|
|
8621
|
-
import {
|
|
8622
|
-
|
|
8623
|
-
import { render } from "ink";
|
|
8624
|
-
import React4 from "react";
|
|
8625
|
-
dotenv.config();
|
|
8626
|
-
process.on("SIGTERM", () => {
|
|
8627
|
-
if (process.stdin.isTTY && process.stdin.setRawMode) {
|
|
8628
|
-
try {
|
|
8629
|
-
process.stdin.setRawMode(false);
|
|
8630
|
-
} catch (e) {}
|
|
8631
|
-
}
|
|
8632
|
-
console.log(`
|
|
8633
|
-
Gracefully shutting down...`);
|
|
8634
|
-
process.exit(0);
|
|
8635
|
-
});
|
|
8636
|
-
process.on("uncaughtException", (error) => {
|
|
8637
|
-
console.error("Uncaught exception:", error);
|
|
8638
|
-
process.exit(1);
|
|
8639
|
-
});
|
|
8640
|
-
process.on("unhandledRejection", (reason, promise) => {
|
|
8641
|
-
console.error("Unhandled rejection at:", promise, "reason:", reason);
|
|
8642
|
-
process.exit(1);
|
|
8643
|
-
});
|
|
8644
|
-
function ensureUserSettingsDirectory() {
|
|
8645
|
-
try {
|
|
8646
|
-
const manager = getSettingsManager();
|
|
8647
|
-
manager.loadUserSettings();
|
|
8648
|
-
} catch (error) {}
|
|
8649
|
-
}
|
|
8650
|
-
function loadApiKey() {
|
|
9679
|
+
// src/commands/git.ts
|
|
9680
|
+
init_settings_manager();
|
|
9681
|
+
import { Command as Command9 } from "commander";
|
|
9682
|
+
async function loadApiKey() {
|
|
8651
9683
|
const manager = getSettingsManager();
|
|
8652
9684
|
return manager.getApiKey();
|
|
8653
9685
|
}
|
|
8654
|
-
function loadBaseURL() {
|
|
9686
|
+
async function loadBaseURL() {
|
|
8655
9687
|
const manager = getSettingsManager();
|
|
8656
9688
|
return manager.getBaseURL();
|
|
8657
9689
|
}
|
|
9690
|
+
async function loadModel() {
|
|
9691
|
+
const manager = getSettingsManager();
|
|
9692
|
+
return process.env.SUPER_AGENT_MODEL || manager.getCurrentModel();
|
|
9693
|
+
}
|
|
8658
9694
|
async function saveCommandLineSettings(apiKey, baseURL) {
|
|
8659
|
-
|
|
8660
|
-
|
|
8661
|
-
|
|
8662
|
-
|
|
8663
|
-
|
|
8664
|
-
|
|
8665
|
-
|
|
9695
|
+
if (!apiKey && !baseURL) {
|
|
9696
|
+
return;
|
|
9697
|
+
}
|
|
9698
|
+
const manager = getSettingsManager();
|
|
9699
|
+
const settings = manager.loadUserSettings();
|
|
9700
|
+
const activeProviderId = settings.active_provider;
|
|
9701
|
+
if (settings.providers[activeProviderId]) {
|
|
8666
9702
|
if (apiKey) {
|
|
8667
9703
|
settings.providers[activeProviderId].api_key = apiKey;
|
|
8668
|
-
console.log(`✅ API key saved for provider '${activeProviderId}' to ~/.super-agent/settings.json`);
|
|
8669
9704
|
}
|
|
8670
9705
|
if (baseURL) {
|
|
8671
9706
|
settings.providers[activeProviderId].base_url = baseURL;
|
|
8672
|
-
console.log(`✅ Base URL saved for provider '${activeProviderId}' to ~/.super-agent/settings.json`);
|
|
8673
9707
|
}
|
|
8674
9708
|
manager.saveUserSettings(settings);
|
|
8675
|
-
} catch (error) {
|
|
8676
|
-
console.warn("⚠️ Could not save settings to file:", error instanceof Error ? error.message : "Unknown error");
|
|
8677
|
-
}
|
|
8678
|
-
}
|
|
8679
|
-
function loadModel() {
|
|
8680
|
-
let model = process.env.SUPER_AGENT_MODEL;
|
|
8681
|
-
if (!model) {
|
|
8682
|
-
try {
|
|
8683
|
-
const manager = getSettingsManager();
|
|
8684
|
-
model = manager.getCurrentModel();
|
|
8685
|
-
} catch (error) {}
|
|
8686
9709
|
}
|
|
8687
|
-
return model;
|
|
8688
9710
|
}
|
|
8689
9711
|
async function handleCommitAndPushHeadless(apiKey, baseURL, model, maxToolRounds) {
|
|
8690
9712
|
try {
|
|
@@ -8759,6 +9781,122 @@ Respond with ONLY the commit message, no additional text.`;
|
|
|
8759
9781
|
process.exit(1);
|
|
8760
9782
|
}
|
|
8761
9783
|
}
|
|
9784
|
+
function createGitCommand() {
|
|
9785
|
+
const gitCommand = new Command9("git").description("Git operations with AI assistance");
|
|
9786
|
+
gitCommand.command("commit-and-push").description("Generate AI commit message and push to remote").option("-d, --directory <dir>", "set working directory", process.cwd()).option("-k, --api-key <key>", "Super Agent API key (or set SUPER_AGENT_API_KEY env var)").option("-u, --base-url <url>", "Super Agent API base URL (or set SUPER_AGENT_BASE_URL env var)").option("-m, --model <model>", "AI model to use (e.g., GLM-4.7) (or set SUPER_AGENT_MODEL env var)").option("--max-tool-rounds <rounds>", "maximum number of tool execution rounds (default: 400)", "400").action(async (options) => {
|
|
9787
|
+
if (options.directory) {
|
|
9788
|
+
try {
|
|
9789
|
+
process.chdir(options.directory);
|
|
9790
|
+
} catch (error) {
|
|
9791
|
+
console.error(`Error changing directory to ${options.directory}:`, error.message);
|
|
9792
|
+
process.exit(1);
|
|
9793
|
+
}
|
|
9794
|
+
}
|
|
9795
|
+
try {
|
|
9796
|
+
const apiKey = options.apiKey || await loadApiKey();
|
|
9797
|
+
const baseURL = options.baseUrl || await loadBaseURL();
|
|
9798
|
+
const model = options.model || await loadModel();
|
|
9799
|
+
const maxToolRounds = parseInt(options.maxToolRounds) || 400;
|
|
9800
|
+
if (!apiKey) {
|
|
9801
|
+
console.error("❌ Error: API key required for git operations. Set SUPER_AGENT_API_KEY environment variable.");
|
|
9802
|
+
process.exit(1);
|
|
9803
|
+
}
|
|
9804
|
+
if (options.apiKey || options.baseUrl) {
|
|
9805
|
+
await saveCommandLineSettings(options.apiKey, options.baseUrl);
|
|
9806
|
+
}
|
|
9807
|
+
await handleCommitAndPushHeadless(apiKey, baseURL, model, maxToolRounds);
|
|
9808
|
+
} catch (error) {
|
|
9809
|
+
console.error("❌ Error during git commit-and-push:", error.message);
|
|
9810
|
+
process.exit(1);
|
|
9811
|
+
}
|
|
9812
|
+
});
|
|
9813
|
+
return gitCommand;
|
|
9814
|
+
}
|
|
9815
|
+
|
|
9816
|
+
// src/commands/index.ts
|
|
9817
|
+
function registerCommands(program) {
|
|
9818
|
+
program.addCommand(createMCPCommand());
|
|
9819
|
+
program.addCommand(createPluginsCommand());
|
|
9820
|
+
program.addCommand(createGitCommand());
|
|
9821
|
+
program.addCommand(createWebCommand());
|
|
9822
|
+
program.addCommand(createServeCommand());
|
|
9823
|
+
program.addCommand(createSkillsCommand());
|
|
9824
|
+
program.addCommand(createAgentsCommand());
|
|
9825
|
+
program.addCommand(createImportCommand());
|
|
9826
|
+
program.addCommand(createProviderCommand());
|
|
9827
|
+
program.addCommand(createIndexCommand());
|
|
9828
|
+
}
|
|
9829
|
+
|
|
9830
|
+
// src/index.ts
|
|
9831
|
+
var import__package = __toESM(require_package(), 1);
|
|
9832
|
+
import { program } from "commander";
|
|
9833
|
+
import * as dotenv from "dotenv";
|
|
9834
|
+
import { render } from "ink";
|
|
9835
|
+
import React4 from "react";
|
|
9836
|
+
dotenv.config();
|
|
9837
|
+
process.on("SIGTERM", () => {
|
|
9838
|
+
if (process.stdin.isTTY && process.stdin.setRawMode) {
|
|
9839
|
+
try {
|
|
9840
|
+
process.stdin.setRawMode(false);
|
|
9841
|
+
} catch (e) {}
|
|
9842
|
+
}
|
|
9843
|
+
console.log(`
|
|
9844
|
+
Gracefully shutting down...`);
|
|
9845
|
+
process.exit(0);
|
|
9846
|
+
});
|
|
9847
|
+
process.on("uncaughtException", (error) => {
|
|
9848
|
+
console.error("Uncaught exception:", error);
|
|
9849
|
+
process.exit(1);
|
|
9850
|
+
});
|
|
9851
|
+
process.on("unhandledRejection", (reason, promise) => {
|
|
9852
|
+
console.error("Unhandled rejection at:", promise, "reason:", reason);
|
|
9853
|
+
process.exit(1);
|
|
9854
|
+
});
|
|
9855
|
+
function ensureUserSettingsDirectory() {
|
|
9856
|
+
try {
|
|
9857
|
+
const manager = getSettingsManager();
|
|
9858
|
+
manager.loadUserSettings();
|
|
9859
|
+
} catch (error) {}
|
|
9860
|
+
}
|
|
9861
|
+
function loadApiKey2() {
|
|
9862
|
+
const manager = getSettingsManager();
|
|
9863
|
+
return manager.getApiKey();
|
|
9864
|
+
}
|
|
9865
|
+
function loadBaseURL2() {
|
|
9866
|
+
const manager = getSettingsManager();
|
|
9867
|
+
return manager.getBaseURL();
|
|
9868
|
+
}
|
|
9869
|
+
async function saveCommandLineSettings2(apiKey, baseURL) {
|
|
9870
|
+
try {
|
|
9871
|
+
const manager = getSettingsManager();
|
|
9872
|
+
const settings = manager.loadUserSettings();
|
|
9873
|
+
const activeProviderId = settings.active_provider;
|
|
9874
|
+
if (!settings.providers[activeProviderId]) {
|
|
9875
|
+
return;
|
|
9876
|
+
}
|
|
9877
|
+
if (apiKey) {
|
|
9878
|
+
settings.providers[activeProviderId].api_key = apiKey;
|
|
9879
|
+
console.log(`✅ API key saved for provider '${activeProviderId}' to ~/.super-agent/settings.json`);
|
|
9880
|
+
}
|
|
9881
|
+
if (baseURL) {
|
|
9882
|
+
settings.providers[activeProviderId].base_url = baseURL;
|
|
9883
|
+
console.log(`✅ Base URL saved for provider '${activeProviderId}' to ~/.super-agent/settings.json`);
|
|
9884
|
+
}
|
|
9885
|
+
manager.saveUserSettings(settings);
|
|
9886
|
+
} catch (error) {
|
|
9887
|
+
console.warn("⚠️ Could not save settings to file:", error instanceof Error ? error.message : "Unknown error");
|
|
9888
|
+
}
|
|
9889
|
+
}
|
|
9890
|
+
function loadModel2() {
|
|
9891
|
+
let model = process.env.SUPER_AGENT_MODEL;
|
|
9892
|
+
if (!model) {
|
|
9893
|
+
try {
|
|
9894
|
+
const manager = getSettingsManager();
|
|
9895
|
+
model = manager.getCurrentModel();
|
|
9896
|
+
} catch (error) {}
|
|
9897
|
+
}
|
|
9898
|
+
return model;
|
|
9899
|
+
}
|
|
8762
9900
|
async function processPromptHeadless(prompt, apiKey, baseURL, model, maxToolRounds) {
|
|
8763
9901
|
try {
|
|
8764
9902
|
const agent = new SuperAgent(apiKey, baseURL, model, maxToolRounds);
|
|
@@ -8823,9 +9961,9 @@ program.name("super-agent").description("A conversational AI CLI tool powered by
|
|
|
8823
9961
|
}
|
|
8824
9962
|
}
|
|
8825
9963
|
try {
|
|
8826
|
-
const apiKey = options.apiKey ||
|
|
8827
|
-
const baseURL = options.baseUrl ||
|
|
8828
|
-
const model = options.model ||
|
|
9964
|
+
const apiKey = options.apiKey || loadApiKey2();
|
|
9965
|
+
const baseURL = options.baseUrl || loadBaseURL2();
|
|
9966
|
+
const model = options.model || loadModel2();
|
|
8829
9967
|
const maxToolRounds = parseInt(options.maxToolRounds) || 400;
|
|
8830
9968
|
if (!apiKey && !options.prompt) {
|
|
8831
9969
|
console.warn("⚠️ Warning: No API key found. Some features may not work. Use /config or set SUPER_AGENT_API_KEY.");
|
|
@@ -8834,7 +9972,7 @@ program.name("super-agent").description("A conversational AI CLI tool powered by
|
|
|
8834
9972
|
process.exit(1);
|
|
8835
9973
|
}
|
|
8836
9974
|
if (options.apiKey || options.baseUrl) {
|
|
8837
|
-
await
|
|
9975
|
+
await saveCommandLineSettings2(options.apiKey, options.baseUrl);
|
|
8838
9976
|
}
|
|
8839
9977
|
if (options.prompt) {
|
|
8840
9978
|
await processPromptHeadless(options.prompt, apiKey, baseURL, model, maxToolRounds);
|
|
@@ -8862,141 +10000,6 @@ program.name("super-agent").description("A conversational AI CLI tool powered by
|
|
|
8862
10000
|
process.exit(1);
|
|
8863
10001
|
}
|
|
8864
10002
|
});
|
|
8865
|
-
|
|
8866
|
-
|
|
8867
|
-
console.log(import__package.default.description);
|
|
8868
|
-
console.log(`
|
|
8869
|
-
Maintained by: ` + import__package.default.author);
|
|
8870
|
-
console.log(`
|
|
8871
|
-
Source code: ` + import__package.default.repository.url);
|
|
8872
|
-
console.log(`
|
|
8873
|
-
Funding: ` + import__package.default.funding);
|
|
8874
|
-
process.exit(0);
|
|
8875
|
-
});
|
|
8876
|
-
var pluginsCommand = program.command("plugins list/install/uninstall <name> / <path>").description("Manage plugins for Super Agent CLI");
|
|
8877
|
-
pluginsCommand.command("list").description("List installed plugins").action(() => {
|
|
8878
|
-
console.log("List installed plugins");
|
|
8879
|
-
process.exit(0);
|
|
8880
|
-
});
|
|
8881
|
-
pluginsCommand.command("install <name> / <path>").description("Install a plugin").action(() => {
|
|
8882
|
-
console.log("Install a plugin");
|
|
8883
|
-
process.exit(0);
|
|
8884
|
-
});
|
|
8885
|
-
pluginsCommand.command("uninstall <name>").description("Uninstall a plugin").action(() => {
|
|
8886
|
-
console.log("Uninstall a plugin");
|
|
8887
|
-
process.exit(0);
|
|
8888
|
-
});
|
|
8889
|
-
var gitCommand = program.command("git").description("Git operations with AI assistance");
|
|
8890
|
-
gitCommand.command("commit-and-push").description("Generate AI commit message and push to remote").option("-d, --directory <dir>", "set working directory", process.cwd()).option("-k, --api-key <key>", "Super Agent API key (or set SUPER_AGENT_API_KEY env var)").option("-u, --base-url <url>", "Super Agent API base URL (or set SUPER_AGENT_BASE_URL env var)").option("-m, --model <model>", "AI model to use (e.g., GLM-4.7) (or set SUPER_AGENT_MODEL env var)").option("--max-tool-rounds <rounds>", "maximum number of tool execution rounds (default: 400)", "400").action(async (options) => {
|
|
8891
|
-
if (options.directory) {
|
|
8892
|
-
try {
|
|
8893
|
-
process.chdir(options.directory);
|
|
8894
|
-
} catch (error) {
|
|
8895
|
-
console.error(`Error changing directory to ${options.directory}:`, error.message);
|
|
8896
|
-
process.exit(1);
|
|
8897
|
-
}
|
|
8898
|
-
}
|
|
8899
|
-
try {
|
|
8900
|
-
const apiKey = options.apiKey || loadApiKey();
|
|
8901
|
-
const baseURL = options.baseUrl || loadBaseURL();
|
|
8902
|
-
const model = options.model || loadModel();
|
|
8903
|
-
const maxToolRounds = parseInt(options.maxToolRounds) || 400;
|
|
8904
|
-
if (!apiKey) {
|
|
8905
|
-
console.error("❌ Error: API key required for git operations. Set SUPER_AGENT_API_KEY environment variable.");
|
|
8906
|
-
process.exit(1);
|
|
8907
|
-
}
|
|
8908
|
-
if (options.apiKey || options.baseUrl) {
|
|
8909
|
-
await saveCommandLineSettings(options.apiKey, options.baseUrl);
|
|
8910
|
-
}
|
|
8911
|
-
await handleCommitAndPushHeadless(apiKey, baseURL, model, maxToolRounds);
|
|
8912
|
-
} catch (error) {
|
|
8913
|
-
console.error("❌ Error during git commit-and-push:", error.message);
|
|
8914
|
-
process.exit(1);
|
|
8915
|
-
}
|
|
8916
|
-
});
|
|
8917
|
-
var webCommand = program.command("web").description("Start web server interface").option("--hostname <hostname>", "Server hostname", "localhost").option("--port <port>", "Server port", "3000").option("-d, --directory <dir>", "set working directory", process.cwd()).option("-k, --api-key <key>", "Super Agent API key (or set SUPER_AGENT_API_KEY env var)").option("-u, --base-url <url>", "Super Agent API base URL (or set SUPER_AGENT_BASE_URL env var)").option("-m, --model <model>", "AI model to use (e.g., GLM-4.7) (or set SUPER_AGENT_MODEL env var)").option("--max-tool-rounds <rounds>", "maximum number of tool execution rounds (default: 400)", "400").option("--no-open", "Don't open browser automatically").action(async (options) => {
|
|
8918
|
-
if (options.directory) {
|
|
8919
|
-
try {
|
|
8920
|
-
process.chdir(options.directory);
|
|
8921
|
-
} catch (error) {
|
|
8922
|
-
console.error(`Error changing directory to ${options.directory}:`, error.message);
|
|
8923
|
-
process.exit(1);
|
|
8924
|
-
}
|
|
8925
|
-
}
|
|
8926
|
-
try {
|
|
8927
|
-
const { WebServer: WebServer2 } = await Promise.resolve().then(() => (init_server(), exports_server));
|
|
8928
|
-
const apiKey = options.apiKey || loadApiKey();
|
|
8929
|
-
const baseURL = options.baseUrl || loadBaseURL();
|
|
8930
|
-
const model = options.model || loadModel();
|
|
8931
|
-
const maxToolRounds = parseInt(options.maxToolRounds) || 400;
|
|
8932
|
-
if (!apiKey) {
|
|
8933
|
-
console.warn("⚠️ Warning: No API key found. Web interface may not work properly.");
|
|
8934
|
-
}
|
|
8935
|
-
if (options.apiKey || options.baseUrl) {
|
|
8936
|
-
await saveCommandLineSettings(options.apiKey, options.baseUrl);
|
|
8937
|
-
}
|
|
8938
|
-
const agent = new SuperAgent(apiKey || "", baseURL, model, maxToolRounds);
|
|
8939
|
-
const server = new WebServer2({
|
|
8940
|
-
hostname: options.hostname,
|
|
8941
|
-
port: parseInt(options.port),
|
|
8942
|
-
agent
|
|
8943
|
-
});
|
|
8944
|
-
await server.start();
|
|
8945
|
-
if (options.open !== false) {
|
|
8946
|
-
await server.openBrowser();
|
|
8947
|
-
}
|
|
8948
|
-
process.on("SIGINT", () => {
|
|
8949
|
-
server.stop();
|
|
8950
|
-
process.exit(0);
|
|
8951
|
-
});
|
|
8952
|
-
} catch (error) {
|
|
8953
|
-
console.error("❌ Error starting web server:", error.message);
|
|
8954
|
-
process.exit(1);
|
|
8955
|
-
}
|
|
8956
|
-
});
|
|
8957
|
-
var serveCommand = program.command("serve").description("Run both CLI and web interface simultaneously").option("--hostname <hostname>", "Server hostname", "localhost").option("--port <port>", "Server port", "3000").option("-d, --directory <dir>", "set working directory", process.cwd()).option("-k, --api-key <key>", "Super Agent API key (or set SUPER_AGENT_API_KEY env var)").option("-u, --base-url <url>", "Super Agent API base URL (or set SUPER_AGENT_BASE_URL env var)").option("-m, --model <model>", "AI model to use (e.g., GLM-4.7) (or set SUPER_AGENT_MODEL env var)").option("--max-tool-rounds <rounds>", "maximum number of tool execution rounds (default: 400)", "400").option("--no-open", "Don't open browser automatically").action(async (options) => {
|
|
8958
|
-
if (options.directory) {
|
|
8959
|
-
try {
|
|
8960
|
-
process.chdir(options.directory);
|
|
8961
|
-
} catch (error) {
|
|
8962
|
-
console.error(`Error changing directory to ${options.directory}:`, error.message);
|
|
8963
|
-
process.exit(1);
|
|
8964
|
-
}
|
|
8965
|
-
}
|
|
8966
|
-
try {
|
|
8967
|
-
const { WebServer: WebServer2 } = await Promise.resolve().then(() => (init_server(), exports_server));
|
|
8968
|
-
const apiKey = options.apiKey || loadApiKey();
|
|
8969
|
-
const baseURL = options.baseUrl || loadBaseURL();
|
|
8970
|
-
const model = options.model || loadModel();
|
|
8971
|
-
const maxToolRounds = parseInt(options.maxToolRounds) || 400;
|
|
8972
|
-
if (!apiKey) {
|
|
8973
|
-
console.warn("⚠️ Warning: No API key found. Some features may not work.");
|
|
8974
|
-
}
|
|
8975
|
-
if (options.apiKey || options.baseUrl) {
|
|
8976
|
-
await saveCommandLineSettings(options.apiKey, options.baseUrl);
|
|
8977
|
-
}
|
|
8978
|
-
const agent = new SuperAgent(apiKey || "", baseURL, model, maxToolRounds);
|
|
8979
|
-
const server = new WebServer2({
|
|
8980
|
-
hostname: options.hostname,
|
|
8981
|
-
port: parseInt(options.port),
|
|
8982
|
-
agent
|
|
8983
|
-
});
|
|
8984
|
-
await server.start();
|
|
8985
|
-
if (options.open !== false) {
|
|
8986
|
-
await server.openBrowser();
|
|
8987
|
-
}
|
|
8988
|
-
console.log(`\uD83E\uDD16 Starting CLI interface...
|
|
8989
|
-
`);
|
|
8990
|
-
ensureUserSettingsDirectory();
|
|
8991
|
-
render(React4.createElement(ChatInterface, { agent }));
|
|
8992
|
-
process.on("SIGINT", () => {
|
|
8993
|
-
server.stop();
|
|
8994
|
-
process.exit(0);
|
|
8995
|
-
});
|
|
8996
|
-
} catch (error) {
|
|
8997
|
-
console.error("❌ Error starting serve mode:", error.message);
|
|
8998
|
-
process.exit(1);
|
|
8999
|
-
}
|
|
9000
|
-
});
|
|
9001
|
-
program.addCommand(createMCPCommand());
|
|
10003
|
+
registerCommands(program);
|
|
10004
|
+
program.parse();
|
|
9002
10005
|
program.parse();
|