@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.
Files changed (2) hide show
  1. package/dist/index.js +416 -18
  2. 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 Command30 } from "commander";
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
- var initCommand = new Command("init").description("Create and register a new agent wallet (safe to re-run)").action(async () => {
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 Command26 } from "commander";
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 Command26("wallet").description("Wallet management commands");
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 Command27 } from "commander";
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 Command27("withdraw").description("Withdraw USDC to the registered withdrawal address").argument("<amount>", "Amount in USDC (e.g. 5 for 5 USDC)").action(async (amount) => {
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 Command28 } from "commander";
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 = hkdfSync("sha256", ikm, "", "taskmarket-xmtp-db", 32);
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 Command28("xmtp").description("Manage XMTP messaging for this agent");
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 Command29 } from "commander";
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 Command29("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(
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 Command30();
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.7.1",
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/shared": "1.0.0",
22
- "@taskmarket/prettier-config": "0.0.0"
21
+ "@taskmarket/prettier-config": "0.0.0",
22
+ "@taskmarket/shared": "1.0.0"
23
23
  },
24
24
  "files": [
25
25
  "dist"