heyatlas 1.2.2 → 1.3.3
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/cli.js +292 -58
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -5496,7 +5496,7 @@ var DEFAULT_HOST = "agent.heyatlas.app";
|
|
|
5496
5496
|
class AtlasTunnel {
|
|
5497
5497
|
client = null;
|
|
5498
5498
|
options;
|
|
5499
|
-
agentId = "
|
|
5499
|
+
agentId = "local";
|
|
5500
5500
|
currentUserId = null;
|
|
5501
5501
|
seenTaskIds = new Set;
|
|
5502
5502
|
taskCallback = null;
|
|
@@ -52114,9 +52114,9 @@ _a153 = symbol153;
|
|
|
52114
52114
|
// agents/acp-provider.ts
|
|
52115
52115
|
var ACP_COMMANDS = {
|
|
52116
52116
|
opencode: { command: "opencode", args: ["acp"] },
|
|
52117
|
-
claude: { command: "claude-code-acp", args: [] },
|
|
52117
|
+
"claude-code": { command: "claude-code-acp", args: [] },
|
|
52118
52118
|
goose: { command: "goose", args: ["acp"] },
|
|
52119
|
-
gemini: { command: "gemini", args: ["--experimental-acp"] },
|
|
52119
|
+
"gemini-code": { command: "gemini", args: ["--experimental-acp"] },
|
|
52120
52120
|
codex: { command: "npx", args: ["@zed-industries/codex-acp"] },
|
|
52121
52121
|
kimi: { command: "kimi", args: ["--acp"] },
|
|
52122
52122
|
vibe: { command: "vibe-acp", args: [] },
|
|
@@ -52199,17 +52199,259 @@ class ACPProviderAgent {
|
|
|
52199
52199
|
}
|
|
52200
52200
|
}
|
|
52201
52201
|
|
|
52202
|
+
// agents/config.ts
|
|
52203
|
+
function isHTTPAgent(agent) {
|
|
52204
|
+
return agent === "agent-smith-py";
|
|
52205
|
+
}
|
|
52206
|
+
|
|
52207
|
+
// agents/http-agent.ts
|
|
52208
|
+
import { spawn as spawn2 } from "child_process";
|
|
52209
|
+
var HTTP_AGENT_CONFIG = {
|
|
52210
|
+
"agent-smith-py": {
|
|
52211
|
+
command: "uv",
|
|
52212
|
+
args: ["run", "python", "main.py"],
|
|
52213
|
+
port: 3141,
|
|
52214
|
+
healthPath: "/health",
|
|
52215
|
+
taskPath: "/agents/agent-smith/text",
|
|
52216
|
+
streamPath: "/agents/agent-smith/stream",
|
|
52217
|
+
cwd: "desktop-sandbox/agent-smith-py"
|
|
52218
|
+
}
|
|
52219
|
+
};
|
|
52220
|
+
|
|
52221
|
+
class HTTPAgent {
|
|
52222
|
+
agentType;
|
|
52223
|
+
options;
|
|
52224
|
+
process = null;
|
|
52225
|
+
baseUrl;
|
|
52226
|
+
config;
|
|
52227
|
+
constructor(agentType, options = {}) {
|
|
52228
|
+
this.agentType = agentType;
|
|
52229
|
+
this.options = options;
|
|
52230
|
+
this.config = HTTP_AGENT_CONFIG[agentType];
|
|
52231
|
+
this.baseUrl = `http://localhost:${this.config.port}`;
|
|
52232
|
+
}
|
|
52233
|
+
get name() {
|
|
52234
|
+
return this.agentType;
|
|
52235
|
+
}
|
|
52236
|
+
get port() {
|
|
52237
|
+
return this.config.port;
|
|
52238
|
+
}
|
|
52239
|
+
async isAvailable() {
|
|
52240
|
+
try {
|
|
52241
|
+
const { promisify } = await import("node:util");
|
|
52242
|
+
const exec = promisify((await import("node:child_process")).exec);
|
|
52243
|
+
await exec("which uv || where uv");
|
|
52244
|
+
return true;
|
|
52245
|
+
} catch {
|
|
52246
|
+
return false;
|
|
52247
|
+
}
|
|
52248
|
+
}
|
|
52249
|
+
async start() {
|
|
52250
|
+
const env = {
|
|
52251
|
+
...process.env,
|
|
52252
|
+
PYTHONUNBUFFERED: "1"
|
|
52253
|
+
};
|
|
52254
|
+
const cwd = this.config.cwd ? `${this.options.cwd || process.cwd()}/${this.config.cwd}` : this.options.cwd || process.cwd();
|
|
52255
|
+
this.process = spawn2(this.config.command, [...this.config.args, "--port", String(this.config.port)], {
|
|
52256
|
+
cwd,
|
|
52257
|
+
env,
|
|
52258
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
52259
|
+
});
|
|
52260
|
+
this.process.stdout?.on("data", (data) => {
|
|
52261
|
+
console.log(`[${this.agentType}] ${data.toString().trim()}`);
|
|
52262
|
+
});
|
|
52263
|
+
this.process.stderr?.on("data", (data) => {
|
|
52264
|
+
console.error(`[${this.agentType}] ${data.toString().trim()}`);
|
|
52265
|
+
});
|
|
52266
|
+
await this.waitForReady();
|
|
52267
|
+
}
|
|
52268
|
+
async waitForReady(maxAttempts = 30) {
|
|
52269
|
+
const delay2 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
52270
|
+
for (let i = 0;i < maxAttempts; i++) {
|
|
52271
|
+
try {
|
|
52272
|
+
const response = await fetch(`${this.baseUrl}${this.config.healthPath}`);
|
|
52273
|
+
if (response.ok) {
|
|
52274
|
+
return;
|
|
52275
|
+
}
|
|
52276
|
+
} catch {}
|
|
52277
|
+
await delay2(1000);
|
|
52278
|
+
}
|
|
52279
|
+
throw new Error(`Agent ${this.agentType} failed to start after ${maxAttempts}s`);
|
|
52280
|
+
}
|
|
52281
|
+
async executeTask(prompt, taskId) {
|
|
52282
|
+
const response = await fetch(`${this.baseUrl}${this.config.taskPath}`, {
|
|
52283
|
+
method: "POST",
|
|
52284
|
+
headers: { "Content-Type": "application/json" },
|
|
52285
|
+
body: JSON.stringify({ prompt, task_id: taskId })
|
|
52286
|
+
});
|
|
52287
|
+
if (!response.ok) {
|
|
52288
|
+
throw new Error(`Task failed: ${response.statusText}`);
|
|
52289
|
+
}
|
|
52290
|
+
const data = await response.json();
|
|
52291
|
+
return data;
|
|
52292
|
+
}
|
|
52293
|
+
async* executeTaskStream(prompt, taskId) {
|
|
52294
|
+
const response = await fetch(`${this.baseUrl}${this.config.streamPath}`, {
|
|
52295
|
+
method: "POST",
|
|
52296
|
+
headers: { "Content-Type": "application/json" },
|
|
52297
|
+
body: JSON.stringify({ prompt, task_id: taskId })
|
|
52298
|
+
});
|
|
52299
|
+
if (!response.ok) {
|
|
52300
|
+
throw new Error(`Stream failed: ${response.statusText}`);
|
|
52301
|
+
}
|
|
52302
|
+
const reader = response.body?.getReader();
|
|
52303
|
+
if (!reader) {
|
|
52304
|
+
throw new Error("No response body");
|
|
52305
|
+
}
|
|
52306
|
+
const decoder = new TextDecoder;
|
|
52307
|
+
let buffer = "";
|
|
52308
|
+
while (true) {
|
|
52309
|
+
const { done, value } = await reader.read();
|
|
52310
|
+
if (done)
|
|
52311
|
+
break;
|
|
52312
|
+
buffer += decoder.decode(value, { stream: true });
|
|
52313
|
+
const lines = buffer.split(`
|
|
52314
|
+
`);
|
|
52315
|
+
buffer = lines.pop() || "";
|
|
52316
|
+
for (const line of lines) {
|
|
52317
|
+
if (line.startsWith("data: ")) {
|
|
52318
|
+
try {
|
|
52319
|
+
const event = JSON.parse(line.slice(6));
|
|
52320
|
+
yield event;
|
|
52321
|
+
} catch {}
|
|
52322
|
+
}
|
|
52323
|
+
}
|
|
52324
|
+
}
|
|
52325
|
+
}
|
|
52326
|
+
stop() {
|
|
52327
|
+
if (this.process) {
|
|
52328
|
+
this.process.kill("SIGTERM");
|
|
52329
|
+
this.process = null;
|
|
52330
|
+
}
|
|
52331
|
+
}
|
|
52332
|
+
}
|
|
52333
|
+
|
|
52202
52334
|
// commands/connect.ts
|
|
52203
52335
|
async function connect(agentType, options = {}) {
|
|
52204
52336
|
const credentials = await login();
|
|
52205
|
-
if (
|
|
52206
|
-
|
|
52207
|
-
|
|
52337
|
+
if (isHTTPAgent(agentType)) {
|
|
52338
|
+
return connectHTTPAgent(agentType, credentials, options);
|
|
52339
|
+
}
|
|
52340
|
+
if (isACPAgent(agentType)) {
|
|
52341
|
+
return connectACPAgent(agentType, credentials, options);
|
|
52342
|
+
}
|
|
52343
|
+
console.error(`Error: Unknown agent type '${agentType}'`);
|
|
52344
|
+
process.exit(1);
|
|
52345
|
+
}
|
|
52346
|
+
async function connectHTTPAgent(agentType, credentials, options) {
|
|
52347
|
+
const agent = new HTTPAgent(agentType, { cwd: process.cwd() });
|
|
52348
|
+
const available = await agent.isAvailable();
|
|
52349
|
+
if (!available) {
|
|
52350
|
+
console.error(`Error: Python not found. Install Python 3.11+ to use ${agentType}`);
|
|
52351
|
+
process.exit(1);
|
|
52352
|
+
}
|
|
52353
|
+
console.log(`Agent: ${agentType} (HTTP mode)`);
|
|
52354
|
+
try {
|
|
52355
|
+
console.log("Starting agent server...");
|
|
52356
|
+
await agent.start();
|
|
52357
|
+
console.log(`Agent server running on port ${agent.port}`);
|
|
52358
|
+
} catch (error87) {
|
|
52359
|
+
console.error(`Failed to start agent: ${error87}`);
|
|
52208
52360
|
process.exit(1);
|
|
52209
52361
|
}
|
|
52210
|
-
const
|
|
52211
|
-
|
|
52362
|
+
const tunnel = new AtlasTunnel({
|
|
52363
|
+
host: process.env.ATLAS_AGENT_HOST || "agent.heyatlas.app",
|
|
52364
|
+
token: credentials.accessToken,
|
|
52365
|
+
interactive: true
|
|
52212
52366
|
});
|
|
52367
|
+
tunnel.onNewTask(async (task) => {
|
|
52368
|
+
const prompt = task.description || "Hello";
|
|
52369
|
+
console.log(`Task: ${prompt.slice(0, 50)}...`);
|
|
52370
|
+
await tunnel.updateTask(task.id, { state: "in-progress" });
|
|
52371
|
+
await tunnel.appendContext(task.id, [
|
|
52372
|
+
{
|
|
52373
|
+
type: "message",
|
|
52374
|
+
timestamp: Date.now(),
|
|
52375
|
+
data: { role: "user", content: prompt }
|
|
52376
|
+
}
|
|
52377
|
+
]);
|
|
52378
|
+
await tunnel.broadcastTaskEvent(task.id, {
|
|
52379
|
+
type: "workforce_event",
|
|
52380
|
+
timestamp: Date.now(),
|
|
52381
|
+
data: { event_type: "task_started", task_content: prompt }
|
|
52382
|
+
});
|
|
52383
|
+
try {
|
|
52384
|
+
let finalResult = "Task completed";
|
|
52385
|
+
let finalStatus = "completed";
|
|
52386
|
+
const parts = [];
|
|
52387
|
+
for await (const event of agent.executeTaskStream(prompt, task.id)) {
|
|
52388
|
+
await tunnel.broadcastTaskEvent(task.id, {
|
|
52389
|
+
type: "workforce_event",
|
|
52390
|
+
timestamp: Date.now(),
|
|
52391
|
+
data: event
|
|
52392
|
+
});
|
|
52393
|
+
if (event.event_type === "result") {
|
|
52394
|
+
finalResult = event.result || event.error || "Task completed";
|
|
52395
|
+
finalStatus = event.status || "completed";
|
|
52396
|
+
}
|
|
52397
|
+
if (event.event_type === "task_assigned") {
|
|
52398
|
+
console.log(` → Assigned to: ${event.worker_name?.slice(0, 40)}...`);
|
|
52399
|
+
} else if (event.event_type === "task_decomposed") {
|
|
52400
|
+
console.log(` → Decomposed into ${event.subtasks?.length || 0} subtasks`);
|
|
52401
|
+
}
|
|
52402
|
+
}
|
|
52403
|
+
await tunnel.appendContext(task.id, [
|
|
52404
|
+
{
|
|
52405
|
+
type: "ui_message",
|
|
52406
|
+
timestamp: Date.now(),
|
|
52407
|
+
data: {
|
|
52408
|
+
id: crypto.randomUUID(),
|
|
52409
|
+
role: "assistant",
|
|
52410
|
+
parts: [{ type: "text", text: finalResult }]
|
|
52411
|
+
}
|
|
52412
|
+
}
|
|
52413
|
+
]);
|
|
52414
|
+
await tunnel.updateTask(task.id, {
|
|
52415
|
+
state: finalStatus === "completed" ? "completed" : "failed",
|
|
52416
|
+
result: finalResult
|
|
52417
|
+
});
|
|
52418
|
+
console.log(`Task ${finalStatus}`);
|
|
52419
|
+
} catch (error87) {
|
|
52420
|
+
console.error(`Task failed: ${error87}`);
|
|
52421
|
+
await tunnel.updateTask(task.id, {
|
|
52422
|
+
state: "failed",
|
|
52423
|
+
result: String(error87)
|
|
52424
|
+
});
|
|
52425
|
+
}
|
|
52426
|
+
});
|
|
52427
|
+
await tunnel.connect(credentials.userId, agentType);
|
|
52428
|
+
console.log("Tunnel established");
|
|
52429
|
+
const voiceUrl = `${process.env.HEYATLAS_API || "https://heyatlas.app"}/chat`;
|
|
52430
|
+
if (options.openBrowser !== false) {
|
|
52431
|
+
try {
|
|
52432
|
+
const { execSync } = await import("child_process");
|
|
52433
|
+
const cmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? 'start ""' : "xdg-open";
|
|
52434
|
+
execSync(`${cmd} "${voiceUrl}"`, { stdio: "ignore" });
|
|
52435
|
+
} catch {}
|
|
52436
|
+
}
|
|
52437
|
+
console.log(`
|
|
52438
|
+
HeyAtlas connected to ${agentType}`);
|
|
52439
|
+
console.log(`Continue here: ${voiceUrl}`);
|
|
52440
|
+
console.log(`
|
|
52441
|
+
Press Ctrl+C to disconnect
|
|
52442
|
+
`);
|
|
52443
|
+
process.on("SIGINT", async () => {
|
|
52444
|
+
console.log(`
|
|
52445
|
+
Disconnecting...
|
|
52446
|
+
`);
|
|
52447
|
+
agent.stop();
|
|
52448
|
+
await tunnel.disconnect();
|
|
52449
|
+
process.exit(0);
|
|
52450
|
+
});
|
|
52451
|
+
await new Promise(() => {});
|
|
52452
|
+
}
|
|
52453
|
+
async function connectACPAgent(agentType, credentials, options) {
|
|
52454
|
+
const agent = new ACPProviderAgent(agentType, { cwd: process.cwd() });
|
|
52213
52455
|
const available = await agent.isAvailable();
|
|
52214
52456
|
if (!available) {
|
|
52215
52457
|
const cmd = getACPCommand(agentType);
|
|
@@ -52220,7 +52462,7 @@ async function connect(agentType, options = {}) {
|
|
|
52220
52462
|
console.log(`Agent: ${agentType} (via ACP AI Provider)`);
|
|
52221
52463
|
try {
|
|
52222
52464
|
await agent.init();
|
|
52223
|
-
console.log(
|
|
52465
|
+
console.log("ACP provider initialized");
|
|
52224
52466
|
} catch (error87) {
|
|
52225
52467
|
console.error(`Failed to initialize agent: ${error87}`);
|
|
52226
52468
|
process.exit(1);
|
|
@@ -52269,49 +52511,56 @@ async function connect(agentType, options = {}) {
|
|
|
52269
52511
|
text: "",
|
|
52270
52512
|
state: "streaming"
|
|
52271
52513
|
};
|
|
52272
|
-
activeReasoningParts.set(chunk.id, reasoningPart);
|
|
52514
|
+
activeReasoningParts.set(chunk.id || "default", reasoningPart);
|
|
52273
52515
|
parts.push(reasoningPart);
|
|
52274
52516
|
break;
|
|
52275
52517
|
}
|
|
52276
|
-
case "reasoning-delta":
|
|
52277
|
-
|
|
52278
|
-
|
|
52279
|
-
|
|
52518
|
+
case "reasoning-delta":
|
|
52519
|
+
case "reasoning": {
|
|
52520
|
+
const id = chunk.id || "default";
|
|
52521
|
+
let reasoningPart = activeReasoningParts.get(id);
|
|
52522
|
+
if (!reasoningPart) {
|
|
52523
|
+
reasoningPart = { type: "reasoning", text: "", state: "streaming" };
|
|
52524
|
+
activeReasoningParts.set(id, reasoningPart);
|
|
52525
|
+
parts.push(reasoningPart);
|
|
52280
52526
|
}
|
|
52527
|
+
reasoningPart.text += chunk.delta || chunk.text || "";
|
|
52281
52528
|
break;
|
|
52282
52529
|
}
|
|
52283
52530
|
case "reasoning-end": {
|
|
52284
|
-
const
|
|
52531
|
+
const id = chunk.id || "default";
|
|
52532
|
+
const reasoningPart = activeReasoningParts.get(id);
|
|
52285
52533
|
if (reasoningPart) {
|
|
52286
52534
|
reasoningPart.state = "done";
|
|
52287
|
-
activeReasoningParts.delete(
|
|
52535
|
+
activeReasoningParts.delete(id);
|
|
52288
52536
|
}
|
|
52289
52537
|
break;
|
|
52290
52538
|
}
|
|
52291
|
-
case "tool-input-available":
|
|
52539
|
+
case "tool-input-available": {
|
|
52540
|
+
const input = chunk.input;
|
|
52541
|
+
const realToolName = input?.toolName || chunk.toolName;
|
|
52542
|
+
const realArgs = input?.args || input || {};
|
|
52292
52543
|
toolCalls.set(chunk.toolCallId, {
|
|
52293
52544
|
type: "dynamic-tool",
|
|
52294
52545
|
toolCallId: chunk.toolCallId,
|
|
52295
|
-
toolName:
|
|
52546
|
+
toolName: realToolName,
|
|
52296
52547
|
state: "input-available",
|
|
52297
|
-
input:
|
|
52548
|
+
input: realArgs
|
|
52298
52549
|
});
|
|
52299
52550
|
parts.push(toolCalls.get(chunk.toolCallId));
|
|
52300
52551
|
break;
|
|
52301
|
-
|
|
52552
|
+
}
|
|
52553
|
+
case "tool-output-available": {
|
|
52302
52554
|
const existing = toolCalls.get(chunk.toolCallId);
|
|
52303
52555
|
if (existing) {
|
|
52304
|
-
const updated = {
|
|
52305
|
-
...existing,
|
|
52306
|
-
state: "output-available",
|
|
52307
|
-
output: chunk.output
|
|
52308
|
-
};
|
|
52556
|
+
const updated = { ...existing, state: "output-available", output: chunk.output };
|
|
52309
52557
|
toolCalls.set(chunk.toolCallId, updated);
|
|
52310
52558
|
const idx = parts.findIndex((p) => p.type === "dynamic-tool" && p.toolCallId === chunk.toolCallId);
|
|
52311
52559
|
if (idx >= 0)
|
|
52312
52560
|
parts[idx] = updated;
|
|
52313
52561
|
}
|
|
52314
52562
|
break;
|
|
52563
|
+
}
|
|
52315
52564
|
}
|
|
52316
52565
|
}
|
|
52317
52566
|
if (parts.length > 0) {
|
|
@@ -52319,29 +52568,19 @@ async function connect(agentType, options = {}) {
|
|
|
52319
52568
|
{
|
|
52320
52569
|
type: "ui_message",
|
|
52321
52570
|
timestamp: Date.now(),
|
|
52322
|
-
data: {
|
|
52323
|
-
id: crypto.randomUUID(),
|
|
52324
|
-
role: "assistant",
|
|
52325
|
-
parts
|
|
52326
|
-
}
|
|
52571
|
+
data: { id: crypto.randomUUID(), role: "assistant", parts }
|
|
52327
52572
|
}
|
|
52328
52573
|
]);
|
|
52329
52574
|
}
|
|
52330
|
-
await tunnel.updateTask(task.id, {
|
|
52331
|
-
|
|
52332
|
-
result: "end_turn"
|
|
52333
|
-
});
|
|
52334
|
-
console.log(`Task completed`);
|
|
52575
|
+
await tunnel.updateTask(task.id, { state: "completed", result: "end_turn" });
|
|
52576
|
+
console.log("Task completed");
|
|
52335
52577
|
} catch (error87) {
|
|
52336
52578
|
console.error(`Task failed: ${error87}`);
|
|
52337
|
-
await tunnel.updateTask(task.id, {
|
|
52338
|
-
state: "failed",
|
|
52339
|
-
result: String(error87)
|
|
52340
|
-
});
|
|
52579
|
+
await tunnel.updateTask(task.id, { state: "failed", result: String(error87) });
|
|
52341
52580
|
}
|
|
52342
52581
|
});
|
|
52343
52582
|
await tunnel.connect(credentials.userId, agentType);
|
|
52344
|
-
console.log(
|
|
52583
|
+
console.log("Tunnel established");
|
|
52345
52584
|
const voiceUrl = `${process.env.HEYATLAS_API || "https://heyatlas.app"}/chat`;
|
|
52346
52585
|
if (options.openBrowser !== false) {
|
|
52347
52586
|
try {
|
|
@@ -52386,10 +52625,7 @@ function buildPromptWithContext(task) {
|
|
|
52386
52625
|
} else if (e.type === "message" && e.data) {
|
|
52387
52626
|
const data = e.data;
|
|
52388
52627
|
if (data.role && data.content) {
|
|
52389
|
-
messages.push({
|
|
52390
|
-
role: String(data.role),
|
|
52391
|
-
content: String(data.content)
|
|
52392
|
-
});
|
|
52628
|
+
messages.push({ role: String(data.role), content: String(data.content) });
|
|
52393
52629
|
}
|
|
52394
52630
|
} else if (e.role && e.content) {
|
|
52395
52631
|
messages.push({ role: String(e.role), content: String(e.content) });
|
|
@@ -52421,11 +52657,11 @@ Please continue based on the above context.`;
|
|
|
52421
52657
|
}
|
|
52422
52658
|
|
|
52423
52659
|
// index.ts
|
|
52424
|
-
var
|
|
52660
|
+
var ACP_AGENTS = [
|
|
52425
52661
|
"opencode",
|
|
52426
|
-
"claude",
|
|
52662
|
+
"claude-code",
|
|
52427
52663
|
"goose",
|
|
52428
|
-
"gemini",
|
|
52664
|
+
"gemini-code",
|
|
52429
52665
|
"codex",
|
|
52430
52666
|
"kimi",
|
|
52431
52667
|
"vibe",
|
|
@@ -52434,6 +52670,8 @@ var SUPPORTED_AGENTS = [
|
|
|
52434
52670
|
"openhands",
|
|
52435
52671
|
"cagent"
|
|
52436
52672
|
];
|
|
52673
|
+
var HTTP_AGENTS = ["agent-smith-py"];
|
|
52674
|
+
var SUPPORTED_AGENTS = [...ACP_AGENTS, ...HTTP_AGENTS];
|
|
52437
52675
|
var { positionals, values } = parseArgs({
|
|
52438
52676
|
args: process.argv.slice(2),
|
|
52439
52677
|
options: {
|
|
@@ -52445,27 +52683,23 @@ var { positionals, values } = parseArgs({
|
|
|
52445
52683
|
});
|
|
52446
52684
|
function printHelp() {
|
|
52447
52685
|
console.log(`
|
|
52448
|
-
heyatlas - Tunnel local AI agents to the cloud
|
|
52686
|
+
heyatlas - Tunnel local AI agents to the cloud
|
|
52449
52687
|
|
|
52450
52688
|
Usage:
|
|
52451
|
-
heyatlas connect <agent> Connect agent to Atlas
|
|
52689
|
+
heyatlas connect <agent> Connect agent to Atlas
|
|
52452
52690
|
|
|
52453
|
-
|
|
52454
|
-
${
|
|
52691
|
+
Supported Agents:
|
|
52692
|
+
ACP Agents: ${ACP_AGENTS.join(", ")}
|
|
52693
|
+
HTTP Agents: ${HTTP_AGENTS.join(", ")}
|
|
52455
52694
|
|
|
52456
52695
|
Options:
|
|
52457
52696
|
-h, --help Show this help message
|
|
52458
52697
|
-v, --version Show version
|
|
52459
52698
|
--no-browser Don't open browser automatically
|
|
52460
52699
|
|
|
52461
|
-
Prerequisites:
|
|
52462
|
-
- The agent must be installed and support ACP mode
|
|
52463
|
-
- Agent-specific setup (API keys, etc.)
|
|
52464
|
-
|
|
52465
52700
|
Examples:
|
|
52466
|
-
heyatlas connect opencode
|
|
52467
|
-
heyatlas connect
|
|
52468
|
-
heyatlas connect claude Connect Claude Code via ACP
|
|
52701
|
+
heyatlas connect opencode Connect OpenCode via ACP
|
|
52702
|
+
heyatlas connect agent-smith-py Connect Agent Smith (CAMEL-AI workforce)
|
|
52469
52703
|
`);
|
|
52470
52704
|
}
|
|
52471
52705
|
async function main() {
|