@optima-chat/browser-cli 0.2.0 → 0.3.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.
Files changed (2) hide show
  1. package/dist/index.js +198 -0
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -249,6 +249,12 @@ var BrowserAPI = class {
249
249
  { method: "DELETE" }
250
250
  );
251
251
  }
252
+ async uploadFiles(sessionId, index, filePaths) {
253
+ return request(`/api/sessions/${sessionId}/upload`, {
254
+ method: "POST",
255
+ body: JSON.stringify({ index, file_paths: filePaths })
256
+ });
257
+ }
252
258
  // Workflow methods
253
259
  async saveWorkflow(sessionId, name, description) {
254
260
  return request("/api/workflows", {
@@ -293,6 +299,37 @@ var BrowserAPI = class {
293
299
  body: JSON.stringify({})
294
300
  });
295
301
  }
302
+ // Script methods
303
+ async submitScript(name, code) {
304
+ return request(`/api/scripts`, {
305
+ method: "POST",
306
+ body: JSON.stringify({ name, code })
307
+ });
308
+ }
309
+ async updateScript(name, code) {
310
+ return request(`/api/scripts/${encodeURIComponent(name)}`, {
311
+ method: "PUT",
312
+ body: JSON.stringify({ code })
313
+ });
314
+ }
315
+ async listScripts() {
316
+ return request("/api/scripts");
317
+ }
318
+ async getScript(name) {
319
+ return request(`/api/scripts/${encodeURIComponent(name)}`);
320
+ }
321
+ async deleteScript(name) {
322
+ await request(`/api/scripts/${encodeURIComponent(name)}`, { method: "DELETE" });
323
+ }
324
+ async runScript(scriptName, params = {}) {
325
+ return request(`/api/scripts/${encodeURIComponent(scriptName)}/run`, {
326
+ method: "POST",
327
+ body: JSON.stringify({ params })
328
+ });
329
+ }
330
+ async getScriptTask(taskId) {
331
+ return request(`/api/script-tasks/${taskId}`);
332
+ }
296
333
  };
297
334
  var api = new BrowserAPI();
298
335
 
@@ -594,6 +631,16 @@ function registerInteractionCommands(program2) {
594
631
  process.exit(1);
595
632
  }
596
633
  });
634
+ program2.command("upload").description("Upload file(s) to a file input element").argument("<index>", "File input element index from DOM").argument("<files...>", "File path(s) to upload").action(async (index, files) => {
635
+ try {
636
+ const sessionId = loadSessionId();
637
+ const state = await api.uploadFiles(sessionId, parseInt(index, 10), files);
638
+ console.log(formatPageState(state));
639
+ } catch (err) {
640
+ console.error(formatError(err));
641
+ process.exit(1);
642
+ }
643
+ });
597
644
  }
598
645
 
599
646
  // src/commands/info.ts
@@ -961,6 +1008,156 @@ function cleanConsecutiveClick(steps) {
961
1008
  return result;
962
1009
  }
963
1010
 
