heyatlas 1.8.0 → 1.9.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/cli.js +113 -9
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -5559,6 +5559,22 @@ class AtlasTunnel {
5559
5559
  };
5560
5560
  });
5561
5561
  }
5562
+ async waitForState(timeoutMs = 1e4) {
5563
+ if (this.currentState)
5564
+ return;
5565
+ return new Promise((resolve, reject) => {
5566
+ const timeout = setTimeout(() => reject(new Error("Timed out waiting for state")), timeoutMs);
5567
+ const check = () => {
5568
+ if (this.currentState) {
5569
+ clearTimeout(timeout);
5570
+ resolve();
5571
+ } else {
5572
+ setTimeout(check, 100);
5573
+ }
5574
+ };
5575
+ check();
5576
+ });
5577
+ }
5562
5578
  handleStateUpdate(state, source) {
5563
5579
  if (source === "server") {
5564
5580
  this.currentState = state;
@@ -52195,7 +52211,31 @@ You coordinate the following specialized subagents — delegate to them via the
52195
52211
  - Update your plan as tasks progress
52196
52212
  - Use absolute paths for all file operations
52197
52213
  - If you encounter auth barriers (logins, CAPTCHAs), ask the user to complete the manual step
52198
- - Provide a comprehensive summary when done`,
52214
+ - Provide a comprehensive summary when done
52215
+
52216
+ ## Output Upload
52217
+
52218
+ After completing a task that produces files, upload them to cloud storage using rclone:
52219
+
52220
+ 1. Read \\\`/home/user/agents/task-meta.json\\\` to get the bucket name, userId, and taskId
52221
+ 2. Upload all output files using: \\\`rclone copy <file-or-dir> r2:<bucket>/<userId>/<taskId>/\\\`
52222
+ 3. Include the uploaded file paths in your summary
52223
+
52224
+ Example:
52225
+ \\\`\\\`\\\`bash
52226
+ # Read task metadata
52227
+ META=$(cat /home/user/agents/task-meta.json)
52228
+ BUCKET=$(echo $META | jq -r '.bucket')
52229
+ USER_ID=$(echo $META | jq -r '.userId')
52230
+ TASK_ID=$(echo $META | jq -r '.taskId')
52231
+ PUBLIC_URL=$(echo $META | jq -r '.publicUrl')
52232
+
52233
+ # Upload output files
52234
+ rclone copy /home/user/output.docx r2:$BUCKET/$USER_ID/$TASK_ID/
52235
+
52236
+ # Share the public URL
52237
+ echo "File available at: $PUBLIC_URL/$USER_ID/$TASK_ID/output.docx"
52238
+ \\\`\\\`\\\``,
52199
52239
  "smith-browser.md": `---
52200
52240
  description: Browser automation expert — navigates websites, fills forms, extracts data, and performs interactive web workflows
52201
52241
  mode: subagent
@@ -52545,6 +52585,26 @@ async function connect(agentType, options = {}) {
52545
52585
  interactive: true,
52546
52586
  agentType: options.agentType || "local"
52547
52587
  });
52588
+ if (options.taskFile) {
52589
+ const fs = await import("fs");
52590
+ const taskData = JSON.parse(fs.readFileSync(options.taskFile, "utf-8"));
52591
+ console.log(`Task: ${taskData.description.slice(0, 80)}...`);
52592
+ await tunnel.connect(credentials.userId, agent.name);
52593
+ await tunnel.waitForState();
52594
+ console.log("Tunnel established");
52595
+ try {
52596
+ await handleTask(taskData, agent, tunnel);
52597
+ console.log(`
52598
+ Task complete. Disconnecting...`);
52599
+ } catch (error87) {
52600
+ console.error(`Task failed: ${error87}`);
52601
+ } finally {
52602
+ agent.cleanup();
52603
+ await tunnel.disconnect();
52604
+ process.exit(0);
52605
+ }
52606
+ return;
52607
+ }
52548
52608
  tunnel.onNewTask(async (task) => {
52549
52609
  await handleTask(task, agent, tunnel);
52550
52610
  });
@@ -52602,7 +52662,12 @@ async function handleTask(task, agent, tunnel) {
52602
52662
  { type: "ui_message", timestamp: Date.now(), data: { id: crypto.randomUUID(), role: "assistant", parts } }
52603
52663
  ]);
52604
52664
  }
52605
- await tunnel.updateTask(task.id, { state: "completed", result: "end_turn" });
52665
+ const outputs = extractOutputUrls(parts);
52666
+ await tunnel.updateTask(task.id, {
52667
+ state: "completed",
52668
+ result: "end_turn",
52669
+ ...outputs.length > 0 ? { outputs } : {}
52670
+ });
52606
52671
  console.log("Task completed");
52607
52672
  } catch (error87) {
52608
52673
  console.error(`Task failed: ${error87}`);
@@ -52729,6 +52794,41 @@ Please continue based on the above context.`;
52729
52794
  }
52730
52795
  return { prompt, latestUserMessage };
52731
52796
  }
