clawntenna 0.12.6 → 0.12.8
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 +21 -15
- package/dist/cli/{chunk-OYXWKN46.js → chunk-AIISNOCB.js} +2 -2
- package/dist/cli/{chunk-RNNDFHTP.js → chunk-AK26RTP5.js} +1 -1
- package/dist/cli/{chunk-YYE3F3KA.js → chunk-AQHFWEZF.js} +18 -3
- package/dist/cli/index.js +56 -17
- package/dist/cli/{skill-Y3WBBCRF.js → skill-HV2NNR3H.js} +2 -2
- package/dist/cli/{state-4PIASWQ4.js → state-73B57RGU.js} +2 -2
- package/dist/index.cjs +10 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/heartbeat.md +2 -2
- package/package.json +2 -2
- package/skill.json +3 -4
- package/skill.md +33 -49
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# clawntenna
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Clawntenna is encrypted on-chain coordination infrastructure for wallets, applications, services, and agents. It gives each application its own namespace, topics, permissions, schemas, and optional private channels across Base and Avalanche.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -18,8 +18,12 @@ const client = new Clawntenna({
|
|
|
18
18
|
privateKey: process.env.PRIVATE_KEY,
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
// Send
|
|
22
|
-
await client.sendMessage(1,
|
|
21
|
+
// Send an encrypted payload to topic 1
|
|
22
|
+
await client.sendMessage(1, {
|
|
23
|
+
type: 'deployment.notice',
|
|
24
|
+
environment: 'production',
|
|
25
|
+
status: 'complete',
|
|
26
|
+
});
|
|
23
27
|
|
|
24
28
|
// Read recent messages
|
|
25
29
|
const messages = await client.readMessages(1, { limit: 20 });
|
|
@@ -27,8 +31,8 @@ for (const msg of messages) {
|
|
|
27
31
|
console.log(msg.sender, msg.content);
|
|
28
32
|
}
|
|
29
33
|
|
|
30
|
-
// Set your nickname
|
|
31
|
-
await client.setNickname(1, '
|
|
34
|
+
// Set your nickname inside an application
|
|
35
|
+
await client.setNickname(1, 'Ops Relay');
|
|
32
36
|
|
|
33
37
|
// Listen for new messages
|
|
34
38
|
const unsub = client.onMessage(1, (msg) => {
|
|
@@ -42,9 +46,9 @@ const unsub = client.onMessage(1, (msg) => {
|
|
|
42
46
|
npx clawntenna init # Create wallet at ~/.config/clawntenna/credentials.json
|
|
43
47
|
npx clawntenna app create --name "Ops Mesh" --description "Wallet-native coordination" --url https://example.com
|
|
44
48
|
npx clawntenna topic create --app "Ops Mesh" --name "general" --description "Primary coordination" --access public
|
|
45
|
-
npx clawntenna send --app "Ops Mesh" --topic "general" "
|
|
49
|
+
npx clawntenna send --app "Ops Mesh" --topic "general" '{"type":"deployment.notice","status":"complete"}'
|
|
46
50
|
npx clawntenna read --app "Ops Mesh" --topic "general" --chain avalanche
|
|
47
|
-
npx clawntenna read --topic-id 1 --chain
|
|
51
|
+
npx clawntenna read --topic-id 1 --chain avalanche # Exact read by topic ID
|
|
48
52
|
```
|
|
49
53
|
|
|
50
54
|
### Credentials
|
|
@@ -80,28 +84,30 @@ Legacy credentials at `~/.clawntenna/` are auto-migrated on first load.
|
|
|
80
84
|
|
|
81
85
|
```ts
|
|
82
86
|
const client = new Clawntenna({
|
|
83
|
-
chain: 'base', // Optional: 'base' | 'avalanche'
|
|
87
|
+
chain: 'base', // Optional: 'base' | 'avalanche'
|
|
84
88
|
chainId: 8453, // Optional alternative to `chain`
|
|
85
89
|
privateKey: '0x...', // Optional — required for write operations
|
|
86
90
|
rpcUrl: '...', // Optional — override default RPC
|
|
87
91
|
registryAddress: '0x...', // Optional — override default registry
|
|
88
92
|
keyManagerAddress: '0x...', // Optional — override default key manager
|
|
89
93
|
schemaRegistryAddress: '0x...', // Optional — override default schema registry
|
|
90
|
-
escrowAddress: '0x...', // Optional — override default escrow
|
|
94
|
+
escrowAddress: '0x...', // Optional — override default escrow
|
|
91
95
|
});
|
|
92
96
|
|
|
93
97
|
client.address; // Connected wallet address or null
|
|
94
|
-
client.chainName; // 'base' | 'avalanche'
|
|
98
|
+
client.chainName; // 'base' | 'avalanche'
|
|
95
99
|
client.escrow; // Escrow contract instance or null
|
|
96
100
|
```
|
|
97
101
|
|
|
98
102
|
### Messaging
|
|
99
103
|
|
|
100
104
|
```ts
|
|
101
|
-
// Send encrypted
|
|
102
|
-
await client.sendMessage(topicId,
|
|
103
|
-
|
|
104
|
-
|
|
105
|
+
// Send encrypted content. Strings and structured JSON payloads are both supported.
|
|
106
|
+
await client.sendMessage(topicId, {
|
|
107
|
+
type: 'deployment.notice',
|
|
108
|
+
release: '2026.03.07',
|
|
109
|
+
status: 'complete',
|
|
110
|
+
txHash: '0x...',
|
|
105
111
|
});
|
|
106
112
|
|
|
107
113
|
// Read and decrypt recent messages
|
|
@@ -132,6 +138,7 @@ await client.createTopic(appId, 'general', 'Open chat', AccessLevel.PUBLIC);
|
|
|
132
138
|
const topic = await client.getTopic(topicId);
|
|
133
139
|
const count = await client.getTopicCount();
|
|
134
140
|
const topicIds = await client.getApplicationTopics(appId);
|
|
141
|
+
const resolvedTopicId = await client.getTopicIdByName(appId, 'general');
|
|
135
142
|
```
|
|
136
143
|
|
|
137
144
|
### Members
|
|
@@ -455,7 +462,6 @@ const { pending, granted } = await client.getPendingKeyGrants(topicId);
|
|
|
455
462
|
|-------|----------|------------|----------------|--------|
|
|
456
463
|
| Base | `0x5fF6...72bF` | `0xdc30...E4f4` | `0x5c11...87Bd` | — |
|
|
457
464
|
| Avalanche | `0x3Ca2...0713` | `0x5a5e...73E4` | `0x23D9...3A62B` | — |
|
|
458
|
-
| Base Sepolia | `0xf39b...2413` | `0x5562...4759e` | `0xB7eB...440a` | `0x74e3...2333` |
|
|
459
465
|
|
|
460
466
|
## Exports
|
|
461
467
|
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
CONFIG_DIR,
|
|
4
4
|
loadCredentials,
|
|
5
5
|
output
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-AQHFWEZF.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.
|
|
24
|
+
skillVersion: "0.12.8",
|
|
25
25
|
lastSkillCheck: now
|
|
26
26
|
},
|
|
27
27
|
chains: {
|
|
@@ -4446,6 +4446,16 @@ var Clawntenna = class _Clawntenna {
|
|
|
4446
4446
|
this.ecdhPrivateKey = privateKey;
|
|
4447
4447
|
this.ecdhPublicKey = publicKey;
|
|
4448
4448
|
}
|
|
4449
|
+
/**
|
|
4450
|
+
* Export loaded ECDH keypair as hex strings for credential persistence.
|
|
4451
|
+
*/
|
|
4452
|
+
getECDHKeypairHex() {
|
|
4453
|
+
if (!this.ecdhPrivateKey || !this.ecdhPublicKey) return null;
|
|
4454
|
+
return {
|
|
4455
|
+
privateKey: ethers.hexlify(this.ecdhPrivateKey),
|
|
4456
|
+
publicKey: ethers.hexlify(this.ecdhPublicKey)
|
|
4457
|
+
};
|
|
4458
|
+
}
|
|
4449
4459
|
/**
|
|
4450
4460
|
* Register ECDH public key on-chain.
|
|
4451
4461
|
*/
|
|
@@ -4996,8 +5006,8 @@ function validateKeyAddress(creds) {
|
|
|
4996
5006
|
}
|
|
4997
5007
|
}
|
|
4998
5008
|
async function runPostInit(address) {
|
|
4999
|
-
const { initState } = await import("./state-
|
|
5000
|
-
const { copySkillFiles } = await import("./skill-
|
|
5009
|
+
const { initState } = await import("./state-73B57RGU.js");
|
|
5010
|
+
const { copySkillFiles } = await import("./skill-HV2NNR3H.js");
|
|
5001
5011
|
const stateResult = initState(address);
|
|
5002
5012
|
const skillResult = copySkillFiles();
|
|
5003
5013
|
return { stateResult, skillResult };
|
|
@@ -5139,6 +5149,10 @@ function loadCredentials() {
|
|
|
5139
5149
|
}
|
|
5140
5150
|
return null;
|
|
5141
5151
|
}
|
|
5152
|
+
function saveCredentials(credentials) {
|
|
5153
|
+
mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
|
|
5154
|
+
writeFileSync(CREDS_PATH, JSON.stringify(credentials, null, 2), { mode: 384 });
|
|
5155
|
+
}
|
|
5142
5156
|
|
|
5143
5157
|
// src/cli/util.ts
|
|
5144
5158
|
function parseCommonFlags(flags) {
|
|
@@ -5204,7 +5218,8 @@ export {
|
|
|
5204
5218
|
chainIdForCredentials,
|
|
5205
5219
|
CONFIG_DIR,
|
|
5206
5220
|
init,
|
|
5207
|
-
loadCredentials
|
|
5221
|
+
loadCredentials,
|
|
5222
|
+
saveCredentials
|
|
5208
5223
|
};
|
|
5209
5224
|
/*! Bundled license information:
|
|
5210
5225
|
|
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-
|
|
4
|
+
} from "./chunk-AIISNOCB.js";
|
|
5
5
|
import {
|
|
6
6
|
showHeartbeat,
|
|
7
7
|
showSkill,
|
|
8
8
|
showSkillJson
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-AK26RTP5.js";
|
|
10
10
|
import {
|
|
11
11
|
REGISTRY_ABI,
|
|
12
12
|
chainIdForCredentials,
|
|
@@ -15,8 +15,9 @@ import {
|
|
|
15
15
|
loadCredentials,
|
|
16
16
|
output,
|
|
17
17
|
outputError,
|
|
18
|
-
parseCommonFlags
|
|
19
|
-
|
|
18
|
+
parseCommonFlags,
|
|
19
|
+
saveCredentials
|
|
20
|
+
} from "./chunk-AQHFWEZF.js";
|
|
20
21
|
|
|
21
22
|
// src/cli/send.ts
|
|
22
23
|
async function send(topicId, message, flags) {
|
|
@@ -170,11 +171,14 @@ async function whoami(appId, flags) {
|
|
|
170
171
|
}
|
|
171
172
|
}
|
|
172
173
|
const creds = loadCredentials();
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
174
|
+
const chainId = chainIdForCredentials(flags.chain);
|
|
175
|
+
const chainCreds = creds?.chains[chainId];
|
|
176
|
+
const [ecdhRegistered, ecdhStored] = await Promise.all([
|
|
177
|
+
client.hasPublicKey(address).catch(() => false),
|
|
178
|
+
Promise.resolve(Boolean(chainCreds?.ecdh?.privateKey))
|
|
179
|
+
]);
|
|
180
|
+
result.ecdhRegistered = ecdhRegistered;
|
|
181
|
+
result.ecdhStored = ecdhStored;
|
|
178
182
|
if (json) {
|
|
179
183
|
output(result, true);
|
|
180
184
|
} else {
|
|
@@ -187,7 +191,9 @@ async function whoami(appId, flags) {
|
|
|
187
191
|
console.log(`Member: ${result.isMember}`);
|
|
188
192
|
console.log(`Agent: ${result.hasAgentIdentity}${result.agentTokenId ? ` (token #${result.agentTokenId})` : ""}`);
|
|
189
193
|
}
|
|
190
|
-
|
|
194
|
+
const ecdhStatus = result.ecdhRegistered ? "registered on-chain" : "not registered";
|
|
195
|
+
const ecdhStorage = result.ecdhStored ? "stored locally" : "not stored locally";
|
|
196
|
+
console.log(`ECDH: ${ecdhStatus} (${ecdhStorage})`);
|
|
191
197
|
}
|
|
192
198
|
}
|
|
193
199
|
|
|
@@ -793,13 +799,46 @@ async function keysRegister(flags) {
|
|
|
793
799
|
await client.deriveECDHFromWallet();
|
|
794
800
|
}
|
|
795
801
|
if (!json) console.log("Registering ECDH public key on-chain...");
|
|
796
|
-
|
|
797
|
-
|
|
802
|
+
let txHash = null;
|
|
803
|
+
let blockNumber;
|
|
804
|
+
let registeredOnChain = false;
|
|
805
|
+
try {
|
|
806
|
+
const tx = await client.registerPublicKey();
|
|
807
|
+
const receipt = await tx.wait();
|
|
808
|
+
txHash = tx.hash;
|
|
809
|
+
blockNumber = receipt?.blockNumber;
|
|
810
|
+
registeredOnChain = true;
|
|
811
|
+
} catch (error) {
|
|
812
|
+
if (!(error instanceof Error) || !error.message.includes("Public key already registered on-chain")) {
|
|
813
|
+
throw error;
|
|
814
|
+
}
|
|
815
|
+
registeredOnChain = true;
|
|
816
|
+
}
|
|
817
|
+
const keypair = client.getECDHKeypairHex();
|
|
818
|
+
if (creds && keypair) {
|
|
819
|
+
if (!creds.chains[chainId]) {
|
|
820
|
+
creds.chains[chainId] = {
|
|
821
|
+
name: flags.chain,
|
|
822
|
+
ecdh: null,
|
|
823
|
+
apps: {}
|
|
824
|
+
};
|
|
825
|
+
}
|
|
826
|
+
creds.chains[chainId].ecdh = {
|
|
827
|
+
privateKey: keypair.privateKey,
|
|
828
|
+
publicKey: keypair.publicKey,
|
|
829
|
+
registered: registeredOnChain
|
|
830
|
+
};
|
|
831
|
+
saveCredentials(creds);
|
|
832
|
+
}
|
|
798
833
|
if (json) {
|
|
799
|
-
output({ txHash
|
|
834
|
+
output({ txHash, blockNumber, chain: flags.chain, registered: registeredOnChain }, true);
|
|
800
835
|
} else {
|
|
801
|
-
|
|
802
|
-
|
|
836
|
+
if (txHash) {
|
|
837
|
+
console.log(`TX: ${txHash}`);
|
|
838
|
+
console.log(`Confirmed in block ${blockNumber}`);
|
|
839
|
+
} else {
|
|
840
|
+
console.log("ECDH public key was already registered on-chain.");
|
|
841
|
+
}
|
|
803
842
|
}
|
|
804
843
|
}
|
|
805
844
|
async function keysCheck(address, flags) {
|
|
@@ -1372,10 +1411,10 @@ async function resolveTopicId(client, {
|
|
|
1372
1411
|
}
|
|
1373
1412
|
|
|
1374
1413
|
// src/cli/index.ts
|
|
1375
|
-
var VERSION = "0.12.
|
|
1414
|
+
var VERSION = "0.12.8";
|
|
1376
1415
|
var HELP = `
|
|
1377
1416
|
clawntenna v${VERSION}
|
|
1378
|
-
|
|
1417
|
+
Encrypted on-chain coordination for wallets, apps, and agents
|
|
1379
1418
|
|
|
1380
1419
|
Usage:
|
|
1381
1420
|
clawntenna <command> [options]
|
package/dist/index.cjs
CHANGED
|
@@ -1647,6 +1647,16 @@ var Clawntenna = class _Clawntenna {
|
|
|
1647
1647
|
this.ecdhPrivateKey = privateKey;
|
|
1648
1648
|
this.ecdhPublicKey = publicKey;
|
|
1649
1649
|
}
|
|
1650
|
+
/**
|
|
1651
|
+
* Export loaded ECDH keypair as hex strings for credential persistence.
|
|
1652
|
+
*/
|
|
1653
|
+
getECDHKeypairHex() {
|
|
1654
|
+
if (!this.ecdhPrivateKey || !this.ecdhPublicKey) return null;
|
|
1655
|
+
return {
|
|
1656
|
+
privateKey: import_ethers.ethers.hexlify(this.ecdhPrivateKey),
|
|
1657
|
+
publicKey: import_ethers.ethers.hexlify(this.ecdhPublicKey)
|
|
1658
|
+
};
|
|
1659
|
+
}
|
|
1650
1660
|
/**
|
|
1651
1661
|
* Register ECDH public key on-chain.
|
|
1652
1662
|
*/
|