@annals/agent-mesh 0.13.1 → 0.15.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 +388 -129
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2611,7 +2611,8 @@ var ERROR_HINTS = {
2611
2611
  github_required: "GitHub account required. Visit https://agents.hot/settings to link one.",
2612
2612
  validation_error: "Invalid input. Check your skill.json or command flags.",
2613
2613
  permission_denied: "You don't have permission to modify this skill.",
2614
- file_too_large: "Package file exceeds the 50MB limit."
2614
+ file_too_large: "Package file exceeds the 50MB limit.",
2615
+ subscription_required: "This is a private agent. Subscribe first: agent-mesh subscribe <author-login>"
2615
2616
  };
2616
2617
  var PlatformClient = class {
2617
2618
  token;
@@ -2942,18 +2943,18 @@ async function asyncChat(opts) {
2942
2943
  }
2943
2944
  throw new Error(msg);
2944
2945
  }
2945
- const { task_id, status, error_message, error_code } = await res.json();
2946
+ const { request_id, status, error_message, error_code } = await res.json();
2946
2947
  if (status === "failed") {
2947
2948
  throw new Error(`Task failed: ${error_message || error_code}`);
2948
2949
  }
2949
- process.stderr.write(`${GRAY}[async] task=${task_id.slice(0, 8)}... polling${RESET}`);
2950
+ process.stderr.write(`${GRAY}[async] request=${request_id.slice(0, 8)}... polling${RESET}`);
2950
2951
  const maxWait = 5 * 60 * 1e3;
2951
2952
  const pollInterval = 2e3;
2952
2953
  const startTime = Date.now();