52797
+ function extractOutputUrls(parts) {
52798
+ const outputs = [];
52799
+ const urlPattern = /https?:\/\/[^\s"'<>]+/g;
52800
+ for (const part of parts) {
52801
+ if (part.type === "text" && typeof part.text === "string") {
52802
+ const matches = part.text.match(urlPattern);
52803
+ if (!matches)
52804
+ continue;
52805
+ for (const url3 of matches) {
52806
+ const filename = url3.split("/").pop() || "";
52807
+ const ext = filename.includes(".") ? filename.split(".").pop()?.toLowerCase() : null;
52808
+ if (!ext)
52809
+ continue;
52810
+ const typeMap = {
52811
+ pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
52812
+ docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
52813
+ xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
52814
+ pdf: "application/pdf",
52815
+ html: "text/html",
52816
+ png: "image/png",
52817
+ jpg: "image/jpeg",
52818
+ jpeg: "image/jpeg",
52819
+ csv: "text/csv",
52820
+ json: "application/json"
52821
+ };
52822
+ outputs.push({
52823
+ url: url3,
52824
+ filename: decodeURIComponent(filename),
52825
+ type: typeMap[ext] || undefined
52826
+ });
52827
+ }
52828
+ }
52829
+ }
52830
+ return [...new Map(outputs.map((o) => [o.url, o])).values()];
52831
+ }
52732
52832
  function openBrowser(url3) {
52733
52833
  try {
52734
52834
  const { execSync } = __require("child_process");
@@ -52758,7 +52858,8 @@ var { positionals, values } = parseArgs({
52758
52858
  options: {
52759
52859
  help: { type: "boolean", short: "h" },
52760
52860
  version: { type: "boolean", short: "v" },
52761
- "no-browser": { type: "boolean" }
52861
+ "no-browser": { type: "boolean" },
52862
+ "task-file": { type: "string" }
52762
52863
  },
52763
52864
  allowPositionals: true
52764
52865
  });
@@ -52773,13 +52874,15 @@ Supported Agents:
52773
52874
  ${SUPPORTED_AGENTS.join(", ")}
52774
52875
 
52775
52876
  Options:
52776
- -h, --help Show this help message
52777
- -v, --version Show version
52778
- --no-browser Don't open browser automatically
52877
+ -h, --help Show this help message
52878
+ -v, --version Show version
52879
+ --no-browser Don't open browser automatically
52880
+ --task-file <path> Run a single task from a JSON file and exit
52779
52881
 
52780
52882
  Examples:
52781
- heyatlas connect opencode Connect OpenCode via ACP
52782
- heyatlas connect smith Connect Smith via OpenCode
52883
+ heyatlas connect opencode Connect OpenCode via ACP
52884
+ heyatlas connect smith Connect Smith via OpenCode
52885
+ heyatlas connect smith --task-file task.json Run a single task and exit
52783
52886
  `);
52784
52887
  }
52785
52888
  async function main() {
@@ -52806,7 +52909,8 @@ async function main() {
52806
52909
  process.exit(1);
52807
52910
  }
52808
52911
  await connect(agent, {
52809
- openBrowser: !values["no-browser"]
52912
+ openBrowser: !values["no-browser"],
52913
+ taskFile: values["task-file"]
52810
52914
  });
52811
52915
  } else {
52812
52916
  console.error(`Unknown command: ${command}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "heyatlas",
3
- "version": "1.8.0",
3
+ "version": "1.9.0",
4
4
  "description": "Tunnel local AI agents to the cloud for voice-powered interactions",
5
5
  "author": "Bishwendu Kundu <bishwenduk029@gmail.com>",
6
6
  "license": "MIT",