@proagentstore/cli 0.1.13 → 0.1.15

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.
Files changed (2) hide show
  1. package/dist/index.js +214 -11
  2. package/package.json +4 -3
package/dist/index.js CHANGED
@@ -989,16 +989,119 @@ function createRunnerCommand() {
989
989
 
990
990
  // src/commands/up.ts
991
991
  import { Command as Command7 } from "commander";
992
+
993
+ // src/tui.ts
994
+ import chalk from "chalk";
995
+ import readline from "readline";
996
+ var ACCENT = "#7c3aed";
997
+ var c = chalk.hex(ACCENT);
998
+ var d = chalk.dim;
999
+ var w = chalk.white;
1000
+ var pad = " ";
1001
+ var LOGO = [
1002
+ "\u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557",
1003
+ "\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2557\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D",
1004
+ "\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557",
1005
+ "\u2588\u2588\u2554\u2550\u2550\u2550\u255D \u2588\u2588\u2554\u2550\u2550\u2588\u2588\u2551\u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551",
1006
+ "\u2588\u2588\u2551 \u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551",
1007
+ "\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D"
1008
+ ];
1009
+ function clearScreen() {
1010
+ console.clear();
1011
+ }
1012
+ function printLogo() {
1013
+ console.log("");
1014
+ for (const line of LOGO) {
1015
+ console.log(pad + c(line));
1016
+ }
1017
+ console.log("");
1018
+ }
1019
+ function printStatus(state) {
1020
+ clearScreen();
1021
+ printLogo();
1022
+ const statusIcon = (s) => {
1023
+ if (s === "online" || s === "registered") return chalk.green("\u25CF");
1024
+ if (s === "starting" || s === "pending") return chalk.yellow("\u25C9");
1025
+ if (s === "error" || s === "failed") return chalk.red("\u25CF");
1026
+ return d("\u25CB");
1027
+ };
1028
+ const statusText = (s) => {
1029
+ if (s === "online" || s === "registered") return chalk.green(s);
1030
+ if (s === "starting" || s === "pending") return chalk.yellow(s);
1031
+ if (s === "error" || s === "failed") return chalk.red(s);
1032
+ return d(s);
1033
+ };
1034
+ console.log(pad + d("User ") + w(state.user));
1035
+ console.log(pad + d("Instance ") + w(state.activeInstance));
1036
+ console.log(pad + d("Runner ") + statusIcon(state.runner) + " " + statusText(state.runner));
1037
+ console.log(pad + d("Tunnel ") + statusIcon(state.tunnel) + " " + statusText(state.tunnel));
1038
+ console.log(pad + d("PAGS ") + statusIcon(state.registration) + " " + statusText(state.registration));
1039
+ if (state.tunnelUrl) {
1040
+ console.log(pad + d("URL ") + c(state.tunnelUrl));
1041
+ }
1042
+ console.log("");
1043
+ if (state.lastEvent) {
1044
+ console.log(pad + d("Last: ") + d(state.lastEvent));
1045
+ }
1046
+ console.log("");
1047
+ console.log(
1048
+ pad + c("r") + d(" Refresh ") + c("l") + d(" Logs ") + c("q") + d(" Quit")
1049
+ );
1050
+ console.log("");
1051
+ }
1052
+ function printStep(label, status) {
1053
+ const icon = status === "ok" ? chalk.green("\u2713") : status === "fail" ? chalk.red("\u2717") : chalk.yellow("\u2026");
1054
+ console.log(pad + icon + " " + label);
1055
+ }
1056
+ async function waitForKey(keys) {
1057
+ return new Promise((resolve5) => {
1058
+ readline.emitKeypressEvents(process.stdin);
1059
+ if (process.stdin.isTTY) process.stdin.setRawMode(true);
1060
+ process.stdin.resume();
1061
+ const onKeypress = (str, key) => {
1062
+ if (key?.ctrl && key.name === "c") {
1063
+ cleanup();
1064
+ process.exit(0);
1065
+ }
1066
+ const val = (str || "").trim().toLowerCase();
1067
+ if (keys.includes(val)) {
1068
+ cleanup();
1069
+ resolve5(val);
1070
+ }
1071
+ };
1072
+ const cleanup = () => {
1073
+ process.stdin.off("keypress", onKeypress);
1074
+ if (process.stdin.isTTY) process.stdin.setRawMode(false);
1075
+ process.stdin.pause();
1076
+ };
1077
+ process.stdin.on("keypress", onKeypress);
1078
+ });
1079
+ }
1080
+
1081
+ // src/commands/up.ts
992
1082
  var API_BASE2 = "https://api.proagentstore.online";
993
1083
  var upCommand = new Command7("up").description("Start the browser runner for all your agent instances").option("--headless", "Run browser in headless mode").option("--instance <id>", "Connect to a specific instance only").action(async (opts) => {
994
1084
  const session = requireSession();
995
- writeLine(`Signed in as ${session.user.login}`);
996
- writeLine("Fetching your instances...");
1085
+ const state = {
1086
+ user: session.user.login,
1087
+ instances: [],
1088
+ activeInstance: "",
1089
+ runner: "starting",
1090
+ tunnel: "offline",
1091
+ tunnelUrl: "",
1092
+ registration: "pending",
1093
+ lastEvent: "Fetching instances...",
1094
+ taskCount: 0
1095
+ };
1096
+ clearScreen();
1097
+ printLogo();
1098
+ printStep("Signed in as " + session.user.login, "ok");
1099
+ printStep("Fetching instances...", "wait");
997
1100
  const res = await fetch(`${API_BASE2}/v1/instances/my/instances`, {
998
1101
  headers: { Authorization: `Bearer ${session.token}` }
999
1102
  });
1000
1103
  if (!res.ok) {
1001
- writeError(`Failed to fetch instances: ${res.status}`);
1104
+ printStep("Failed to fetch instances: " + res.status, "fail");
1002
1105
  process.exit(1);
1003
1106
  }
1004
1107
  const data = await res.json();
@@ -1007,27 +1110,127 @@ var upCommand = new Command7("up").description("Start the browser runner for all
1007
1110
  instances = instances.filter((i) => i.id === opts.instance || i.slug === opts.instance);
1008
1111
  }
1009
1112
  if (instances.length === 0) {
1010
- writeError("No active instances found. Subscribe to an agent first at https://proagentstore.online");
1113
+ printStep("No active instances found", "fail");
1114
+ writeLine(" Subscribe to an agent at https://proagentstore.online");
1011
1115
  process.exit(1);
1012
1116
  }
1013
- writeLine(`Found ${instances.length} instance${instances.length === 1 ? "" : "s"}:`);
1014
- for (const inst of instances) {
1015
- writeLine(` ${inst.name || inst.slug || inst.id.slice(0, 8)} (${inst.id.slice(0, 8)}...)`);
1117
+ state.instances = instances.map((i) => ({ id: i.id, name: i.name || i.slug || i.id.slice(0, 8) }));
1118
+ printStep(`Found ${instances.length} instance${instances.length === 1 ? "" : "s"}`, "ok");
1119
+ for (const inst of state.instances) {
1120
+ writeLine(` ${inst.name} (${inst.id.slice(0, 8)}...)`);
1016
1121
  }
1017
1122
  const target = instances[0];
1018
- writeLine(`
1019
- Connecting runner to: ${target.name || target.id.slice(0, 8)}...`);
1123
+ state.activeInstance = target.name || target.slug || target.id.slice(0, 8);
1124
+ printStep(`Connecting: ${state.activeInstance}`, "wait");
1020
1125
  const { spawn: spawn3 } = await import("child_process");
1021
1126
  const cliPath = process.argv[1];
1022
1127
  const args = [cliPath, "runner", "connect", target.id];
1023
1128
  if (opts.headless) args.push("--headless");
1024
1129
  const child = spawn3(process.execPath, args, {
1025
- stdio: "inherit",
1130
+ stdio: ["ignore", "pipe", "pipe"],
1026
1131
  env: { ...process.env, PAGS_TOKEN: session.token }
1027
1132
  });
1133
+ const logs = [];
1134
+ const handleOutput = (data2) => {
1135
+ const text = data2.toString("utf-8");
1136
+ for (const line of text.split("\n")) {
1137
+ const trimmed = line.trim();
1138
+ if (!trimmed) continue;
1139
+ logs.push(trimmed);
1140
+ if (logs.length > 200) logs.shift();
1141
+ const tunnelMatch = trimmed.match(/https:\/\/[a-z0-9-]+\.trycloudflare\.com/i);
1142
+ if (tunnelMatch) {
1143
+ state.tunnel = "online";
1144
+ state.tunnelUrl = tunnelMatch[0];
1145
+ state.lastEvent = "Tunnel created";
1146
+ printStatus(state);
1147
+ continue;
1148
+ }
1149
+ if (trimmed.includes("FAGS browser runtime listening")) {
1150
+ state.runner = "online";
1151
+ state.lastEvent = "Runner started";
1152
+ printStatus(state);
1153
+ continue;
1154
+ }
1155
+ if (trimmed.includes("Runtime registered") || trimmed.includes("CONNECTED")) {
1156
+ state.registration = "registered";
1157
+ state.lastEvent = "Registered with PAGS \u2014 ready for tasks";
1158
+ printStatus(state);
1159
+ continue;
1160
+ }
1161
+ if (trimmed.includes("fetch failed")) {
1162
+ state.registration = "failed";
1163
+ state.lastEvent = "PAGS registration failed (will retry on next task)";
1164
+ printStatus(state);
1165
+ continue;
1166
+ }
1167
+ if (trimmed.includes("INF ")) continue;
1168
+ if (/error|Error|EADDRINUSE|ECONNREFUSED|failed/i.test(trimmed)) {
1169
+ state.lastEvent = trimmed.slice(0, 80);
1170
+ printStatus(state);
1171
+ }
1172
+ }
1173
+ };
1174
+ child.stdout?.on("data", handleOutput);
1175
+ child.stderr?.on("data", handleOutput);
1176
+ let childDead = false;
1028
1177
  child.on("exit", (code) => {
1029
- process.exit(code || 0);
1178
+ childDead = true;
1179
+ if (code && code !== 0) {
1180
+ state.runner = "error";
1181
+ state.lastEvent = `Runner exited (code ${code})`;
1182
+ const recent = logs.slice(-5).filter((l) => !l.includes("INF "));
1183
+ if (recent.length) state.lastEvent += ": " + recent[recent.length - 1].slice(0, 60);
1184
+ printStatus(state);
1185
+ }
1030
1186
  });
1187
+ const shutdown = () => {
1188
+ child.kill();
1189
+ clearScreen();
1190
+ writeLine(" Runner stopped.");
1191
+ process.exit(0);
1192
+ };
1193
+ process.on("SIGINT", shutdown);
1194
+ process.on("SIGTERM", shutdown);
1195
+ while (true) {
1196
+ const key = await waitForKey(["r", "l", "q"]);
1197
+ if (key === "q") {
1198
+ shutdown();
1199
+ break;
1200
+ }
1201
+ if (key === "l") {
1202
+ clearScreen();
1203
+ writeLine(" Recent logs (last 30 lines):");
1204
+ writeLine("");
1205
+ for (const line of logs.slice(-30)) {
1206
+ writeLine(" " + line);
1207
+ }
1208
+ writeLine("");
1209
+ writeLine(" Press any key to go back...");
1210
+ await waitForKey(["r", "l", "q", " ", "\r"]);
1211
+ printStatus(state);
1212
+ }
1213
+ if (key === "r") {
1214
+ if (childDead) {
1215
+ writeLine(" Restarting runner...");
1216
+ state.runner = "starting";
1217
+ state.tunnel = "offline";
1218
+ state.tunnelUrl = "";
1219
+ state.registration = "pending";
1220
+ state.lastEvent = "Restarting...";
1221
+ const { execSync } = await import("child_process");
1222
+ try {
1223
+ execSync(`${process.execPath} ${process.argv[1]} up${opts.headless ? " --headless" : ""}`, {
1224
+ stdio: "inherit",
1225
+ env: process.env
1226
+ });
1227
+ } catch {
1228
+ }
1229
+ process.exit(0);
1230
+ }
1231
+ printStatus(state);
1232
+ }
1233
+ }
1031
1234
  });
1032
1235
 
1033
1236
  // src/index.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@proagentstore/cli",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "CLI for creating, publishing, and running ProAgentStore agents",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -30,14 +30,15 @@
30
30
  "typecheck": "tsc --noEmit"
31
31
  },
32
32
  "dependencies": {
33
+ "chalk": "^5.6.2",
33
34
  "commander": "^13.0.0",
34
35
  "playwright": "^1.60.0"
35
36
  },
36
37
  "devDependencies": {
38
+ "@types/node": "^22.0.0",
37
39
  "tsup": "^8.4.0",
38
40
  "tsx": "^4.21.0",
39
- "typescript": "^5.7.0",
40
- "@types/node": "^22.0.0"
41
+ "typescript": "^5.7.0"
41
42
  },
42
43
  "files": [
43
44
  "dist"