2953
2954
  while (Date.now() - startTime < maxWait) {
2954
2955
  if (opts.signal?.aborted) throw new Error("Aborted");
2955
2956
  await sleep4(pollInterval);
2956
- const pollRes = await fetch(`${opts.baseUrl}/api/tasks/${task_id}`, {
2957
+ const pollRes = await fetch(`${opts.baseUrl}/api/agents/${opts.agentId}/task-status/${request_id}`, {
2957
2958
  headers: { Authorization: `Bearer ${opts.token}` },
2958
2959
  signal: opts.signal
2959
2960
  });
@@ -2979,7 +2980,7 @@ async function asyncChat(opts) {
2979
2980
  throw new Error("Task timed out waiting for result");
2980
2981
  }
2981
2982
  async function streamChat(opts) {
2982
- if ((opts.mode ?? "async") === "async") {
2983
+ if (opts.mode === "async") {
2983
2984
  return asyncChat(opts);
2984
2985
  }
2985
2986
  const res = await fetch(`${opts.baseUrl}/api/agents/${opts.agentId}/chat`, {
@@ -3082,7 +3083,7 @@ ${"\x1B[31m"}Error: ${event.errorText}${RESET}
3082
3083
  }
3083
3084
  }
3084
3085
  function registerChatCommand(program2) {
3085
- program2.command("chat <agent> [message]").description("Chat with an agent through the platform (for debugging)").option("--no-thinking", "Hide thinking/reasoning output").option("--stream", "Force SSE streaming mode (default is async)").option("--base-url <url>", "Platform base URL", DEFAULT_BASE_URL3).action(async (agentInput, inlineMessage, opts) => {
3086
+ program2.command("chat <agent> [message]").description("Chat with an agent through the platform (for debugging)").option("--no-thinking", "Hide thinking/reasoning output").option("--async", "Use async polling mode (default is stream)").option("--base-url <url>", "Platform base URL", DEFAULT_BASE_URL3).action(async (agentInput, inlineMessage, opts) => {
3086
3087
  const token = loadToken();
3087
3088
  if (!token) {
3088
3089
  log.error("Not authenticated. Run `agent-mesh login` first.");
@@ -3099,7 +3100,7 @@ function registerChatCommand(program2) {
3099
3100
  log.error(err.message);
3100
3101
  process.exit(1);
3101
3102
  }
3102
- const mode = opts.stream ? "stream" : "async";
3103
+ const mode = opts.async ? "async" : "stream";
3103
3104
  if (inlineMessage) {
3104
3105
  log.info(`Chatting with ${BOLD}${agentName}${RESET} (${mode})`);
3105
3106
  try {
@@ -3807,7 +3808,10 @@ function registerDiscoverCommand(program2) {
3807
3808
  params.set("limit", opts.limit);
3808
3809
  params.set("offset", opts.offset);
3809
3810
  const url = `${BASE_URL}/api/agents/discover?${params}`;
3810
- const res = await fetch(url);
3811
+ const token = loadToken();
3812
+ const headers = {};
3813
+ if (token) headers["Authorization"] = `Bearer ${token}`;
3814
+ const res = await fetch(url, { headers });
3811
3815
  if (!res.ok) {
3812
3816
  const body = await res.json().catch(() => ({}));
3813
3817
  console.error(` Error: ${body.message ?? `HTTP ${res.status}`}`);
@@ -3849,6 +3853,9 @@ function registerDiscoverCommand(program2) {
3849
3853
  // src/commands/call.ts
3850
3854
  import { readFileSync, writeFileSync as writeFileSync2 } from "fs";
3851
3855
  var DEFAULT_BASE_URL4 = "https://agents.hot";
3856
+ function sleep5(ms) {
3857
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
3858
+ }
3852
3859
  function handleError2(err) {
3853
3860
  if (err instanceof PlatformApiError) {
3854
3861
  log.error(err.message);
@@ -3857,8 +3864,228 @@ function handleError2(err) {
3857
3864
  }
3858
3865
  process.exit(1);
3859
3866
  }
3867
+ async function asyncCall(opts) {
3868
+ const selfAgentId = process.env.AGENT_BRIDGE_AGENT_ID;
3869
+ const res = await fetch(`${DEFAULT_BASE_URL4}/api/agents/${opts.id}/call`, {
3870
+ method: "POST",
3871
+ headers: {
3872
+ Authorization: `Bearer ${opts.token}`,
3873
+ "Content-Type": "application/json",
3874
+ ...selfAgentId ? { "X-Caller-Agent-Id": selfAgentId } : {}
3875
+ },
3876
+ body: JSON.stringify({ task_description: opts.taskDescription, mode: "async" }),
3877
+ signal: opts.signal
3878
+ });
3879
+ if (!res.ok) {
3880
+ let msg = `HTTP ${res.status}`;
3881
+ let errorCode = "";
3882
+ try {
3883
+ const body = await res.json();
3884
+ errorCode = body.error || "";
3885
+ msg = body.message || body.error || msg;
3886
+ } catch {
3887
+ }
3888
+ if (errorCode === "subscription_required") {
3889
+ log.error("This is a private agent.");
3890
+ console.error(` Subscribe first: agent-mesh subscribe <author-login>`);
3891
+ } else {
3892
+ log.error(msg);
3893
+ }
3894
+ process.exit(1);
3895
+ }
3896
+ const { request_id, call_id, status, error_message, error_code } = await res.json();
3897
+ if (status === "failed") {
3898
+ log.error(`Call failed: ${error_message || error_code}`);
3899
+ process.exit(1);
3900
+ }
3901
+ if (!opts.json) {
3902
+ process.stderr.write(`${GRAY}[async] call=${call_id.slice(0, 8)}... request=${request_id.slice(0, 8)}... polling${RESET}`);
3903
+ }
3904
+ const pollInterval = 2e3;
3905
+ const startTime = Date.now();
3906
+ while (Date.now() - startTime < opts.timeoutMs) {
3907
+ if (opts.signal?.aborted) {
3908
+ log.error("Aborted");
3909
+ process.exit(1);
3910
+ }
3911
+ await sleep5(pollInterval);
3912
+ const pollRes = await fetch(`${DEFAULT_BASE_URL4}/api/agents/${opts.id}/task-status/${request_id}`, {
3913
+ headers: { Authorization: `Bearer ${opts.token}` },
3914
+ signal: opts.signal
3915
+ });
3916
+ if (!pollRes.ok) {
3917
+ log.error(`Poll failed: HTTP ${pollRes.status}`);
3918
+ process.exit(1);
3919
+ }
3920
+ const task = await pollRes.json();
3921
+ if (task.status === "completed") {
3922
+ if (!opts.json) {
3923
+ process.stderr.write(` done
3924
+ `);
3925
+ }
3926
+ const result = task.result || "";
3927
+ if (opts.json) {
3928
+ console.log(JSON.stringify({ call_id, request_id, status: "completed", result }));
3929
+ } else {
3930
+ process.stdout.write(result + "\n");
3931
+ }
3932
+ if (opts.outputFile && result) {
3933
+ writeFileSync2(opts.outputFile, result);
3934
+ if (!opts.json) log.info(`Saved to ${opts.outputFile}`);
3935
+ }
3936
+ return;
3937
+ }
3938
+ if (task.status === "failed") {
3939
+ if (!opts.json) {
3940
+ process.stderr.write(` failed
3941
+ `);
3942
+ }
3943
+ log.error(`Call failed: ${task.error_message || task.error_code}`);
3944
+ process.exit(1);
3945
+ }
3946
+ if (!opts.json) {
3947
+ process.stderr.write(".");
3948
+ }
3949
+ }
3950
+ if (!opts.json) {
3951
+ process.stderr.write(` timeout
3952
+ `);
3953
+ }
3954
+ log.error("Call timed out waiting for result");
3955
+ process.exit(1);
3956
+ }
3957
+ async function streamCall(opts) {
3958
+ const selfAgentId = process.env.AGENT_BRIDGE_AGENT_ID;
3959
+ const res = await fetch(`${DEFAULT_BASE_URL4}/api/agents/${opts.id}/call`, {
3960
+ method: "POST",
3961
+ headers: {
3962
+ Authorization: `Bearer ${opts.token}`,
3963
+ "Content-Type": "application/json",
3964
+ Accept: "text/event-stream",
3965
+ ...selfAgentId ? { "X-Caller-Agent-Id": selfAgentId } : {}
3966
+ },
3967
+ body: JSON.stringify({ task_description: opts.taskDescription }),
3968
+ signal: opts.signal
3969
+ });
3970
+ if (!res.ok) {
3971
+ let msg = `HTTP ${res.status}`;
3972
+ let errorCode = "";
3973
+ try {
3974
+ const body = await res.json();
3975
+ errorCode = body.error || "";
3976
+ msg = body.message || body.error || msg;
3977
+ } catch {
3978
+ }
3979
+ if (errorCode === "subscription_required") {
3980
+ log.error("This is a private agent.");
3981
+ console.error(` Subscribe first: agent-mesh subscribe <author-login>`);
3982
+ } else {
3983
+ log.error(msg);
3984
+ }
3985
+ process.exit(1);
3986
+ }
3987
+ const contentType = res.headers.get("Content-Type") || "";
3988
+ if (contentType.includes("application/json")) {
3989
+ const result = await res.json();
3990
+ if (opts.json) {
3991
+ console.log(JSON.stringify(result));
3992
+ } else {
3993
+ console.log("");
3994
+ log.success(`Call created for ${BOLD}${opts.name}${RESET}`);
3995
+ console.log(` ${GRAY}Call ID${RESET} ${result.call_id}`);
3996
+ console.log(` ${GRAY}Status${RESET} ${result.status}`);
3997
+ console.log(` ${GRAY}Created${RESET} ${result.created_at}`);
3998
+ console.log("");
3999
+ }
4000
+ return;
4001
+ }
4002
+ if (!res.body) {
4003
+ log.error("Empty response body");
4004
+ process.exit(1);
4005
+ }
4006
+ if (!opts.json) {
4007
+ log.info(`Calling ${BOLD}${opts.name}${RESET}...`);
4008
+ console.log("");
4009
+ }
4010
+ const reader = res.body.getReader();
4011
+ const decoder = new TextDecoder();
4012
+ let buffer = "";
4013
+ let outputBuffer = "";
4014
+ let inThinkingBlock = false;
4015
+ while (true) {
4016
+ const { done, value } = await reader.read();
4017
+ if (done) break;
4018
+ const chunk = decoder.decode(value, { stream: true });
4019
+ const parsed = parseSseChunk(chunk, buffer);
4020
+ buffer = parsed.carry;
4021
+ for (const data of parsed.events) {
4022
+ if (data === "[DONE]") continue;
4023
+ try {
4024
+ const event = JSON.parse(data);
4025
+ if (opts.json) {
4026
+ console.log(JSON.stringify(event));
4027
+ } else {
4028
+ if (event.type === "chunk" && event.delta) {
4029
+ process.stdout.write(event.delta);
4030
+ if (!event.kind || event.kind === "text") {
4031
+ const delta = event.delta;
4032
+ if (delta.startsWith("{") && delta.includes('"type":')) {
4033
+ if (delta.includes('"type":"thinking"') && delta.includes("content_block_start")) {
4034
+ inThinkingBlock = true;
4035
+ } else if (delta.includes('"type":"text"') && delta.includes("content_block_start")) {
4036
+ inThinkingBlock = false;
4037
+ }
4038
+ } else if (!inThinkingBlock) {
4039
+ outputBuffer += delta;
4040
+ }
4041
+ }
4042
+ } else if (event.type === "done" && event.attachments?.length) {
4043
+ console.log("");
4044
+ for (const att of event.attachments) {
4045
+ log.info(` ${GRAY}File:${RESET} ${att.name} ${GRAY}${att.url}${RESET}`);
4046
+ }
4047
+ } else if (event.type === "error") {
4048
+ process.stderr.write(`
4049
+ Error: ${event.message}
4050
+ `);
4051
+ }
4052
+ }
4053
+ } catch {
4054
+ }
4055
+ }
4056
+ }
4057
+ if (buffer.trim()) {
4058
+ const parsed = parseSseChunk("\n\n", buffer);
4059
+ for (const data of parsed.events) {
4060
+ if (data === "[DONE]") continue;
4061
+ try {
4062
+ const event = JSON.parse(data);
4063
+ if (opts.json) {
4064
+ console.log(JSON.stringify(event));
4065
+ } else if (event.type === "chunk" && event.delta) {
4066
+ process.stdout.write(event.delta);
4067
+ if (!event.kind || event.kind === "text") {
4068
+ const delta = event.delta;
4069
+ if (!(delta.startsWith("{") && delta.includes('"type":')) && !inThinkingBlock) {
4070
+ outputBuffer += delta;
4071
+ }
4072
+ }
4073
+ }
4074
+ } catch {
4075
+ }
4076
+ }
4077
+ }
4078
+ if (opts.outputFile && outputBuffer) {
4079
+ writeFileSync2(opts.outputFile, outputBuffer);
4080
+ if (!opts.json) log.info(`Saved to ${opts.outputFile}`);
4081
+ }
4082
+ if (!opts.json) {
4083
+ console.log("\n");
4084
+ log.success("Call completed");
4085
+ }
4086
+ }
3860
4087
  function registerCallCommand(program2) {
3861
- program2.command("call <agent>").description("Call an agent on the A2A network").requiredOption("--task <description>", "Task description").option("--input-file <path>", "Read file and append to task description").option("--output-file <path>", "Save response text to file").option("--json", "Output JSONL events").option("--timeout <seconds>", "Timeout in seconds", "300").action(async (agentInput, opts) => {
4088
+ program2.command("call <agent>").description("Call an agent on the A2A network (default: async polling)").requiredOption("--task <description>", "Task description").option("--input-file <path>", "Read file and append to task description").option("--output-file <path>", "Save response text to file").option("--stream", "Use SSE streaming instead of async polling").option("--json", "Output JSONL events").option("--timeout <seconds>", "Timeout in seconds", "300").action(async (agentInput, opts) => {
3862
4089
  try {
3863
4090
  const token = loadToken();
3864
4091
  if (!token) {
@@ -3879,128 +4106,22 @@ ${content}`;
3879
4106
  const timeoutMs = parseInt(opts.timeout || "300", 10) * 1e3;
3880
4107
  const abortController = new AbortController();
3881
4108
  const timer = setTimeout(() => abortController.abort(), timeoutMs);
3882
- const selfAgentId = process.env.AGENT_BRIDGE_AGENT_ID;
3883
- const res = await fetch(`${DEFAULT_BASE_URL4}/api/agents/${id}/call`, {
3884
- method: "POST",
3885
- headers: {
3886
- Authorization: `Bearer ${token}`,
3887
- "Content-Type": "application/json",
3888
- Accept: "text/event-stream",
3889
- ...selfAgentId ? { "X-Caller-Agent-Id": selfAgentId } : {}
3890
- },
3891
- body: JSON.stringify({ task_description: taskDescription }),
4109
+ const callOpts = {
4110
+ id,
4111
+ name,
4112
+ token,
4113
+ taskDescription,
4114
+ timeoutMs,
4115
+ json: opts.json,
4116
+ outputFile: opts.outputFile,
3892
4117
  signal: abortController.signal
3893
- });
3894
- clearTimeout(timer);
3895
- if (!res.ok) {
3896
- let msg = `HTTP ${res.status}`;
3897
- try {
3898
- const body = await res.json();
3899
- msg = body.message || body.error || msg;
3900
- } catch {
3901
- }
3902
- log.error(msg);
3903
- process.exit(1);
3904
- }
3905
- const contentType = res.headers.get("Content-Type") || "";
3906
- if (contentType.includes("application/json")) {
3907
- const result = await res.json();
3908
- if (opts.json) {
3909
- console.log(JSON.stringify(result));
3910
- } else {
3911
- console.log("");
3912
- log.success(`Call created for ${BOLD}${name}${RESET}`);
3913
- console.log(` ${GRAY}Call ID${RESET} ${result.call_id}`);
3914
- console.log(` ${GRAY}Status${RESET} ${result.status}`);
3915
- console.log(` ${GRAY}Created${RESET} ${result.created_at}`);
3916
- console.log("");
3917
- }
3918
- return;
3919
- }
3920
- if (!res.body) {
3921
- log.error("Empty response body");
3922
- process.exit(1);
3923
- }
3924
- if (!opts.json) {
3925
- log.info(`Calling ${BOLD}${name}${RESET}...`);
3926
- console.log("");
3927
- }
3928
- const reader = res.body.getReader();
3929
- const decoder = new TextDecoder();
3930
- let buffer = "";
3931
- let outputBuffer = "";
3932
- let inThinkingBlock = false;
3933
- while (true) {
3934
- const { done, value } = await reader.read();
3935
- if (done) break;
3936
- const chunk = decoder.decode(value, { stream: true });
3937
- const parsed = parseSseChunk(chunk, buffer);
3938
- buffer = parsed.carry;
3939
- for (const data of parsed.events) {
3940
- if (data === "[DONE]") continue;
3941
- try {
3942
- const event = JSON.parse(data);
3943
- if (opts.json) {
3944
- console.log(JSON.stringify(event));
3945
- } else {
3946
- if (event.type === "chunk" && event.delta) {
3947
- process.stdout.write(event.delta);
3948
- if (!event.kind || event.kind === "text") {
3949
- const delta = event.delta;
3950
- if (delta.startsWith("{") && delta.includes('"type":')) {
3951
- if (delta.includes('"type":"thinking"') && delta.includes("content_block_start")) {
3952
- inThinkingBlock = true;
3953
- } else if (delta.includes('"type":"text"') && delta.includes("content_block_start")) {
3954
- inThinkingBlock = false;
3955
- }
3956
- } else if (!inThinkingBlock) {
3957
- outputBuffer += delta;
3958
- }
3959
- }
3960
- } else if (event.type === "done" && event.attachments?.length) {
3961
- console.log("");
3962
- for (const att of event.attachments) {
3963
- log.info(` ${GRAY}File:${RESET} ${att.name} ${GRAY}${att.url}${RESET}`);
3964
- }
3965
- } else if (event.type === "error") {
3966
- process.stderr.write(`
3967
- Error: ${event.message}
3968
- `);
3969
- }
3970
- }
3971
- } catch {
3972
- }
3973
- }
3974
- }
3975
- if (buffer.trim()) {
3976
- const parsed = parseSseChunk("\n\n", buffer);
3977
- for (const data of parsed.events) {
3978
- if (data === "[DONE]") continue;
3979
- try {
3980
- const event = JSON.parse(data);
3981
- if (opts.json) {
3982
- console.log(JSON.stringify(event));
3983
- } else if (event.type === "chunk" && event.delta) {
3984
- process.stdout.write(event.delta);
3985
- if (!event.kind || event.kind === "text") {
3986
- const delta = event.delta;
3987
- if (!(delta.startsWith("{") && delta.includes('"type":')) && !inThinkingBlock) {
3988
- outputBuffer += delta;
3989
- }
3990
- }
3991
- }
3992
- } catch {
3993
- }
3994
- }
3995
- }
3996
- if (opts.outputFile && outputBuffer) {
3997
- writeFileSync2(opts.outputFile, outputBuffer);
3998
- if (!opts.json) log.info(`Saved to ${opts.outputFile}`);
3999
- }
4000
- if (!opts.json) {
4001
- console.log("\n");
4002
- log.success("Call completed");
4118
+ };
4119
+ if (opts.stream) {
4120
+ await streamCall(callOpts);
4121
+ } else {
4122
+ await asyncCall(callOpts);
4003
4123
  }
4124
+ clearTimeout(timer);
4004
4125
  } catch (err) {
4005
4126
  if (err.name === "AbortError") {
4006
4127
  log.error("Call timed out");
@@ -4164,6 +4285,142 @@ function printAgentStats(name, stats) {
4164
4285
  console.log("");
4165
4286
  }
4166
4287
 
4288
+ // src/commands/subscribe.ts
4289
+ var BASE_URL2 = "https://agents.hot";
4290
+ function handleError5(err) {
4291
+ if (err instanceof PlatformApiError) {
4292
+ log.error(err.message);
4293
+ } else {
4294
+ log.error(err.message);
4295
+ }
4296
+ process.exit(1);
4297
+ }
4298
+ async function resolveAuthorLogin(login) {
4299
+ const res = await fetch(`${BASE_URL2}/api/authors/resolve?login=${encodeURIComponent(login)}`);
4300
+ if (!res.ok) {
4301
+ if (res.status === 404) {
4302
+ throw new PlatformApiError(404, "not_found", `Author not found: ${login}`);
4303
+ }
4304
+ throw new PlatformApiError(res.status, "unknown", `Failed to resolve author: HTTP ${res.status}`);
4305
+ }
4306
+ return res.json();
4307
+ }
4308
+ function registerSubscribeCommand(program2) {
4309
+ program2.command("subscribe <author-login>").description("Subscribe to an author to access their private agents").action(async (authorLogin) => {
4310
+ try {
4311
+ const client = createClient();
4312
+ const author = await resolveAuthorLogin(authorLogin);
4313
+ await client.post(`/api/authors/${author.id}/subscribe`);
4314
+ log.success(`Subscribed to ${author.github_login}${author.name ? ` (${author.name})` : ""}`);
4315
+ } catch (err) {
4316
+ handleError5(err);
4317
+ }
4318
+ });
4319
+ program2.command("unsubscribe <author-login>").description("Unsubscribe from an author").action(async (authorLogin) => {
4320
+ try {
4321
+ const client = createClient();
4322
+ const author = await resolveAuthorLogin(authorLogin);
4323
+ await client.del(`/api/authors/${author.id}/subscribe`);
4324
+ log.success(`Unsubscribed from ${author.github_login}`);
4325
+ } catch (err) {
4326
+ handleError5(err);
4327
+ }
4328
+ });
4329
+ program2.command("subscriptions").description("List your author subscriptions").option("--json", "Output raw JSON").action(async (opts) => {
4330
+ try {
4331
+ const client = createClient();
4332
+ const data = await client.get("/api/user/subscriptions");
4333
+ if (opts.json) {
4334
+ console.log(JSON.stringify(data, null, 2));
4335
+ return;
4336
+ }
4337
+ if (data.subscriptions.length === 0) {
4338
+ console.log(" No subscriptions yet.");
4339
+ return;
4340
+ }
4341
+ const table = renderTable(
4342
+ [
4343
+ { key: "login", label: "AUTHOR", width: 24 },
4344
+ { key: "name", label: "NAME", width: 24 },
4345
+ { key: "since", label: "SINCE", width: 20 }
4346
+ ],
4347
+ data.subscriptions.map((s) => ({
4348
+ login: s.author.github_login,
4349
+ name: s.author.name || `${GRAY}\u2014${RESET}`,
4350
+ since: new Date(s.created_at).toLocaleDateString()
4351
+ }))
4352
+ );
4353
+ console.log(table);
4354
+ console.log(`
4355
+ ${GRAY}${data.subscriptions.length} subscription(s)${RESET}`);
4356
+ } catch (err) {
4357
+ handleError5(err);
4358
+ }
4359
+ });
4360
+ }
4361
+
4362
+ // src/commands/register.ts
4363
+ var DEFAULT_BASE_URL5 = "https://agents.hot";
4364
+ var VALID_AGENT_TYPES = ["openclaw", "claude-code", "cursor", "windsurf", "custom"];
4365
+ function registerRegisterCommand(program2) {
4366
+ program2.command("register").description("Register a new agent on the platform and get an API key").requiredOption("--name <name>", "Agent name (alphanumeric + hyphens, 3-64 chars)").option("--type <type>", "Agent type", "claude-code").option("--description <text>", "Agent description").option("--capabilities <list>", "Comma-separated capabilities").option("--base-url <url>", "Platform base URL", DEFAULT_BASE_URL5).action(async (opts) => {
4367
+ if (!VALID_AGENT_TYPES.includes(opts.type)) {
4368
+ log.error(`Invalid agent type: ${opts.type}. Must be one of: ${VALID_AGENT_TYPES.join(", ")}`);
4369
+ process.exit(1);
4370
+ }
4371
+ const capabilities = opts.capabilities ? opts.capabilities.split(",").map((c) => c.trim()).filter(Boolean) : [];
4372
+ log.info(`Registering agent ${BOLD}${opts.name}${RESET}...`);
4373
+ let res;
4374
+ try {
4375
+ res = await fetch(`${opts.baseUrl}/api/auth/agent/register`, {
4376
+ method: "POST",
4377
+ headers: { "Content-Type": "application/json" },
4378
+ body: JSON.stringify({
4379
+ agent_name: opts.name,
4380
+ agent_type: opts.type,
4381
+ description: opts.description,
4382
+ capabilities
4383
+ })
4384
+ });
4385
+ } catch (err) {
4386
+ log.error(`Network error: ${err.message}`);
4387
+ process.exit(1);
4388
+ }
4389
+ if (!res.ok) {
4390
+ let msg = `HTTP ${res.status}`;
4391
+ try {
4392
+ const body = await res.json();
4393
+ msg = body.message || body.error || msg;
4394
+ } catch {
4395
+ }
4396
+ log.error(msg);
4397
+ process.exit(1);
4398
+ }
4399
+ const data = await res.json();
4400
+ if (!hasToken()) {
4401
+ saveToken(data.api_key);
4402
+ log.info("Saved API key as platform token (auto-login)");
4403
+ }
4404
+ const slug = uniqueSlug(opts.name);
4405
+ const workspaceDir = getAgentWorkspaceDir(slug);
4406
+ addAgent(slug, {
4407
+ agentId: data.agent_id,
4408
+ agentType: opts.type,
4409
+ bridgeUrl: opts.baseUrl.replace("https://", "wss://").replace("http://", "ws://") + "/ws",
4410
+ projectPath: workspaceDir,
4411
+ addedAt: (/* @__PURE__ */ new Date()).toISOString()
4412
+ });
4413
+ log.success(`Agent registered: ${BOLD}${data.agent_name}${RESET}`);
4414
+ console.log("");
4415
+ console.log(` Agent ID: ${data.agent_id}`);
4416
+ console.log(` API Key: ${data.api_key}`);
4417
+ console.log(` Type: ${data.agent_type}`);
4418
+ console.log(` Workspace: ${workspaceDir}`);
4419
+ console.log("");
4420
+ console.log(`${GRAY}Next: agent-mesh connect ${slug}${RESET}`);
4421
+ });
4422
+ }
4423
+
4167
4424
  // src/index.ts
4168
4425
  var require2 = createRequire(import.meta.url);
4169
4426
  var { version } = require2("../package.json");
@@ -4190,4 +4447,6 @@ registerDiscoverCommand(program);
4190
4447
  registerCallCommand(program);
4191
4448
  registerConfigCommand(program);
4192
4449
  registerStatsCommand(program);
4450
+ registerSubscribeCommand(program);
4451
+ registerRegisterCommand(program);
4193
4452
  program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@annals/agent-mesh",
3
- "version": "0.13.1",
3
+ "version": "0.15.0",
4
4
  "description": "CLI bridge connecting local AI agents to the Agents.Hot platform",
5
5
  "type": "module",
6
6
  "bin": {