starkbot-cli 0.1.4 → 0.2.1
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 +313 -103
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -867,13 +867,159 @@ var init_connect = __esm({
|
|
|
867
867
|
}
|
|
868
868
|
});
|
|
869
869
|
|
|
870
|
+
// src/lib/status.ts
|
|
871
|
+
import ora2 from "ora";
|
|
872
|
+
import chalk2 from "chalk";
|
|
873
|
+
var subtypeColor, toolColor, subagentColor, dimText, StatusTracker;
|
|
874
|
+
var init_status2 = __esm({
|
|
875
|
+
"src/lib/status.ts"() {
|
|
876
|
+
"use strict";
|
|
877
|
+
subtypeColor = chalk2.hex("#7C3AED").bold;
|
|
878
|
+
toolColor = chalk2.yellow;
|
|
879
|
+
subagentColor = chalk2.cyan;
|
|
880
|
+
dimText = chalk2.dim;
|
|
881
|
+
StatusTracker = class {
|
|
882
|
+
spinner;
|
|
883
|
+
activeSubtype = "";
|
|
884
|
+
activeTools = [];
|
|
885
|
+
activeSubagents = /* @__PURE__ */ new Map();
|
|
886
|
+
// label -> subtype
|
|
887
|
+
paused = false;
|
|
888
|
+
constructor() {
|
|
889
|
+
this.spinner = ora2({ color: "magenta", spinner: "dots" });
|
|
890
|
+
}
|
|
891
|
+
handleEvent(event) {
|
|
892
|
+
switch (event.type) {
|
|
893
|
+
case "tool_call":
|
|
894
|
+
this.addTool(event.tool_name ?? "unknown");
|
|
895
|
+
break;
|
|
896
|
+
case "tool_result":
|
|
897
|
+
this.removeTool(event.tool_name ?? "unknown");
|
|
898
|
+
break;
|
|
899
|
+
case "subagent_spawned":
|
|
900
|
+
this.addSubagent(event.label ?? "?", event.agent_subtype);
|
|
901
|
+
break;
|
|
902
|
+
case "subagent_completed":
|
|
903
|
+
case "subagent_failed":
|
|
904
|
+
this.removeSubagent(event.label ?? "?");
|
|
905
|
+
break;
|
|
906
|
+
case "subtype_change":
|
|
907
|
+
this.setSubtype(event.agent_subtype ?? event.label ?? "");
|
|
908
|
+
break;
|
|
909
|
+
case "thinking":
|
|
910
|
+
this.setThinking(event.content);
|
|
911
|
+
break;
|
|
912
|
+
case "task_started":
|
|
913
|
+
if (event.task_name) this.setTask(event.task_name);
|
|
914
|
+
break;
|
|
915
|
+
case "task_completed":
|
|
916
|
+
this.updateSpinner();
|
|
917
|
+
break;
|
|
918
|
+
case "text":
|
|
919
|
+
this.pauseForText();
|
|
920
|
+
if (event.content) process.stdout.write(event.content);
|
|
921
|
+
this.resumeAfterText();
|
|
922
|
+
break;
|
|
923
|
+
case "done":
|
|
924
|
+
this.finish();
|
|
925
|
+
break;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
prefix() {
|
|
929
|
+
if (this.activeSubtype) {
|
|
930
|
+
return `${subtypeColor(`[${this.activeSubtype}]`)} `;
|
|
931
|
+
}
|
|
932
|
+
return "";
|
|
933
|
+
}
|
|
934
|
+
addTool(name) {
|
|
935
|
+
if (!this.activeTools.includes(name)) {
|
|
936
|
+
this.activeTools.push(name);
|
|
937
|
+
}
|
|
938
|
+
this.updateSpinner();
|
|
939
|
+
}
|
|
940
|
+
removeTool(name) {
|
|
941
|
+
this.activeTools = this.activeTools.filter((t) => t !== name);
|
|
942
|
+
this.updateSpinner();
|
|
943
|
+
}
|
|
944
|
+
addSubagent(label, subtype) {
|
|
945
|
+
this.activeSubagents.set(label, subtype ?? "");
|
|
946
|
+
this.updateSpinner();
|
|
947
|
+
}
|
|
948
|
+
removeSubagent(label) {
|
|
949
|
+
this.activeSubagents.delete(label);
|
|
950
|
+
this.updateSpinner();
|
|
951
|
+
}
|
|
952
|
+
setSubtype(subtype) {
|
|
953
|
+
this.activeSubtype = subtype;
|
|
954
|
+
this.updateSpinner();
|
|
955
|
+
}
|
|
956
|
+
setThinking(message) {
|
|
957
|
+
const text = `${this.prefix()}${dimText(message || "thinking...")}`;
|
|
958
|
+
this.ensureSpinning(text);
|
|
959
|
+
}
|
|
960
|
+
setTask(taskName) {
|
|
961
|
+
const text = `${this.prefix()}${dimText(taskName)}`;
|
|
962
|
+
this.ensureSpinning(text);
|
|
963
|
+
}
|
|
964
|
+
updateSpinner() {
|
|
965
|
+
const parts = [];
|
|
966
|
+
for (const [label, subtype] of this.activeSubagents) {
|
|
967
|
+
const st = subtype ? ` (${subtype})` : "";
|
|
968
|
+
parts.push(subagentColor(`subagent "${label}"${st} running`));
|
|
969
|
+
}
|
|
970
|
+
if (this.activeTools.length > 0) {
|
|
971
|
+
const names = this.activeTools.map((t) => toolColor(t)).join(", ");
|
|
972
|
+
parts.push(`calling ${names}`);
|
|
973
|
+
}
|
|
974
|
+
if (parts.length === 0) {
|
|
975
|
+
if (this.spinner.isSpinning && !this.paused) {
|
|
976
|
+
this.spinner.stop();
|
|
977
|
+
}
|
|
978
|
+
return;
|
|
979
|
+
}
|
|
980
|
+
const text = `${this.prefix()}${parts.join(" | ")}`;
|
|
981
|
+
this.ensureSpinning(text);
|
|
982
|
+
}
|
|
983
|
+
ensureSpinning(text) {
|
|
984
|
+
if (this.paused) return;
|
|
985
|
+
if (this.spinner.isSpinning) {
|
|
986
|
+
this.spinner.text = text;
|
|
987
|
+
} else {
|
|
988
|
+
this.spinner.start(text);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
pauseForText() {
|
|
992
|
+
if (this.spinner.isSpinning) {
|
|
993
|
+
this.spinner.stop();
|
|
994
|
+
}
|
|
995
|
+
this.paused = true;
|
|
996
|
+
}
|
|
997
|
+
resumeAfterText() {
|
|
998
|
+
this.paused = false;
|
|
999
|
+
if (this.activeTools.length > 0 || this.activeSubagents.size > 0) {
|
|
1000
|
+
this.updateSpinner();
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
finish() {
|
|
1004
|
+
if (this.spinner.isSpinning) {
|
|
1005
|
+
this.spinner.stop();
|
|
1006
|
+
}
|
|
1007
|
+
this.activeTools = [];
|
|
1008
|
+
this.activeSubagents.clear();
|
|
1009
|
+
this.activeSubtype = "";
|
|
1010
|
+
this.paused = false;
|
|
1011
|
+
}
|
|
1012
|
+
};
|
|
1013
|
+
}
|
|
1014
|
+
});
|
|
1015
|
+
|
|
870
1016
|
// src/commands/chat.ts
|
|
871
1017
|
var chat_exports = {};
|
|
872
1018
|
__export(chat_exports, {
|
|
873
1019
|
chatOneShotCommand: () => chatOneShotCommand,
|
|
874
1020
|
chatReplCommand: () => chatReplCommand
|
|
875
1021
|
});
|
|
876
|
-
import { createInterface as createInterface2 } from "readline";
|
|
1022
|
+
import { createInterface as createInterface2 } from "readline/promises";
|
|
877
1023
|
function requireGateway() {
|
|
878
1024
|
const creds = requireCredentials();
|
|
879
1025
|
if (!creds.gateway_token || !creds.instance_domain) {
|
|
@@ -886,41 +1032,66 @@ function requireGateway() {
|
|
|
886
1032
|
creds.gateway_token
|
|
887
1033
|
);
|
|
888
1034
|
}
|
|
889
|
-
function
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
1035
|
+
function isAuthError(err) {
|
|
1036
|
+
return err?.message?.includes("HTTP 401") || err?.message?.includes("Invalid gateway token");
|
|
1037
|
+
}
|
|
1038
|
+
async function tryRefreshToken() {
|
|
1039
|
+
const creds = loadCredentials();
|
|
1040
|
+
if (!creds?.jwt) return null;
|
|
1041
|
+
try {
|
|
1042
|
+
const client = new FlashClient(creds.jwt);
|
|
1043
|
+
const { token, domain } = await client.getGatewayToken();
|
|
1044
|
+
updateCredentials({ gateway_token: token, instance_domain: domain });
|
|
1045
|
+
const gw = new GatewayClient(`https://${domain}`, token);
|
|
1046
|
+
const ok = await gw.ping();
|
|
1047
|
+
if (ok) {
|
|
1048
|
+
printSuccess("Gateway token refreshed automatically.");
|
|
1049
|
+
return gw;
|
|
895
1050
|
}
|
|
896
|
-
|
|
897
|
-
break;
|
|
898
|
-
case "text":
|
|
899
|
-
if (event.content) {
|
|
900
|
-
process.stdout.write(event.content);
|
|
901
|
-
}
|
|
902
|
-
break;
|
|
903
|
-
case "done":
|
|
904
|
-
break;
|
|
1051
|
+
} catch {
|
|
905
1052
|
}
|
|
1053
|
+
return null;
|
|
906
1054
|
}
|
|
907
1055
|
async function chatOneShotCommand(message) {
|
|
908
|
-
|
|
1056
|
+
let gw = requireGateway();
|
|
1057
|
+
const status = new StatusTracker();
|
|
909
1058
|
process.stdout.write(`${prefix.agent} `);
|
|
910
1059
|
try {
|
|
911
|
-
await gw.chatStream(message,
|
|
1060
|
+
await gw.chatStream(message, (event) => status.handleEvent(event));
|
|
912
1061
|
console.log();
|
|
913
1062
|
} catch (err) {
|
|
1063
|
+
status.finish();
|
|
914
1064
|
console.log();
|
|
915
|
-
|
|
1065
|
+
if (isAuthError(err)) {
|
|
1066
|
+
printWarning("Gateway token is invalid or expired. Attempting to refresh...");
|
|
1067
|
+
const refreshed = await tryRefreshToken();
|
|
1068
|
+
if (refreshed) {
|
|
1069
|
+
gw = refreshed;
|
|
1070
|
+
process.stdout.write(`${prefix.agent} `);
|
|
1071
|
+
const status2 = new StatusTracker();
|
|
1072
|
+
try {
|
|
1073
|
+
await gw.chatStream(message, (event) => status2.handleEvent(event));
|
|
1074
|
+
console.log();
|
|
1075
|
+
return;
|
|
1076
|
+
} catch (retryErr) {
|
|
1077
|
+
status2.finish();
|
|
1078
|
+
console.log();
|
|
1079
|
+
printError(retryErr.message);
|
|
1080
|
+
}
|
|
1081
|
+
} else {
|
|
1082
|
+
printError("Could not refresh token. Run `starkbot connect` to set a new gateway token.");
|
|
1083
|
+
}
|
|
1084
|
+
} else {
|
|
1085
|
+
printError(err.message);
|
|
1086
|
+
}
|
|
916
1087
|
process.exit(1);
|
|
917
1088
|
}
|
|
918
1089
|
}
|
|
919
1090
|
async function chatReplCommand() {
|
|
920
|
-
|
|
1091
|
+
let gw = requireGateway();
|
|
921
1092
|
console.log(
|
|
922
1093
|
dim(
|
|
923
|
-
"Starkbot CLI \u2014 type a message, /new to reset, /sessions to list, /quit to exit"
|
|
1094
|
+
"Starkbot CLI \u2014 type a message, /new to reset, /sessions to list, /connect to refresh token, /quit to exit"
|
|
924
1095
|
)
|
|
925
1096
|
);
|
|
926
1097
|
const rl = createInterface2({
|
|
@@ -928,109 +1099,148 @@ async function chatReplCommand() {
|
|
|
928
1099
|
output: process.stdout,
|
|
929
1100
|
terminal: true
|
|
930
1101
|
});
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
1102
|
+
let running = true;
|
|
1103
|
+
while (running) {
|
|
1104
|
+
let input;
|
|
1105
|
+
try {
|
|
1106
|
+
input = await rl.question(`${prefix.you} `);
|
|
1107
|
+
} catch {
|
|
1108
|
+
break;
|
|
1109
|
+
}
|
|
1110
|
+
const trimmed = input.trim();
|
|
1111
|
+
if (!trimmed) continue;
|
|
1112
|
+
switch (trimmed) {
|
|
1113
|
+
case "/quit":
|
|
1114
|
+
case "/exit":
|
|
1115
|
+
case "/q":
|
|
1116
|
+
running = false;
|
|
1117
|
+
console.log(dim("Goodbye!"));
|
|
1118
|
+
break;
|
|
1119
|
+
case "/new": {
|
|
1120
|
+
try {
|
|
1121
|
+
const resp = await gw.newSession();
|
|
1122
|
+
console.log(
|
|
1123
|
+
`${prefix.system} New session created (id: ${resp.session_id})`
|
|
1124
|
+
);
|
|
1125
|
+
} catch (err) {
|
|
1126
|
+
console.log(`${prefix.error} ${err.message}`);
|
|
1127
|
+
}
|
|
1128
|
+
break;
|
|
937
1129
|
}
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
);
|
|
951
|
-
} catch (err) {
|
|
952
|
-
console.log(`${prefix.error} ${err.message}`);
|
|
1130
|
+
case "/sessions": {
|
|
1131
|
+
try {
|
|
1132
|
+
const resp = await gw.listSessions();
|
|
1133
|
+
if (resp.sessions.length === 0) {
|
|
1134
|
+
console.log(`${prefix.system} No sessions found`);
|
|
1135
|
+
} else {
|
|
1136
|
+
console.log(`${prefix.system} Sessions:`);
|
|
1137
|
+
for (const s of resp.sessions) {
|
|
1138
|
+
console.log(
|
|
1139
|
+
` ${info(s.session_key)} | ${s.message_count} msgs | last active: ${dim(s.last_activity_at)}`
|
|
1140
|
+
);
|
|
1141
|
+
}
|
|
953
1142
|
}
|
|
954
|
-
|
|
955
|
-
|
|
1143
|
+
} catch (err) {
|
|
1144
|
+
console.log(`${prefix.error} ${err.message}`);
|
|
956
1145
|
}
|
|
957
|
-
|
|
1146
|
+
break;
|
|
1147
|
+
}
|
|
1148
|
+
case "/connect": {
|
|
1149
|
+
console.log(`${prefix.system} Refreshing gateway token...`);
|
|
1150
|
+
const refreshed = await tryRefreshToken();
|
|
1151
|
+
if (refreshed) {
|
|
1152
|
+
gw = refreshed;
|
|
1153
|
+
} else {
|
|
1154
|
+
console.log(`${prefix.system} Auto-refresh failed. Enter a new gateway token manually.`);
|
|
958
1155
|
try {
|
|
959
|
-
const
|
|
960
|
-
if (
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
);
|
|
1156
|
+
const newToken = (await rl.question(`${prefix.system} Gateway token: `)).trim();
|
|
1157
|
+
if (newToken) {
|
|
1158
|
+
const creds = requireCredentials();
|
|
1159
|
+
const domain = creds.instance_domain;
|
|
1160
|
+
updateCredentials({ gateway_token: newToken });
|
|
1161
|
+
gw = new GatewayClient(`https://${domain}`, newToken);
|
|
1162
|
+
const ok = await gw.ping();
|
|
1163
|
+
if (ok) {
|
|
1164
|
+
printSuccess(`Reconnected to ${domain}`);
|
|
1165
|
+
} else {
|
|
1166
|
+
printWarning("Token saved but instance is not responding.");
|
|
968
1167
|
}
|
|
1168
|
+
} else {
|
|
1169
|
+
console.log(`${prefix.system} Cancelled.`);
|
|
969
1170
|
}
|
|
970
|
-
} catch
|
|
971
|
-
console.log(`${prefix.error} ${err.message}`);
|
|
1171
|
+
} catch {
|
|
972
1172
|
}
|
|
973
|
-
prompt();
|
|
974
|
-
return;
|
|
975
1173
|
}
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
1174
|
+
break;
|
|
1175
|
+
}
|
|
1176
|
+
case "/help":
|
|
1177
|
+
console.log(`${prefix.system} Commands:`);
|
|
1178
|
+
console.log(` ${info("/new")} \u2014 Start a new session`);
|
|
1179
|
+
console.log(` ${info("/sessions")} \u2014 List sessions`);
|
|
1180
|
+
console.log(
|
|
1181
|
+
` ${info("/history <id>")} \u2014 Show message history`
|
|
1182
|
+
);
|
|
1183
|
+
console.log(` ${info("/connect")} \u2014 Refresh gateway token`);
|
|
1184
|
+
console.log(` ${info("/quit")} \u2014 Exit`);
|
|
1185
|
+
break;
|
|
1186
|
+
default:
|
|
1187
|
+
if (trimmed.startsWith("/history")) {
|
|
1188
|
+
const parts = trimmed.split(/\s+/);
|
|
1189
|
+
if (parts.length < 2) {
|
|
1190
|
+
console.log(
|
|
1191
|
+
`${prefix.system} Usage: /history <session_id>`
|
|
1192
|
+
);
|
|
1193
|
+
} else {
|
|
1194
|
+
const sid = parseInt(parts[1], 10);
|
|
1195
|
+
if (isNaN(sid)) {
|
|
1196
|
+
console.log(`${prefix.error} Invalid session ID: ${parts[1]}`);
|
|
993
1197
|
} else {
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
const resp = await gw.getHistory(sid);
|
|
1000
|
-
for (const m of resp.messages) {
|
|
1001
|
-
const p = m.role === "user" ? prefix.you : m.role === "assistant" ? prefix.agent : dim(`${m.role}>`);
|
|
1002
|
-
console.log(`${p} ${m.content}`);
|
|
1003
|
-
}
|
|
1004
|
-
} catch (err) {
|
|
1005
|
-
console.log(`${prefix.error} ${err.message}`);
|
|
1198
|
+
try {
|
|
1199
|
+
const resp = await gw.getHistory(sid);
|
|
1200
|
+
for (const m of resp.messages) {
|
|
1201
|
+
const p = m.role === "user" ? prefix.you : m.role === "assistant" ? prefix.agent : dim(`${m.role}>`);
|
|
1202
|
+
console.log(`${p} ${m.content}`);
|
|
1006
1203
|
}
|
|
1204
|
+
} catch (err) {
|
|
1205
|
+
console.log(`${prefix.error} ${err.message}`);
|
|
1007
1206
|
}
|
|
1008
1207
|
}
|
|
1009
|
-
prompt();
|
|
1010
|
-
return;
|
|
1011
1208
|
}
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1209
|
+
break;
|
|
1210
|
+
}
|
|
1211
|
+
process.stdout.write(`${prefix.agent} `);
|
|
1212
|
+
try {
|
|
1213
|
+
const status = new StatusTracker();
|
|
1214
|
+
await gw.chatStream(trimmed, (event) => status.handleEvent(event));
|
|
1215
|
+
console.log();
|
|
1216
|
+
} catch (err) {
|
|
1217
|
+
console.log();
|
|
1218
|
+
if (isAuthError(err)) {
|
|
1219
|
+
console.log(`${prefix.error} ${err.message}`);
|
|
1220
|
+
console.log(warn(" Gateway token is invalid or expired. Attempting to refresh..."));
|
|
1221
|
+
const refreshed = await tryRefreshToken();
|
|
1222
|
+
if (refreshed) {
|
|
1223
|
+
gw = refreshed;
|
|
1224
|
+
console.log(dim(" Try your message again."));
|
|
1225
|
+
} else {
|
|
1226
|
+
console.log(warn(" Auto-refresh failed. Use /connect to enter a new token."));
|
|
1227
|
+
}
|
|
1228
|
+
} else {
|
|
1018
1229
|
console.log(`${prefix.error} ${err.message}`);
|
|
1019
1230
|
}
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
rl.on("close", () => {
|
|
1026
|
-
process.exit(0);
|
|
1027
|
-
});
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
rl.close();
|
|
1235
|
+
process.exit(0);
|
|
1028
1236
|
}
|
|
1029
1237
|
var init_chat = __esm({
|
|
1030
1238
|
"src/commands/chat.ts"() {
|
|
1031
1239
|
"use strict";
|
|
1032
1240
|
init_credentials();
|
|
1241
|
+
init_flash_client();
|
|
1033
1242
|
init_gateway_client();
|
|
1243
|
+
init_status2();
|
|
1034
1244
|
init_ui();
|
|
1035
1245
|
}
|
|
1036
1246
|
});
|