1011
+ // src/commands/script.ts
1012
+ import { readFileSync as readFileSync3 } from "fs";
1013
+ var POLL_INTERVAL_MS = 2e3;
1014
+ var POLL_TIMEOUT_MS = 18e4;
1015
+ function formatScriptList(scripts) {
1016
+ if (scripts.length === 0) return "No scripts registered.";
1017
+ const lines = [];
1018
+ for (const s of scripts) {
1019
+ const tag = s.source ? ` [${s.source}]` : "";
1020
+ lines.push(`${s.name} \u2014 ${s.description}${tag}`);
1021
+ for (let i = 0; i < s.steps.length; i++) {
1022
+ lines.push(` [${i + 1}] ${s.steps[i].id} \u2014 ${s.steps[i].description}`);
1023
+ }
1024
+ lines.push("");
1025
+ }
1026
+ return lines.join("\n").trimEnd();
1027
+ }
1028
+ function formatScriptTask(task) {
1029
+ const lines = [];
1030
+ if (task.status === "completed") {
1031
+ lines.push("\u2713 Script completed");
1032
+ if (task.output) {
1033
+ for (const [k, v] of Object.entries(task.output)) {
1034
+ lines.push(`${k}: ${v}`);
1035
+ }
1036
+ }
1037
+ } else if (task.status === "needs_fallback") {
1038
+ lines.push("\u26A0 Script needs fallback");
1039
+ lines.push("");
1040
+ const output = task.output ?? {};
1041
+ const completed = output.completed_steps ?? [];
1042
+ const remaining = output.remaining_steps ?? [];
1043
+ const error = output.error;
1044
+ if (completed.length > 0) {
1045
+ lines.push("\u2713 Completed:");
1046
+ for (let i = 0; i < completed.length; i++) {
1047
+ lines.push(` [${i + 1}] ${completed[i].id} \u2014 ${completed[i].description}`);
1048
+ }
1049
+ lines.push("");
1050
+ }
1051
+ if (error) {
1052
+ const failedStep = completed.length + 1;
1053
+ const failedId = remaining.length > 0 ? remaining[0].id : "unknown";
1054
+ lines.push(`\u2717 Failed at step [${failedStep}] ${failedId}: ${error}`);
1055
+ lines.push("");
1056
+ }
1057
+ if (remaining.length > 0) {
1058
+ lines.push("\u2192 Remaining steps:");
1059
+ for (let i = 0; i < remaining.length; i++) {
1060
+ const stepNum = completed.length + i + 1;
1061
+ lines.push(` [${stepNum}] ${remaining[i].id} \u2014 ${remaining[i].description}`);
1062
+ }
1063
+ lines.push("");
1064
+ }
1065
+ lines.push("Session is still open \u2014 use browser-cli dom/click/input to continue");
1066
+ } else if (task.status === "failed") {
1067
+ lines.push(`\u2717 Script failed: ${task.error ?? "unknown error"}`);
1068
+ } else {
1069
+ lines.push(`Script status: ${task.status} (step ${task.current_step}/${task.total_steps})`);
1070
+ }
1071
+ return lines.join("\n");
1072
+ }
1073
+ function registerScriptCommands(program2) {
1074
+ program2.command("submit-script").description("Submit a script (write to EFS)").requiredOption("--name <name>", "Script name").requiredOption("--code-file <path>", "Path to Python script file").action(async (opts) => {
1075
+ try {
1076
+ const code = readFileSync3(opts.codeFile, "utf-8");
1077
+ const result = await api.submitScript(opts.name, code);
1078
+ console.log(`\u2713 Script ${result.name} ${result.created ? "created" : "updated"}`);
1079
+ } catch (err) {
1080
+ console.error(formatError(err));
1081
+ process.exit(1);
1082
+ }
1083
+ });
1084
+ program2.command("script-code").argument("<name>", "Script name").description("Show script source code").action(async (name) => {
1085
+ try {
1086
+ const detail = await api.getScript(name);
1087
+ console.log(detail.code);
1088
+ } catch (err) {
1089
+ console.error(formatError(err));
1090
+ process.exit(1);
1091
+ }
1092
+ });
1093
+ program2.command("delete-script").argument("<name>", "Script name").description("Delete a script").action(async (name) => {
1094
+ try {
1095
+ await api.deleteScript(name);
1096
+ console.log(`\u2713 Script ${name} deleted`);
1097
+ } catch (err) {
1098
+ console.error(formatError(err));
1099
+ process.exit(1);
1100
+ }
1101
+ });
1102
+ program2.command("scripts").description("List scripts").action(async () => {
1103
+ try {
1104
+ const resp = await api.listScripts();
1105
+ console.log(formatScriptList(resp.scripts));
1106
+ } catch (err) {
1107
+ console.error(formatError(err));
1108
+ process.exit(1);
1109
+ }
1110
+ });
1111
+ program2.command("runscript").argument("<name>", "Script name").description("Run a script (polls until complete)").option("--param <params...>", "Parameters as key=value").option("--no-poll", "Return immediately without polling").action(async (name, opts) => {
1112
+ try {
1113
+ const params = {};
1114
+ if (opts.param) {
1115
+ for (const p of opts.param) {
1116
+ const [k, ...rest] = p.split("=");
1117
+ params[k] = rest.join("=");
1118
+ }
1119
+ }
1120
+ clearSessionId();
1121
+ const task = await api.runScript(name, params);
1122
+ console.log(`Script started (task: ${task.id})`);
1123
+ if (!opts.poll) {
1124
+ console.log(`Poll with: browser-cli script-task ${task.id}`);
1125
+ return;
1126
+ }
1127
+ const deadline = Date.now() + POLL_TIMEOUT_MS;
1128
+ let result = task;
1129
+ while (result.status === "running" && Date.now() < deadline) {
1130
+ await sleep(POLL_INTERVAL_MS);
1131
+ result = await api.getScriptTask(task.id);
1132
+ }
1133
+ if (result.status === "running") {
1134
+ console.log(`Polling timed out. Task ${task.id} still running.`);
1135
+ console.log(`Poll with: browser-cli script-task ${task.id}`);
1136
+ return;
1137
+ }
1138
+ if (result.status === "needs_fallback" && result.session_id) {
1139
+ saveSessionId(result.session_id);
1140
+ }
1141
+ console.log(formatScriptTask(result));
1142
+ } catch (err) {
1143
+ console.error(formatError(err));
1144
+ process.exit(1);
1145
+ }
1146
+ });
1147
+ program2.command("script-task").argument("<task-id>", "Task ID").description("Check script task status").action(async (taskId) => {
1148
+ try {
1149
+ const task = await api.getScriptTask(taskId);
1150
+ console.log(formatScriptTask(task));
1151
+ } catch (err) {
1152
+ console.error(formatError(err));
1153
+ process.exit(1);
1154
+ }
1155
+ });
1156
+ }
1157
+ function sleep(ms) {
1158
+ return new Promise((resolve) => setTimeout(resolve, ms));
1159
+ }
1160
+
964
1161
  // src/index.ts
965
1162
  var require2 = createRequire(import.meta.url);
966
1163
  var { version } = require2("../package.json");
@@ -978,4 +1175,5 @@ registerInteractionCommands(program);
978
1175
  registerInfoCommands(program);
979
1176
  registerTabCommands(program);
980
1177
  registerWorkflowCommands(program);
1178
+ registerScriptCommands(program);
981
1179
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@optima-chat/browser-cli",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "bin": {