heyatlas 1.2.3 → 1.3.5

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 +396 -58
  2. package/package.json +2 -2
package/dist/cli.js CHANGED
@@ -4815,6 +4815,15 @@ async function pollForToken(deviceCode, interval) {
4815
4815
  }
4816
4816
  }
4817
4817
  async function login() {
4818
+ const envToken = process.env.HEYATLAS_ACCESS_TOKEN;
4819
+ const envUserId = process.env.HEYATLAS_USER_ID;
4820
+ if (envToken && envUserId) {
4821
+ return {
4822
+ accessToken: envToken,
4823
+ userId: envUserId,
4824
+ email: "sandbox@heyatlas.app"
4825
+ };
4826
+ }
4818
4827
  const existing = loadCredentials();
4819
4828
  if (existing) {
4820
4829
  return existing;
@@ -5496,7 +5505,7 @@ var DEFAULT_HOST = "agent.heyatlas.app";
5496
5505
  class AtlasTunnel {
5497
5506
  client = null;
5498
5507
  options;
5499
- agentId = "heyatlas-cli";
5508
+ agentId = "local";
5500
5509
  currentUserId = null;
5501
5510
  seenTaskIds = new Set;
5502
5511
  taskCallback = null;
@@ -52114,9 +52123,9 @@ _a153 = symbol153;
52114
52123
  // agents/acp-provider.ts
52115
52124
  var ACP_COMMANDS = {
52116
52125
  opencode: { command: "opencode", args: ["acp"] },
52117
- claude: { command: "claude-code-acp", args: [] },
52126
+ "claude-code": { command: "claude-code-acp", args: [] },
52118
52127
  goose: { command: "goose", args: ["acp"] },
52119
- gemini: { command: "gemini", args: ["--experimental-acp"] },
52128
+ "gemini-code": { command: "gemini", args: ["--experimental-acp"] },
52120
52129
  codex: { command: "npx", args: ["@zed-industries/codex-acp"] },
52121
52130
  kimi: { command: "kimi", args: ["--acp"] },
52122
52131
  vibe: { command: "vibe-acp", args: [] },
@@ -52199,17 +52208,354 @@ class ACPProviderAgent {
52199
52208
  }
52200
52209
  }
52201
52210
 
52211
+ // agents/config.ts
52212
+ function isSmith(agent) {
52213
+ return agent === "smith";
52214
+ }
52215
+
52216
+ // agents/smith.ts
52217
+ import { spawn as spawn2 } from "child_process";
52218
+ var SANDBOX_BUNDLE_PATH = "/home/user/agents/agent-smith.cjs";
52219
+ var SMITH_CONFIG = {
52220
+ port: 3141,
52221
+ agentId: "workflow-orchestrator",
52222
+ healthPath: "/agents",
52223
+ chatPath: "/agents/workflow-orchestrator/chat",
52224
+ command: "npx",
52225
+ args: ["tsx", "src/index.ts"],
52226
+ cwd: "smith",
52227
+ sandboxCommand: "node",
52228
+ sandboxArgs: [SANDBOX_BUNDLE_PATH]
52229
+ };
52230
+
52231
+ class Smith {
52232
+ options;
52233
+ baseUrl;
52234
+ process = null;
52235
+ constructor(options = {}) {
52236
+ this.options = options;
52237
+ this.baseUrl = `http://localhost:${SMITH_CONFIG.port}`;
52238
+ }
52239
+ get name() {
52240
+ return "smith";
52241
+ }
52242
+ get agentId() {
52243
+ return SMITH_CONFIG.agentId;
52244
+ }
52245
+ get port() {
52246
+ return SMITH_CONFIG.port;
52247
+ }
52248
+ async isRunning() {
52249
+ try {
52250
+ const response = await fetch(`${this.baseUrl}${SMITH_CONFIG.healthPath}`, {
52251
+ method: "GET",
52252
+ signal: AbortSignal.timeout(2000)
52253
+ });
52254
+ return response.ok;
52255
+ } catch {
52256
+ return false;
52257
+ }
52258
+ }
52259
+ async isAvailable() {
52260
+ try {
52261
+ const { promisify } = await import("node:util");
52262
+ const exec = promisify((await import("node:child_process")).exec);
52263
+ await exec("which npx || where npx");
52264
+ return true;
52265
+ } catch {
52266
+ return false;
52267
+ }
52268
+ }
52269
+ async isSandboxMode() {
52270
+ try {
52271
+ const fs = await import("node:fs/promises");
52272
+ await fs.access(SANDBOX_BUNDLE_PATH);
52273
+ return true;
52274
+ } catch {
52275
+ return false;
52276
+ }
52277
+ }
52278
+ async start() {
52279
+ if (await this.isRunning()) {
52280
+ console.log(`[smith] Server already running on port ${SMITH_CONFIG.port}`);
52281
+ return;
52282
+ }
52283
+ const isSandbox = await this.isSandboxMode();
52284
+ let command;
52285
+ let args;
52286
+ let cwd;
52287
+ if (isSandbox) {
52288
+ command = SMITH_CONFIG.sandboxCommand;
52289
+ args = SMITH_CONFIG.sandboxArgs;
52290
+ cwd = "/home/user/agents";
52291
+ console.log(`[smith] Running in sandbox mode with pre-built bundle`);
52292
+ } else {
52293
+ const baseCwd = this.options.cwd || process.cwd();
52294
+ const path = await import("node:path");
52295
+ const fs = await import("node:fs/promises");
52296
+ let smithPath = path.join(baseCwd, SMITH_CONFIG.cwd);
52297
+ try {
52298
+ await fs.access(smithPath);
52299
+ } catch {
52300
+ smithPath = path.join(baseCwd, "..", SMITH_CONFIG.cwd);
52301
+ }
52302
+ command = SMITH_CONFIG.command;
52303
+ args = SMITH_CONFIG.args;
52304
+ cwd = smithPath;
52305
+ console.log(`[smith] Running in development mode from: ${cwd}`);
52306
+ }
52307
+ const env = {
52308
+ ...process.env,
52309
+ PORT: String(SMITH_CONFIG.port)
52310
+ };
52311
+ this.process = spawn2(command, args, {
52312
+ cwd,
52313
+ env,
52314
+ stdio: ["pipe", "pipe", "pipe"],
52315
+ shell: true
52316
+ });
52317
+ this.process.stdout?.on("data", (data) => {
52318
+ console.log(`[smith] ${data.toString().trim()}`);
52319
+ });
52320
+ this.process.stderr?.on("data", (data) => {
52321
+ console.error(`[smith] ${data.toString().trim()}`);
52322
+ });
52323
+ this.process.on("error", (err) => {
52324
+ console.error(`[smith] Process error:`, err.message);
52325
+ });
52326
+ await this.waitForReady();
52327
+ }
52328
+ async waitForReady(maxAttempts = 60) {
52329
+ const delay2 = (ms) => new Promise((r) => setTimeout(r, ms));
52330
+ for (let i = 0;i < maxAttempts; i++) {
52331
+ if (await this.isRunning()) {
52332
+ return;
52333
+ }
52334
+ await delay2(1000);
52335
+ }
52336
+ throw new Error(`Smith failed to start after ${maxAttempts}s`);
52337
+ }
52338
+ stop() {
52339
+ if (this.process) {
52340
+ this.process.kill("SIGTERM");
52341
+ this.process = null;
52342
+ }
52343
+ }
52344
+ async* streamChat(prompt) {
52345
+ const response = await fetch(`${this.baseUrl}${SMITH_CONFIG.chatPath}`, {
52346
+ method: "POST",
52347
+ headers: { "Content-Type": "application/json" },
52348
+ body: JSON.stringify({
52349
+ messages: [{ role: "user", content: prompt }]
52350
+ })
52351
+ });
52352
+ if (!response.ok) {
52353
+ throw new Error(`Chat request failed: ${response.statusText}`);
52354
+ }
52355
+ const reader = response.body?.getReader();
52356
+ if (!reader) {
52357
+ throw new Error("No response body");
52358
+ }
52359
+ const decoder = new TextDecoder;
52360
+ let buffer = "";
52361
+ while (true) {
52362
+ const { done, value } = await reader.read();
52363
+ if (done)
52364
+ break;
52365
+ buffer += decoder.decode(value, { stream: true });
52366
+ const lines = buffer.split(`
52367
+ `);
52368
+ buffer = lines.pop() || "";
52369
+ for (const line of lines) {
52370
+ const trimmed = line.trim();
52371
+ if (!trimmed)
52372
+ continue;
52373
+ let jsonStr = null;
52374
+ if (trimmed.startsWith("data: ")) {
52375
+ jsonStr = trimmed.slice(6);
52376
+ } else if (/^\d+:/.test(trimmed)) {
52377
+ const colonIndex = trimmed.indexOf(":");
52378
+ jsonStr = trimmed.slice(colonIndex + 1);
52379
+ }
52380
+ if (jsonStr && jsonStr !== "[DONE]") {
52381
+ try {
52382
+ const event = JSON.parse(jsonStr);
52383
+ yield event;
52384
+ } catch {}
52385
+ }
52386
+ }
52387
+ }
52388
+ }
52389
+ }
52390
+
52202
52391
  // commands/connect.ts
52203
52392
  async function connect(agentType, options = {}) {
52204
52393
  const credentials = await login();
52205
- if (!isACPAgent(agentType)) {
52206
- console.error(`Error: Agent '${agentType}' is not ACP-compatible`);
52207
- console.error(`Supported agents: opencode, claude, goose, gemini, codex, etc.`);
52394
+ if (isSmith(agentType)) {
52395
+ return connectSmith(credentials, options);
52396
+ }
52397
+ if (isACPAgent(agentType)) {
52398
+ return connectACPAgent(agentType, credentials, options);
52399
+ }
52400
+ console.error(`Error: Unknown agent type '${agentType}'`);
52401
+ process.exit(1);
52402
+ }
52403
+ async function connectSmith(credentials, options) {
52404
+ const agent = new Smith({ cwd: process.cwd() });
52405
+ const available = await agent.isAvailable();
52406
+ if (!available) {
52407
+ console.error("Error: npx not found. Install Node.js to use smith");
52408
+ process.exit(1);
52409
+ }
52410
+ console.log("Agent: smith");
52411
+ try {
52412
+ console.log("Starting smith server...");
52413
+ await agent.start();
52414
+ console.log(`Smith server running on port ${agent.port}`);
52415
+ } catch (error87) {
52416
+ console.error(`Failed to start agent: ${error87}`);
52208
52417
  process.exit(1);
52209
52418
  }
52210
- const agent = new ACPProviderAgent(agentType, {
52211
- cwd: process.cwd()
52419
+ const tunnel = new AtlasTunnel({
52420
+ host: process.env.ATLAS_AGENT_HOST || "agent.heyatlas.app",
52421
+ token: credentials.accessToken,
52422
+ interactive: true
52423
+ });
52424
+ tunnel.onNewTask(async (task) => {
52425
+ const { prompt, latestUserMessage } = buildPromptWithContext(task);
52426
+ const isNewTask = task.state === "new";
52427
+ console.log(`${isNewTask ? "New" : "Continue"}: ${latestUserMessage.slice(0, 50)}...`);
52428
+ await tunnel.updateTask(task.id, { state: "in-progress" });
52429
+ await tunnel.appendContext(task.id, [
52430
+ {
52431
+ type: "message",
52432
+ timestamp: Date.now(),
52433
+ data: { role: "user", content: latestUserMessage }
52434
+ }
52435
+ ]);
52436
+ try {
52437
+ const parts = [];
52438
+ const toolCalls = new Map;
52439
+ const activeReasoningParts = new Map;
52440
+ for await (const chunk of agent.streamChat(prompt)) {
52441
+ await tunnel.broadcastTaskEvent(task.id, {
52442
+ type: "ui_stream_chunk",
52443
+ timestamp: Date.now(),
52444
+ data: chunk
52445
+ });
52446
+ switch (chunk.type) {
52447
+ case "text-delta": {
52448
+ const existingText = parts.find((p) => p.type === "text");
52449
+ if (existingText && "text" in existingText) {
52450
+ existingText.text += chunk.delta || "";
52451
+ } else {
52452
+ parts.push({ type: "text", text: chunk.delta || "" });
52453
+ }
52454
+ break;
52455
+ }
52456
+ case "reasoning-start": {
52457
+ const reasoningPart = {
52458
+ type: "reasoning",
52459
+ text: "",
52460
+ state: "streaming"
52461
+ };
52462
+ activeReasoningParts.set(chunk.id || "default", reasoningPart);
52463
+ parts.push(reasoningPart);
52464
+ break;
52465
+ }
52466
+ case "reasoning-delta":
52467
+ case "reasoning": {
52468
+ const id = chunk.id || "default";
52469
+ let reasoningPart = activeReasoningParts.get(id);
52470
+ if (!reasoningPart) {
52471
+ reasoningPart = { type: "reasoning", text: "", state: "streaming" };
52472
+ activeReasoningParts.set(id, reasoningPart);
52473
+ parts.push(reasoningPart);
52474
+ }
52475
+ reasoningPart.text += chunk.delta || chunk.text || "";
52476
+ break;
52477
+ }
52478
+ case "reasoning-end": {
52479
+ const id = chunk.id || "default";
52480
+ const reasoningPart = activeReasoningParts.get(id);
52481
+ if (reasoningPart) {
52482
+ reasoningPart.state = "done";
52483
+ activeReasoningParts.delete(id);
52484
+ }
52485
+ break;
52486
+ }
52487
+ case "tool-input-available": {
52488
+ const input = chunk.input;
52489
+ const realToolName = input?.toolName || chunk.toolName || "tool";
52490
+ const realArgs = input?.args || input || {};
52491
+ toolCalls.set(chunk.toolCallId || "", {
52492
+ type: "dynamic-tool",
52493
+ toolCallId: chunk.toolCallId,
52494
+ toolName: realToolName,
52495
+ state: "input-available",
52496
+ input: realArgs,
52497
+ subAgentName: chunk.subAgentName
52498
+ });
52499
+ parts.push(toolCalls.get(chunk.toolCallId || ""));
52500
+ break;
52501
+ }
52502
+ case "tool-output-available": {
52503
+ const existing = toolCalls.get(chunk.toolCallId || "");
52504
+ if (existing) {
52505
+ const updated = { ...existing, state: "output-available", output: chunk.output };
52506
+ toolCalls.set(chunk.toolCallId || "", updated);
52507
+ const idx = parts.findIndex((p) => p.type === "dynamic-tool" && p.toolCallId === chunk.toolCallId);
52508
+ if (idx >= 0)
52509
+ parts[idx] = updated;
52510
+ }
52511
+ break;
52512
+ }
52513
+ }
52514
+ }
52515
+ if (parts.length > 0) {
52516
+ await tunnel.appendContext(task.id, [
52517
+ {
52518
+ type: "ui_message",
52519
+ timestamp: Date.now(),
52520
+ data: { id: crypto.randomUUID(), role: "assistant", parts }
52521
+ }
52522
+ ]);
52523
+ }
52524
+ await tunnel.updateTask(task.id, { state: "completed", result: "end_turn" });
52525
+ console.log("Task completed");
52526
+ } catch (error87) {
52527
+ console.error(`Task failed: ${error87}`);
52528
+ await tunnel.updateTask(task.id, { state: "failed", result: String(error87) });
52529
+ }
52530
+ });
52531
+ await tunnel.connect(credentials.userId, "smith");
52532
+ console.log("Tunnel established");
52533
+ const voiceUrl = `${process.env.HEYATLAS_API || "https://heyatlas.app"}/chat`;
52534
+ if (options.openBrowser !== false) {
52535
+ try {
52536
+ const { execSync } = await import("child_process");
52537
+ const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? 'start ""' : "xdg-open";
52538
+ execSync(`${cmd} "${voiceUrl}"`, { stdio: "ignore" });
52539
+ } catch {}
52540
+ }
52541
+ console.log(`
52542
+ HeyAtlas connected to smith`);
52543
+ console.log(`Continue here: ${voiceUrl}`);
52544
+ console.log(`
52545
+ Press Ctrl+C to disconnect
52546
+ `);
52547
+ process.on("SIGINT", async () => {
52548
+ console.log(`
52549
+ Disconnecting...
52550
+ `);
52551
+ agent.stop();
52552
+ await tunnel.disconnect();
52553
+ process.exit(0);
52212
52554
  });
52555
+ await new Promise(() => {});
52556
+ }
52557
+ async function connectACPAgent(agentType, credentials, options) {
52558
+ const agent = new ACPProviderAgent(agentType, { cwd: process.cwd() });
52213
52559
  const available = await agent.isAvailable();
52214
52560
  if (!available) {
52215
52561
  const cmd = getACPCommand(agentType);
@@ -52220,7 +52566,7 @@ async function connect(agentType, options = {}) {
52220
52566
  console.log(`Agent: ${agentType} (via ACP AI Provider)`);
52221
52567
  try {
52222
52568
  await agent.init();
52223
- console.log(`ACP provider initialized`);
52569
+ console.log("ACP provider initialized");
52224
52570
  } catch (error87) {
52225
52571
  console.error(`Failed to initialize agent: ${error87}`);
52226
52572
  process.exit(1);
@@ -52269,49 +52615,56 @@ async function connect(agentType, options = {}) {
52269
52615
  text: "",
52270
52616
  state: "streaming"
52271
52617
  };
52272
- activeReasoningParts.set(chunk.id, reasoningPart);
52618
+ activeReasoningParts.set(chunk.id || "default", reasoningPart);
52273
52619
  parts.push(reasoningPart);
52274
52620
  break;
52275
52621
  }
52276
- case "reasoning-delta": {
52277
- const reasoningPart = activeReasoningParts.get(chunk.id);
52278
- if (reasoningPart && "text" in reasoningPart) {
52279
- reasoningPart.text += chunk.delta || "";
52622
+ case "reasoning-delta":
52623
+ case "reasoning": {
52624
+ const id = chunk.id || "default";
52625
+ let reasoningPart = activeReasoningParts.get(id);
52626
+ if (!reasoningPart) {
52627
+ reasoningPart = { type: "reasoning", text: "", state: "streaming" };
52628
+ activeReasoningParts.set(id, reasoningPart);
52629
+ parts.push(reasoningPart);
52280
52630
  }
52631
+ reasoningPart.text += chunk.delta || chunk.text || "";
52281
52632
  break;
52282
52633
  }
52283
52634
  case "reasoning-end": {
52284
- const reasoningPart = activeReasoningParts.get(chunk.id);
52635
+ const id = chunk.id || "default";
52636
+ const reasoningPart = activeReasoningParts.get(id);
52285
52637
  if (reasoningPart) {
52286
52638
  reasoningPart.state = "done";
52287
- activeReasoningParts.delete(chunk.id);
52639
+ activeReasoningParts.delete(id);
52288
52640
  }
52289
52641
  break;
52290
52642
  }
52291
- case "tool-input-available":
52643
+ case "tool-input-available": {
52644
+ const input = chunk.input;
52645
+ const realToolName = input?.toolName || chunk.toolName;
52646
+ const realArgs = input?.args || input || {};
52292
52647
  toolCalls.set(chunk.toolCallId, {
52293
52648
  type: "dynamic-tool",
52294
52649
  toolCallId: chunk.toolCallId,
52295
- toolName: chunk.toolName,
52650
+ toolName: realToolName,
52296
52651
  state: "input-available",
52297
- input: chunk.input
52652
+ input: realArgs
52298
52653
  });
52299
52654
  parts.push(toolCalls.get(chunk.toolCallId));
52300
52655
  break;
52301
- case "tool-output-available":
52656
+ }
52657
+ case "tool-output-available": {
52302
52658
  const existing = toolCalls.get(chunk.toolCallId);
52303
52659
  if (existing) {
52304
- const updated = {
52305
- ...existing,
52306
- state: "output-available",
52307
- output: chunk.output
52308
- };
52660
+ const updated = { ...existing, state: "output-available", output: chunk.output };
52309
52661
  toolCalls.set(chunk.toolCallId, updated);
52310
52662
  const idx = parts.findIndex((p) => p.type === "dynamic-tool" && p.toolCallId === chunk.toolCallId);
52311
52663
  if (idx >= 0)
52312
52664
  parts[idx] = updated;
52313
52665
  }
52314
52666
  break;
52667
+ }
52315
52668
  }
52316
52669
  }
52317
52670
  if (parts.length > 0) {
@@ -52319,29 +52672,19 @@ async function connect(agentType, options = {}) {
52319
52672
  {
52320
52673
  type: "ui_message",
52321
52674
  timestamp: Date.now(),
52322
- data: {
52323
- id: crypto.randomUUID(),
52324
- role: "assistant",
52325
- parts
52326
- }
52675
+ data: { id: crypto.randomUUID(), role: "assistant", parts }
52327
52676
  }
52328
52677
  ]);
52329
52678
  }
52330
- await tunnel.updateTask(task.id, {
52331
- state: "completed",
52332
- result: "end_turn"
52333
- });
52334
- console.log(`Task completed`);
52679
+ await tunnel.updateTask(task.id, { state: "completed", result: "end_turn" });
52680
+ console.log("Task completed");
52335
52681
  } catch (error87) {
52336
52682
  console.error(`Task failed: ${error87}`);
52337
- await tunnel.updateTask(task.id, {
52338
- state: "failed",
52339
- result: String(error87)
52340
- });
52683
+ await tunnel.updateTask(task.id, { state: "failed", result: String(error87) });
52341
52684
  }
52342
52685
  });
52343
52686
  await tunnel.connect(credentials.userId, agentType);
52344
- console.log(`Tunnel established`);
52687
+ console.log("Tunnel established");
52345
52688
  const voiceUrl = `${process.env.HEYATLAS_API || "https://heyatlas.app"}/chat`;
52346
52689
  if (options.openBrowser !== false) {
52347
52690
  try {
@@ -52386,10 +52729,7 @@ function buildPromptWithContext(task) {
52386
52729
  } else if (e.type === "message" && e.data) {
52387
52730
  const data = e.data;
52388
52731
  if (data.role && data.content) {
52389
- messages.push({
52390
- role: String(data.role),
52391
- content: String(data.content)
52392
- });
52732
+ messages.push({ role: String(data.role), content: String(data.content) });
52393
52733
  }
52394
52734
  } else if (e.role && e.content) {
52395
52735
  messages.push({ role: String(e.role), content: String(e.content) });
@@ -52421,11 +52761,11 @@ Please continue based on the above context.`;
52421
52761
  }
52422
52762
 
52423
52763
  // index.ts
52424
- var SUPPORTED_AGENTS = [
52764
+ var ACP_AGENTS = [
52425
52765
  "opencode",
52426
- "claude",
52766
+ "claude-code",
52427
52767
  "goose",
52428
- "gemini",
52768
+ "gemini-code",
52429
52769
  "codex",
52430
52770
  "kimi",
52431
52771
  "vibe",
@@ -52434,6 +52774,8 @@ var SUPPORTED_AGENTS = [
52434
52774
  "openhands",
52435
52775
  "cagent"
52436
52776
  ];
52777
+ var SMITH_AGENTS = ["smith"];
52778
+ var SUPPORTED_AGENTS = [...ACP_AGENTS, ...SMITH_AGENTS];
52437
52779
  var { positionals, values } = parseArgs({
52438
52780
  args: process.argv.slice(2),
52439
52781
  options: {
@@ -52445,27 +52787,23 @@ var { positionals, values } = parseArgs({
52445
52787
  });
52446
52788
  function printHelp() {
52447
52789
  console.log(`
52448
- heyatlas - Tunnel local AI agents to the cloud via ACP
52790
+ heyatlas - Tunnel local AI agents to the cloud
52449
52791
 
52450
52792
  Usage:
52451
- heyatlas connect <agent> Connect agent to Atlas (via ACP protocol)
52793
+ heyatlas connect <agent> Connect agent to Atlas
52452
52794
 
52453
- ACP-Compatible Agents:
52454
- ${SUPPORTED_AGENTS.join(", ")}
52795
+ Supported Agents:
52796
+ ACP Agents: ${ACP_AGENTS.join(", ")}
52797
+ Smith: ${SMITH_AGENTS.join(", ")}
52455
52798
 
52456
52799
  Options:
52457
52800
  -h, --help Show this help message
52458
52801
  -v, --version Show version
52459
52802
  --no-browser Don't open browser automatically
52460
52803
 
52461
- Prerequisites:
52462
- - The agent must be installed and support ACP mode
52463
- - Agent-specific setup (API keys, etc.)
52464
-
52465
52804
  Examples:
52466
- heyatlas connect opencode Connect OpenCode via ACP
52467
- heyatlas connect goose Connect Goose via ACP
52468
- heyatlas connect claude Connect Claude Code via ACP
52805
+ heyatlas connect opencode Connect OpenCode via ACP
52806
+ heyatlas connect smith Connect Smith
52469
52807
  `);
52470
52808
  }
52471
52809
  async function main() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "heyatlas",
3
- "version": "1.2.3",
3
+ "version": "1.3.5",
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",
@@ -50,4 +50,4 @@
50
50
  "engines": {
51
51
  "node": ">=18.0.0"
52
52
  }
53
- }
53
+ }