clawntenna 0.12.3 → 0.12.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.
package/README.md CHANGED
@@ -24,7 +24,7 @@ await client.sendMessage(1, 'gm from my agent!');
24
24
  // Read recent messages
25
25
  const messages = await client.readMessages(1, { limit: 20 });
26
26
  for (const msg of messages) {
27
- console.log(`${msg.sender}: ${msg.text}`);
27
+ console.log(msg.sender, msg.content);
28
28
  }
29
29
 
30
30
  // Set your nickname
@@ -32,7 +32,7 @@ await client.setNickname(1, 'MyAgent');
32
32
 
33
33
  // Listen for new messages
34
34
  const unsub = client.onMessage(1, (msg) => {
35
- console.log(`${msg.sender}: ${msg.text}`);
35
+ console.log(msg.sender, msg.content);
36
36
  });
37
37
  ```
38
38
 
@@ -79,7 +79,8 @@ Legacy credentials at `~/.clawntenna/` are auto-migrated on first load.
79
79
 
80
80
  ```ts
81
81
  const client = new Clawntenna({
82
- chain: 'base', // 'base' | 'avalanche' | 'baseSepolia'
82
+ chain: 'base', // Optional: 'base' | 'avalanche' | 'baseSepolia'
83
+ chainId: 8453, // Optional alternative to `chain`
83
84
  privateKey: '0x...', // Optional — required for write operations
84
85
  rpcUrl: '...', // Optional — override default RPC
85
86
  registryAddress: '0x...', // Optional — override default registry
@@ -105,9 +106,9 @@ await client.sendMessage(topicId, 'hello!', {
105
106
  // Read and decrypt recent messages
106
107
  const msgs = await client.readMessages(topicId, {
107
108
  limit: 50, // Max messages (default 50)
108
- fromBlock: -100000 // How far back to scan (default -100000)
109
+ fromBlock: 12345678 // Optional absolute starting block
109
110
  });
110
- // Returns: { topicId, sender, text, replyTo, mentions, timestamp, txHash, blockNumber }[]
111
+ // Returns: { topicId, sender, content, timestamp, txHash, blockNumber }[]
111
112
 
112
113
  // Subscribe to real-time messages
113
114
  const unsub = client.onMessage(topicId, (msg) => { ... });
@@ -3,7 +3,7 @@ import {
3
3
  CONFIG_DIR,
4
4
  loadCredentials,
5
5
  output
6
- } from "./chunk-6VM633OH.js";
6
+ } from "./chunk-C5RR5Q6G.js";
7
7
 
8
8
  // src/cli/state.ts
9
9
  import { existsSync, mkdirSync, writeFileSync } from "fs";
@@ -21,7 +21,7 @@ function initState(address) {
21
21
  startedAt: now,
22
22
  lastScanAt: now,
23
23
  mode: "active",
24
- skillVersion: "0.12.3",
24
+ skillVersion: "0.12.5",
25
25
  lastSkillCheck: now
26
26
  },
27
27
  chains: {
@@ -11,12 +11,14 @@ var CHAINS = {
11
11
  shortName: "Sepolia",
12
12
  rpc: "https://sepolia.base.org",
13
13
  explorer: "https://sepolia.basescan.org",
14
+ explorerApi: "https://api.routescan.io/v2/network/testnet/evm/84532/etherscan/api",
14
15
  registry: "0xf39b193aedC1Ec9FD6C5ccc24fBAe58ba9f52413",
15
16
  keyManager: "0x5562B553a876CBdc8AA4B3fb0687f22760F4759e",
16
17
  schemaRegistry: "0xB7eB50e9058198b99b5b2589E6D70b2d99d5440a",
17
18
  identityRegistry: "0x8004AA63c570c570eBF15376c0dB199918BFe9Fb",
18
19
  escrow: "0x74e376C53f4afd5Cd32a77dDc627f477FcFC2333",
19
- defaultLookback: 2e5
20
+ defaultLookback: 2e5,
21
+ logChunkSize: 1e3
20
22
  },
21
23
  base: {
22
24
  chainId: 8453,
@@ -24,12 +26,14 @@ var CHAINS = {
24
26
  shortName: "Base",
25
27
  rpc: "https://base.publicnode.com",
26
28
  explorer: "https://basescan.org",
29
+ explorerApi: "https://api.routescan.io/v2/network/mainnet/evm/8453/etherscan/api",
27
30
  registry: "0x5fF6BF04F1B5A78ae884D977a3C80A0D8E2072bF",
28
31
  keyManager: "0xdc302ff43a34F6aEa19426D60C9D150e0661E4f4",
29
32
  schemaRegistry: "0x5c11d2eA4470eD9025D810A21a885FE16dC987Bd",
30
33
  identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
31
34
  escrow: "0x04eC9a25C942192834F447eC9192831B56Ae2D7D",
32
- defaultLookback: 2e5
35
+ defaultLookback: 2e5,
36
+ logChunkSize: 1e3
33
37
  },
34
38
  avalanche: {
35
39
  chainId: 43114,
@@ -37,14 +41,21 @@ var CHAINS = {
37
41
  shortName: "Avalanche",
38
42
  rpc: "https://api.avax.network/ext/bc/C/rpc",
39
43
  explorer: "https://snowtrace.io",
44
+ explorerApi: "https://api.routescan.io/v2/network/mainnet/evm/43114/etherscan/api",
40
45
  registry: "0x3Ca2FF0bD1b3633513299EB5d3e2d63e058b0713",
41
46
  keyManager: "0x5a5ea9D408FBA984fFf6e243Dcc71ff6E00C73E4",
42
47
  schemaRegistry: "0x23D96e610E8E3DA5341a75B77F1BFF7EA9c3A62B",
43
48
  identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
44
49
  escrow: "0x4068245c35a498Da4336aD1Ab0Fb71ef534bfd03",
45
- defaultLookback: 5e5
50
+ defaultLookback: 5e5,
51
+ logChunkSize: 2e3
46
52
  }
47
53
  };
54
+ var CHAIN_IDS = {
55
+ 84532: "baseSepolia",
56
+ 8453: "base",
57
+ 43114: "avalanche"
58
+ };
48
59
 
49
60
  // src/contracts.ts
50
61
  var REGISTRY_ABI = [
@@ -1415,21 +1426,20 @@ function decryptMessage(jsonStr, key) {
1415
1426
  const decrypted = decrypt(jsonStr, key);
1416
1427
  if (!decrypted) return null;
1417
1428
  try {
1418
- const content = JSON.parse(decrypted);
1419
- if (typeof content === "object" && content.text) {
1420
- return {
1421
- text: content.text,
1422
- replyTo: content.replyTo || null,
1423
- replyText: content.replyText || null,
1424
- replyAuthor: content.replyAuthor || null,
1425
- mentions: content.mentions || null
1426
- };
1427
- }
1428
- return { text: decrypted, replyTo: null, replyText: null, replyAuthor: null, mentions: null };
1429
+ return JSON.parse(decrypted);
1429
1430
  } catch {
1430
- return { text: decrypted, replyTo: null, replyText: null, replyAuthor: null, mentions: null };
1431
+ return decrypted;
1431
1432
  }
1432
1433
  }
1434
+ function getMessageText(content) {
1435
+ if (typeof content === "string") return content;
1436
+ if (content && typeof content === "object" && "text" in content) {
1437
+ const text = content.text;
1438
+ if (typeof text === "string") return text;
1439
+ return JSON.stringify(text);
1440
+ }
1441
+ return null;
1442
+ }
1433
1443
  function toBase64(bytes) {
1434
1444
  if (typeof Buffer !== "undefined") {
1435
1445
  return Buffer.from(bytes).toString("base64");
@@ -3447,6 +3457,7 @@ async function withRetry(fn, options) {
3447
3457
  var Clawntenna = class _Clawntenna {
3448
3458
  provider;
3449
3459
  chainName;
3460
+ historyApiKey;
3450
3461
  _signer;
3451
3462
  _address;
3452
3463
  _registry;
@@ -3484,12 +3495,13 @@ var Clawntenna = class _Clawntenna {
3484
3495
  tokenDecimalsCache = /* @__PURE__ */ new Map();
3485
3496
  static ERC20_DECIMALS_ABI = ["function decimals() view returns (uint8)"];
3486
3497
  constructor(options = {}) {
3487
- const chainName = options.chain ?? "base";
3498
+ const chainName = options.chain ?? (options.chainId != null ? CHAIN_IDS[options.chainId] : void 0) ?? "base";
3488
3499
  const chain = CHAINS[chainName];
3489
3500
  if (!chain) throw new Error(`Unsupported chain: ${chainName}`);
3490
3501
  this.chainName = chainName;
3491
3502
  const rpcUrl = options.rpcUrl ?? chain.rpc;
3492
3503
  this.provider = new ethers.JsonRpcProvider(rpcUrl);
3504
+ this.historyApiKey = options.historyApiKey ?? null;
3493
3505
  const registryAddr = options.registryAddress ?? chain.registry;
3494
3506
  const keyManagerAddr = options.keyManagerAddress ?? chain.keyManager;
3495
3507
  const schemaRegistryAddr = options.schemaRegistryAddress ?? chain.schemaRegistry;
@@ -3547,6 +3559,16 @@ var Clawntenna = class _Clawntenna {
3547
3559
  get address() {
3548
3560
  return this._address;
3549
3561
  }
3562
+ supportsIndexedHistory() {
3563
+ return Boolean(CHAINS[this.chainName].explorerApi);
3564
+ }
3565
+ getIndexedHistorySource() {
3566
+ const api = CHAINS[this.chainName].explorerApi;
3567
+ if (!api) return null;
3568
+ if (api.includes("routescan")) return "RouteScan";
3569
+ if (api.includes("basescan")) return "BaseScan";
3570
+ return "Explorer API";
3571
+ }
3550
3572
  // ===== MESSAGING =====
3551
3573
  /**
3552
3574
  * Send an encrypted message to a topic.
@@ -3567,7 +3589,10 @@ var Clawntenna = class _Clawntenna {
3567
3589
  const messages = await this.readMessages(topicId, { limit: 50 });
3568
3590
  const original = messages.find((m) => m.txHash === options.replyTo);
3569
3591
  if (original) {
3570
- replyText = replyText || original.text.slice(0, 100);
3592
+ const originalText = getMessageText(original.content);
3593
+ if (originalText) {
3594
+ replyText = replyText || originalText.slice(0, 100);
3595
+ }
3571
3596
  replyAuthor = replyAuthor || original.sender;
3572
3597
  }
3573
3598
  } catch {
@@ -3619,40 +3644,42 @@ var Clawntenna = class _Clawntenna {
3619
3644
  async readMessages(topicId, options) {
3620
3645
  const limit = options?.limit ?? 50;
3621
3646
  const key = await this.getEncryptionKey(topicId);
3647
+ const chain = CHAINS[this.chainName];
3648
+ if (options?.fromBlock == null && chain.explorerApi) {
3649
+ return this._readMessagesFromExplorer(topicId, limit, key);
3650
+ }
3622
3651
  const filter = this.registry.filters.MessageSent(topicId);
3623
- const CHUNK_SIZE = 2e3;
3624
3652
  const currentBlock = await this.provider.getBlockNumber();
3625
- const chain = CHAINS[this.chainName];
3653
+ const chunkSize = chain.logChunkSize;
3626
3654
  const maxRange = options?.fromBlock != null ? currentBlock - options.fromBlock : chain.defaultLookback;
3627
3655
  const startBlock = currentBlock - maxRange;
3628
3656
  const allEvents = [];
3629
3657
  let toBlock = currentBlock;
3658
+ let batchSpan = chunkSize;
3630
3659
  while (toBlock > startBlock && allEvents.length < limit) {
3631
- const chunkFrom = Math.max(toBlock - CHUNK_SIZE + 1, startBlock);
3632
- const events = await this._wrapRpcError(
3633
- () => this.registry.queryFilter(filter, chunkFrom, toBlock),
3634
- "readMessages"
3660
+ const batchFrom = Math.max(toBlock - batchSpan + 1, startBlock);
3661
+ const queryCount = Math.ceil((toBlock - batchFrom + 1) / chunkSize);
3662
+ options?.onProgress?.({
3663
+ fromBlock: batchFrom,
3664
+ toBlock,
3665
+ queryCount
3666
+ });
3667
+ const events = await this._queryFilterChunked(
3668
+ this.registry,
3669
+ filter,
3670
+ batchFrom,
3671
+ toBlock,
3672
+ chunkSize
3635
3673
  );
3636
3674
  allEvents.unshift(...events);
3637
- toBlock = chunkFrom - 1;
3638
- }
3639
- const recent = allEvents.slice(-limit);
3640
- const messages = [];
3641
- for (const log of recent) {
3642
- const payloadStr = ethers.toUtf8String(log.args.payload);
3643
- const parsed = decryptMessage(payloadStr, key);
3644
- messages.push({
3645
- topicId,
3646
- sender: log.args.sender,
3647
- text: parsed?.text ?? "[decryption failed]",
3648
- replyTo: parsed?.replyTo ?? null,
3649
- mentions: parsed?.mentions ?? null,
3650
- timestamp: Number(log.args.timestamp),
3651
- txHash: log.transactionHash,
3652
- blockNumber: log.blockNumber
3653
- });
3675
+ toBlock = batchFrom - 1;
3676
+ if (options?.fromBlock != null) {
3677
+ batchSpan = chunkSize;
3678
+ } else {
3679
+ batchSpan = Math.min(batchSpan * 2, Math.max(toBlock - startBlock + 1, chunkSize));
3680
+ }
3654
3681
  }
3655
- return messages;
3682
+ return allEvents.slice(-limit).map((log) => this._decodeMessageLog(topicId, key, log));
3656
3683
  }
3657
3684
  /**
3658
3685
  * Subscribe to real-time messages on a topic.
@@ -3666,13 +3693,11 @@ var Clawntenna = class _Clawntenna {
3666
3693
  const handler = (tId, sender, payload, timestamp, event) => {
3667
3694
  if (!key) return;
3668
3695
  const payloadStr = ethers.toUtf8String(payload);
3669
- const parsed = decryptMessage(payloadStr, key);
3696
+ const content = decryptMessage(payloadStr, key);
3670
3697
  callback({
3671
3698
  topicId: Number(tId),
3672
3699
  sender,
3673
- text: parsed?.text ?? "[decryption failed]",
3674
- replyTo: parsed?.replyTo ?? null,
3675
- mentions: parsed?.mentions ?? null,
3700
+ content,
3676
3701
  timestamp: Number(timestamp),
3677
3702
  txHash: event.transactionHash,
3678
3703
  blockNumber: event.blockNumber
@@ -4200,6 +4225,65 @@ var Clawntenna = class _Clawntenna {
4200
4225
  }
4201
4226
  return results;
4202
4227
  }
4228
+ async _readMessagesFromExplorer(topicId, limit, key) {
4229
+ const chain = CHAINS[this.chainName];
4230
+ if (!chain.explorerApi) {
4231
+ throw new Error(`Indexed history is not configured for ${this.chainName}.`);
4232
+ }
4233
+ const url = new URL(chain.explorerApi);
4234
+ url.searchParams.set("module", "logs");
4235
+ url.searchParams.set("action", "getLogs");
4236
+ url.searchParams.set("fromBlock", "0");
4237
+ url.searchParams.set("toBlock", "latest");
4238
+ url.searchParams.set("address", chain.registry);
4239
+ url.searchParams.set("topic0", ethers.id("MessageSent(uint256,address,bytes,uint256)"));
4240
+ url.searchParams.set("topic1", ethers.zeroPadValue(ethers.toBeHex(topicId), 32));
4241
+ url.searchParams.set("topic0_1_opr", "and");
4242
+ url.searchParams.set("page", "1");
4243
+ url.searchParams.set("offset", String(limit));
4244
+ url.searchParams.set("sort", "desc");
4245
+ if (this.historyApiKey) {
4246
+ url.searchParams.set("apikey", this.historyApiKey);
4247
+ }
4248
+ const response = await withRetry(() => fetch(url));
4249
+ if (!response.ok) {
4250
+ throw new Error(`Historical message lookup failed with HTTP ${response.status}.`);
4251
+ }
4252
+ const body = await response.json();
4253
+ if (Array.isArray(body.result)) {
4254
+ const iface = new ethers.Interface(REGISTRY_ABI);
4255
+ const decoded = body.result.map((log) => {
4256
+ const parsed = iface.parseLog({
4257
+ topics: log.topics,
4258
+ data: log.data
4259
+ });
4260
+ if (!parsed || parsed.name !== "MessageSent") return null;
4261
+ return this._decodeMessageLog(topicId, key, {
4262
+ args: parsed.args,
4263
+ transactionHash: log.transactionHash,
4264
+ blockNumber: Number(log.blockNumber)
4265
+ });
4266
+ }).filter((msg) => msg !== null);
4267
+ decoded.sort((a, b) => a.blockNumber - b.blockNumber);
4268
+ return decoded;
4269
+ }
4270
+ if (body.message === "No records found") {
4271
+ return [];
4272
+ }
4273
+ throw new Error(`Historical message lookup failed: ${body.message ?? "unexpected explorer response"}.`);
4274
+ }
4275
+ _decodeMessageLog(topicId, key, log) {
4276
+ const payloadStr = ethers.toUtf8String(log.args.payload);
4277
+ const content = decryptMessage(payloadStr, key);
4278
+ return {
4279
+ topicId,
4280
+ sender: log.args.sender,
4281
+ content,
4282
+ timestamp: Number(log.args.timestamp),
4283
+ txHash: log.transactionHash,
4284
+ blockNumber: log.blockNumber
4285
+ };
4286
+ }
4203
4287
  // ===== ESCROW INBOX (deposit → message bridge) =====
4204
4288
  /**
4205
4289
  * Reverse lookup: find the transaction hash that created a deposit.
@@ -4266,7 +4350,7 @@ var Clawntenna = class _Clawntenna {
4266
4350
  const receipt = await this.provider.getTransactionReceipt(txHash);
4267
4351
  if (receipt) {
4268
4352
  const msg = await this._parseMessageFromReceipt(receipt);
4269
- messageText = msg?.text ?? null;
4353
+ messageText = msg ? getMessageText(msg.content) : null;
4270
4354
  }
4271
4355
  } catch {
4272
4356
  }
@@ -4307,20 +4391,17 @@ var Clawntenna = class _Clawntenna {
4307
4391
  const sender = parsed.args.sender;
4308
4392
  const payloadBytes = parsed.args.payload;
4309
4393
  const timestamp = Number(parsed.args.timestamp);
4310
- let text = "[unable to decrypt]";
4394
+ let content = null;
4311
4395
  try {
4312
4396
  const key = await this.getEncryptionKey(topicId);
4313
4397
  const payloadStr = ethers.toUtf8String(payloadBytes);
4314
- const result = decryptMessage(payloadStr, key);
4315
- if (result) text = result.text;
4398
+ content = decryptMessage(payloadStr, key);
4316
4399
  } catch {
4317
4400
  }
4318
4401
  return {
4319
4402
  topicId,
4320
4403
  sender,
4321
- text,
4322
- replyTo: null,
4323
- mentions: null,
4404
+ content,
4324
4405
  timestamp,
4325
4406
  txHash: receipt.hash,
4326
4407
  blockNumber: receipt.blockNumber
@@ -4906,8 +4987,8 @@ function validateKeyAddress(creds) {
4906
4987
  }
4907
4988
  }
4908
4989
  async function runPostInit(address) {
4909
- const { initState } = await import("./state-AIF4NWKT.js");
4910
- const { copySkillFiles } = await import("./skill-NOMAG55P.js");
4990
+ const { initState } = await import("./state-DNMI7HY4.js");
4991
+ const { copySkillFiles } = await import("./skill-FSWNTKL5.js");
4911
4992
  const stateResult = initState(address);
4912
4993
  const skillResult = copySkillFiles();
4913
4994
  return { stateResult, skillResult };
@@ -5068,7 +5149,13 @@ function loadClient(flags, requireWallet = true) {
5068
5149
  const chainId = chainIdForCredentials(flags.chain);
5069
5150
  const credsRpc = creds?.chains[chainId]?.rpc;
5070
5151
  const rpcUrl = flags.rpc ?? process.env.CLAWNTENNA_RPC_URL ?? credsRpc;
5071
- return new Clawntenna({ chain: flags.chain, privateKey: privateKey ?? void 0, rpcUrl });
5152
+ const historyApiKey = process.env.ROUTESCAN_API_KEY ?? process.env.BASESCAN_API_KEY;
5153
+ return new Clawntenna({
5154
+ chain: flags.chain,
5155
+ privateKey: privateKey ?? void 0,
5156
+ rpcUrl,
5157
+ historyApiKey
5158
+ });
5072
5159
  }
5073
5160
  function output(data, json) {
5074
5161
  if (json) {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CONFIG_DIR
4
- } from "./chunk-6VM633OH.js";
4
+ } from "./chunk-C5RR5Q6G.js";
5
5
 
6
6
  // src/cli/skill.ts
7
7
  import { readFileSync, existsSync, copyFileSync, mkdirSync } from "fs";
package/dist/cli/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  stateInit
4
- } from "./chunk-VMA7BES6.js";
4
+ } from "./chunk-5MUM5BAH.js";
5
5
  import {
6
6
  showHeartbeat,
7
7
  showSkill,
8
8
  showSkillJson
9
- } from "./chunk-KDFBD47K.js";
9
+ } from "./chunk-VCEFHKGA.js";
10
10
  import {
11
11
  REGISTRY_ABI,
12
12
  chainIdForCredentials,
@@ -16,7 +16,7 @@ import {
16
16
  output,
17
17
  outputError,
18
18
  parseCommonFlags
19
- } from "./chunk-6VM633OH.js";
19
+ } from "./chunk-C5RR5Q6G.js";
20
20
 
21
21
  // src/cli/send.ts
22
22
  async function send(topicId, message, flags) {
@@ -85,9 +85,21 @@ async function read(topicId, flags) {
85
85
  } catch {
86
86
  }
87
87
  }
88
- if (!json) console.log(`Reading topic ${topicId} on ${flags.chain} (last ${flags.limit} messages)...
88
+ if (!json) {
89
+ console.log(`Reading topic ${topicId} on ${flags.chain} (last ${flags.limit} messages)...
89
90
  `);
90
- const messages = await client.readMessages(topicId, { limit: flags.limit });
91
+ const source = client.supportsIndexedHistory() ? client.getIndexedHistorySource() : null;
92
+ if (source) {
93
+ console.log(`Loading historical messages from ${source}...
94
+ `);
95
+ }
96
+ }
97
+ const messages = await client.readMessages(topicId, {
98
+ limit: flags.limit,
99
+ onProgress: json ? void 0 : ({ fromBlock, toBlock, queryCount }) => {
100
+ console.log(`Scanning blocks ${fromBlock}-${toBlock} (${queryCount} RPC quer${queryCount === 1 ? "y" : "ies"})...`);
101
+ }
102
+ });
91
103
  if (json) {
92
104
  const agentStatus = {};
93
105
  const uniqueSenders = [...new Set(messages.map((m) => m.sender))];
@@ -108,9 +120,7 @@ async function read(topicId, flags) {
108
120
  }
109
121
  output(messages.map((m) => ({
110
122
  sender: m.sender,
111
- text: m.text,
112
- replyTo: m.replyTo,
113
- mentions: m.mentions,
123
+ content: m.content,
114
124
  timestamp: m.timestamp.toString(),
115
125
  txHash: m.txHash,
116
126
  blockNumber: m.blockNumber,
@@ -124,8 +134,8 @@ async function read(topicId, flags) {
124
134
  }
125
135
  for (const msg of messages) {
126
136
  const time = new Date(Number(msg.timestamp) * 1e3).toISOString().slice(0, 19).replace("T", " ");
127
- const reply = msg.replyTo ? ` (reply to ${msg.replyTo.slice(0, 10)}...)` : "";
128
- console.log(`[${time}] ${msg.sender.slice(0, 8)}...: ${msg.text}${reply}`);
137
+ const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
138
+ console.log(`[${time}] ${msg.sender.slice(0, 8)}...: ${content}`);
129
139
  }
130
140
  console.log(`
131
141
  ${messages.length} message(s) displayed.`);
@@ -907,17 +917,15 @@ async function subscribe(topicId, flags) {
907
917
  if (json) {
908
918
  console.log(JSON.stringify({
909
919
  sender: msg.sender,
910
- text: msg.text,
911
- replyTo: msg.replyTo,
912
- mentions: msg.mentions,
920
+ content: msg.content,
913
921
  timestamp: msg.timestamp.toString(),
914
922
  txHash: msg.txHash,
915
923
  blockNumber: msg.blockNumber
916
924
  }));
917
925
  } else {
918
926
  const time = new Date(Number(msg.timestamp) * 1e3).toISOString().slice(0, 19).replace("T", " ");
919
- const reply = msg.replyTo ? ` (reply to ${msg.replyTo.slice(0, 10)}...)` : "";
920
- console.log(`[${time}] ${msg.sender.slice(0, 8)}...: ${msg.text}${reply}`);
927
+ const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content);
928
+ console.log(`[${time}] ${msg.sender.slice(0, 8)}...: ${content}`);
921
929
  }
922
930
  }
923
931
  lastBlock = currentBlock;
@@ -1299,7 +1307,7 @@ function decodeContractError(err) {
1299
1307
  }
1300
1308
 
1301
1309
  // src/cli/index.ts
1302
- var VERSION = "0.12.3";
1310
+ var VERSION = "0.12.5";
1303
1311
  var HELP = `
1304
1312
  clawntenna v${VERSION}
1305
1313
  On-chain encrypted messaging for AI agents
@@ -4,8 +4,8 @@ import {
4
4
  showHeartbeat,
5
5
  showSkill,
6
6
  showSkillJson
7
- } from "./chunk-KDFBD47K.js";
8
- import "./chunk-6VM633OH.js";
7
+ } from "./chunk-VCEFHKGA.js";
8
+ import "./chunk-C5RR5Q6G.js";
9
9
  export {
10
10
  copySkillFiles,
11
11
  showHeartbeat,
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  initState,
4
4
  stateInit
5
- } from "./chunk-VMA7BES6.js";
6
- import "./chunk-6VM633OH.js";
5
+ } from "./chunk-5MUM5BAH.js";
6
+ import "./chunk-C5RR5Q6G.js";
7
7
  export {
8
8
  initState,
9
9
  stateInit