@involvex/super-agent-cli 0.0.61 → 0.0.62
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 +1188 -696
- package/dist/super-agent-cli.exe +0 -0
- package/package.json +4 -1
- package/tsc_output.txt +2 -0
package/dist/index.js
CHANGED
|
@@ -536,11 +536,122 @@ var init_indexer = __esm(() => {
|
|
|
536
536
|
init_settings_manager();
|
|
537
537
|
});
|
|
538
538
|
|
|
539
|
+
// src/utils/session-manager.ts
|
|
540
|
+
var exports_session_manager = {};
|
|
541
|
+
__export(exports_session_manager, {
|
|
542
|
+
getSessionManager: () => getSessionManager,
|
|
543
|
+
SessionManager: () => SessionManager
|
|
544
|
+
});
|
|
545
|
+
import * as fs13 from "fs-extra";
|
|
546
|
+
import * as path12 from "path";
|
|
547
|
+
|
|
548
|
+
class SessionManager {
|
|
549
|
+
static instance;
|
|
550
|
+
sessionsDir;
|
|
551
|
+
currentSession = null;
|
|
552
|
+
constructor() {
|
|
553
|
+
const settingsManager = getSettingsManager();
|
|
554
|
+
this.sessionsDir = path12.join(settingsManager.getStorageDirectory(), "sessions");
|
|
555
|
+
fs13.ensureDirSync(this.sessionsDir);
|
|
556
|
+
}
|
|
557
|
+
static getInstance() {
|
|
558
|
+
if (!SessionManager.instance) {
|
|
559
|
+
SessionManager.instance = new SessionManager;
|
|
560
|
+
}
|
|
561
|
+
return SessionManager.instance;
|
|
562
|
+
}
|
|
563
|
+
generateSessionId(workingDir) {
|
|
564
|
+
const normalized = path12.normalize(workingDir).toLowerCase();
|
|
565
|
+
return Buffer.from(normalized).toString("base64").replace(/[/+=]/g, "_");
|
|
566
|
+
}
|
|
567
|
+
getSessionFilePath(sessionId) {
|
|
568
|
+
return path12.join(this.sessionsDir, `${sessionId}.json`);
|
|
569
|
+
}
|
|
570
|
+
async getOrCreateSession(workingDirectory, name) {
|
|
571
|
+
const sessionId = this.generateSessionId(workingDirectory);
|
|
572
|
+
const sessionFile = this.getSessionFilePath(sessionId);
|
|
573
|
+
try {
|
|
574
|
+
if (await fs13.pathExists(sessionFile)) {
|
|
575
|
+
const session = await fs13.readJson(sessionFile);
|
|
576
|
+
session.lastAccessed = Date.now();
|
|
577
|
+
this.currentSession = session;
|
|
578
|
+
await this.saveSession(session);
|
|
579
|
+
return session;
|
|
580
|
+
}
|
|
581
|
+
} catch (error) {}
|
|
582
|
+
const newSession = {
|
|
583
|
+
id: sessionId,
|
|
584
|
+
workingDirectory,
|
|
585
|
+
name: name || path12.basename(workingDirectory),
|
|
586
|
+
messages: [],
|
|
587
|
+
lastAccessed: Date.now(),
|
|
588
|
+
createdAt: Date.now()
|
|
589
|
+
};
|
|
590
|
+
this.currentSession = newSession;
|
|
591
|
+
await this.saveSession(newSession);
|
|
592
|
+
return newSession;
|
|
593
|
+
}
|
|
594
|
+
async saveSession(session) {
|
|
595
|
+
const sessionFile = this.getSessionFilePath(session.id);
|
|
596
|
+
await fs13.outputJson(sessionFile, session, { spaces: 2 });
|
|
597
|
+
}
|
|
598
|
+
async addMessage(message) {
|
|
599
|
+
if (!this.currentSession) {
|
|
600
|
+
throw new Error("No active session");
|
|
601
|
+
}
|
|
602
|
+
this.currentSession.messages.push(message);
|
|
603
|
+
this.currentSession.lastAccessed = Date.now();
|
|
604
|
+
await this.saveSession(this.currentSession);
|
|
605
|
+
}
|
|
606
|
+
async listSessions() {
|
|
607
|
+
const sessionFiles = await fs13.readdir(this.sessionsDir);
|
|
608
|
+
const sessions = [];
|
|
609
|
+
for (const file of sessionFiles) {
|
|
610
|
+
if (file.endsWith(".json")) {
|
|
611
|
+
try {
|
|
612
|
+
const session = await fs13.readJson(path12.join(this.sessionsDir, file));
|
|
613
|
+
sessions.push(session);
|
|
614
|
+
} catch (error) {}
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
sessions.sort((a, b) => b.lastAccessed - a.lastAccessed);
|
|
618
|
+
return sessions;
|
|
619
|
+
}
|
|
620
|
+
async deleteSession(sessionId) {
|
|
621
|
+
const sessionFile = this.getSessionFilePath(sessionId);
|
|
622
|
+
if (await fs13.pathExists(sessionFile)) {
|
|
623
|
+
await fs13.remove(sessionFile);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
getCurrentSession() {
|
|
627
|
+
return this.currentSession;
|
|
628
|
+
}
|
|
629
|
+
async switchSession(sessionId) {
|
|
630
|
+
const sessionFile = this.getSessionFilePath(sessionId);
|
|
631
|
+
try {
|
|
632
|
+
if (await fs13.pathExists(sessionFile)) {
|
|
633
|
+
const session = await fs13.readJson(sessionFile);
|
|
634
|
+
session.lastAccessed = Date.now();
|
|
635
|
+
this.currentSession = session;
|
|
636
|
+
await this.saveSession(session);
|
|
637
|
+
return session;
|
|
638
|
+
}
|
|
639
|
+
} catch (error) {}
|
|
640
|
+
return null;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
function getSessionManager() {
|
|
644
|
+
return SessionManager.getInstance();
|
|
645
|
+
}
|
|
646
|
+
var init_session_manager = __esm(() => {
|
|
647
|
+
init_settings_manager();
|
|
648
|
+
});
|
|
649
|
+
|
|
539
650
|
// package.json
|
|
540
651
|
var require_package = __commonJS((exports, module) => {
|
|
541
652
|
module.exports = {
|
|
542
653
|
name: "@involvex/super-agent-cli",
|
|
543
|
-
version: "0.0.
|
|
654
|
+
version: "0.0.62",
|
|
544
655
|
description: "An open-source AI agent that brings the power of Super Agent directly into your terminal.",
|
|
545
656
|
keywords: [
|
|
546
657
|
"cli",
|
|
@@ -592,6 +703,7 @@ var require_package = __commonJS((exports, module) => {
|
|
|
592
703
|
dependencies: {
|
|
593
704
|
"@google/generative-ai": "^0.24.1",
|
|
594
705
|
"@modelcontextprotocol/sdk": "^1.25.3",
|
|
706
|
+
"@types/mime": "^4.0.0",
|
|
595
707
|
axios: "^1.13.4",
|
|
596
708
|
cfonts: "^3.3.1",
|
|
597
709
|
chalk: "^5.6.2",
|
|
@@ -600,7 +712,9 @@ var require_package = __commonJS((exports, module) => {
|
|
|
600
712
|
dotenv: "^17.2.3",
|
|
601
713
|
enquirer: "^2.4.1",
|
|
602
714
|
"fs-extra": "^11.3.3",
|
|
715
|
+
ignore: "^7.0.5",
|
|
603
716
|
ink: "^6.6.0",
|
|
717
|
+
inquirer: "^13.2.2",
|
|
604
718
|
marked: "^17.0.1",
|
|
605
719
|
"marked-terminal": "^7.3.0",
|
|
606
720
|
mime: "^4.1.0",
|
|
@@ -638,46 +752,14 @@ var require_package = __commonJS((exports, module) => {
|
|
|
638
752
|
};
|
|
639
753
|
});
|
|
640
754
|
|
|
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
755
|
// src/utils/update-checker.ts
|
|
674
756
|
var exports_update_checker = {};
|
|
675
757
|
__export(exports_update_checker, {
|
|
676
758
|
getUpdateChecker: () => getUpdateChecker,
|
|
677
759
|
UpdateChecker: () => UpdateChecker
|
|
678
760
|
});
|
|
679
|
-
import * as
|
|
680
|
-
import * as
|
|
761
|
+
import * as fs14 from "fs-extra";
|
|
762
|
+
import * as path13 from "path";
|
|
681
763
|
import axios3 from "axios";
|
|
682
764
|
|
|
683
765
|
class UpdateChecker {
|
|
@@ -686,7 +768,7 @@ class UpdateChecker {
|
|
|
686
768
|
currentVersion;
|
|
687
769
|
constructor(currentVersion) {
|
|
688
770
|
const settingsManager = getSettingsManager();
|
|
689
|
-
this.cacheFile =
|
|
771
|
+
this.cacheFile = path13.join(settingsManager.getStorageDirectory(), "update-cache.json");
|
|
690
772
|
this.currentVersion = currentVersion;
|
|
691
773
|
}
|
|
692
774
|
static getInstance(currentVersion) {
|
|
@@ -697,8 +779,8 @@ class UpdateChecker {
|
|
|
697
779
|
}
|
|
698
780
|
async loadCache() {
|
|
699
781
|
try {
|
|
700
|
-
if (await
|
|
701
|
-
const cache = await
|
|
782
|
+
if (await fs14.pathExists(this.cacheFile)) {
|
|
783
|
+
const cache = await fs14.readJson(this.cacheFile);
|
|
702
784
|
const now = Date.now();
|
|
703
785
|
if (cache.lastChecked && now - cache.lastChecked < CACHE_DURATION) {
|
|
704
786
|
return cache;
|
|
@@ -709,7 +791,7 @@ class UpdateChecker {
|
|
|
709
791
|
}
|
|
710
792
|
async saveCache(info) {
|
|
711
793
|
try {
|
|
712
|
-
await
|
|
794
|
+
await fs14.outputJson(this.cacheFile, info);
|
|
713
795
|
} catch (error) {}
|
|
714
796
|
}
|
|
715
797
|
compareVersions(v1, v2) {
|
|
@@ -778,459 +860,129 @@ var init_update_checker = __esm(() => {
|
|
|
778
860
|
CACHE_DURATION = 24 * 60 * 60 * 1000;
|
|
779
861
|
});
|
|
780
862
|
|
|
781
|
-
// src/utils/
|
|
782
|
-
var
|
|
783
|
-
__export(
|
|
784
|
-
|
|
785
|
-
|
|
863
|
+
// src/utils/banner.ts
|
|
864
|
+
var exports_banner = {};
|
|
865
|
+
__export(exports_banner, {
|
|
866
|
+
HELP_BANNER: () => HELP_BANNER,
|
|
867
|
+
BANNER: () => BANNER
|
|
786
868
|
});
|
|
787
|
-
|
|
788
|
-
|
|
869
|
+
var BANNER = `
|
|
870
|
+
╔═══════════════════════════════════════════════════════════════╗
|
|
871
|
+
║ ║
|
|
872
|
+
║ ███████╗██╗ ██╗██████╗ ███████╗██████╗ ║
|
|
873
|
+
║ ██╔════╝██║ ██║██╔══██╗██╔════╝██╔══██╗ ║
|
|
874
|
+
║ ███████╗██║ ██║██████╔╝█████╗ ██████╔╝ ║
|
|
875
|
+
║ ╚════██║██║ ██║██╔═══╝ ██╔══╝ ██╔══██╗ ║
|
|
876
|
+
║ ███████║╚██████╔╝██║ ███████╗██║ ██║ ║
|
|
877
|
+
║ ╚══════╝ ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═╝ ║
|
|
878
|
+
║ ║
|
|
879
|
+
║ █████╗ ██████╗ ███████╗███╗ ██╗████████╗ ║
|
|
880
|
+
║ ██╔══██╗██╔════╝ ██╔════╝████╗ ██║╚══██╔══╝ ║
|
|
881
|
+
║ ███████║██║ ███╗█████╗ ██╔██╗ ██║ ██║ ║
|
|
882
|
+
║ ██╔══██║██║ ██║██╔══╝ ██║╚██╗██║ ██║ ║
|
|
883
|
+
║ ██║ ██║╚██████╔╝███████╗██║ ╚████║ ██║ ║
|
|
884
|
+
║ ╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═╝ ║
|
|
885
|
+
║ ║
|
|
886
|
+
║ \uD83E\uDD16 AI-Powered Terminal Assistant ║
|
|
887
|
+
║ ║
|
|
888
|
+
╚═══════════════════════════════════════════════════════════════╝
|
|
889
|
+
`, HELP_BANNER = `
|
|
890
|
+
╔═══════════════════════════════════════════╗
|
|
891
|
+
║ \uD83E\uDD16 SUPER AGENT - Help & Usage ║
|
|
892
|
+
╚═══════════════════════════════════════════╝
|
|
893
|
+
`;
|
|
789
894
|
|
|
790
|
-
|
|
895
|
+
// src/utils/confirmation-service.ts
|
|
896
|
+
import { EventEmitter } from "events";
|
|
897
|
+
import { exec } from "child_process";
|
|
898
|
+
import { promisify } from "util";
|
|
899
|
+
var execAsync = promisify(exec);
|
|
900
|
+
|
|
901
|
+
class ConfirmationService extends EventEmitter {
|
|
791
902
|
static instance;
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
903
|
+
skipConfirmationThisSession = false;
|
|
904
|
+
pendingConfirmation = null;
|
|
905
|
+
resolveConfirmation = null;
|
|
906
|
+
sessionFlags = {
|
|
907
|
+
fileOperations: false,
|
|
908
|
+
bashCommands: false,
|
|
909
|
+
allOperations: false
|
|
910
|
+
};
|
|
799
911
|
static getInstance() {
|
|
800
|
-
if (!
|
|
801
|
-
|
|
912
|
+
if (!ConfirmationService.instance) {
|
|
913
|
+
ConfirmationService.instance = new ConfirmationService;
|
|
802
914
|
}
|
|
803
|
-
return
|
|
804
|
-
}
|
|
805
|
-
generateSessionId(workingDir) {
|
|
806
|
-
const normalized = path13.normalize(workingDir).toLowerCase();
|
|
807
|
-
return Buffer.from(normalized).toString("base64").replace(/[/+=]/g, "_");
|
|
808
|
-
}
|
|
809
|
-
getSessionFilePath(sessionId) {
|
|
810
|
-
return path13.join(this.sessionsDir, `${sessionId}.json`);
|
|
811
|
-
}
|
|
812
|
-
async getOrCreateSession(workingDirectory, name) {
|
|
813
|
-
const sessionId = this.generateSessionId(workingDirectory);
|
|
814
|
-
const sessionFile = this.getSessionFilePath(sessionId);
|
|
815
|
-
try {
|
|
816
|
-
if (await fs14.pathExists(sessionFile)) {
|
|
817
|
-
const session = await fs14.readJson(sessionFile);
|
|
818
|
-
session.lastAccessed = Date.now();
|
|
819
|
-
this.currentSession = session;
|
|
820
|
-
await this.saveSession(session);
|
|
821
|
-
return session;
|
|
822
|
-
}
|
|
823
|
-
} catch (error) {}
|
|
824
|
-
const newSession = {
|
|
825
|
-
id: sessionId,
|
|
826
|
-
workingDirectory,
|
|
827
|
-
name: name || path13.basename(workingDirectory),
|
|
828
|
-
messages: [],
|
|
829
|
-
lastAccessed: Date.now(),
|
|
830
|
-
createdAt: Date.now()
|
|
831
|
-
};
|
|
832
|
-
this.currentSession = newSession;
|
|
833
|
-
await this.saveSession(newSession);
|
|
834
|
-
return newSession;
|
|
915
|
+
return ConfirmationService.instance;
|
|
835
916
|
}
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
await fs14.outputJson(sessionFile, session, { spaces: 2 });
|
|
917
|
+
constructor() {
|
|
918
|
+
super();
|
|
839
919
|
}
|
|
840
|
-
async
|
|
841
|
-
if (
|
|
842
|
-
|
|
920
|
+
async requestConfirmation(options, operationType = "file") {
|
|
921
|
+
if (this.sessionFlags.allOperations || operationType === "file" && this.sessionFlags.fileOperations || operationType === "bash" && this.sessionFlags.bashCommands) {
|
|
922
|
+
return { confirmed: true };
|
|
843
923
|
}
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
const sessionFiles = await fs14.readdir(this.sessionsDir);
|
|
850
|
-
const sessions = [];
|
|
851
|
-
for (const file of sessionFiles) {
|
|
852
|
-
if (file.endsWith(".json")) {
|
|
853
|
-
try {
|
|
854
|
-
const session = await fs14.readJson(path13.join(this.sessionsDir, file));
|
|
855
|
-
sessions.push(session);
|
|
856
|
-
} catch (error) {}
|
|
924
|
+
if (options.showVSCodeOpen) {
|
|
925
|
+
try {
|
|
926
|
+
await this.openInVSCode(options.filename);
|
|
927
|
+
} catch (error) {
|
|
928
|
+
options.showVSCodeOpen = false;
|
|
857
929
|
}
|
|
858
930
|
}
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
}
|
|
862
|
-
async deleteSession(sessionId) {
|
|
863
|
-
const sessionFile = this.getSessionFilePath(sessionId);
|
|
864
|
-
if (await fs14.pathExists(sessionFile)) {
|
|
865
|
-
await fs14.remove(sessionFile);
|
|
866
|
-
}
|
|
867
|
-
}
|
|
868
|
-
getCurrentSession() {
|
|
869
|
-
return this.currentSession;
|
|
870
|
-
}
|
|
871
|
-
async switchSession(sessionId) {
|
|
872
|
-
const sessionFile = this.getSessionFilePath(sessionId);
|
|
873
|
-
try {
|
|
874
|
-
if (await fs14.pathExists(sessionFile)) {
|
|
875
|
-
const session = await fs14.readJson(sessionFile);
|
|
876
|
-
session.lastAccessed = Date.now();
|
|
877
|
-
this.currentSession = session;
|
|
878
|
-
await this.saveSession(session);
|
|
879
|
-
return session;
|
|
880
|
-
}
|
|
881
|
-
} catch (error) {}
|
|
882
|
-
return null;
|
|
883
|
-
}
|
|
884
|
-
}
|
|
885
|
-
function getSessionManager() {
|
|
886
|
-
return SessionManager.getInstance();
|
|
887
|
-
}
|
|
888
|
-
var init_session_manager = __esm(() => {
|
|
889
|
-
init_settings_manager();
|
|
890
|
-
});
|
|
891
|
-
|
|
892
|
-
// src/web/server.ts
|
|
893
|
-
var exports_server = {};
|
|
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";
|
|
903
|
-
|
|
904
|
-
class WebServer {
|
|
905
|
-
httpServer;
|
|
906
|
-
wss;
|
|
907
|
-
agent;
|
|
908
|
-
hostname;
|
|
909
|
-
port;
|
|
910
|
-
clients = new Set;
|
|
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);
|
|
931
|
+
this.pendingConfirmation = new Promise((resolve) => {
|
|
932
|
+
this.resolveConfirmation = resolve;
|
|
917
933
|
});
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
this.handleWebSocketConnection(ws);
|
|
934
|
+
setImmediate(() => {
|
|
935
|
+
this.emit("confirmation-requested", options);
|
|
921
936
|
});
|
|
922
|
-
|
|
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");
|
|
937
|
+
const result = await this.pendingConfirmation;
|
|
938
|
+
if (result.dontAskAgain) {
|
|
939
|
+
if (operationType === "file") {
|
|
940
|
+
this.sessionFlags.fileOperations = true;
|
|
941
|
+
} else if (operationType === "bash") {
|
|
942
|
+
this.sessionFlags.bashCommands = true;
|
|
948
943
|
}
|
|
949
|
-
} catch (error) {
|
|
950
|
-
console.error("Error serving file:", error);
|
|
951
|
-
res.writeHead(500);
|
|
952
|
-
res.end("Internal Server Error");
|
|
953
944
|
}
|
|
945
|
+
return result;
|
|
954
946
|
}
|
|
955
|
-
|
|
956
|
-
this.
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
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
|
-
});
|
|
947
|
+
confirmOperation(confirmed, dontAskAgain) {
|
|
948
|
+
if (this.resolveConfirmation) {
|
|
949
|
+
this.resolveConfirmation({ confirmed, dontAskAgain });
|
|
950
|
+
this.resolveConfirmation = null;
|
|
951
|
+
this.pendingConfirmation = null;
|
|
952
|
+
}
|
|
985
953
|
}
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
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
|
-
}));
|
|
954
|
+
rejectOperation(feedback) {
|
|
955
|
+
if (this.resolveConfirmation) {
|
|
956
|
+
this.resolveConfirmation({ confirmed: false, feedback });
|
|
957
|
+
this.resolveConfirmation = null;
|
|
958
|
+
this.pendingConfirmation = null;
|
|
1016
959
|
}
|
|
1017
960
|
}
|
|
1018
|
-
async
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
ws.send(JSON.stringify({ type: "file_tree", tree: [] }));
|
|
961
|
+
async openInVSCode(filename) {
|
|
962
|
+
const commands = ["code", "code-insiders", "codium"];
|
|
963
|
+
for (const cmd of commands) {
|
|
964
|
+
try {
|
|
965
|
+
await execAsync(`which ${cmd}`);
|
|
966
|
+
await execAsync(`${cmd} "${filename}"`);
|
|
1025
967
|
return;
|
|
968
|
+
} catch (error) {
|
|
969
|
+
continue;
|
|
1026
970
|
}
|
|
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
971
|
}
|
|
972
|
+
throw new Error("VS Code not found");
|
|
1037
973
|
}
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
const fullPath = path14.join(process.cwd(), filePath);
|
|
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
|
-
}
|
|
974
|
+
isPending() {
|
|
975
|
+
return this.pendingConfirmation !== null;
|
|
1053
976
|
}
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
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
|
-
}
|
|
977
|
+
resetSession() {
|
|
978
|
+
this.sessionFlags = {
|
|
979
|
+
fileOperations: false,
|
|
980
|
+
bashCommands: false,
|
|
981
|
+
allOperations: false
|
|
982
|
+
};
|
|
1072
983
|
}
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
const { getSessionManager: getSessionManager2 } = await Promise.resolve().then(() => (init_session_manager(), exports_session_manager));
|
|
1076
|
-
const sessionManager = getSessionManager2();
|
|
1077
|
-
const session = await sessionManager.switchSession(sessionId);
|
|
1078
|
-
if (session) {
|
|
1079
|
-
ws.send(JSON.stringify({
|
|
1080
|
-
type: "session_switched",
|
|
1081
|
-
session: {
|
|
1082
|
-
id: session.id,
|
|
1083
|
-
name: session.name,
|
|
1084
|
-
workingDirectory: session.workingDirectory,
|
|
1085
|
-
messages: session.messages
|
|
1086
|
-
}
|
|
1087
|
-
}));
|
|
1088
|
-
} else {
|
|
1089
|
-
throw new Error("Session not found");
|
|
1090
|
-
}
|
|
1091
|
-
} catch (error) {
|
|
1092
|
-
ws.send(JSON.stringify({ type: "error", content: error.message }));
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
async checkAndSendUpdateNotification(ws) {
|
|
1096
|
-
try {
|
|
1097
|
-
const pkg = await Promise.resolve().then(() => __toESM(require_package(), 1));
|
|
1098
|
-
const { getUpdateChecker: getUpdateChecker2 } = await Promise.resolve().then(() => (init_update_checker(), exports_update_checker));
|
|
1099
|
-
const updateChecker = getUpdateChecker2(pkg.version);
|
|
1100
|
-
const updateInfo = await updateChecker.checkForUpdates();
|
|
1101
|
-
if (updateInfo?.updateAvailable) {
|
|
1102
|
-
ws.send(JSON.stringify({
|
|
1103
|
-
type: "update_available",
|
|
1104
|
-
currentVersion: updateInfo.currentVersion,
|
|
1105
|
-
latestVersion: updateInfo.latestVersion
|
|
1106
|
-
}));
|
|
1107
|
-
}
|
|
1108
|
-
} catch (error) {}
|
|
1109
|
-
}
|
|
1110
|
-
async start() {
|
|
1111
|
-
return new Promise((resolve5, reject) => {
|
|
1112
|
-
this.httpServer.listen(this.port, this.hostname, () => {
|
|
1113
|
-
const url = `http://${this.hostname}:${this.port}`;
|
|
1114
|
-
console.log(`\uD83C\uDF10 Web interface available at ${url}`);
|
|
1115
|
-
resolve5();
|
|
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");
|
|
1138
|
-
}
|
|
1139
|
-
}
|
|
1140
|
-
var __dirname = "/home/runner/work/super-agent-cli/super-agent-cli/src/web";
|
|
1141
|
-
var init_server = () => {};
|
|
1142
|
-
|
|
1143
|
-
// src/utils/confirmation-service.ts
|
|
1144
|
-
import { EventEmitter } from "events";
|
|
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
|
|
1158
|
-
};
|
|
1159
|
-
static getInstance() {
|
|
1160
|
-
if (!ConfirmationService.instance) {
|
|
1161
|
-
ConfirmationService.instance = new ConfirmationService;
|
|
1162
|
-
}
|
|
1163
|
-
return ConfirmationService.instance;
|
|
1164
|
-
}
|
|
1165
|
-
constructor() {
|
|
1166
|
-
super();
|
|
1167
|
-
}
|
|
1168
|
-
async requestConfirmation(options, operationType = "file") {
|
|
1169
|
-
if (this.sessionFlags.allOperations || operationType === "file" && this.sessionFlags.fileOperations || operationType === "bash" && this.sessionFlags.bashCommands) {
|
|
1170
|
-
return { confirmed: true };
|
|
1171
|
-
}
|
|
1172
|
-
if (options.showVSCodeOpen) {
|
|
1173
|
-
try {
|
|
1174
|
-
await this.openInVSCode(options.filename);
|
|
1175
|
-
} catch (error) {
|
|
1176
|
-
options.showVSCodeOpen = false;
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1179
|
-
this.pendingConfirmation = new Promise((resolve) => {
|
|
1180
|
-
this.resolveConfirmation = resolve;
|
|
1181
|
-
});
|
|
1182
|
-
setImmediate(() => {
|
|
1183
|
-
this.emit("confirmation-requested", options);
|
|
1184
|
-
});
|
|
1185
|
-
const result = await this.pendingConfirmation;
|
|
1186
|
-
if (result.dontAskAgain) {
|
|
1187
|
-
if (operationType === "file") {
|
|
1188
|
-
this.sessionFlags.fileOperations = true;
|
|
1189
|
-
} else if (operationType === "bash") {
|
|
1190
|
-
this.sessionFlags.bashCommands = true;
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1193
|
-
return result;
|
|
1194
|
-
}
|
|
1195
|
-
confirmOperation(confirmed, dontAskAgain) {
|
|
1196
|
-
if (this.resolveConfirmation) {
|
|
1197
|
-
this.resolveConfirmation({ confirmed, dontAskAgain });
|
|
1198
|
-
this.resolveConfirmation = null;
|
|
1199
|
-
this.pendingConfirmation = null;
|
|
1200
|
-
}
|
|
1201
|
-
}
|
|
1202
|
-
rejectOperation(feedback) {
|
|
1203
|
-
if (this.resolveConfirmation) {
|
|
1204
|
-
this.resolveConfirmation({ confirmed: false, feedback });
|
|
1205
|
-
this.resolveConfirmation = null;
|
|
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
|
-
}
|
|
1219
|
-
}
|
|
1220
|
-
throw new Error("VS Code not found");
|
|
1221
|
-
}
|
|
1222
|
-
isPending() {
|
|
1223
|
-
return this.pendingConfirmation !== null;
|
|
1224
|
-
}
|
|
1225
|
-
resetSession() {
|
|
1226
|
-
this.sessionFlags = {
|
|
1227
|
-
fileOperations: false,
|
|
1228
|
-
bashCommands: false,
|
|
1229
|
-
allOperations: false
|
|
1230
|
-
};
|
|
1231
|
-
}
|
|
1232
|
-
getSessionFlags() {
|
|
1233
|
-
return { ...this.sessionFlags };
|
|
984
|
+
getSessionFlags() {
|
|
985
|
+
return { ...this.sessionFlags };
|
|
1234
986
|
}
|
|
1235
987
|
setSessionFlag(flagType, value) {
|
|
1236
988
|
this.sessionFlags[flagType] = value;
|
|
@@ -8416,45 +8168,844 @@ function ChatInterface({
|
|
|
8416
8168
|
onApiKeySet: handleApiKeySet
|
|
8417
8169
|
}, undefined, false, undefined, this);
|
|
8418
8170
|
}
|
|
8419
|
-
return /* @__PURE__ */ jsxDEV16(ChatInterfaceWithAgent, {
|
|
8420
|
-
agent: currentAgent,
|
|
8421
|
-
initialMessage
|
|
8422
|
-
}, undefined, false, undefined, this);
|
|
8171
|
+
return /* @__PURE__ */ jsxDEV16(ChatInterfaceWithAgent, {
|
|
8172
|
+
agent: currentAgent,
|
|
8173
|
+
initialMessage
|
|
8174
|
+
}, undefined, false, undefined, this);
|
|
8175
|
+
}
|
|
8176
|
+
|
|
8177
|
+
// src/commands/web.ts
|
|
8178
|
+
init_settings_manager();
|
|
8179
|
+
|
|
8180
|
+
// src/web/server.ts
|
|
8181
|
+
import { createServer } from "http";
|
|
8182
|
+
import { WebSocketServer } from "ws";
|
|
8183
|
+
import * as fs15 from "fs-extra";
|
|
8184
|
+
import * as path14 from "path";
|
|
8185
|
+
import open from "open";
|
|
8186
|
+
import mime from "mime";
|
|
8187
|
+
var __dirname = "/home/runner/work/super-agent-cli/super-agent-cli/src/web";
|
|
8188
|
+
|
|
8189
|
+
class WebServer {
|
|
8190
|
+
httpServer;
|
|
8191
|
+
wss;
|
|
8192
|
+
agent;
|
|
8193
|
+
hostname;
|
|
8194
|
+
port;
|
|
8195
|
+
clients = new Set;
|
|
8196
|
+
constructor(options) {
|
|
8197
|
+
this.hostname = options.hostname || "localhost";
|
|
8198
|
+
this.port = options.port || 3000;
|
|
8199
|
+
this.agent = options.agent;
|
|
8200
|
+
this.httpServer = createServer((req, res) => {
|
|
8201
|
+
this.handleHttpRequest(req, res);
|
|
8202
|
+
});
|
|
8203
|
+
this.wss = new WebSocketServer({ server: this.httpServer });
|
|
8204
|
+
this.wss.on("connection", (ws) => {
|
|
8205
|
+
this.handleWebSocketConnection(ws);
|
|
8206
|
+
});
|
|
8207
|
+
}
|
|
8208
|
+
async handleHttpRequest(req, res) {
|
|
8209
|
+
const url = req.url || "/";
|
|
8210
|
+
const requestedPath = url === "/" ? "index.html" : url;
|
|
8211
|
+
const sanitizedPath = requestedPath.split("?")[0].split("#")[0];
|
|
8212
|
+
const clientDir = path14.join(__dirname, "../web/client");
|
|
8213
|
+
const absolutePath = path14.resolve(clientDir, sanitizedPath.substring(1));
|
|
8214
|
+
if (!absolutePath.startsWith(clientDir)) {
|
|
8215
|
+
res.writeHead(403, { "Content-Type": "text/plain" });
|
|
8216
|
+
res.end("Forbidden");
|
|
8217
|
+
return;
|
|
8218
|
+
}
|
|
8219
|
+
try {
|
|
8220
|
+
if (await fs15.pathExists(absolutePath)) {
|
|
8221
|
+
const stat5 = await fs15.stat(absolutePath);
|
|
8222
|
+
let filePath = absolutePath;
|
|
8223
|
+
if (stat5.isDirectory()) {
|
|
8224
|
+
filePath = path14.join(absolutePath, "index.html");
|
|
8225
|
+
}
|
|
8226
|
+
const content = await fs15.readFile(filePath);
|
|
8227
|
+
const mimeType = mime.getType(filePath) || "application/octet-stream";
|
|
8228
|
+
res.writeHead(200, { "Content-Type": mimeType });
|
|
8229
|
+
res.end(content);
|
|
8230
|
+
} else {
|
|
8231
|
+
res.writeHead(404);
|
|
8232
|
+
res.end("Not Found");
|
|
8233
|
+
}
|
|
8234
|
+
} catch (error) {
|
|
8235
|
+
console.error("Error serving file:", error);
|
|
8236
|
+
res.writeHead(500);
|
|
8237
|
+
res.end("Internal Server Error");
|
|
8238
|
+
}
|
|
8239
|
+
}
|
|
8240
|
+
handleWebSocketConnection(ws) {
|
|
8241
|
+
this.clients.add(ws);
|
|
8242
|
+
console.log(`\uD83D\uDCE1 Web client connected (${this.clients.size} total)`);
|
|
8243
|
+
this.checkAndSendUpdateNotification(ws);
|
|
8244
|
+
ws.on("message", async (data) => {
|
|
8245
|
+
try {
|
|
8246
|
+
const message = JSON.parse(data.toString());
|
|
8247
|
+
if (message.type === "prompt") {
|
|
8248
|
+
await this.handlePrompt(message.content, ws);
|
|
8249
|
+
} else if (message.type === "get_file_tree") {
|
|
8250
|
+
await this.handleGetFileTree(ws);
|
|
8251
|
+
} else if (message.type === "get_file_content") {
|
|
8252
|
+
await this.handleGetFileContent(message.path, ws);
|
|
8253
|
+
} else if (message.type === "list_sessions") {
|
|
8254
|
+
await this.handleListSessions(ws);
|
|
8255
|
+
} else if (message.type === "switch_session") {
|
|
8256
|
+
await this.handleSwitchSession(message.sessionId, ws);
|
|
8257
|
+
}
|
|
8258
|
+
} catch (error) {
|
|
8259
|
+
console.error("WebSocket message error:", error);
|
|
8260
|
+
ws.send(JSON.stringify({ type: "error", content: "Invalid message format" }));
|
|
8261
|
+
}
|
|
8262
|
+
});
|
|
8263
|
+
ws.on("close", () => {
|
|
8264
|
+
this.clients.delete(ws);
|
|
8265
|
+
console.log(`\uD83D\uDCE1 Web client disconnected (${this.clients.size} remaining)`);
|
|
8266
|
+
});
|
|
8267
|
+
ws.on("error", (error) => {
|
|
8268
|
+
console.error("WebSocket error:", error);
|
|
8269
|
+
});
|
|
8270
|
+
}
|
|
8271
|
+
async handlePrompt(prompt, ws) {
|
|
8272
|
+
try {
|
|
8273
|
+
ws.send(JSON.stringify({ type: "user_message", content: prompt }));
|
|
8274
|
+
const entries = await this.agent.processUserMessage(prompt);
|
|
8275
|
+
for (const entry of entries) {
|
|
8276
|
+
if (entry.type === "assistant") {
|
|
8277
|
+
ws.send(JSON.stringify({
|
|
8278
|
+
type: "assistant_message",
|
|
8279
|
+
content: entry.content
|
|
8280
|
+
}));
|
|
8281
|
+
} else if (entry.type === "tool_call") {
|
|
8282
|
+
ws.send(JSON.stringify({
|
|
8283
|
+
type: "tool_call",
|
|
8284
|
+
tool: entry.toolCall?.function.name,
|
|
8285
|
+
content: "Executing..."
|
|
8286
|
+
}));
|
|
8287
|
+
} else if (entry.type === "tool_result") {
|
|
8288
|
+
ws.send(JSON.stringify({
|
|
8289
|
+
type: "tool_result",
|
|
8290
|
+
tool: entry.toolCall?.function.name,
|
|
8291
|
+
content: entry.content
|
|
8292
|
+
}));
|
|
8293
|
+
}
|
|
8294
|
+
}
|
|
8295
|
+
ws.send(JSON.stringify({ type: "done" }));
|
|
8296
|
+
} catch (error) {
|
|
8297
|
+
ws.send(JSON.stringify({
|
|
8298
|
+
type: "error",
|
|
8299
|
+
content: error.message
|
|
8300
|
+
}));
|
|
8301
|
+
}
|
|
8302
|
+
}
|
|
8303
|
+
async handleGetFileTree(ws) {
|
|
8304
|
+
try {
|
|
8305
|
+
const { getFileIndexer: getFileIndexer2 } = await Promise.resolve().then(() => (init_indexer(), exports_indexer));
|
|
8306
|
+
const indexer = getFileIndexer2();
|
|
8307
|
+
const index = indexer.getIndex();
|
|
8308
|
+
if (!index) {
|
|
8309
|
+
ws.send(JSON.stringify({ type: "file_tree", tree: [] }));
|
|
8310
|
+
return;
|
|
8311
|
+
}
|
|
8312
|
+
const tree = index.entries.filter((e) => !e.path.includes("node_modules") && !e.path.startsWith(".")).map((e) => ({
|
|
8313
|
+
path: e.path,
|
|
8314
|
+
name: path14.basename(e.path),
|
|
8315
|
+
isDirectory: e.isDirectory,
|
|
8316
|
+
size: e.size
|
|
8317
|
+
})).slice(0, 500);
|
|
8318
|
+
ws.send(JSON.stringify({ type: "file_tree", tree }));
|
|
8319
|
+
} catch (error) {
|
|
8320
|
+
ws.send(JSON.stringify({ type: "error", content: error.message }));
|
|
8321
|
+
}
|
|
8322
|
+
}
|
|
8323
|
+
async handleGetFileContent(filePath, ws) {
|
|
8324
|
+
try {
|
|
8325
|
+
const fullPath = path14.join(process.cwd(), filePath);
|
|
8326
|
+
if (!fullPath.startsWith(process.cwd())) {
|
|
8327
|
+
throw new Error("Access denied");
|
|
8328
|
+
}
|
|
8329
|
+
const content = await fs15.readFile(fullPath, "utf-8");
|
|
8330
|
+
ws.send(JSON.stringify({
|
|
8331
|
+
type: "file_content",
|
|
8332
|
+
path: filePath,
|
|
8333
|
+
content: content.slice(0, 1e4)
|
|
8334
|
+
}));
|
|
8335
|
+
} catch (error) {
|
|
8336
|
+
ws.send(JSON.stringify({ type: "error", content: error.message }));
|
|
8337
|
+
}
|
|
8338
|
+
}
|
|
8339
|
+
async handleListSessions(ws) {
|
|
8340
|
+
try {
|
|
8341
|
+
const { getSessionManager: getSessionManager2 } = await Promise.resolve().then(() => (init_session_manager(), exports_session_manager));
|
|
8342
|
+
const sessionManager = getSessionManager2();
|
|
8343
|
+
const sessions = await sessionManager.listSessions();
|
|
8344
|
+
ws.send(JSON.stringify({
|
|
8345
|
+
type: "sessions_list",
|
|
8346
|
+
sessions: sessions.map((s) => ({
|
|
8347
|
+
id: s.id,
|
|
8348
|
+
name: s.name,
|
|
8349
|
+
workingDirectory: s.workingDirectory,
|
|
8350
|
+
messageCount: s.messages.length,
|
|
8351
|
+
lastAccessed: s.lastAccessed
|
|
8352
|
+
}))
|
|
8353
|
+
}));
|
|
8354
|
+
} catch (error) {
|
|
8355
|
+
ws.send(JSON.stringify({ type: "error", content: error.message }));
|
|
8356
|
+
}
|
|
8357
|
+
}
|
|
8358
|
+
async handleSwitchSession(sessionId, ws) {
|
|
8359
|
+
try {
|
|
8360
|
+
const { getSessionManager: getSessionManager2 } = await Promise.resolve().then(() => (init_session_manager(), exports_session_manager));
|
|
8361
|
+
const sessionManager = getSessionManager2();
|
|
8362
|
+
const session = await sessionManager.switchSession(sessionId);
|
|
8363
|
+
if (session) {
|
|
8364
|
+
ws.send(JSON.stringify({
|
|
8365
|
+
type: "session_switched",
|
|
8366
|
+
session: {
|
|
8367
|
+
id: session.id,
|
|
8368
|
+
name: session.name,
|
|
8369
|
+
workingDirectory: session.workingDirectory,
|
|
8370
|
+
messages: session.messages
|
|
8371
|
+
}
|
|
8372
|
+
}));
|
|
8373
|
+
} else {
|
|
8374
|
+
throw new Error("Session not found");
|
|
8375
|
+
}
|
|
8376
|
+
} catch (error) {
|
|
8377
|
+
ws.send(JSON.stringify({ type: "error", content: error.message }));
|
|
8378
|
+
}
|
|
8379
|
+
}
|
|
8380
|
+
async checkAndSendUpdateNotification(ws) {
|
|
8381
|
+
try {
|
|
8382
|
+
const pkg = await Promise.resolve().then(() => __toESM(require_package(), 1));
|
|
8383
|
+
const { getUpdateChecker: getUpdateChecker2 } = await Promise.resolve().then(() => (init_update_checker(), exports_update_checker));
|
|
8384
|
+
const updateChecker = getUpdateChecker2(pkg.version);
|
|
8385
|
+
const updateInfo = await updateChecker.checkForUpdates();
|
|
8386
|
+
if (updateInfo?.updateAvailable) {
|
|
8387
|
+
ws.send(JSON.stringify({
|
|
8388
|
+
type: "update_available",
|
|
8389
|
+
currentVersion: updateInfo.currentVersion,
|
|
8390
|
+
latestVersion: updateInfo.latestVersion
|
|
8391
|
+
}));
|
|
8392
|
+
}
|
|
8393
|
+
} catch (error) {}
|
|
8394
|
+
}
|
|
8395
|
+
async start() {
|
|
8396
|
+
return new Promise((resolve5, reject) => {
|
|
8397
|
+
this.httpServer.listen(this.port, this.hostname, () => {
|
|
8398
|
+
const url = `http://${this.hostname}:${this.port}`;
|
|
8399
|
+
console.log(`\uD83C\uDF10 Web interface available at ${url}`);
|
|
8400
|
+
resolve5();
|
|
8401
|
+
});
|
|
8402
|
+
this.httpServer.on("error", (error) => {
|
|
8403
|
+
reject(error);
|
|
8404
|
+
});
|
|
8405
|
+
});
|
|
8406
|
+
}
|
|
8407
|
+
async openBrowser() {
|
|
8408
|
+
const url = `http://${this.hostname}:${this.port}`;
|
|
8409
|
+
try {
|
|
8410
|
+
await open(url);
|
|
8411
|
+
console.log(`\uD83D\uDE80 Opened browser at ${url}`);
|
|
8412
|
+
} catch (error) {
|
|
8413
|
+
console.warn(`Could not open browser automatically. Please visit ${url}`);
|
|
8414
|
+
}
|
|
8415
|
+
}
|
|
8416
|
+
stop() {
|
|
8417
|
+
this.clients.forEach((client) => {
|
|
8418
|
+
client.close();
|
|
8419
|
+
});
|
|
8420
|
+
this.wss.close();
|
|
8421
|
+
this.httpServer.close();
|
|
8422
|
+
console.log("\uD83D\uDED1 Web server stopped");
|
|
8423
|
+
}
|
|
8424
|
+
}
|
|
8425
|
+
|
|
8426
|
+
// src/commands/web.ts
|
|
8427
|
+
import { Command } from "commander";
|
|
8428
|
+
import chalk from "chalk";
|
|
8429
|
+
function createWebCommand() {
|
|
8430
|
+
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) => {
|
|
8431
|
+
const port = parseInt(options.port);
|
|
8432
|
+
const settingsManager = getSettingsManager();
|
|
8433
|
+
const apiKey = settingsManager.getApiKey();
|
|
8434
|
+
const baseURL = settingsManager.getBaseURL() || "https://api.openai.com/v1";
|
|
8435
|
+
const model = settingsManager.getCurrentModel();
|
|
8436
|
+
if (!apiKey) {
|
|
8437
|
+
console.error(chalk.red("API Key not found. Please configure it first."));
|
|
8438
|
+
process.exit(1);
|
|
8439
|
+
}
|
|
8440
|
+
console.log(chalk.blue(`Starting web server on port ${port}...`));
|
|
8441
|
+
const agent = new SuperAgent(apiKey, baseURL, model);
|
|
8442
|
+
const server = new WebServer({
|
|
8443
|
+
port,
|
|
8444
|
+
agent,
|
|
8445
|
+
openBrowser: options.browser
|
|
8446
|
+
});
|
|
8447
|
+
try {
|
|
8448
|
+
await server.start();
|
|
8449
|
+
if (options.browser) {
|
|
8450
|
+
await server.openBrowser();
|
|
8451
|
+
}
|
|
8452
|
+
process.on("SIGINT", () => {
|
|
8453
|
+
console.log(chalk.yellow(`
|
|
8454
|
+
Stopping server...`));
|
|
8455
|
+
server.stop();
|
|
8456
|
+
process.exit(0);
|
|
8457
|
+
});
|
|
8458
|
+
} catch (error) {
|
|
8459
|
+
console.error(chalk.red(`Failed to start server: ${error.message}`));
|
|
8460
|
+
process.exit(1);
|
|
8461
|
+
}
|
|
8462
|
+
});
|
|
8463
|
+
return webCommand;
|
|
8464
|
+
}
|
|
8465
|
+
function createServeCommand() {
|
|
8466
|
+
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) => {
|
|
8467
|
+
console.log(chalk.yellow("Serve mode is currently an alias for 'web' mode with background persistence capabilities."));
|
|
8468
|
+
const port = parseInt(options.port);
|
|
8469
|
+
const settingsManager = getSettingsManager();
|
|
8470
|
+
const apiKey = settingsManager.getApiKey();
|
|
8471
|
+
if (!apiKey) {
|
|
8472
|
+
console.error(chalk.red("API Key not found."));
|
|
8473
|
+
process.exit(1);
|
|
8474
|
+
}
|
|
8475
|
+
const agent = new SuperAgent(apiKey, settingsManager.getBaseURL() || "", settingsManager.getCurrentModel());
|
|
8476
|
+
const server = new WebServer({ port, agent, openBrowser: true });
|
|
8477
|
+
await server.start();
|
|
8478
|
+
await server.openBrowser();
|
|
8479
|
+
});
|
|
8480
|
+
return serveCommand;
|
|
8481
|
+
}
|
|
8482
|
+
|
|
8483
|
+
// src/commands/index-cmd.ts
|
|
8484
|
+
import { Command as Command2 } from "commander";
|
|
8485
|
+
import fs16 from "fs/promises";
|
|
8486
|
+
import ignore from "ignore";
|
|
8487
|
+
import chalk2 from "chalk";
|
|
8488
|
+
import path15 from "path";
|
|
8489
|
+
var DEFAULT_IGNORES = [
|
|
8490
|
+
"node_modules",
|
|
8491
|
+
".git",
|
|
8492
|
+
"dist",
|
|
8493
|
+
"build",
|
|
8494
|
+
"coverage",
|
|
8495
|
+
".env",
|
|
8496
|
+
"*.log",
|
|
8497
|
+
".DS_Store",
|
|
8498
|
+
"Thumbs.db"
|
|
8499
|
+
];
|
|
8500
|
+
function createIndexCommand() {
|
|
8501
|
+
const indexCommand = new Command2("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) => {
|
|
8502
|
+
try {
|
|
8503
|
+
const rootDir = path15.resolve(directory);
|
|
8504
|
+
const outputFile2 = options.output ? path15.resolve(options.output) : path15.join(rootDir, "index.md");
|
|
8505
|
+
const maxDepth = parseInt(options.depth);
|
|
8506
|
+
console.log(chalk2.blue(`Indexing directory: ${rootDir}`));
|
|
8507
|
+
const ig = ignore().add(DEFAULT_IGNORES);
|
|
8508
|
+
if (options.ignore !== false) {
|
|
8509
|
+
try {
|
|
8510
|
+
const gitignorePath = path15.join(rootDir, ".gitignore");
|
|
8511
|
+
const gitignoreContent = await fs16.readFile(gitignorePath, "utf-8");
|
|
8512
|
+
ig.add(gitignoreContent);
|
|
8513
|
+
} catch (e) {}
|
|
8514
|
+
}
|
|
8515
|
+
let outputContent = `# Directory Index
|
|
8516
|
+
|
|
8517
|
+
Generated for: ${rootDir}
|
|
8518
|
+
Date: ${new Date().toISOString()}
|
|
8519
|
+
|
|
8520
|
+
`;
|
|
8521
|
+
outputContent += "## File Structure\n\n```\n";
|
|
8522
|
+
async function buildTree(currentPath, depth, prefix = "") {
|
|
8523
|
+
if (depth > maxDepth) {
|
|
8524
|
+
return;
|
|
8525
|
+
}
|
|
8526
|
+
const relativePath = path15.relative(rootDir, currentPath);
|
|
8527
|
+
if (relativePath && ig.ignores(relativePath)) {
|
|
8528
|
+
return;
|
|
8529
|
+
}
|
|
8530
|
+
const stats = await fs16.stat(currentPath);
|
|
8531
|
+
const isDir = stats.isDirectory();
|
|
8532
|
+
const name = path15.basename(currentPath);
|
|
8533
|
+
if (isDir) {
|
|
8534
|
+
if (relativePath) {
|
|
8535
|
+
outputContent += `${prefix}${name}/
|
|
8536
|
+
`;
|
|
8537
|
+
}
|
|
8538
|
+
const entries = await fs16.readdir(currentPath, {
|
|
8539
|
+
withFileTypes: true
|
|
8540
|
+
});
|
|
8541
|
+
const sortedEntries = entries.sort((a, b) => {
|
|
8542
|
+
if (a.isDirectory() && !b.isDirectory()) {
|
|
8543
|
+
return -1;
|
|
8544
|
+
}
|
|
8545
|
+
if (!a.isDirectory() && b.isDirectory()) {
|
|
8546
|
+
return 1;
|
|
8547
|
+
}
|
|
8548
|
+
return a.name.localeCompare(b.name);
|
|
8549
|
+
});
|
|
8550
|
+
for (let i = 0;i < sortedEntries.length; i++) {
|
|
8551
|
+
const entry = sortedEntries[i];
|
|
8552
|
+
const isLast = i === sortedEntries.length - 1;
|
|
8553
|
+
const newPrefix = relativePath ? prefix + " " : "";
|
|
8554
|
+
await buildTree(path15.join(currentPath, entry.name), depth + 1, newPrefix);
|
|
8555
|
+
}
|
|
8556
|
+
} else {
|
|
8557
|
+
outputContent += `${prefix}${name}
|
|
8558
|
+
`;
|
|
8559
|
+
}
|
|
8560
|
+
}
|
|
8561
|
+
const files = [];
|
|
8562
|
+
async function walk(dir, currentDepth) {
|
|
8563
|
+
if (currentDepth > maxDepth) {
|
|
8564
|
+
return;
|
|
8565
|
+
}
|
|
8566
|
+
const entries = await fs16.readdir(dir, { withFileTypes: true });
|
|
8567
|
+
for (const entry of entries) {
|
|
8568
|
+
const fullPath = path15.join(dir, entry.name);
|
|
8569
|
+
const relPath = path15.relative(rootDir, fullPath);
|
|
8570
|
+
if (ig.ignores(relPath)) {
|
|
8571
|
+
continue;
|
|
8572
|
+
}
|
|
8573
|
+
if (entry.isDirectory()) {
|
|
8574
|
+
await walk(fullPath, currentDepth + 1);
|
|
8575
|
+
} else {
|
|
8576
|
+
files.push(relPath);
|
|
8577
|
+
}
|
|
8578
|
+
}
|
|
8579
|
+
}
|
|
8580
|
+
await walk(rootDir, 0);
|
|
8581
|
+
console.log(chalk2.blue(`Found ${files.length} files.`));
|
|
8582
|
+
outputContent = `# Project Index: ${path15.basename(rootDir)}
|
|
8583
|
+
|
|
8584
|
+
`;
|
|
8585
|
+
outputContent += `Total Files: ${files.length}
|
|
8586
|
+
|
|
8587
|
+
`;
|
|
8588
|
+
outputContent += `## Files
|
|
8589
|
+
|
|
8590
|
+
`;
|
|
8591
|
+
for (const file of files) {
|
|
8592
|
+
outputContent += `### ${file}
|
|
8593
|
+
`;
|
|
8594
|
+
const stats = await fs16.stat(path15.join(rootDir, file));
|
|
8595
|
+
outputContent += `- Size: ${stats.size} bytes
|
|
8596
|
+
`;
|
|
8597
|
+
outputContent += `- Modified: ${stats.mtime.toISOString()}
|
|
8598
|
+
|
|
8599
|
+
`;
|
|
8600
|
+
}
|
|
8601
|
+
await fs16.writeFile(outputFile2, outputContent);
|
|
8602
|
+
console.log(chalk2.green(`✓ Index generated at: ${outputFile2}`));
|
|
8603
|
+
} catch (error) {
|
|
8604
|
+
console.error(chalk2.red(`Error indexing directory: ${error.message}`));
|
|
8605
|
+
process.exit(1);
|
|
8606
|
+
}
|
|
8607
|
+
});
|
|
8608
|
+
return indexCommand;
|
|
8609
|
+
}
|
|
8610
|
+
|
|
8611
|
+
// src/commands/plugins.ts
|
|
8612
|
+
init_settings_manager();
|
|
8613
|
+
import { Command as Command3 } from "commander";
|
|
8614
|
+
function createPluginsCommand() {
|
|
8615
|
+
const pluginsCommand = new Command3("plugins").description("Manage plugins for Super Agent CLI").argument("[action]", "Action to perform (list, install, uninstall)").argument("[target]", "Plugin name or path");
|
|
8616
|
+
pluginsCommand.command("list").description("List installed plugins").action(() => {
|
|
8617
|
+
const manager = getSettingsManager();
|
|
8618
|
+
const settings = manager.loadUserSettings();
|
|
8619
|
+
const plugins = settings.plugins || [];
|
|
8620
|
+
if (plugins.length === 0) {
|
|
8621
|
+
console.log("No plugins installed.");
|
|
8622
|
+
return;
|
|
8623
|
+
}
|
|
8624
|
+
console.log("Installed plugins:");
|
|
8625
|
+
plugins.forEach((p) => console.log(`- ${p}`));
|
|
8626
|
+
});
|
|
8627
|
+
pluginsCommand.command("install <path>").description("Install a plugin from a path, GitHub URL, or registry").action(async (path16) => {
|
|
8628
|
+
try {
|
|
8629
|
+
const manager = PluginManager.getInstance();
|
|
8630
|
+
console.log(`Installing plugin from: ${path16}...`);
|
|
8631
|
+
const installedPath = await manager.installPlugin(path16);
|
|
8632
|
+
console.log(`✅ Plugin installed successfully: ${installedPath}`);
|
|
8633
|
+
} catch (error) {
|
|
8634
|
+
console.error(`❌ Error installing plugin: ${error.message}`);
|
|
8635
|
+
process.exit(1);
|
|
8636
|
+
}
|
|
8637
|
+
});
|
|
8638
|
+
pluginsCommand.command("uninstall <path>").description("Uninstall a plugin").action(async (path16) => {
|
|
8639
|
+
try {
|
|
8640
|
+
const manager = PluginManager.getInstance();
|
|
8641
|
+
await manager.removePlugin(path16);
|
|
8642
|
+
console.log(`✅ Plugin uninstalled: ${path16}`);
|
|
8643
|
+
} catch (error) {
|
|
8644
|
+
console.error(`❌ Error uninstalling plugin: ${error.message}`);
|
|
8645
|
+
process.exit(1);
|
|
8646
|
+
}
|
|
8647
|
+
});
|
|
8648
|
+
return pluginsCommand;
|
|
8649
|
+
}
|
|
8650
|
+
|
|
8651
|
+
// src/commands/skills.ts
|
|
8652
|
+
init_settings_manager();
|
|
8653
|
+
|
|
8654
|
+
// src/skills/manager.ts
|
|
8655
|
+
init_settings_manager();
|
|
8656
|
+
import fs17 from "fs/promises";
|
|
8657
|
+
import path16 from "path";
|
|
8658
|
+
|
|
8659
|
+
class SkillsManager {
|
|
8660
|
+
static instance;
|
|
8661
|
+
skillsPath;
|
|
8662
|
+
constructor() {
|
|
8663
|
+
this.skillsPath = path16.join(getSettingsManager().getStorageDirectory(), "skills");
|
|
8664
|
+
}
|
|
8665
|
+
static getInstance() {
|
|
8666
|
+
if (!SkillsManager.instance) {
|
|
8667
|
+
SkillsManager.instance = new SkillsManager;
|
|
8668
|
+
}
|
|
8669
|
+
return SkillsManager.instance;
|
|
8670
|
+
}
|
|
8671
|
+
async ensureSkillsDirectory() {
|
|
8672
|
+
try {
|
|
8673
|
+
await fs17.mkdir(this.skillsPath, { recursive: true });
|
|
8674
|
+
} catch (error) {}
|
|
8675
|
+
}
|
|
8676
|
+
async listSkills() {
|
|
8677
|
+
await this.ensureSkillsDirectory();
|
|
8678
|
+
try {
|
|
8679
|
+
const files = await fs17.readdir(this.skillsPath);
|
|
8680
|
+
return files.filter((file) => file.endsWith(".ts") || file.endsWith(".js") || file.endsWith(".json")).map((file) => path16.parse(file).name);
|
|
8681
|
+
} catch (error) {
|
|
8682
|
+
return [];
|
|
8683
|
+
}
|
|
8684
|
+
}
|
|
8685
|
+
async getSkillPath(name) {
|
|
8686
|
+
const extensions = [".ts", ".js", ".json"];
|
|
8687
|
+
for (const ext of extensions) {
|
|
8688
|
+
const fullPath = path16.join(this.skillsPath, `${name}${ext}`);
|
|
8689
|
+
try {
|
|
8690
|
+
await fs17.access(fullPath);
|
|
8691
|
+
return fullPath;
|
|
8692
|
+
} catch {
|
|
8693
|
+
continue;
|
|
8694
|
+
}
|
|
8695
|
+
}
|
|
8696
|
+
throw new Error(`Skill '${name}' not found`);
|
|
8697
|
+
}
|
|
8698
|
+
async getSkillContent(name) {
|
|
8699
|
+
const skillPath = await this.getSkillPath(name);
|
|
8700
|
+
return await fs17.readFile(skillPath, "utf-8");
|
|
8701
|
+
}
|
|
8702
|
+
async createSkill(name, description, agent) {
|
|
8703
|
+
await this.ensureSkillsDirectory();
|
|
8704
|
+
const prompt = `Create a robust TypeScript skill for the Super Agent CLI named "${name}".
|
|
8705
|
+
|
|
8706
|
+
Description: ${description}
|
|
8707
|
+
|
|
8708
|
+
The skill should be a module that exports a default function or class that implements the desired functionality.
|
|
8709
|
+
It should valid standalone TypeScript code.
|
|
8710
|
+
Include comments explaining how it works.
|
|
8711
|
+
|
|
8712
|
+
Structure:
|
|
8713
|
+
\`\`\`typescript
|
|
8714
|
+
// ${name} skill
|
|
8715
|
+
export default async function(args: any) {
|
|
8716
|
+
// implementation
|
|
8717
|
+
}
|
|
8718
|
+
\`\`\`
|
|
8719
|
+
|
|
8720
|
+
Return ONLY the code block.`;
|
|
8721
|
+
const response = await agent.processUserMessage(prompt);
|
|
8722
|
+
let code = "";
|
|
8723
|
+
for (const entry of response) {
|
|
8724
|
+
if (entry.type === "assistant") {
|
|
8725
|
+
const match = entry.content.match(/```(?:typescript|ts)?\n([\s\S]*?)```/);
|
|
8726
|
+
if (match) {
|
|
8727
|
+
code = match[1];
|
|
8728
|
+
break;
|
|
8729
|
+
} else {
|
|
8730
|
+
code = entry.content;
|
|
8731
|
+
}
|
|
8732
|
+
}
|
|
8733
|
+
}
|
|
8734
|
+
if (!code) {
|
|
8735
|
+
throw new Error("Failed to generate skill code");
|
|
8736
|
+
}
|
|
8737
|
+
const filePath = path16.join(this.skillsPath, `${name}.ts`);
|
|
8738
|
+
await fs17.writeFile(filePath, code);
|
|
8739
|
+
}
|
|
8740
|
+
async deleteSkill(name) {
|
|
8741
|
+
try {
|
|
8742
|
+
const skillPath = await this.getSkillPath(name);
|
|
8743
|
+
await fs17.unlink(skillPath);
|
|
8744
|
+
} catch (error) {
|
|
8745
|
+
throw new Error(`Failed to delete skill '${name}': ${error.message}`);
|
|
8746
|
+
}
|
|
8747
|
+
}
|
|
8748
|
+
}
|
|
8749
|
+
|
|
8750
|
+
// src/commands/skills.ts
|
|
8751
|
+
import { Command as Command4 } from "commander";
|
|
8752
|
+
import inquirer from "inquirer";
|
|
8753
|
+
import chalk3 from "chalk";
|
|
8754
|
+
function createSkillsCommand() {
|
|
8755
|
+
const skillsCommand = new Command4("skills").description("Manage AI skills");
|
|
8756
|
+
skillsCommand.command("list").description("List available skills").action(async () => {
|
|
8757
|
+
const manager = SkillsManager.getInstance();
|
|
8758
|
+
const skills = await manager.listSkills();
|
|
8759
|
+
if (skills.length === 0) {
|
|
8760
|
+
console.log("No skills found.");
|
|
8761
|
+
} else {
|
|
8762
|
+
console.log("Available skills:");
|
|
8763
|
+
skills.forEach((skill) => console.log(`- ${skill}`));
|
|
8764
|
+
}
|
|
8765
|
+
});
|
|
8766
|
+
skillsCommand.command("create <name>").description("Create a new skill with AI assistance").option("-d, --description <description>", "Description of the skill").action(async (name, options) => {
|
|
8767
|
+
try {
|
|
8768
|
+
const manager = SkillsManager.getInstance();
|
|
8769
|
+
const settingsManager = getSettingsManager();
|
|
8770
|
+
let description = options.description;
|
|
8771
|
+
if (!description) {
|
|
8772
|
+
const answer = await inquirer.prompt([
|
|
8773
|
+
{
|
|
8774
|
+
type: "input",
|
|
8775
|
+
name: "description",
|
|
8776
|
+
message: "Describe what this skill should do:"
|
|
8777
|
+
}
|
|
8778
|
+
]);
|
|
8779
|
+
description = answer.description;
|
|
8780
|
+
}
|
|
8781
|
+
console.log(chalk3.blue(`Generating skill '${name}' based on description: "${description}"...`));
|
|
8782
|
+
const apiKey = settingsManager.getApiKey();
|
|
8783
|
+
const baseURL = settingsManager.getBaseURL();
|
|
8784
|
+
const model = settingsManager.getCurrentModel();
|
|
8785
|
+
if (!apiKey) {
|
|
8786
|
+
console.error(chalk3.red("API Key not found. Please configure it first."));
|
|
8787
|
+
return;
|
|
8788
|
+
}
|
|
8789
|
+
const agent = new SuperAgent(apiKey, baseURL, model);
|
|
8790
|
+
await manager.createSkill(name, description, agent);
|
|
8791
|
+
console.log(chalk3.green(`✓ Skill '${name}' created successfully.`));
|
|
8792
|
+
} catch (error) {
|
|
8793
|
+
console.error(chalk3.red(`Error creating skill: ${error.message}`));
|
|
8794
|
+
}
|
|
8795
|
+
});
|
|
8796
|
+
skillsCommand.command("delete <name>").description("Delete a skill").action(async (name) => {
|
|
8797
|
+
try {
|
|
8798
|
+
const manager = SkillsManager.getInstance();
|
|
8799
|
+
await manager.deleteSkill(name);
|
|
8800
|
+
console.log(chalk3.green(`✓ Skill '${name}' deleted.`));
|
|
8801
|
+
} catch (error) {
|
|
8802
|
+
console.error(chalk3.red(`Error deleting skill: ${error.message}`));
|
|
8803
|
+
}
|
|
8804
|
+
});
|
|
8805
|
+
return skillsCommand;
|
|
8806
|
+
}
|
|
8807
|
+
|
|
8808
|
+
// src/commands/agents.ts
|
|
8809
|
+
init_settings_manager();
|
|
8810
|
+
|
|
8811
|
+
// src/agents/manager.ts
|
|
8812
|
+
init_settings_manager();
|
|
8813
|
+
import fs18 from "fs/promises";
|
|
8814
|
+
import path17 from "path";
|
|
8815
|
+
|
|
8816
|
+
class AgentsManager {
|
|
8817
|
+
static instance;
|
|
8818
|
+
agentsPath;
|
|
8819
|
+
constructor() {
|
|
8820
|
+
this.agentsPath = path17.join(getSettingsManager().getStorageDirectory(), "agents");
|
|
8821
|
+
}
|
|
8822
|
+
static getInstance() {
|
|
8823
|
+
if (!AgentsManager.instance) {
|
|
8824
|
+
AgentsManager.instance = new AgentsManager;
|
|
8825
|
+
}
|
|
8826
|
+
return AgentsManager.instance;
|
|
8827
|
+
}
|
|
8828
|
+
async ensureAgentsDirectory() {
|
|
8829
|
+
try {
|
|
8830
|
+
await fs18.mkdir(this.agentsPath, { recursive: true });
|
|
8831
|
+
} catch (error) {}
|
|
8832
|
+
}
|
|
8833
|
+
async listAgents() {
|
|
8834
|
+
await this.ensureAgentsDirectory();
|
|
8835
|
+
try {
|
|
8836
|
+
const files = await fs18.readdir(this.agentsPath);
|
|
8837
|
+
const agents = [];
|
|
8838
|
+
for (const file of files) {
|
|
8839
|
+
if (file.endsWith(".json")) {
|
|
8840
|
+
try {
|
|
8841
|
+
const content = await fs18.readFile(path17.join(this.agentsPath, file), "utf-8");
|
|
8842
|
+
agents.push(JSON.parse(content));
|
|
8843
|
+
} catch (e) {}
|
|
8844
|
+
}
|
|
8845
|
+
}
|
|
8846
|
+
return agents;
|
|
8847
|
+
} catch (error) {
|
|
8848
|
+
return [];
|
|
8849
|
+
}
|
|
8850
|
+
}
|
|
8851
|
+
async getAgent(name) {
|
|
8852
|
+
try {
|
|
8853
|
+
const content = await fs18.readFile(path17.join(this.agentsPath, `${name}.json`), "utf-8");
|
|
8854
|
+
return JSON.parse(content);
|
|
8855
|
+
} catch (error) {
|
|
8856
|
+
return null;
|
|
8857
|
+
}
|
|
8858
|
+
}
|
|
8859
|
+
async createAgent(config) {
|
|
8860
|
+
await this.ensureAgentsDirectory();
|
|
8861
|
+
const filePath = path17.join(this.agentsPath, `${config.name}.json`);
|
|
8862
|
+
await fs18.writeFile(filePath, JSON.stringify(config, null, 2));
|
|
8863
|
+
}
|
|
8864
|
+
async generateAgent(name, description, agent) {
|
|
8865
|
+
const prompt = `Create a configuration for an AI agent named "${name}" based on this description: "${description}".
|
|
8866
|
+
|
|
8867
|
+
The configuration should be a JSON object matching this interface:
|
|
8868
|
+
interface AgentConfig {
|
|
8869
|
+
name: string;
|
|
8870
|
+
role: string;
|
|
8871
|
+
description: string;
|
|
8872
|
+
model?: string; // suggest a model if appropriate, or leave undefined
|
|
8873
|
+
tools?: string[]; // suggest relevant tools/skills names
|
|
8874
|
+
temperature?: number;
|
|
8875
|
+
systemPrompt?: string; // a detailed system prompt for this agent
|
|
8876
|
+
}
|
|
8877
|
+
|
|
8878
|
+
Return ONLY the JSON object.`;
|
|
8879
|
+
const response = await agent.processUserMessage(prompt);
|
|
8880
|
+
let jsonData = "";
|
|
8881
|
+
for (const entry of response) {
|
|
8882
|
+
if (entry.type === "assistant") {
|
|
8883
|
+
const match = entry.content.match(/```(?:json)?\n([\s\S]*?)```/);
|
|
8884
|
+
if (match) {
|
|
8885
|
+
jsonData = match[1];
|
|
8886
|
+
break;
|
|
8887
|
+
} else {
|
|
8888
|
+
if (entry.content.trim().startsWith("{")) {
|
|
8889
|
+
jsonData = entry.content;
|
|
8890
|
+
}
|
|
8891
|
+
}
|
|
8892
|
+
}
|
|
8893
|
+
}
|
|
8894
|
+
if (!jsonData) {
|
|
8895
|
+
throw new Error("Failed to generate agent configuration");
|
|
8896
|
+
}
|
|
8897
|
+
try {
|
|
8898
|
+
const config = JSON.parse(jsonData);
|
|
8899
|
+
config.name = name;
|
|
8900
|
+
await this.createAgent(config);
|
|
8901
|
+
} catch (e) {
|
|
8902
|
+
throw new Error(`Failed to parse generated agent config: ${e.message}`);
|
|
8903
|
+
}
|
|
8904
|
+
}
|
|
8905
|
+
async deleteAgent(name) {
|
|
8906
|
+
try {
|
|
8907
|
+
const filePath = path17.join(this.agentsPath, `${name}.json`);
|
|
8908
|
+
await fs18.unlink(filePath);
|
|
8909
|
+
} catch (error) {
|
|
8910
|
+
throw new Error(`Failed to delete agent '${name}'`);
|
|
8911
|
+
}
|
|
8912
|
+
}
|
|
8913
|
+
}
|
|
8914
|
+
|
|
8915
|
+
// src/commands/agents.ts
|
|
8916
|
+
import { Command as Command5 } from "commander";
|
|
8917
|
+
import inquirer2 from "inquirer";
|
|
8918
|
+
import chalk4 from "chalk";
|
|
8919
|
+
function createAgentsCommand() {
|
|
8920
|
+
const agentsCommand = new Command5("agents").description("Manage AI agents");
|
|
8921
|
+
agentsCommand.command("list").description("List available agents").action(async () => {
|
|
8922
|
+
const manager = AgentsManager.getInstance();
|
|
8923
|
+
const agents = await manager.listAgents();
|
|
8924
|
+
if (agents.length === 0) {
|
|
8925
|
+
console.log("No agents found.");
|
|
8926
|
+
} else {
|
|
8927
|
+
console.log("Available agents:");
|
|
8928
|
+
agents.forEach((agent) => {
|
|
8929
|
+
console.log(`- ${chalk4.bold(agent.name)} (${agent.role})`);
|
|
8930
|
+
console.log(` ${chalk4.dim(agent.description)}`);
|
|
8931
|
+
});
|
|
8932
|
+
}
|
|
8933
|
+
});
|
|
8934
|
+
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) => {
|
|
8935
|
+
try {
|
|
8936
|
+
const manager = AgentsManager.getInstance();
|
|
8937
|
+
const settingsManager = getSettingsManager();
|
|
8938
|
+
let description = options.description;
|
|
8939
|
+
if (!description) {
|
|
8940
|
+
const answer = await inquirer2.prompt([
|
|
8941
|
+
{
|
|
8942
|
+
type: "input",
|
|
8943
|
+
name: "description",
|
|
8944
|
+
message: "Describe the agent's role and purpose:"
|
|
8945
|
+
}
|
|
8946
|
+
]);
|
|
8947
|
+
description = answer.description;
|
|
8948
|
+
}
|
|
8949
|
+
console.log(chalk4.blue(`Generating agent configuration for '${name}'...`));
|
|
8950
|
+
const apiKey = settingsManager.getApiKey();
|
|
8951
|
+
const baseURL = settingsManager.getBaseURL();
|
|
8952
|
+
const model = settingsManager.getCurrentModel();
|
|
8953
|
+
if (!apiKey) {
|
|
8954
|
+
console.error(chalk4.red("API Key not found. Please configure it first."));
|
|
8955
|
+
return;
|
|
8956
|
+
}
|
|
8957
|
+
const agent = new SuperAgent(apiKey, baseURL, model);
|
|
8958
|
+
await manager.generateAgent(name, description, agent);
|
|
8959
|
+
console.log(chalk4.green(`✓ Agent '${name}' created successfully.`));
|
|
8960
|
+
} catch (error) {
|
|
8961
|
+
console.error(chalk4.red(`Error creating agent: ${error.message}`));
|
|
8962
|
+
}
|
|
8963
|
+
});
|
|
8964
|
+
agentsCommand.command("delete <name>").description("Delete an agent").action(async (name) => {
|
|
8965
|
+
try {
|
|
8966
|
+
const manager = AgentsManager.getInstance();
|
|
8967
|
+
await manager.deleteAgent(name);
|
|
8968
|
+
console.log(chalk4.green(`✓ Agent '${name}' deleted.`));
|
|
8969
|
+
} catch (error) {
|
|
8970
|
+
console.error(chalk4.red(`Error deleting agent: ${error.message}`));
|
|
8971
|
+
}
|
|
8972
|
+
});
|
|
8973
|
+
return agentsCommand;
|
|
8423
8974
|
}
|
|
8424
8975
|
|
|
8425
8976
|
// src/commands/mcp.ts
|
|
8426
8977
|
init_config();
|
|
8427
|
-
import { Command } from "commander";
|
|
8428
|
-
import
|
|
8978
|
+
import { Command as Command6 } from "commander";
|
|
8979
|
+
import chalk5 from "chalk";
|
|
8429
8980
|
function createMCPCommand() {
|
|
8430
|
-
const mcpCommand = new
|
|
8981
|
+
const mcpCommand = new Command6("mcp");
|
|
8431
8982
|
mcpCommand.description("Manage MCP (Model Context Protocol) servers");
|
|
8432
8983
|
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
8984
|
try {
|
|
8434
8985
|
if (PREDEFINED_SERVERS[name]) {
|
|
8435
8986
|
const config2 = PREDEFINED_SERVERS[name];
|
|
8436
8987
|
addMCPServer(config2);
|
|
8437
|
-
console.log(
|
|
8988
|
+
console.log(chalk5.green(`✓ Added predefined MCP server: ${name}`));
|
|
8438
8989
|
const manager2 = getMCPManager();
|
|
8439
8990
|
await manager2.addServer(config2);
|
|
8440
|
-
console.log(
|
|
8991
|
+
console.log(chalk5.green(`✓ Connected to MCP server: ${name}`));
|
|
8441
8992
|
const tools2 = manager2.getTools().filter((t) => t.serverName === name);
|
|
8442
|
-
console.log(
|
|
8993
|
+
console.log(chalk5.blue(` Available tools: ${tools2.length}`));
|
|
8443
8994
|
return;
|
|
8444
8995
|
}
|
|
8445
8996
|
const transportType = options.transport.toLowerCase();
|
|
8446
8997
|
if (transportType === "stdio") {
|
|
8447
8998
|
if (!options.command) {
|
|
8448
|
-
console.error(
|
|
8999
|
+
console.error(chalk5.red("Error: --command is required for stdio transport"));
|
|
8449
9000
|
process.exit(1);
|
|
8450
9001
|
}
|
|
8451
9002
|
} else if (transportType === "http" || transportType === "sse" || transportType === "streamable_http") {
|
|
8452
9003
|
if (!options.url) {
|
|
8453
|
-
console.error(
|
|
9004
|
+
console.error(chalk5.red(`Error: --url is required for ${transportType} transport`));
|
|
8454
9005
|
process.exit(1);
|
|
8455
9006
|
}
|
|
8456
9007
|
} else {
|
|
8457
|
-
console.error(
|
|
9008
|
+
console.error(chalk5.red("Error: Transport type must be stdio, http, sse, or streamable_http"));
|
|
8458
9009
|
process.exit(1);
|
|
8459
9010
|
}
|
|
8460
9011
|
const env = {};
|
|
@@ -8483,14 +9034,14 @@ function createMCPCommand() {
|
|
|
8483
9034
|
}
|
|
8484
9035
|
};
|
|
8485
9036
|
addMCPServer(config);
|
|
8486
|
-
console.log(
|
|
9037
|
+
console.log(chalk5.green(`✓ Added MCP server: ${name}`));
|
|
8487
9038
|
const manager = getMCPManager();
|
|
8488
9039
|
await manager.addServer(config);
|
|
8489
|
-
console.log(
|
|
9040
|
+
console.log(chalk5.green(`✓ Connected to MCP server: ${name}`));
|
|
8490
9041
|
const tools = manager.getTools().filter((t) => t.serverName === name);
|
|
8491
|
-
console.log(
|
|
9042
|
+
console.log(chalk5.blue(` Available tools: ${tools.length}`));
|
|
8492
9043
|
} catch (error) {
|
|
8493
|
-
console.error(
|
|
9044
|
+
console.error(chalk5.red(`Error adding MCP server: ${error.message}`));
|
|
8494
9045
|
process.exit(1);
|
|
8495
9046
|
}
|
|
8496
9047
|
});
|
|
@@ -8500,7 +9051,7 @@ function createMCPCommand() {
|
|
|
8500
9051
|
try {
|
|
8501
9052
|
config = JSON.parse(jsonConfig);
|
|
8502
9053
|
} catch (error) {
|
|
8503
|
-
console.error(
|
|
9054
|
+
console.error(chalk5.red("Error: Invalid JSON configuration"));
|
|
8504
9055
|
process.exit(1);
|
|
8505
9056
|
}
|
|
8506
9057
|
const serverConfig = {
|
|
@@ -8525,14 +9076,14 @@ function createMCPCommand() {
|
|
|
8525
9076
|
}
|
|
8526
9077
|
}
|
|
8527
9078
|
addMCPServer(serverConfig);
|
|
8528
|
-
console.log(
|
|
9079
|
+
console.log(chalk5.green(`✓ Added MCP server: ${name}`));
|
|
8529
9080
|
const manager = getMCPManager();
|
|
8530
9081
|
await manager.addServer(serverConfig);
|
|
8531
|
-
console.log(
|
|
9082
|
+
console.log(chalk5.green(`✓ Connected to MCP server: ${name}`));
|
|
8532
9083
|
const tools = manager.getTools().filter((t) => t.serverName === name);
|
|
8533
|
-
console.log(
|
|
9084
|
+
console.log(chalk5.blue(` Available tools: ${tools.length}`));
|
|
8534
9085
|
} catch (error) {
|
|
8535
|
-
console.error(
|
|
9086
|
+
console.error(chalk5.red(`Error adding MCP server: ${error.message}`));
|
|
8536
9087
|
process.exit(1);
|
|
8537
9088
|
}
|
|
8538
9089
|
});
|
|
@@ -8541,9 +9092,9 @@ function createMCPCommand() {
|
|
|
8541
9092
|
const manager = getMCPManager();
|
|
8542
9093
|
await manager.removeServer(name);
|
|
8543
9094
|
removeMCPServer(name);
|
|
8544
|
-
console.log(
|
|
9095
|
+
console.log(chalk5.green(`✓ Removed MCP server: ${name}`));
|
|
8545
9096
|
} catch (error) {
|
|
8546
|
-
console.error(
|
|
9097
|
+
console.error(chalk5.red(`Error removing MCP server: ${error.message}`));
|
|
8547
9098
|
process.exit(1);
|
|
8548
9099
|
}
|
|
8549
9100
|
});
|
|
@@ -8551,15 +9102,15 @@ function createMCPCommand() {
|
|
|
8551
9102
|
const config = loadMCPConfig();
|
|
8552
9103
|
const manager = getMCPManager();
|
|
8553
9104
|
if (config.servers.length === 0) {
|
|
8554
|
-
console.log(
|
|
9105
|
+
console.log(chalk5.yellow("No MCP servers configured"));
|
|
8555
9106
|
return;
|
|
8556
9107
|
}
|
|
8557
|
-
console.log(
|
|
9108
|
+
console.log(chalk5.bold("Configured MCP servers:"));
|
|
8558
9109
|
console.log();
|
|
8559
9110
|
for (const server of config.servers) {
|
|
8560
9111
|
const isConnected = manager.getServers().includes(server.name);
|
|
8561
|
-
const status = isConnected ?
|
|
8562
|
-
console.log(`${
|
|
9112
|
+
const status = isConnected ? chalk5.green("✓ Connected") : chalk5.red("✗ Disconnected");
|
|
9113
|
+
console.log(`${chalk5.bold(server.name)}: ${status}`);
|
|
8563
9114
|
if (server.transport) {
|
|
8564
9115
|
console.log(` Transport: ${server.transport.type}`);
|
|
8565
9116
|
if (server.transport.type === "stdio") {
|
|
@@ -8592,15 +9143,15 @@ function createMCPCommand() {
|
|
|
8592
9143
|
const config = loadMCPConfig();
|
|
8593
9144
|
const serverConfig = config.servers.find((s) => s.name === name);
|
|
8594
9145
|
if (!serverConfig) {
|
|
8595
|
-
console.error(
|
|
9146
|
+
console.error(chalk5.red(`Server ${name} not found`));
|
|
8596
9147
|
process.exit(1);
|
|
8597
9148
|
}
|
|
8598
|
-
console.log(
|
|
9149
|
+
console.log(chalk5.blue(`Testing connection to ${name}...`));
|
|
8599
9150
|
const manager = getMCPManager();
|
|
8600
9151
|
await manager.addServer(serverConfig);
|
|
8601
9152
|
const tools = manager.getTools().filter((t) => t.serverName === name);
|
|
8602
|
-
console.log(
|
|
8603
|
-
console.log(
|
|
9153
|
+
console.log(chalk5.green(`✓ Successfully connected to ${name}`));
|
|
9154
|
+
console.log(chalk5.blue(` Available tools: ${tools.length}`));
|
|
8604
9155
|
if (tools.length > 0) {
|
|
8605
9156
|
console.log(" Tools:");
|
|
8606
9157
|
tools.forEach((tool) => {
|
|
@@ -8609,82 +9160,44 @@ function createMCPCommand() {
|
|
|
8609
9160
|
});
|
|
8610
9161
|
}
|
|
8611
9162
|
} catch (error) {
|
|
8612
|
-
console.error(
|
|
9163
|
+
console.error(chalk5.red(`✗ Failed to connect to ${name}: ${error.message}`));
|
|
8613
9164
|
process.exit(1);
|
|
8614
9165
|
}
|
|
8615
9166
|
});
|
|
8616
9167
|
return mcpCommand;
|
|
8617
9168
|
}
|
|
8618
9169
|
|
|
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() {
|
|
9170
|
+
// src/commands/git.ts
|
|
9171
|
+
init_settings_manager();
|
|
9172
|
+
import { Command as Command7 } from "commander";
|
|
9173
|
+
async function loadApiKey() {
|
|
8651
9174
|
const manager = getSettingsManager();
|
|
8652
9175
|
return manager.getApiKey();
|
|
8653
9176
|
}
|
|
8654
|
-
function loadBaseURL() {
|
|
9177
|
+
async function loadBaseURL() {
|
|
8655
9178
|
const manager = getSettingsManager();
|
|
8656
9179
|
return manager.getBaseURL();
|
|
8657
9180
|
}
|
|
9181
|
+
async function loadModel() {
|
|
9182
|
+
const manager = getSettingsManager();
|
|
9183
|
+
return process.env.SUPER_AGENT_MODEL || manager.getCurrentModel();
|
|
9184
|
+
}
|
|
8658
9185
|
async function saveCommandLineSettings(apiKey, baseURL) {
|
|
8659
|
-
|
|
8660
|
-
|
|
8661
|
-
|
|
8662
|
-
|
|
8663
|
-
|
|
8664
|
-
|
|
8665
|
-
|
|
9186
|
+
if (!apiKey && !baseURL) {
|
|
9187
|
+
return;
|
|
9188
|
+
}
|
|
9189
|
+
const manager = getSettingsManager();
|
|
9190
|
+
const settings = manager.loadUserSettings();
|
|
9191
|
+
const activeProviderId = settings.active_provider;
|
|
9192
|
+
if (settings.providers[activeProviderId]) {
|
|
8666
9193
|
if (apiKey) {
|
|
8667
9194
|
settings.providers[activeProviderId].api_key = apiKey;
|
|
8668
|
-
console.log(`✅ API key saved for provider '${activeProviderId}' to ~/.super-agent/settings.json`);
|
|
8669
9195
|
}
|
|
8670
9196
|
if (baseURL) {
|
|
8671
9197
|
settings.providers[activeProviderId].base_url = baseURL;
|
|
8672
|
-
console.log(`✅ Base URL saved for provider '${activeProviderId}' to ~/.super-agent/settings.json`);
|
|
8673
9198
|
}
|
|
8674
9199
|
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
9200
|
}
|
|
8687
|
-
return model;
|
|
8688
9201
|
}
|
|
8689
9202
|
async function handleCommitAndPushHeadless(apiKey, baseURL, model, maxToolRounds) {
|
|
8690
9203
|
try {
|
|
@@ -8759,6 +9272,120 @@ Respond with ONLY the commit message, no additional text.`;
|
|
|
8759
9272
|
process.exit(1);
|
|
8760
9273
|
}
|
|
8761
9274
|
}
|
|
9275
|
+
function createGitCommand() {
|
|
9276
|
+
const gitCommand = new Command7("git").description("Git operations with AI assistance");
|
|
9277
|
+
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) => {
|
|
9278
|
+
if (options.directory) {
|
|
9279
|
+
try {
|
|
9280
|
+
process.chdir(options.directory);
|
|
9281
|
+
} catch (error) {
|
|
9282
|
+
console.error(`Error changing directory to ${options.directory}:`, error.message);
|
|
9283
|
+
process.exit(1);
|
|
9284
|
+
}
|
|
9285
|
+
}
|
|
9286
|
+
try {
|
|
9287
|
+
const apiKey = options.apiKey || await loadApiKey();
|
|
9288
|
+
const baseURL = options.baseUrl || await loadBaseURL();
|
|
9289
|
+
const model = options.model || await loadModel();
|
|
9290
|
+
const maxToolRounds = parseInt(options.maxToolRounds) || 400;
|
|
9291
|
+
if (!apiKey) {
|
|
9292
|
+
console.error("❌ Error: API key required for git operations. Set SUPER_AGENT_API_KEY environment variable.");
|
|
9293
|
+
process.exit(1);
|
|
9294
|
+
}
|
|
9295
|
+
if (options.apiKey || options.baseUrl) {
|
|
9296
|
+
await saveCommandLineSettings(options.apiKey, options.baseUrl);
|
|
9297
|
+
}
|
|
9298
|
+
await handleCommitAndPushHeadless(apiKey, baseURL, model, maxToolRounds);
|
|
9299
|
+
} catch (error) {
|
|
9300
|
+
console.error("❌ Error during git commit-and-push:", error.message);
|
|
9301
|
+
process.exit(1);
|
|
9302
|
+
}
|
|
9303
|
+
});
|
|
9304
|
+
return gitCommand;
|
|
9305
|
+
}
|
|
9306
|
+
|
|
9307
|
+
// src/commands/index.ts
|
|
9308
|
+
function registerCommands(program) {
|
|
9309
|
+
program.addCommand(createMCPCommand());
|
|
9310
|
+
program.addCommand(createPluginsCommand());
|
|
9311
|
+
program.addCommand(createGitCommand());
|
|
9312
|
+
program.addCommand(createWebCommand());
|
|
9313
|
+
program.addCommand(createServeCommand());
|
|
9314
|
+
program.addCommand(createSkillsCommand());
|
|
9315
|
+
program.addCommand(createAgentsCommand());
|
|
9316
|
+
program.addCommand(createIndexCommand());
|
|
9317
|
+
}
|
|
9318
|
+
|
|
9319
|
+
// src/index.ts
|
|
9320
|
+
var import__package = __toESM(require_package(), 1);
|
|
9321
|
+
import { program } from "commander";
|
|
9322
|
+
import * as dotenv from "dotenv";
|
|
9323
|
+
import { render } from "ink";
|
|
9324
|
+
import React4 from "react";
|
|
9325
|
+
dotenv.config();
|
|
9326
|
+
process.on("SIGTERM", () => {
|
|
9327
|
+
if (process.stdin.isTTY && process.stdin.setRawMode) {
|
|
9328
|
+
try {
|
|
9329
|
+
process.stdin.setRawMode(false);
|
|
9330
|
+
} catch (e) {}
|
|
9331
|
+
}
|
|
9332
|
+
console.log(`
|
|
9333
|
+
Gracefully shutting down...`);
|
|
9334
|
+
process.exit(0);
|
|
9335
|
+
});
|
|
9336
|
+
process.on("uncaughtException", (error) => {
|
|
9337
|
+
console.error("Uncaught exception:", error);
|
|
9338
|
+
process.exit(1);
|
|
9339
|
+
});
|
|
9340
|
+
process.on("unhandledRejection", (reason, promise) => {
|
|
9341
|
+
console.error("Unhandled rejection at:", promise, "reason:", reason);
|
|
9342
|
+
process.exit(1);
|
|
9343
|
+
});
|
|
9344
|
+
function ensureUserSettingsDirectory() {
|
|
9345
|
+
try {
|
|
9346
|
+
const manager = getSettingsManager();
|
|
9347
|
+
manager.loadUserSettings();
|
|
9348
|
+
} catch (error) {}
|
|
9349
|
+
}
|
|
9350
|
+
function loadApiKey2() {
|
|
9351
|
+
const manager = getSettingsManager();
|
|
9352
|
+
return manager.getApiKey();
|
|
9353
|
+
}
|
|
9354
|
+
function loadBaseURL2() {
|
|
9355
|
+
const manager = getSettingsManager();
|
|
9356
|
+
return manager.getBaseURL();
|
|
9357
|
+
}
|
|
9358
|
+
async function saveCommandLineSettings2(apiKey, baseURL) {
|
|
9359
|
+
try {
|
|
9360
|
+
const manager = getSettingsManager();
|
|
9361
|
+
const settings = manager.loadUserSettings();
|
|
9362
|
+
const activeProviderId = settings.active_provider;
|
|
9363
|
+
if (!settings.providers[activeProviderId]) {
|
|
9364
|
+
return;
|
|
9365
|
+
}
|
|
9366
|
+
if (apiKey) {
|
|
9367
|
+
settings.providers[activeProviderId].api_key = apiKey;
|
|
9368
|
+
console.log(`✅ API key saved for provider '${activeProviderId}' to ~/.super-agent/settings.json`);
|
|
9369
|
+
}
|
|
9370
|
+
if (baseURL) {
|
|
9371
|
+
settings.providers[activeProviderId].base_url = baseURL;
|
|
9372
|
+
console.log(`✅ Base URL saved for provider '${activeProviderId}' to ~/.super-agent/settings.json`);
|
|
9373
|
+
}
|
|
9374
|
+
manager.saveUserSettings(settings);
|
|
9375
|
+
} catch (error) {
|
|
9376
|
+
console.warn("⚠️ Could not save settings to file:", error instanceof Error ? error.message : "Unknown error");
|
|
9377
|
+
}
|
|
9378
|
+
}
|
|
9379
|
+
function loadModel2() {
|
|
9380
|
+
let model = process.env.SUPER_AGENT_MODEL;
|
|
9381
|
+
if (!model) {
|
|
9382
|
+
try {
|
|
9383
|
+
const manager = getSettingsManager();
|
|
9384
|
+
model = manager.getCurrentModel();
|
|
9385
|
+
} catch (error) {}
|
|
9386
|
+
}
|
|
9387
|
+
return model;
|
|
9388
|
+
}
|
|
8762
9389
|
async function processPromptHeadless(prompt, apiKey, baseURL, model, maxToolRounds) {
|
|
8763
9390
|
try {
|
|
8764
9391
|
const agent = new SuperAgent(apiKey, baseURL, model, maxToolRounds);
|
|
@@ -8823,9 +9450,9 @@ program.name("super-agent").description("A conversational AI CLI tool powered by
|
|
|
8823
9450
|
}
|
|
8824
9451
|
}
|
|
8825
9452
|
try {
|
|
8826
|
-
const apiKey = options.apiKey ||
|
|
8827
|
-
const baseURL = options.baseUrl ||
|
|
8828
|
-
const model = options.model ||
|
|
9453
|
+
const apiKey = options.apiKey || loadApiKey2();
|
|
9454
|
+
const baseURL = options.baseUrl || loadBaseURL2();
|
|
9455
|
+
const model = options.model || loadModel2();
|
|
8829
9456
|
const maxToolRounds = parseInt(options.maxToolRounds) || 400;
|
|
8830
9457
|
if (!apiKey && !options.prompt) {
|
|
8831
9458
|
console.warn("⚠️ Warning: No API key found. Some features may not work. Use /config or set SUPER_AGENT_API_KEY.");
|
|
@@ -8834,7 +9461,7 @@ program.name("super-agent").description("A conversational AI CLI tool powered by
|
|
|
8834
9461
|
process.exit(1);
|
|
8835
9462
|
}
|
|
8836
9463
|
if (options.apiKey || options.baseUrl) {
|
|
8837
|
-
await
|
|
9464
|
+
await saveCommandLineSettings2(options.apiKey, options.baseUrl);
|
|
8838
9465
|
}
|
|
8839
9466
|
if (options.prompt) {
|
|
8840
9467
|
await processPromptHeadless(options.prompt, apiKey, baseURL, model, maxToolRounds);
|
|
@@ -8862,141 +9489,6 @@ program.name("super-agent").description("A conversational AI CLI tool powered by
|
|
|
8862
9489
|
process.exit(1);
|
|
8863
9490
|
}
|
|
8864
9491
|
});
|
|
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());
|
|
9492
|
+
registerCommands(program);
|
|
9493
|
+
program.parse();
|
|
9002
9494
|
program.parse();
|