@serkanalgur/opencode-nexus 2.7.0 → 2.8.0
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/README.md +63 -28
- package/dist/index.js +754 -120
- package/dist/tui.js +111 -23
- package/package.json +1 -1
package/dist/tui.js
CHANGED
|
@@ -121,6 +121,9 @@ var DEFAULT_CONFIG = {
|
|
|
121
121
|
enabled: true,
|
|
122
122
|
port: 4747,
|
|
123
123
|
host: "127.0.0.1"
|
|
124
|
+
},
|
|
125
|
+
notifications: {
|
|
126
|
+
enabled: true
|
|
124
127
|
}
|
|
125
128
|
};
|
|
126
129
|
|
|
@@ -130,10 +133,12 @@ class NexusConfigManager {
|
|
|
130
133
|
storageConfig = null;
|
|
131
134
|
loadInfo = null;
|
|
132
135
|
dashboardBase;
|
|
133
|
-
|
|
136
|
+
notificationsBase;
|
|
137
|
+
constructor(dashboardBase, notificationsBase) {
|
|
134
138
|
this.projectConfig = null;
|
|
135
139
|
this.globalConfig = null;
|
|
136
140
|
this.dashboardBase = { ...DEFAULT_CONFIG.dashboard, ...dashboardBase };
|
|
141
|
+
this.notificationsBase = { ...DEFAULT_CONFIG.notifications, ...notificationsBase };
|
|
137
142
|
}
|
|
138
143
|
loadConfigs(basePath) {
|
|
139
144
|
if (this.loadInfo === null)
|
|
@@ -200,6 +205,9 @@ class NexusConfigManager {
|
|
|
200
205
|
enabled: this.storageConfig?.dashboard?.enabled ?? this.projectConfig?.dashboard?.enabled ?? this.globalConfig?.dashboard?.enabled ?? this.dashboardBase.enabled,
|
|
201
206
|
port: this.storageConfig?.dashboard?.port ?? this.projectConfig?.dashboard?.port ?? this.globalConfig?.dashboard?.port ?? this.dashboardBase.port,
|
|
202
207
|
host: this.storageConfig?.dashboard?.host ?? this.projectConfig?.dashboard?.host ?? this.globalConfig?.dashboard?.host ?? this.dashboardBase.host
|
|
208
|
+
},
|
|
209
|
+
notifications: {
|
|
210
|
+
enabled: this.storageConfig?.notifications?.enabled ?? this.projectConfig?.notifications?.enabled ?? this.globalConfig?.notifications?.enabled ?? this.notificationsBase.enabled
|
|
203
211
|
}
|
|
204
212
|
};
|
|
205
213
|
}
|
|
@@ -321,6 +329,7 @@ class NexusConfigManager {
|
|
|
321
329
|
result.budget = { ...current.budget };
|
|
322
330
|
result.selfHealing = { ...current.selfHealing };
|
|
323
331
|
result.dashboard = { ...current.dashboard };
|
|
332
|
+
result.notifications = { ...current.notifications };
|
|
324
333
|
return result;
|
|
325
334
|
}
|
|
326
335
|
resetToDefaults() {
|
|
@@ -597,6 +606,11 @@ function parseWebDashboardTarget(input, fallback) {
|
|
|
597
606
|
}
|
|
598
607
|
return { target: { port, host } };
|
|
599
608
|
}
|
|
609
|
+
var LISTEN_CONFIRM_ATTEMPTS = 15;
|
|
610
|
+
var LISTEN_CONFIRM_INTERVAL_MS = 200;
|
|
611
|
+
function defaultWait(ms) {
|
|
612
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
613
|
+
}
|
|
600
614
|
async function handleWebDashboard(input, deps) {
|
|
601
615
|
const parsed = parseWebDashboardTarget(input, {
|
|
602
616
|
port: deps.dashboard.port,
|
|
@@ -629,7 +643,7 @@ async function handleWebDashboard(input, deps) {
|
|
|
629
643
|
await deps.openBrowser(url);
|
|
630
644
|
deps.showToast({
|
|
631
645
|
title: "\u26A1 Nexus Web Dashboard",
|
|
632
|
-
message: `Opened ${url} \u2014 a dashboard is already running there.`,
|
|
646
|
+
message: `Opened ${url} \u2014 a dashboard is already running there, so nothing was started.`,
|
|
633
647
|
variant: "success",
|
|
634
648
|
duration: 6000
|
|
635
649
|
});
|
|
@@ -650,22 +664,62 @@ async function handleWebDashboard(input, deps) {
|
|
|
650
664
|
});
|
|
651
665
|
return;
|
|
652
666
|
}
|
|
667
|
+
let submitted;
|
|
668
|
+
try {
|
|
669
|
+
await deps.submitCommand(`/nexus dashboard ${port} ${host}`);
|
|
670
|
+
submitted = `/nexus dashboard ${port} ${host}`;
|
|
671
|
+
} catch (error) {
|
|
672
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
673
|
+
deps.showToast({
|
|
674
|
+
title: "Nexus Web Dashboard \u2014 could not start",
|
|
675
|
+
message: [
|
|
676
|
+
`The dashboard start command never reached the OpenCode server: ${detail}`,
|
|
677
|
+
"",
|
|
678
|
+
"No server is listening on that port and no browser was opened.",
|
|
679
|
+
"The dashboard runs in the server process, so this needs the server's",
|
|
680
|
+
"HTTP endpoint to be reachable from the TUI."
|
|
681
|
+
].join(`
|
|
682
|
+
`),
|
|
683
|
+
variant: "error",
|
|
684
|
+
duration: 15000
|
|
685
|
+
});
|
|
686
|
+
return;
|
|
687
|
+
}
|
|
688
|
+
const wait = deps.waitImpl ?? defaultWait;
|
|
689
|
+
const attempts = deps.confirmAttempts ?? LISTEN_CONFIRM_ATTEMPTS;
|
|
690
|
+
const intervalMs = deps.confirmIntervalMs ?? LISTEN_CONFIRM_INTERVAL_MS;
|
|
691
|
+
for (let attempt = 0;attempt < attempts; attempt++) {
|
|
692
|
+
if (attempt > 0)
|
|
693
|
+
await wait(intervalMs);
|
|
694
|
+
const check = await probeDashboard(host, port, deps.fetchImpl);
|
|
695
|
+
if (check.isNexusDashboard) {
|
|
696
|
+
await deps.openBrowser(url);
|
|
697
|
+
deps.showToast({
|
|
698
|
+
title: "\u26A1 Nexus Web Dashboard",
|
|
699
|
+
message: `Started and opened ${url} \u2014 a dashboard is serving there now.`,
|
|
700
|
+
variant: "success",
|
|
701
|
+
duration: 8000
|
|
702
|
+
});
|
|
703
|
+
return;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
653
706
|
deps.showToast({
|
|
654
|
-
title: "
|
|
707
|
+
title: "Nexus Web Dashboard \u2014 not started",
|
|
655
708
|
message: [
|
|
656
|
-
`
|
|
657
|
-
"",
|
|
658
|
-
"The dashboard server cannot be started from the TUI: it runs in the OpenCode",
|
|
659
|
-
"server process, next to the orchestrator that feeds it, and the TUI has no",
|
|
660
|
-
"handle on either. So start it from the agent \u2014 this is the one call:",
|
|
709
|
+
`Ran \`${submitted}\`, but nothing is serving on ${host}:${port} after ${Math.round(attempts * intervalMs / 1000)}s,`,
|
|
710
|
+
"so no browser was opened and there is no URL to give you.",
|
|
661
711
|
"",
|
|
662
|
-
|
|
663
|
-
"",
|
|
664
|
-
`
|
|
712
|
+
"The command runs in the OpenCode server process, which is the only place",
|
|
713
|
+
"the dashboard can start. If a Nexus plugin is active in that process, its",
|
|
714
|
+
`result is in this session as the reply to \`${submitted}\` \u2014 that text names`,
|
|
715
|
+
"the reason (a port already in use, or `dashboard.enabled: false`). If no",
|
|
716
|
+
"plugin is active there, the command was never handled at all. If the port",
|
|
717
|
+
"is held by another process, free it or pass a different one:",
|
|
718
|
+
"/nexus web 4748."
|
|
665
719
|
].join(`
|
|
666
720
|
`),
|
|
667
|
-
variant: "
|
|
668
|
-
duration:
|
|
721
|
+
variant: "error",
|
|
722
|
+
duration: 20000
|
|
669
723
|
});
|
|
670
724
|
}
|
|
671
725
|
async function openInBrowser(url) {
|
|
@@ -766,14 +820,28 @@ var tui_default = define({
|
|
|
766
820
|
variant: "success"
|
|
767
821
|
});
|
|
768
822
|
};
|
|
823
|
+
const activeSessionID = () => {
|
|
824
|
+
const route = context.ui.router.current();
|
|
825
|
+
if (route.type === "session")
|
|
826
|
+
return route.sessionID;
|
|
827
|
+
return context.ui.tabs.list().find((tab) => tab.active)?.sessionID;
|
|
828
|
+
};
|
|
829
|
+
const submitServerCommand = async (text) => {
|
|
830
|
+
const sessionID = activeSessionID();
|
|
831
|
+
if (!sessionID) {
|
|
832
|
+
throw new Error("no session is open to run the command in");
|
|
833
|
+
}
|
|
834
|
+
await context.client.session.prompt({ sessionID, text });
|
|
835
|
+
};
|
|
769
836
|
const runWebDashboard = async (input) => {
|
|
770
837
|
await handleWebDashboard(input, {
|
|
771
838
|
dashboard: configManager.getConfig().dashboard,
|
|
772
839
|
showToast: (options) => context.ui.toast.show(options),
|
|
773
|
-
openBrowser: openInBrowser
|
|
840
|
+
openBrowser: openInBrowser,
|
|
841
|
+
submitCommand: submitServerCommand
|
|
774
842
|
});
|
|
775
843
|
};
|
|
776
|
-
const
|
|
844
|
+
const handleOverview = async () => {
|
|
777
845
|
const config = configManager.getConfig();
|
|
778
846
|
const lines = [
|
|
779
847
|
"\u26A1 Nexus Overview",
|
|
@@ -800,7 +868,9 @@ var tui_default = define({
|
|
|
800
868
|
lines.push(" /nexus status - Show config summary");
|
|
801
869
|
lines.push(" /nexus config - Configure models & budget");
|
|
802
870
|
lines.push(" /nexus model - Select model for role");
|
|
803
|
-
lines.push(" /nexus
|
|
871
|
+
lines.push(" /nexus dashboard - Start the web dashboard and open it");
|
|
872
|
+
lines.push(" /nexus web - Same: start it if needed, then open it");
|
|
873
|
+
lines.push(" /nexus overview - Show this overview");
|
|
804
874
|
lines.push(" /nexus reset - Reset to defaults");
|
|
805
875
|
lines.push("");
|
|
806
876
|
lines.push("\uD83D\uDD27 Tools (use in agent prompt):");
|
|
@@ -813,7 +883,7 @@ var tui_default = define({
|
|
|
813
883
|
lines.push("\uD83D\uDCCA Web Dashboard:");
|
|
814
884
|
lines.push(` Enabled: ${config.dashboard.enabled ? "\u2705" : "\u274C"}`);
|
|
815
885
|
lines.push(` Address: http://${config.dashboard.host}:${config.dashboard.port} (when running)`);
|
|
816
|
-
lines.push(" Not running?
|
|
886
|
+
lines.push(" Not running? /nexus dashboard starts it and opens it.");
|
|
817
887
|
context.ui.toast.show({
|
|
818
888
|
title: "Nexus Overview",
|
|
819
889
|
message: lines.join(`
|
|
@@ -858,7 +928,10 @@ var tui_default = define({
|
|
|
858
928
|
break;
|
|
859
929
|
case "dashboard":
|
|
860
930
|
case "d":
|
|
861
|
-
await
|
|
931
|
+
await runWebDashboard(parts.slice(1).join(" "));
|
|
932
|
+
break;
|
|
933
|
+
case "overview":
|
|
934
|
+
await handleOverview();
|
|
862
935
|
break;
|
|
863
936
|
case "web":
|
|
864
937
|
case "w":
|
|
@@ -900,7 +973,7 @@ var tui_default = define({
|
|
|
900
973
|
default:
|
|
901
974
|
context.ui.toast.show({
|
|
902
975
|
title: "Nexus",
|
|
903
|
-
message: "Commands: config, status, dashboard, web [port], model <role>, reset",
|
|
976
|
+
message: "Commands: config, status, dashboard [port], web [port], overview, model <role>, reset",
|
|
904
977
|
variant: "info"
|
|
905
978
|
});
|
|
906
979
|
}
|
|
@@ -922,21 +995,34 @@ var tui_default = define({
|
|
|
922
995
|
}
|
|
923
996
|
},
|
|
924
997
|
{
|
|
925
|
-
id: "nexus.
|
|
998
|
+
id: "nexus.overview",
|
|
926
999
|
title: "Nexus Overview (config, budget, dashboard status)",
|
|
927
1000
|
group: "Nexus",
|
|
928
1001
|
palette: true,
|
|
929
|
-
slash: { name: "nexus-
|
|
1002
|
+
slash: { name: "nexus-overview", aliases: ["no"], arguments: true },
|
|
930
1003
|
enabled: () => true,
|
|
931
1004
|
suggested: true,
|
|
932
1005
|
run: async () => {
|
|
933
|
-
await
|
|
1006
|
+
await handleOverview();
|
|
1007
|
+
}
|
|
1008
|
+
},
|
|
1009
|
+
{
|
|
1010
|
+
id: "nexus.dashboard",
|
|
1011
|
+
title: "Start the Nexus Web Dashboard",
|
|
1012
|
+
description: "Starts the dashboard server if it is not already running, then opens it in your browser",
|
|
1013
|
+
group: "Nexus",
|
|
1014
|
+
palette: true,
|
|
1015
|
+
slash: { name: "nexus-dashboard", aliases: ["nd"], arguments: true },
|
|
1016
|
+
enabled: () => true,
|
|
1017
|
+
suggested: true,
|
|
1018
|
+
run: async (input) => {
|
|
1019
|
+
await runWebDashboard(input);
|
|
934
1020
|
}
|
|
935
1021
|
},
|
|
936
1022
|
{
|
|
937
1023
|
id: "nexus.web",
|
|
938
1024
|
title: "Open the Nexus Web Dashboard",
|
|
939
|
-
description: "
|
|
1025
|
+
description: "Alias of Nexus Dashboard: starts it if needed, then opens it in your browser",
|
|
940
1026
|
group: "Nexus",
|
|
941
1027
|
palette: true,
|
|
942
1028
|
slash: { name: "nexus-web", aliases: ["nw"], arguments: true },
|
|
@@ -1186,6 +1272,8 @@ var tui_default = define({
|
|
|
1186
1272
|
}
|
|
1187
1273
|
});
|
|
1188
1274
|
export {
|
|
1275
|
+
LISTEN_CONFIRM_ATTEMPTS,
|
|
1276
|
+
LISTEN_CONFIRM_INTERVAL_MS,
|
|
1189
1277
|
collectSidebarAgents,
|
|
1190
1278
|
tui_default as default,
|
|
1191
1279
|
handleWebDashboard,
|