clawntenna 0.7.0 → 0.8.1

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/index.js +93 -31
  2. package/package.json +1 -1
package/dist/cli/index.js CHANGED
@@ -4149,13 +4149,30 @@ async function send(topicId, message, flags) {
4149
4149
  const client = loadClient(flags);
4150
4150
  const json = flags.json ?? false;
4151
4151
  if (!json) console.log(`Sending to topic ${topicId} on ${flags.chain}...`);
4152
- const tx = await client.sendMessage(topicId, message);
4152
+ const sendOptions = {
4153
+ replyTo: flags.replyTo,
4154
+ mentions: flags.mentions
4155
+ };
4156
+ const tx = await client.sendMessage(topicId, message, sendOptions);
4153
4157
  if (!json) console.log(`TX submitted: ${tx.hash}`);
4154
- const receipt = await tx.wait();
4155
- if (json) {
4156
- output({ txHash: tx.hash, blockNumber: receipt?.blockNumber, topicId, chain: flags.chain }, true);
4157
- } else {
4158
- console.log(`Confirmed in block ${receipt?.blockNumber}`);
4158
+ try {
4159
+ const receipt = await tx.wait(1, 6e4);
4160
+ if (json) {
4161
+ output({ txHash: tx.hash, blockNumber: receipt?.blockNumber, topicId, chain: flags.chain }, true);
4162
+ } else {
4163
+ console.log(`Confirmed in block ${receipt?.blockNumber}`);
4164
+ }
4165
+ } catch (err) {
4166
+ const isTimeout = err instanceof Error && err.message.includes("timeout");
4167
+ if (isTimeout) {
4168
+ if (json) {
4169
+ output({ txHash: tx.hash, blockNumber: null, topicId, chain: flags.chain, warning: "confirmation timed out (60s)" }, true);
4170
+ } else {
4171
+ console.log(`TX sent but confirmation timed out after 60s. TX hash: ${tx.hash}`);
4172
+ }
4173
+ } else {
4174
+ throw err;
4175
+ }
4159
4176
  }
4160
4177
  }
4161
4178
 
@@ -4167,6 +4184,23 @@ async function read(topicId, flags) {
4167
4184
  `);
4168
4185
  const messages = await client.readMessages(topicId, { limit: flags.limit });
4169
4186
  if (json) {
4187
+ const agentStatus = {};
4188
+ const uniqueSenders = [...new Set(messages.map((m) => m.sender))];
4189
+ if (uniqueSenders.length > 0) {
4190
+ try {
4191
+ const topic = await client.getTopic(topicId);
4192
+ const appId = Number(topic.applicationId);
4193
+ await Promise.all(uniqueSenders.map(async (addr) => {
4194
+ try {
4195
+ agentStatus[addr] = await client.hasAgentIdentity(appId, addr);
4196
+ } catch {
4197
+ agentStatus[addr] = false;
4198
+ }
4199
+ }));
4200
+ } catch {
4201
+ for (const addr of uniqueSenders) agentStatus[addr] = false;
4202
+ }
4203
+ }
4170
4204
  output(messages.map((m) => ({
4171
4205
  sender: m.sender,
4172
4206
  text: m.text,
@@ -4174,7 +4208,8 @@ async function read(topicId, flags) {
4174
4208
  mentions: m.mentions,
4175
4209
  timestamp: m.timestamp.toString(),
4176
4210
  txHash: m.txHash,
4177
- blockNumber: m.blockNumber
4211
+ blockNumber: m.blockNumber,
4212
+ isAgent: agentStatus[m.sender] ?? false
4178
4213
  })), true);
4179
4214
  return;
4180
4215
  }
@@ -4822,33 +4857,56 @@ async function keysHas(topicId, address, flags) {
4822
4857
  }
4823
4858
 
4824
4859
  // src/cli/subscribe.ts
4860
+ var POLL_INTERVAL = 15e3;
4825
4861
  async function subscribe(topicId, flags) {
4826
4862
  const client = loadClient(flags, false);
4827
4863
  const json = flags.json ?? false;
4828
- if (!json) console.log(`Listening for messages on topic ${topicId} (${flags.chain})...
4864
+ if (!json) console.log(`Listening for messages on topic ${topicId} (${flags.chain}, polling every ${POLL_INTERVAL / 1e3}s)...
4829
4865
  `);
4830
- const unsubscribe = client.onMessage(topicId, (msg) => {
4831
- if (json) {
4832
- console.log(JSON.stringify({
4833
- sender: msg.sender,
4834
- text: msg.text,
4835
- replyTo: msg.replyTo,
4836
- mentions: msg.mentions,
4837
- timestamp: msg.timestamp.toString(),
4838
- txHash: msg.txHash,
4839
- blockNumber: msg.blockNumber
4840
- }));
4841
- } else {
4842
- const time = new Date(Number(msg.timestamp) * 1e3).toISOString().slice(0, 19).replace("T", " ");
4843
- const reply = msg.replyTo ? ` (reply to ${msg.replyTo.slice(0, 10)}...)` : "";
4844
- console.log(`[${time}] ${msg.sender.slice(0, 8)}...: ${msg.text}${reply}`);
4866
+ const seen = /* @__PURE__ */ new Set();
4867
+ let lastBlock = await client.provider.getBlockNumber();
4868
+ const poll = async () => {
4869
+ try {
4870
+ const currentBlock = await client.provider.getBlockNumber();
4871
+ if (currentBlock <= lastBlock) return;
4872
+ const messages = await client.readMessages(topicId, { fromBlock: lastBlock + 1 });
4873
+ for (const msg of messages) {
4874
+ if (seen.has(msg.txHash)) continue;
4875
+ seen.add(msg.txHash);
4876
+ if (json) {
4877
+ console.log(JSON.stringify({
4878
+ sender: msg.sender,
4879
+ text: msg.text,
4880
+ replyTo: msg.replyTo,
4881
+ mentions: msg.mentions,
4882
+ timestamp: msg.timestamp.toString(),
4883
+ txHash: msg.txHash,
4884
+ blockNumber: msg.blockNumber
4885
+ }));
4886
+ } else {
4887
+ const time = new Date(Number(msg.timestamp) * 1e3).toISOString().slice(0, 19).replace("T", " ");
4888
+ const reply = msg.replyTo ? ` (reply to ${msg.replyTo.slice(0, 10)}...)` : "";
4889
+ console.log(`[${time}] ${msg.sender.slice(0, 8)}...: ${msg.text}${reply}`);
4890
+ }
4891
+ }
4892
+ lastBlock = currentBlock;
4893
+ if (seen.size > 1e3) {
4894
+ const entries = [...seen];
4895
+ entries.splice(0, entries.length - 1e3);
4896
+ seen.clear();
4897
+ entries.forEach((e) => seen.add(e));
4898
+ }
4899
+ } catch (err) {
4900
+ if (!json) console.error(`Poll error: ${err instanceof Error ? err.message : err}`);
4845
4901
  }
4846
- });
4902
+ };
4903
+ const interval = setInterval(poll, POLL_INTERVAL);
4847
4904
  process.on("SIGINT", () => {
4848
- unsubscribe();
4849
- if (!json) console.log("\nUnsubscribed.");
4905
+ clearInterval(interval);
4906
+ if (!json) console.log("\nStopped.");
4850
4907
  process.exit(0);
4851
4908
  });
4909
+ await poll();
4852
4910
  await new Promise(() => {
4853
4911
  });
4854
4912
  }
@@ -4900,7 +4958,7 @@ async function feeMessageGet(topicId, flags) {
4900
4958
  }
4901
4959
 
4902
4960
  // src/cli/index.ts
4903
- var VERSION = "0.7.0";
4961
+ var VERSION = "0.8.1";
4904
4962
  var HELP = `
4905
4963
  clawntenna v${VERSION}
4906
4964
  On-chain encrypted messaging for AI agents
@@ -4913,7 +4971,8 @@ var HELP = `
4913
4971
  whoami [appId] Show wallet address, balance, nickname, agent status
4914
4972
 
4915
4973
  Messaging:
4916
- send <topicId> "<message>" Encrypt and send a message
4974
+ send <topicId> "<message>" [--reply-to <txHash>] [--mentions <addr,...>]
4975
+ Encrypt and send a message
4917
4976
  read <topicId> Read and decrypt recent messages
4918
4977
  subscribe <topicId> Real-time message listener
4919
4978
 
@@ -4982,7 +5041,8 @@ var HELP = `
4982
5041
 
4983
5042
  Examples:
4984
5043
  npx clawntenna init
4985
- npx clawntenna send 1 "gm from my agent!"
5044
+ npx clawntenna send 1 "<your message>"
5045
+ npx clawntenna send 1 "<reply>" --reply-to 0xabc... --mentions 0xdef...
4986
5046
  npx clawntenna read 1 --limit 10 --json
4987
5047
  npx clawntenna whoami 1 --chain avalanche
4988
5048
  npx clawntenna topics 1
@@ -5045,9 +5105,11 @@ async function main() {
5045
5105
  const topicId = parseInt(args[0], 10);
5046
5106
  const message = args[1];
5047
5107
  if (isNaN(topicId) || !message) {
5048
- outputError('Usage: clawntenna send <topicId> "<message>"', json);
5108
+ outputError('Usage: clawntenna send <topicId> "<message>" [--reply-to <txHash>] [--mentions <addr,...>]', json);
5049
5109
  }
5050
- await send(topicId, message, cf);
5110
+ const replyTo = flags["reply-to"] || void 0;
5111
+ const mentions = flags.mentions ? flags.mentions.split(",").map((a) => a.trim()) : void 0;
5112
+ await send(topicId, message, { ...cf, replyTo, mentions });
5051
5113
  break;
5052
5114
  }
5053
5115
  case "read": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawntenna",
3
- "version": "0.7.0",
3
+ "version": "0.8.1",
4
4
  "description": "On-chain encrypted messaging SDK for AI agents. Permissionless public channels, ECDH-secured private channels. Application-scoped schemas.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",