@lucid-agents/taskmarket 0.7.1 → 0.9.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.
- package/dist/index.js +416 -18
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ var __export = (target, all) => {
|
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// src/index.ts
|
|
9
|
-
import { Command as
|
|
9
|
+
import { Command as Command42 } from "commander";
|
|
10
10
|
import { createRequire } from "module";
|
|
11
11
|
|
|
12
12
|
// src/commands/init.ts
|
|
@@ -128,8 +128,109 @@ async function pollAgentId(address, maxWaitMs = 6e4) {
|
|
|
128
128
|
return null;
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
// src/lib/encryption.ts
|
|
132
|
+
import { createECDH, hkdfSync, createCipheriv as createCipheriv2, createDecipheriv as createDecipheriv2, randomBytes as randomBytes2 } from "crypto";
|
|
133
|
+
var VERSION = 1;
|
|
134
|
+
var EPH_PUB_LEN = 65;
|
|
135
|
+
var IV_LEN = 12;
|
|
136
|
+
var TAG_LEN = 16;
|
|
137
|
+
var HEADER_LEN = 1 + EPH_PUB_LEN + IV_LEN + TAG_LEN;
|
|
138
|
+
function ecdhSharedSecret(privateKeyHex, otherPubKeyHex) {
|
|
139
|
+
const ecdh = createECDH("secp256k1");
|
|
140
|
+
ecdh.setPrivateKey(Buffer.from(privateKeyHex.replace(/^0x/, ""), "hex"));
|
|
141
|
+
const shared = ecdh.computeSecret(Buffer.from(otherPubKeyHex, "hex"));
|
|
142
|
+
return shared;
|
|
143
|
+
}
|
|
144
|
+
function hkdfKey(sharedSecret) {
|
|
145
|
+
return Buffer.from(hkdfSync("sha256", sharedSecret, Buffer.alloc(0), "taskmarket-ecies-v1", 32));
|
|
146
|
+
}
|
|
147
|
+
function aesGcmEncrypt(key, iv, plaintext) {
|
|
148
|
+
const cipher = createCipheriv2("aes-256-gcm", key, iv);
|
|
149
|
+
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
150
|
+
const tag = cipher.getAuthTag();
|
|
151
|
+
return { ciphertext, tag };
|
|
152
|
+
}
|
|
153
|
+
function aesGcmDecrypt(key, iv, tag, ciphertext) {
|
|
154
|
+
const decipher = createDecipheriv2("aes-256-gcm", key, iv);
|
|
155
|
+
decipher.setAuthTag(tag);
|
|
156
|
+
return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
157
|
+
}
|
|
158
|
+
function derivePublicKey(privateKeyHex) {
|
|
159
|
+
const ecdh = createECDH("secp256k1");
|
|
160
|
+
ecdh.setPrivateKey(Buffer.from(privateKeyHex.replace(/^0x/, ""), "hex"));
|
|
161
|
+
return ecdh.getPublicKey(void 0, "uncompressed").toString("hex");
|
|
162
|
+
}
|
|
163
|
+
function deriveCompressedPublicKey(privateKeyHex) {
|
|
164
|
+
const ecdh = createECDH("secp256k1");
|
|
165
|
+
ecdh.setPrivateKey(Buffer.from(privateKeyHex.replace(/^0x/, ""), "hex"));
|
|
166
|
+
return ecdh.getPublicKey(void 0, "compressed").toString("hex");
|
|
167
|
+
}
|
|
168
|
+
function encryptForRecipient(fileBuffer, recipientPubKeyHex) {
|
|
169
|
+
const ephEcdh = createECDH("secp256k1");
|
|
170
|
+
ephEcdh.generateKeys();
|
|
171
|
+
const ephPubKey = ephEcdh.getPublicKey(void 0, "uncompressed");
|
|
172
|
+
const ephPrivKeyHex = ephEcdh.getPrivateKey("hex");
|
|
173
|
+
const shared = ecdhSharedSecret(ephPrivKeyHex, recipientPubKeyHex);
|
|
174
|
+
const aesKey = hkdfKey(shared);
|
|
175
|
+
const iv = randomBytes2(IV_LEN);
|
|
176
|
+
const { ciphertext, tag } = aesGcmEncrypt(aesKey, iv, fileBuffer);
|
|
177
|
+
return Buffer.concat([Buffer.from([VERSION]), ephPubKey, iv, tag, ciphertext]);
|
|
178
|
+
}
|
|
179
|
+
function decryptWithPrivateKey(fileBuffer, privateKeyHex) {
|
|
180
|
+
if (fileBuffer.length < HEADER_LEN + 1) {
|
|
181
|
+
throw new Error("Decryption failed: invalid key or corrupted file");
|
|
182
|
+
}
|
|
183
|
+
const version2 = fileBuffer[0];
|
|
184
|
+
if (version2 !== VERSION) {
|
|
185
|
+
throw new Error(`Decryption failed: unsupported file version 0x${version2.toString(16)}`);
|
|
186
|
+
}
|
|
187
|
+
const ephPubKeyHex = fileBuffer.subarray(1, 1 + EPH_PUB_LEN).toString("hex");
|
|
188
|
+
const iv = fileBuffer.subarray(1 + EPH_PUB_LEN, 1 + EPH_PUB_LEN + IV_LEN);
|
|
189
|
+
const tag = fileBuffer.subarray(1 + EPH_PUB_LEN + IV_LEN, 1 + EPH_PUB_LEN + IV_LEN + TAG_LEN);
|
|
190
|
+
const ciphertext = fileBuffer.subarray(1 + EPH_PUB_LEN + IV_LEN + TAG_LEN);
|
|
191
|
+
const shared = ecdhSharedSecret(privateKeyHex, ephPubKeyHex);
|
|
192
|
+
const aesKey = hkdfKey(shared);
|
|
193
|
+
try {
|
|
194
|
+
return aesGcmDecrypt(aesKey, iv, tag, ciphertext);
|
|
195
|
+
} catch {
|
|
196
|
+
throw new Error("Decryption failed: invalid key or corrupted file");
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
131
200
|
// src/commands/init.ts
|
|
132
|
-
|
|
201
|
+
async function tryRegisterEmail(deviceId, apiToken, username, explicit) {
|
|
202
|
+
try {
|
|
203
|
+
const reg = await apiPost("/api/emails/register", {
|
|
204
|
+
deviceId,
|
|
205
|
+
apiToken,
|
|
206
|
+
username
|
|
207
|
+
});
|
|
208
|
+
return reg.emailAddress;
|
|
209
|
+
} catch (err) {
|
|
210
|
+
if (explicit) {
|
|
211
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
212
|
+
process.stderr.write(
|
|
213
|
+
JSON.stringify({
|
|
214
|
+
ok: false,
|
|
215
|
+
error: `Email registration failed: ${msg}. Run: taskmarket email register --username ${username}`
|
|
216
|
+
}) + "\n"
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
return null;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
var initCommand = new Command("init").description("Create and register a new agent wallet (safe to re-run)").option(
|
|
223
|
+
"--email <username>",
|
|
224
|
+
"Claim a custom email username (default: auto-generated from agent ID)"
|
|
225
|
+
).action(async (opts) => {
|
|
226
|
+
if (opts.email) {
|
|
227
|
+
const check = await apiGet(
|
|
228
|
+
`/api/emails/check-username?username=${encodeURIComponent(opts.email)}`
|
|
229
|
+
);
|
|
230
|
+
if (!check.available) {
|
|
231
|
+
printError(`Email username "${opts.email}" is not available.`);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
133
234
|
if (await keystoreExists()) {
|
|
134
235
|
const keystore = await loadKeystore();
|
|
135
236
|
let agentId2 = keystore.agentId;
|
|
@@ -145,19 +246,38 @@ var initCommand = new Command("init").description("Create and register a new age
|
|
|
145
246
|
networkInfo2 = response.result.data;
|
|
146
247
|
} catch {
|
|
147
248
|
}
|
|
249
|
+
let emailAddress2 = null;
|
|
250
|
+
try {
|
|
251
|
+
const existing = await apiGet(`/api/agents/stats?address=${keystore.walletAddress}`);
|
|
252
|
+
emailAddress2 = existing.emailAddress ?? null;
|
|
253
|
+
} catch {
|
|
254
|
+
}
|
|
255
|
+
if (!emailAddress2) {
|
|
256
|
+
const username2 = opts.email ?? (agentId2 && networkInfo2 ? `${agentId2}-${networkInfo2.chainId}` : null);
|
|
257
|
+
if (username2) {
|
|
258
|
+
emailAddress2 = await tryRegisterEmail(
|
|
259
|
+
keystore.deviceId,
|
|
260
|
+
keystore.apiToken,
|
|
261
|
+
username2,
|
|
262
|
+
!!opts.email
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
148
266
|
printResult({
|
|
149
267
|
address: keystore.walletAddress,
|
|
150
268
|
agentId: agentId2,
|
|
151
269
|
network: networkInfo2?.networkName,
|
|
152
|
-
chainId: networkInfo2?.chainId
|
|
270
|
+
chainId: networkInfo2?.chainId,
|
|
271
|
+
emailAddress: emailAddress2
|
|
153
272
|
});
|
|
154
273
|
return;
|
|
155
274
|
}
|
|
156
275
|
const { privateKey, address } = generateKeypair();
|
|
276
|
+
const publicKey = deriveCompressedPublicKey(privateKey);
|
|
157
277
|
const res = await fetch(`${API_URL}/api/devices`, {
|
|
158
278
|
method: "POST",
|
|
159
279
|
headers: { "Content-Type": "application/json" },
|
|
160
|
-
body: JSON.stringify({ walletAddress: address })
|
|
280
|
+
body: JSON.stringify({ walletAddress: address, publicKey })
|
|
161
281
|
});
|
|
162
282
|
if (!res.ok) {
|
|
163
283
|
const text = await res.text().catch(() => "");
|
|
@@ -185,11 +305,14 @@ var initCommand = new Command("init").description("Create and register a new age
|
|
|
185
305
|
networkInfo = response.result.data;
|
|
186
306
|
} catch {
|
|
187
307
|
}
|
|
308
|
+
const username = opts.email ?? (agentId && networkInfo ? `${agentId}-${networkInfo.chainId}` : null);
|
|
309
|
+
const emailAddress = username ? await tryRegisterEmail(deviceId, apiToken, username, !!opts.email) : null;
|
|
188
310
|
printResult({
|
|
189
311
|
address,
|
|
190
312
|
agentId,
|
|
191
313
|
network: networkInfo?.networkName,
|
|
192
|
-
chainId: networkInfo?.chainId
|
|
314
|
+
chainId: networkInfo?.chainId,
|
|
315
|
+
emailAddress
|
|
193
316
|
});
|
|
194
317
|
});
|
|
195
318
|
|
|
@@ -346,6 +469,7 @@ var statsCommand = new Command4("stats").description("View agent statistics").op
|
|
|
346
469
|
averageRating: result.averageRating,
|
|
347
470
|
totalEarnings: result.totalEarnings,
|
|
348
471
|
skills: result.skills,
|
|
472
|
+
emailAddress: result.emailAddress,
|
|
349
473
|
recentRatings: result.recentRatings
|
|
350
474
|
});
|
|
351
475
|
});
|
|
@@ -660,7 +784,7 @@ var depositCommand = new Command22("deposit").description("Show wallet address a
|
|
|
660
784
|
});
|
|
661
785
|
|
|
662
786
|
// src/commands/wallet/index.ts
|
|
663
|
-
import { Command as
|
|
787
|
+
import { Command as Command27 } from "commander";
|
|
664
788
|
|
|
665
789
|
// src/commands/wallet/balance.ts
|
|
666
790
|
import { Command as Command23 } from "commander";
|
|
@@ -731,10 +855,11 @@ var walletImportCommand = new Command24("import").description("Import an existin
|
|
|
731
855
|
const privateKey = normalizePrivateKey(rawKey);
|
|
732
856
|
const account = privateKeyToAccount3(privateKey);
|
|
733
857
|
const address = account.address;
|
|
858
|
+
const publicKey = deriveCompressedPublicKey(privateKey);
|
|
734
859
|
const res = await fetch(`${API_URL}/api/devices`, {
|
|
735
860
|
method: "POST",
|
|
736
861
|
headers: { "Content-Type": "application/json" },
|
|
737
|
-
body: JSON.stringify({ walletAddress: address })
|
|
862
|
+
body: JSON.stringify({ walletAddress: address, publicKey })
|
|
738
863
|
});
|
|
739
864
|
if (!res.ok) {
|
|
740
865
|
const text = await res.text().catch(() => "");
|
|
@@ -792,14 +917,35 @@ var setWithdrawalAddressCommand = new Command25("set-withdrawal-address").descri
|
|
|
792
917
|
printResult({ withdrawalAddress: result.withdrawalAddress });
|
|
793
918
|
});
|
|
794
919
|
|
|
920
|
+
// src/commands/wallet/publish-key.ts
|
|
921
|
+
import { Command as Command26 } from "commander";
|
|
922
|
+
var publishKeyCommand = new Command26("publish-key").description("Publish your secp256k1 public key so others can encrypt files for you").action(async () => {
|
|
923
|
+
let keystore;
|
|
924
|
+
try {
|
|
925
|
+
keystore = await loadKeystore();
|
|
926
|
+
} catch {
|
|
927
|
+
printError("No keystore found. Run `taskmarket init` first.");
|
|
928
|
+
}
|
|
929
|
+
const dek = await fetchDeviceKey(keystore.deviceId, keystore.apiToken);
|
|
930
|
+
const privateKey = decryptPrivateKey(dek, keystore.encryptedKey);
|
|
931
|
+
const publicKey = deriveCompressedPublicKey(privateKey);
|
|
932
|
+
const result = await apiPost("/trpc/agents.setPublicKey", {
|
|
933
|
+
deviceId: keystore.deviceId,
|
|
934
|
+
apiToken: keystore.apiToken,
|
|
935
|
+
publicKey
|
|
936
|
+
});
|
|
937
|
+
printResult({ publicKey: result.result.data.publicKey });
|
|
938
|
+
});
|
|
939
|
+
|
|
795
940
|
// src/commands/wallet/index.ts
|
|
796
|
-
var walletCommand = new
|
|
941
|
+
var walletCommand = new Command27("wallet").description("Wallet management commands");
|
|
797
942
|
walletCommand.addCommand(walletBalanceCommand);
|
|
798
943
|
walletCommand.addCommand(walletImportCommand);
|
|
799
944
|
walletCommand.addCommand(setWithdrawalAddressCommand);
|
|
945
|
+
walletCommand.addCommand(publishKeyCommand);
|
|
800
946
|
|
|
801
947
|
// src/commands/withdraw.ts
|
|
802
|
-
import { Command as
|
|
948
|
+
import { Command as Command28 } from "commander";
|
|
803
949
|
import { toHex as toHex2 } from "viem";
|
|
804
950
|
var USDC_TYPES = {
|
|
805
951
|
TransferWithAuthorization: [
|
|
@@ -811,7 +957,7 @@ var USDC_TYPES = {
|
|
|
811
957
|
{ name: "nonce", type: "bytes32" }
|
|
812
958
|
]
|
|
813
959
|
};
|
|
814
|
-
var withdrawCommand = new
|
|
960
|
+
var withdrawCommand = new Command28("withdraw").description("Withdraw USDC to the registered withdrawal address").argument("<amount>", "Amount in USDC (e.g. 5 for 5 USDC)").action(async (amount) => {
|
|
815
961
|
const parsed = parseFloat(amount);
|
|
816
962
|
if (isNaN(parsed) || parsed <= 0) {
|
|
817
963
|
printError("Invalid amount: must be a positive number (e.g. 5 for 5 USDC)");
|
|
@@ -860,13 +1006,104 @@ var withdrawCommand = new Command27("withdraw").description("Withdraw USDC to th
|
|
|
860
1006
|
printResult({ txHash: result.txHash, amountBaseUnits: result.amountBaseUnits, to: result.to });
|
|
861
1007
|
});
|
|
862
1008
|
|
|
1009
|
+
// src/commands/encrypt.ts
|
|
1010
|
+
import { Command as Command29 } from "commander";
|
|
1011
|
+
import { promises as fs3 } from "fs";
|
|
1012
|
+
var encryptCommand = new Command29("encrypt").description("Encrypt a file with ECIES using wallet keys").argument("<file>", "Path to the file to encrypt").option("--recipient <address>", "Recipient wallet address (default: self)").option("--output <path>", "Output path (default: <file>.enc)").action(async (file, opts) => {
|
|
1013
|
+
let plaintext;
|
|
1014
|
+
try {
|
|
1015
|
+
plaintext = await fs3.readFile(file);
|
|
1016
|
+
} catch {
|
|
1017
|
+
printError(`Cannot read file: ${file}`);
|
|
1018
|
+
}
|
|
1019
|
+
let keystore;
|
|
1020
|
+
try {
|
|
1021
|
+
keystore = await loadKeystore();
|
|
1022
|
+
} catch {
|
|
1023
|
+
printError("No keystore found. Run `taskmarket init` first.");
|
|
1024
|
+
}
|
|
1025
|
+
let recipientPubKey;
|
|
1026
|
+
let recipientAddress;
|
|
1027
|
+
if (opts.recipient) {
|
|
1028
|
+
recipientAddress = opts.recipient;
|
|
1029
|
+
let result;
|
|
1030
|
+
try {
|
|
1031
|
+
result = await apiGet(
|
|
1032
|
+
`/trpc/agents.publicKey?input=${encodeURIComponent(JSON.stringify({ address: opts.recipient }))}`
|
|
1033
|
+
);
|
|
1034
|
+
} catch (err) {
|
|
1035
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1036
|
+
if (msg.includes("publish their public key") || msg.includes("NOT_FOUND")) {
|
|
1037
|
+
printError(
|
|
1038
|
+
`Recipient has not published their public key. Ask them to run: taskmarket wallet publish-key`
|
|
1039
|
+
);
|
|
1040
|
+
}
|
|
1041
|
+
printError(`Failed to fetch recipient public key: ${msg}`);
|
|
1042
|
+
}
|
|
1043
|
+
recipientPubKey = result.result.data.publicKey;
|
|
1044
|
+
} else {
|
|
1045
|
+
recipientAddress = keystore.walletAddress;
|
|
1046
|
+
const dek = await fetchDeviceKey(keystore.deviceId, keystore.apiToken);
|
|
1047
|
+
const privateKey = decryptPrivateKey(dek, keystore.encryptedKey);
|
|
1048
|
+
recipientPubKey = derivePublicKey(privateKey);
|
|
1049
|
+
}
|
|
1050
|
+
const encrypted = encryptForRecipient(plaintext, recipientPubKey);
|
|
1051
|
+
const outputPath = opts.output ?? `${file}.enc`;
|
|
1052
|
+
await fs3.writeFile(outputPath, encrypted);
|
|
1053
|
+
printResult({
|
|
1054
|
+
output: outputPath,
|
|
1055
|
+
bytes: encrypted.length,
|
|
1056
|
+
recipient: recipientAddress
|
|
1057
|
+
});
|
|
1058
|
+
});
|
|
1059
|
+
|
|
1060
|
+
// src/commands/decrypt.ts
|
|
1061
|
+
import { Command as Command30 } from "commander";
|
|
1062
|
+
import { promises as fs4 } from "fs";
|
|
1063
|
+
var decryptCommand = new Command30("decrypt").description("Decrypt a file using your wallet key").argument("<file>", "Path to the encrypted file").option("--output <path>", "Output path (default: strips .enc, otherwise appends .dec)").action(async (file, opts) => {
|
|
1064
|
+
let ciphertext;
|
|
1065
|
+
try {
|
|
1066
|
+
ciphertext = await fs4.readFile(file);
|
|
1067
|
+
} catch {
|
|
1068
|
+
printError(`Cannot read file: ${file}`);
|
|
1069
|
+
}
|
|
1070
|
+
let keystore;
|
|
1071
|
+
try {
|
|
1072
|
+
keystore = await loadKeystore();
|
|
1073
|
+
} catch {
|
|
1074
|
+
printError("No keystore found. Run `taskmarket init` first.");
|
|
1075
|
+
}
|
|
1076
|
+
const dek = await fetchDeviceKey(keystore.deviceId, keystore.apiToken);
|
|
1077
|
+
const privateKey = decryptPrivateKey(dek, keystore.encryptedKey);
|
|
1078
|
+
let plaintext;
|
|
1079
|
+
try {
|
|
1080
|
+
plaintext = decryptWithPrivateKey(ciphertext, privateKey);
|
|
1081
|
+
} catch (err) {
|
|
1082
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1083
|
+
printError(msg);
|
|
1084
|
+
}
|
|
1085
|
+
let outputPath;
|
|
1086
|
+
if (opts.output) {
|
|
1087
|
+
outputPath = opts.output;
|
|
1088
|
+
} else if (file.endsWith(".enc")) {
|
|
1089
|
+
outputPath = file.slice(0, -4);
|
|
1090
|
+
} else {
|
|
1091
|
+
outputPath = `${file}.dec`;
|
|
1092
|
+
}
|
|
1093
|
+
await fs4.writeFile(outputPath, plaintext);
|
|
1094
|
+
printResult({
|
|
1095
|
+
output: outputPath,
|
|
1096
|
+
bytes: plaintext.length
|
|
1097
|
+
});
|
|
1098
|
+
});
|
|
1099
|
+
|
|
863
1100
|
// src/commands/xmtp.ts
|
|
864
|
-
import { Command as
|
|
1101
|
+
import { Command as Command31 } from "commander";
|
|
865
1102
|
|
|
866
1103
|
// src/lib/xmtp-client.ts
|
|
867
1104
|
import os2 from "os";
|
|
868
1105
|
import path2 from "path";
|
|
869
|
-
import { randomUUID as randomUUID2, hkdfSync } from "crypto";
|
|
1106
|
+
import { randomUUID as randomUUID2, hkdfSync as hkdfSync2 } from "crypto";
|
|
870
1107
|
import { privateKeyToAccount as privateKeyToAccount4 } from "viem/accounts";
|
|
871
1108
|
|
|
872
1109
|
// src/lib/xmtp-envelope.ts
|
|
@@ -5050,6 +5287,7 @@ var AgentStatsSchema = external_exports.object({
|
|
|
5050
5287
|
averageRating: external_exports.number(),
|
|
5051
5288
|
totalEarnings: external_exports.string(),
|
|
5052
5289
|
skills: external_exports.array(external_exports.string()).optional(),
|
|
5290
|
+
emailAddress: external_exports.string().nullable().optional(),
|
|
5053
5291
|
recentRatings: external_exports.array(external_exports.object({
|
|
5054
5292
|
taskId: external_exports.string(),
|
|
5055
5293
|
rating: external_exports.number(),
|
|
@@ -5072,7 +5310,8 @@ var LeaderboardEntrySchema = external_exports.object({
|
|
|
5072
5310
|
completedTasks: external_exports.number(),
|
|
5073
5311
|
averageRating: external_exports.number(),
|
|
5074
5312
|
totalEarnings: external_exports.string(),
|
|
5075
|
-
skills: external_exports.array(external_exports.string())
|
|
5313
|
+
skills: external_exports.array(external_exports.string()),
|
|
5314
|
+
emailAddress: external_exports.string().nullable().optional()
|
|
5076
5315
|
});
|
|
5077
5316
|
var LeaderboardResponseSchema = external_exports.array(LeaderboardEntrySchema);
|
|
5078
5317
|
|
|
@@ -5311,6 +5550,28 @@ var XmtpResolvePeerOutputSchema = external_exports.object({
|
|
|
5311
5550
|
inboxId: external_exports.string().nullable()
|
|
5312
5551
|
});
|
|
5313
5552
|
|
|
5553
|
+
// ../../packages/shared/dist/schemas/email.schemas.js
|
|
5554
|
+
var EmailSchema = external_exports.object({
|
|
5555
|
+
id: external_exports.string(),
|
|
5556
|
+
fromAddress: external_exports.string(),
|
|
5557
|
+
toAddress: external_exports.string(),
|
|
5558
|
+
subject: external_exports.string().nullable(),
|
|
5559
|
+
bodyText: external_exports.string().nullable(),
|
|
5560
|
+
bodyHtml: external_exports.string().nullable(),
|
|
5561
|
+
isRead: external_exports.boolean(),
|
|
5562
|
+
receivedAt: external_exports.string()
|
|
5563
|
+
});
|
|
5564
|
+
var SendEmailInputSchema = external_exports.object({
|
|
5565
|
+
to: external_exports.string().email(),
|
|
5566
|
+
subject: external_exports.string().min(1),
|
|
5567
|
+
bodyText: external_exports.string().min(1)
|
|
5568
|
+
});
|
|
5569
|
+
var EmailInboundHeadersSchema = external_exports.object({
|
|
5570
|
+
"x-webhook-secret": external_exports.string(),
|
|
5571
|
+
"x-email-from": external_exports.string(),
|
|
5572
|
+
"x-email-to": external_exports.string().email()
|
|
5573
|
+
});
|
|
5574
|
+
|
|
5314
5575
|
// ../../packages/shared/dist/lib/agentName.js
|
|
5315
5576
|
var MODIFIERS = [
|
|
5316
5577
|
"Neon",
|
|
@@ -5911,7 +6172,7 @@ async function createSdkClient(factory, signer, options) {
|
|
|
5911
6172
|
}
|
|
5912
6173
|
function deriveXmtpDbKey(dekHex) {
|
|
5913
6174
|
const ikm = Buffer.from(dekHex, "hex");
|
|
5914
|
-
const derived =
|
|
6175
|
+
const derived = hkdfSync2("sha256", ikm, "", "taskmarket-xmtp-db", 32);
|
|
5915
6176
|
return new Uint8Array(derived);
|
|
5916
6177
|
}
|
|
5917
6178
|
async function sendViaConversation(client, toInboxId, body) {
|
|
@@ -6334,7 +6595,7 @@ function getDefaultQueryTimeoutMs() {
|
|
|
6334
6595
|
}
|
|
6335
6596
|
return Math.floor(parsed);
|
|
6336
6597
|
}
|
|
6337
|
-
var xmtpCommand = new
|
|
6598
|
+
var xmtpCommand = new Command31("xmtp").description("Manage XMTP messaging for this agent");
|
|
6338
6599
|
xmtpCommand.command("init").description("Initialize XMTP client and register installation metadata with backend").action(async () => {
|
|
6339
6600
|
const keystore = await loadKeystore();
|
|
6340
6601
|
const client = await createXmtpClient({
|
|
@@ -6562,7 +6823,7 @@ xmtpCommand.command("purge").description("Revoke stale XMTP installations that h
|
|
|
6562
6823
|
});
|
|
6563
6824
|
|
|
6564
6825
|
// src/commands/daemon.ts
|
|
6565
|
-
import { Command as
|
|
6826
|
+
import { Command as Command32 } from "commander";
|
|
6566
6827
|
function diffTaskStatuses(prev, next) {
|
|
6567
6828
|
const changes = [];
|
|
6568
6829
|
for (const [taskId, newStatus] of next) {
|
|
@@ -6590,7 +6851,7 @@ function sleepOrAbort(ms, signal) {
|
|
|
6590
6851
|
});
|
|
6591
6852
|
}
|
|
6592
6853
|
var MAX_SEEN_TASK_IDS = 2e3;
|
|
6593
|
-
var daemonCommand = new
|
|
6854
|
+
var daemonCommand = new Command32("daemon").description("Long-running agent daemon: XMTP stream, heartbeats, and task polling").option("--heartbeat-interval <ms>", "Heartbeat interval in milliseconds", "1800000").option("--inbox-interval <ms>", "Inbox poll interval in milliseconds", "15000").option("--task-interval <ms>", "New task poll interval in milliseconds", "60000").option("--task-filters <json>", "JSON filter object for new-task discovery").option("--no-xmtp", "Disable XMTP stream and heartbeat").action(
|
|
6594
6855
|
async (opts) => {
|
|
6595
6856
|
const heartbeatIntervalMs = Number(opts.heartbeatInterval);
|
|
6596
6857
|
const inboxIntervalMs = Number(opts.inboxInterval);
|
|
@@ -6806,10 +7067,144 @@ var daemonCommand = new Command29("daemon").description("Long-running agent daem
|
|
|
6806
7067
|
}
|
|
6807
7068
|
);
|
|
6808
7069
|
|
|
7070
|
+
// src/commands/email/index.ts
|
|
7071
|
+
import { Command as Command41 } from "commander";
|
|
7072
|
+
|
|
7073
|
+
// src/commands/email/register.ts
|
|
7074
|
+
import { Command as Command33 } from "commander";
|
|
7075
|
+
var registerCommand = new Command33("register").description("Register an email address for this agent").requiredOption("--username <name>", "Desired username (e.g. myagent)").action(async (opts) => {
|
|
7076
|
+
const check = await apiGet(
|
|
7077
|
+
`/api/emails/check-username?username=${encodeURIComponent(opts.username)}`
|
|
7078
|
+
);
|
|
7079
|
+
if (!check.available) {
|
|
7080
|
+
printError(`Username "${opts.username}" is not available.`);
|
|
7081
|
+
}
|
|
7082
|
+
const keystore = await loadKeystore();
|
|
7083
|
+
const result = await apiPost("/api/emails/register", {
|
|
7084
|
+
deviceId: keystore.deviceId,
|
|
7085
|
+
apiToken: keystore.apiToken,
|
|
7086
|
+
username: opts.username
|
|
7087
|
+
});
|
|
7088
|
+
printResult({ emailAddress: result.emailAddress });
|
|
7089
|
+
});
|
|
7090
|
+
|
|
7091
|
+
// src/commands/email/inbox.ts
|
|
7092
|
+
import { Command as Command34 } from "commander";
|
|
7093
|
+
var inboxCommand2 = new Command34("inbox").description("List emails in your inbox").option("--limit <n>", "Number of emails to return", "20").option("--unread", "Show only unread emails").action(async (opts) => {
|
|
7094
|
+
const keystore = await loadKeystore();
|
|
7095
|
+
const params = new URLSearchParams({
|
|
7096
|
+
deviceId: keystore.deviceId,
|
|
7097
|
+
apiToken: keystore.apiToken,
|
|
7098
|
+
limit: opts.limit
|
|
7099
|
+
});
|
|
7100
|
+
if (opts.unread) {
|
|
7101
|
+
params.set("unread", "true");
|
|
7102
|
+
}
|
|
7103
|
+
const result = await apiGet(`/api/emails/list?${params.toString()}`);
|
|
7104
|
+
printResult({ emails: result.emails });
|
|
7105
|
+
});
|
|
7106
|
+
|
|
7107
|
+
// src/commands/email/read.ts
|
|
7108
|
+
import { Command as Command35 } from "commander";
|
|
7109
|
+
var readCommand = new Command35("read").description("Read an email by ID (marks it as read)").argument("<id>", "Email ID").action(async (id) => {
|
|
7110
|
+
const keystore = await loadKeystore();
|
|
7111
|
+
const params = new URLSearchParams({
|
|
7112
|
+
deviceId: keystore.deviceId,
|
|
7113
|
+
apiToken: keystore.apiToken,
|
|
7114
|
+
id
|
|
7115
|
+
});
|
|
7116
|
+
const result = await apiGet(`/api/emails/get?${params.toString()}`);
|
|
7117
|
+
printResult(result);
|
|
7118
|
+
});
|
|
7119
|
+
|
|
7120
|
+
// src/commands/email/send.ts
|
|
7121
|
+
import { Command as Command36 } from "commander";
|
|
7122
|
+
var sendCommand = new Command36("send").description("Send an email").requiredOption("--to <address>", "Recipient email address").requiredOption("--subject <subject>", "Email subject").requiredOption("--body <text>", "Email body text").action(async (opts) => {
|
|
7123
|
+
const keystore = await loadKeystore();
|
|
7124
|
+
const result = await apiPost("/api/emails/send", {
|
|
7125
|
+
deviceId: keystore.deviceId,
|
|
7126
|
+
apiToken: keystore.apiToken,
|
|
7127
|
+
to: opts.to,
|
|
7128
|
+
subject: opts.subject,
|
|
7129
|
+
bodyText: opts.body
|
|
7130
|
+
});
|
|
7131
|
+
printResult({ sent: result.sent });
|
|
7132
|
+
});
|
|
7133
|
+
|
|
7134
|
+
// src/commands/email/reply.ts
|
|
7135
|
+
import { Command as Command37 } from "commander";
|
|
7136
|
+
var replyCommand = new Command37("reply").description("Reply to an email").argument("<id>", "Email ID to reply to").requiredOption("--body <text>", "Reply body text").action(async (id, opts) => {
|
|
7137
|
+
const keystore = await loadKeystore();
|
|
7138
|
+
const params = new URLSearchParams({
|
|
7139
|
+
deviceId: keystore.deviceId,
|
|
7140
|
+
apiToken: keystore.apiToken,
|
|
7141
|
+
id
|
|
7142
|
+
});
|
|
7143
|
+
const original = await apiGet(`/api/emails/get?${params.toString()}`);
|
|
7144
|
+
const to = original.fromAddress;
|
|
7145
|
+
const rawSubject = original.subject ?? "";
|
|
7146
|
+
const subject = rawSubject.startsWith("Re: ") ? rawSubject : `Re: ${rawSubject}`;
|
|
7147
|
+
const result = await apiPost("/api/emails/send", {
|
|
7148
|
+
deviceId: keystore.deviceId,
|
|
7149
|
+
apiToken: keystore.apiToken,
|
|
7150
|
+
to,
|
|
7151
|
+
subject,
|
|
7152
|
+
bodyText: opts.body
|
|
7153
|
+
});
|
|
7154
|
+
printResult({ sent: result.sent });
|
|
7155
|
+
});
|
|
7156
|
+
|
|
7157
|
+
// src/commands/email/delete.ts
|
|
7158
|
+
import { Command as Command38 } from "commander";
|
|
7159
|
+
var deleteCommand = new Command38("delete").description("Delete an email by ID").argument("<id>", "Email ID").action(async (id) => {
|
|
7160
|
+
const keystore = await loadKeystore();
|
|
7161
|
+
const result = await apiPost("/api/emails/delete", {
|
|
7162
|
+
deviceId: keystore.deviceId,
|
|
7163
|
+
apiToken: keystore.apiToken,
|
|
7164
|
+
id
|
|
7165
|
+
});
|
|
7166
|
+
printResult({ deleted: result.deleted });
|
|
7167
|
+
});
|
|
7168
|
+
|
|
7169
|
+
// src/commands/email/address.ts
|
|
7170
|
+
import { Command as Command39 } from "commander";
|
|
7171
|
+
var addressCommand2 = new Command39("address").description("Show your registered email address").action(async () => {
|
|
7172
|
+
const keystore = await loadKeystore();
|
|
7173
|
+
const result = await apiGet(`/api/agents/stats?address=${keystore.walletAddress}`);
|
|
7174
|
+
printResult({ emailAddress: result.emailAddress ?? null });
|
|
7175
|
+
});
|
|
7176
|
+
|
|
7177
|
+
// src/commands/email/mark-read.ts
|
|
7178
|
+
import { Command as Command40 } from "commander";
|
|
7179
|
+
async function setReadStatus(id, read) {
|
|
7180
|
+
const keystore = await loadKeystore();
|
|
7181
|
+
const result = await apiPost("/api/emails/mark-read", {
|
|
7182
|
+
deviceId: keystore.deviceId,
|
|
7183
|
+
apiToken: keystore.apiToken,
|
|
7184
|
+
id,
|
|
7185
|
+
read
|
|
7186
|
+
});
|
|
7187
|
+
printResult({ id: result.id, isRead: result.isRead });
|
|
7188
|
+
}
|
|
7189
|
+
var markReadCommand = new Command40("mark-read").description("Mark an email as read or unread").argument("<id>", "Email ID").option("--unread", "Mark as unread instead of read").action(async (id, opts) => {
|
|
7190
|
+
await setReadStatus(id, !opts.unread);
|
|
7191
|
+
});
|
|
7192
|
+
|
|
7193
|
+
// src/commands/email/index.ts
|
|
7194
|
+
var emailCommand = new Command41("email").description("Email management commands");
|
|
7195
|
+
emailCommand.addCommand(registerCommand);
|
|
7196
|
+
emailCommand.addCommand(inboxCommand2);
|
|
7197
|
+
emailCommand.addCommand(readCommand);
|
|
7198
|
+
emailCommand.addCommand(sendCommand);
|
|
7199
|
+
emailCommand.addCommand(replyCommand);
|
|
7200
|
+
emailCommand.addCommand(deleteCommand);
|
|
7201
|
+
emailCommand.addCommand(addressCommand2);
|
|
7202
|
+
emailCommand.addCommand(markReadCommand);
|
|
7203
|
+
|
|
6809
7204
|
// src/index.ts
|
|
6810
7205
|
var require2 = createRequire(import.meta.url);
|
|
6811
7206
|
var { version } = require2("../package.json");
|
|
6812
|
-
var program = new
|
|
7207
|
+
var program = new Command42();
|
|
6813
7208
|
program.name("taskmarket").description("Taskmarket CLI for AI agents").version(version);
|
|
6814
7209
|
program.addCommand(initCommand);
|
|
6815
7210
|
program.addCommand(walletCommand);
|
|
@@ -6821,8 +7216,11 @@ program.addCommand(agentsCommand);
|
|
|
6821
7216
|
program.addCommand(inboxCommand);
|
|
6822
7217
|
program.addCommand(depositCommand);
|
|
6823
7218
|
program.addCommand(withdrawCommand);
|
|
7219
|
+
program.addCommand(encryptCommand);
|
|
7220
|
+
program.addCommand(decryptCommand);
|
|
6824
7221
|
program.addCommand(xmtpCommand);
|
|
6825
7222
|
program.addCommand(daemonCommand);
|
|
7223
|
+
program.addCommand(emailCommand);
|
|
6826
7224
|
program.parseAsync(process.argv).catch((err) => {
|
|
6827
7225
|
process.stderr.write(JSON.stringify({ ok: false, error: err.message }) + "\n");
|
|
6828
7226
|
process.exit(1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lucid-agents/taskmarket",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"taskmarket": "./dist/index.js"
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
"typescript": "^5.3.3",
|
|
19
19
|
"vitest": "^2.0.0",
|
|
20
20
|
"@taskmarket/eslint-config": "0.0.0",
|
|
21
|
-
"@taskmarket/
|
|
22
|
-
"@taskmarket/
|
|
21
|
+
"@taskmarket/prettier-config": "0.0.0",
|
|
22
|
+
"@taskmarket/shared": "1.0.0"
|
|
23
23
|
},
|
|
24
24
|
"files": [
|
|
25
25
|
"dist"
|