@sherwoodagent/cli 0.65.2 → 0.72.3

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 (93) hide show
  1. package/dist/{abis-4HWN2E3H.js → abis-KP7M4IPM.js} +4 -2
  2. package/dist/addresses-YDPUPGWQ.js +45 -0
  3. package/dist/{agent-AETROOEW.js → agent-6IRZUPFT.js} +10 -10
  4. package/dist/{agent-AETROOEW.js.map → agent-6IRZUPFT.js.map} +1 -1
  5. package/dist/{chat-JSSTSE4K.js → chat-G5M3OK6M.js} +37 -36
  6. package/dist/chat-G5M3OK6M.js.map +1 -0
  7. package/dist/{chunk-IL43IMOC.js → chunk-3NMJ4LUL.js} +23 -18
  8. package/dist/chunk-3NMJ4LUL.js.map +1 -0
  9. package/dist/{chunk-UBAX22KA.js → chunk-52U76TRE.js} +4 -4
  10. package/dist/chunk-52U76TRE.js.map +1 -0
  11. package/dist/{chunk-W2ZUPR3W.js → chunk-5DWB5Y7G.js} +9 -9
  12. package/dist/chunk-5DWB5Y7G.js.map +1 -0
  13. package/dist/{chunk-YZHZSBES.js → chunk-BQMOE4FJ.js} +144 -37
  14. package/dist/chunk-BQMOE4FJ.js.map +1 -0
  15. package/dist/{chunk-VYF2TXPX.js → chunk-D4SPHYXA.js} +6 -6
  16. package/dist/{chunk-UCQEEF3Z.js → chunk-FOAX5PGR.js} +6 -6
  17. package/dist/chunk-FOAX5PGR.js.map +1 -0
  18. package/dist/chunk-FOS47623.js +127 -0
  19. package/dist/chunk-FOS47623.js.map +1 -0
  20. package/dist/{chunk-2W4KGGPU.js → chunk-GSC7PVEO.js} +27 -27
  21. package/dist/chunk-GSC7PVEO.js.map +1 -0
  22. package/dist/chunk-HYUUR6SC.js +111 -0
  23. package/dist/chunk-HYUUR6SC.js.map +1 -0
  24. package/dist/{chunk-RO26TXXE.js → chunk-NWY2U753.js} +2 -2
  25. package/dist/chunk-RAITRCM7.js +308 -0
  26. package/dist/chunk-RAITRCM7.js.map +1 -0
  27. package/dist/{chunk-A6TOJEUD.js → chunk-S6XA7PK4.js} +124 -128
  28. package/dist/chunk-S6XA7PK4.js.map +1 -0
  29. package/dist/{chunk-O4G3SBCI.js → chunk-UUHWD7Y3.js} +109 -129
  30. package/dist/chunk-UUHWD7Y3.js.map +1 -0
  31. package/dist/{chunk-YJSCIQUZ.js → chunk-WECQ6NVS.js} +6 -6
  32. package/dist/chunk-WECQ6NVS.js.map +1 -0
  33. package/dist/{chunk-RHRLYVKM.js → chunk-ZYXFKVYF.js} +25 -12
  34. package/dist/chunk-ZYXFKVYF.js.map +1 -0
  35. package/dist/{client-KBBFAMEI.js → client-QN6SA76M.js} +4 -4
  36. package/dist/{config-REASKDIK.js → config-FAQO37S7.js} +10 -10
  37. package/dist/{cron-EOULYO3R.js → cron-QMLRWDJG.js} +19 -17
  38. package/dist/cron-QMLRWDJG.js.map +1 -0
  39. package/dist/{eas-K4ZBACYN.js → eas-HM2AUOEY.js} +7 -7
  40. package/dist/{governor-2CDSMSG7.js → governor-RRBTDGDX.js} +17 -13
  41. package/dist/index.js +2026 -1222
  42. package/dist/index.js.map +1 -1
  43. package/dist/{ipfs-FAYWUCS2.js → ipfs-VGWTUORE.js} +2 -2
  44. package/dist/{network-3ZU7UBDU.js → network-L6JKNYOJ.js} +7 -7
  45. package/dist/{price-LCTECRQP.js → price-AJ4JMHCT.js} +6 -6
  46. package/dist/{research-FUQOQWKK.js → research-6VEEPEPP.js} +22 -22
  47. package/dist/research-6VEEPEPP.js.map +1 -0
  48. package/dist/research-7Z6SFPPX.js +14 -0
  49. package/dist/{session-FJB2RV2X.js → session-PURMITWE.js} +28 -28
  50. package/dist/session-PURMITWE.js.map +1 -0
  51. package/dist/{session-XAW5UIXP.js → session-XBQY7SBJ.js} +2 -2
  52. package/dist/{trade-U7H5IFH6.js → trade-YTGLGCRQ.js} +34 -34
  53. package/dist/trade-YTGLGCRQ.js.map +1 -0
  54. package/dist/vault-NIPA5JV4.js +54 -0
  55. package/dist/vault-NIPA5JV4.js.map +1 -0
  56. package/dist/{xmtp-6NJ4PW6L.js → xmtp-M32JSE4I.js} +13 -12
  57. package/dist/xmtp-M32JSE4I.js.map +1 -0
  58. package/package.json +4 -3
  59. package/dist/addresses-J2LMGUCT.js +0 -35
  60. package/dist/chat-JSSTSE4K.js.map +0 -1
  61. package/dist/chunk-2LRC7I33.js +0 -186
  62. package/dist/chunk-2LRC7I33.js.map +0 -1
  63. package/dist/chunk-2W4KGGPU.js.map +0 -1
  64. package/dist/chunk-A6TOJEUD.js.map +0 -1
  65. package/dist/chunk-GWMTAW6A.js +0 -494
  66. package/dist/chunk-GWMTAW6A.js.map +0 -1
  67. package/dist/chunk-IL43IMOC.js.map +0 -1
  68. package/dist/chunk-O4G3SBCI.js.map +0 -1
  69. package/dist/chunk-RHRLYVKM.js.map +0 -1
  70. package/dist/chunk-UBAX22KA.js.map +0 -1
  71. package/dist/chunk-UCQEEF3Z.js.map +0 -1
  72. package/dist/chunk-W2ZUPR3W.js.map +0 -1
  73. package/dist/chunk-YJSCIQUZ.js.map +0 -1
  74. package/dist/chunk-YZHZSBES.js.map +0 -1
  75. package/dist/cron-EOULYO3R.js.map +0 -1
  76. package/dist/research-FUQOQWKK.js.map +0 -1
  77. package/dist/research-XEXTHDT3.js +0 -14
  78. package/dist/session-FJB2RV2X.js.map +0 -1
  79. package/dist/trade-U7H5IFH6.js.map +0 -1
  80. package/dist/xmtp-6NJ4PW6L.js.map +0 -1
  81. /package/dist/{abis-4HWN2E3H.js.map → abis-KP7M4IPM.js.map} +0 -0
  82. /package/dist/{addresses-J2LMGUCT.js.map → addresses-YDPUPGWQ.js.map} +0 -0
  83. /package/dist/{chunk-VYF2TXPX.js.map → chunk-D4SPHYXA.js.map} +0 -0
  84. /package/dist/{chunk-RO26TXXE.js.map → chunk-NWY2U753.js.map} +0 -0
  85. /package/dist/{client-KBBFAMEI.js.map → client-QN6SA76M.js.map} +0 -0
  86. /package/dist/{config-REASKDIK.js.map → config-FAQO37S7.js.map} +0 -0
  87. /package/dist/{eas-K4ZBACYN.js.map → eas-HM2AUOEY.js.map} +0 -0
  88. /package/dist/{governor-2CDSMSG7.js.map → governor-RRBTDGDX.js.map} +0 -0
  89. /package/dist/{ipfs-FAYWUCS2.js.map → ipfs-VGWTUORE.js.map} +0 -0
  90. /package/dist/{network-3ZU7UBDU.js.map → network-L6JKNYOJ.js.map} +0 -0
  91. /package/dist/{price-LCTECRQP.js.map → price-AJ4JMHCT.js.map} +0 -0
  92. /package/dist/{research-XEXTHDT3.js.map → research-7Z6SFPPX.js.map} +0 -0
  93. /package/dist/{session-XAW5UIXP.js.map → session-XBQY7SBJ.js.map} +0 -0
@@ -1,35 +1,36 @@
1
1
  import {
2
- getSyndicate,
2
+ getFund,
3
3
  updateMetadata
4
- } from "./chunk-IL43IMOC.js";
4
+ } from "./chunk-3NMJ4LUL.js";
5
5
  import {
6
6
  getTextRecord,
7
- resolveSyndicate,
7
+ resolveFund,
8
8
  setTextRecord
9
- } from "./chunk-O4G3SBCI.js";
9
+ } from "./chunk-FOS47623.js";
10
+ import "./chunk-UUHWD7Y3.js";
10
11
  import {
11
12
  ENS
12
- } from "./chunk-GWMTAW6A.js";
13
+ } from "./chunk-RAITRCM7.js";
13
14
  import {
14
15
  formatContractError,
15
16
  getAccount
16
- } from "./chunk-YJSCIQUZ.js";
17
- import "./chunk-2LRC7I33.js";
17
+ } from "./chunk-WECQ6NVS.js";
18
+ import "./chunk-HYUUR6SC.js";
18
19
  import {
19
20
  cacheGroupId,
20
21
  getCachedGroupId
21
- } from "./chunk-2W4KGGPU.js";
22
- import "./chunk-YZHZSBES.js";
22
+ } from "./chunk-GSC7PVEO.js";
23
+ import "./chunk-BQMOE4FJ.js";
23
24
  import {
24
25
  fetchMetadata,
25
26
  uploadMetadata
26
- } from "./chunk-RHRLYVKM.js";
27
+ } from "./chunk-ZYXFKVYF.js";
27
28
 
28
29
  // src/commands/chat.ts
29
30
  import chalk from "chalk";
30
31
  import ora from "ora";
31
32
  async function loadXmtp() {
32
- return import("./xmtp-6NJ4PW6L.js");
33
+ return import("./xmtp-M32JSE4I.js");
33
34
  }
34
35
  function formatTimestamp(date) {
35
36
  return `${date.getHours().toString().padStart(2, "0")}:${date.getMinutes().toString().padStart(2, "0")}`;
@@ -99,7 +100,7 @@ ${envelope.text || ""}`;
99
100
  async function handleStream(name) {
100
101
  const spinner = ora("Connecting to chat...").start();
101
102
  try {
102
- await resolveSyndicate(name);
103
+ await resolveFund(name);
103
104
  const xmtp = await loadXmtp();
104
105
  const client = await xmtp.getXmtpClient();
105
106
  const group = await xmtp.getGroup(client, name);
@@ -220,7 +221,7 @@ async function handleAdd(name, address) {
220
221
  await xmtp.sendEnvelope(group, {
221
222
  type: "MEMBER_JOIN",
222
223
  from: address,
223
- syndicate: name,
224
+ fund: name,
224
225
  timestamp: Math.floor(Date.now() / 1e3)
225
226
  });
226
227
  spinner.succeed(`Member added: ${address}`);
@@ -291,12 +292,12 @@ async function handleRename(name, newName, newDescription) {
291
292
  }
292
293
  }
293
294
  async function handlePublishMetadata(name, groupIdOpt) {
294
- const spinner = ora("Updating syndicate metadata...").start();
295
+ const spinner = ora("Updating fund metadata...").start();
295
296
  try {
296
- const syndicate = await resolveSyndicate(name);
297
+ const fund = await resolveFund(name);
297
298
  const callerAddress = getAccount().address.toLowerCase();
298
- if (syndicate.creator.toLowerCase() !== callerAddress) {
299
- spinner.fail("Only the syndicate creator can update metadata");
299
+ if (fund.creator.toLowerCase() !== callerAddress) {
300
+ spinner.fail("Only the fund creator can update metadata");
300
301
  process.exit(1);
301
302
  }
302
303
  const xmtp = await loadXmtp();
@@ -314,13 +315,13 @@ async function handlePublishMetadata(name, groupIdOpt) {
314
315
  process.exit(1);
315
316
  }
316
317
  spinner.text = "Fetching current metadata...";
317
- const info = await getSyndicate(syndicate.id);
318
+ const info = await getFund(fund.id);
318
319
  let metadata;
319
320
  try {
320
321
  metadata = await fetchMetadata(info.metadataURI);
321
322
  } catch {
322
323
  metadata = {
323
- schema: "sherwood/syndicate/v1",
324
+ schema: "sherwood/fund/v1",
324
325
  name,
325
326
  description: "",
326
327
  chain: "",
@@ -333,7 +334,7 @@ async function handlePublishMetadata(name, groupIdOpt) {
333
334
  spinner.text = "Pinning updated metadata to IPFS...";
334
335
  const newURI = await uploadMetadata(metadata);
335
336
  spinner.text = "Calling factory.updateMetadata...";
336
- await updateMetadata(syndicate.id, newURI);
337
+ await updateMetadata(fund.id, newURI);
337
338
  spinner.succeed(`Metadata updated \u2014 xmtpGroupId = ${groupId}`);
338
339
  console.log(chalk.dim(` New URI: ${newURI}`));
339
340
  console.log(
@@ -350,10 +351,10 @@ async function handlePublishMetadata(name, groupIdOpt) {
350
351
  async function handlePublishEns(name, groupIdOpt) {
351
352
  const spinner = ora("Publishing group ID to ENS...").start();
352
353
  try {
353
- const syndicate = await resolveSyndicate(name);
354
+ const fund = await resolveFund(name);
354
355
  const callerAddress = getAccount().address.toLowerCase();
355
- if (syndicate.creator.toLowerCase() !== callerAddress) {
356
- spinner.fail("Only the syndicate creator can write ENS records");
356
+ if (fund.creator.toLowerCase() !== callerAddress) {
357
+ spinner.fail("Only the fund creator can write ENS records");
357
358
  process.exit(1);
358
359
  }
359
360
  const xmtp = await loadXmtp();
@@ -370,7 +371,7 @@ async function handlePublishEns(name, groupIdOpt) {
370
371
  );
371
372
  process.exit(1);
372
373
  }
373
- await setTextRecord(name, "xmtpGroupId", groupId, syndicate.vault);
374
+ await setTextRecord(name, "xmtpGroupId", groupId, fund.vault);
374
375
  spinner.succeed(`Published xmtpGroupId \u2192 ${groupId} on ENS`);
375
376
  console.log(chalk.dim(" Dashboard will pick up the group on next page load."));
376
377
  } catch (err) {
@@ -407,16 +408,16 @@ async function handlePublic(name, on) {
407
408
  async function handleInit(name, force, isPublic) {
408
409
  const spinner = ora("Initializing chat group...").start();
409
410
  try {
410
- const syndicate = await resolveSyndicate(name);
411
+ const fund = await resolveFund(name);
411
412
  const callerAddress = getAccount().address.toLowerCase();
412
- if (syndicate.creator.toLowerCase() !== callerAddress) {
413
- spinner.fail("Only the syndicate creator can initialize the chat group");
413
+ if (fund.creator.toLowerCase() !== callerAddress) {
414
+ spinner.fail("Only the fund creator can initialize the chat group");
414
415
  process.exit(1);
415
416
  }
416
417
  if (!force) {
417
418
  const existingId = getCachedGroupId(name) || await getTextRecord(name, "xmtpGroupId");
418
419
  if (existingId) {
419
- spinner.succeed("XMTP group already exists for this syndicate");
420
+ spinner.succeed("XMTP group already exists for this fund");
420
421
  console.log(chalk.dim(` Group ID: ${existingId}`));
421
422
  return;
422
423
  }
@@ -424,17 +425,17 @@ async function handleInit(name, force, isPublic) {
424
425
  spinner.text = "Creating XMTP group...";
425
426
  const xmtp = await loadXmtp();
426
427
  const client = await xmtp.getXmtpClient();
427
- const groupId = await xmtp.createSyndicateGroup(client, name, isPublic);
428
+ const groupId = await xmtp.createFundGroup(client, name, isPublic);
428
429
  cacheGroupId(name, groupId);
429
- spinner.text = "Saving group ID to syndicate metadata...";
430
+ spinner.text = "Saving group ID to fund metadata...";
430
431
  try {
431
- const info = await getSyndicate(syndicate.id);
432
+ const info = await getFund(fund.id);
432
433
  let metadata;
433
434
  try {
434
435
  metadata = await fetchMetadata(info.metadataURI);
435
436
  } catch {
436
437
  metadata = {
437
- schema: "sherwood/syndicate/v1",
438
+ schema: "sherwood/fund/v1",
438
439
  name,
439
440
  description: "",
440
441
  chain: "",
@@ -445,7 +446,7 @@ async function handleInit(name, force, isPublic) {
445
446
  }
446
447
  metadata.xmtpGroupId = groupId;
447
448
  const newURI = await uploadMetadata(metadata);
448
- await updateMetadata(syndicate.id, newURI);
449
+ await updateMetadata(fund.id, newURI);
449
450
  console.log(chalk.dim(`
450
451
  Group ID saved to metadata: ${newURI}`));
451
452
  } catch (metaErr) {
@@ -457,7 +458,7 @@ async function handleInit(name, force, isPublic) {
457
458
  if (hasENS) {
458
459
  try {
459
460
  spinner.text = "Writing group ID to ENS...";
460
- await setTextRecord(name, "xmtpGroupId", groupId, syndicate.vault);
461
+ await setTextRecord(name, "xmtpGroupId", groupId, fund.vault);
461
462
  console.log(chalk.dim(" ENS text record written: xmtpGroupId"));
462
463
  } catch {
463
464
  console.log(chalk.dim(" ENS text record skipped (metadata fallback active)"));
@@ -476,7 +477,7 @@ async function handleInit(name, force, isPublic) {
476
477
  }
477
478
  }
478
479
  function registerChatCommands(program) {
479
- program.command("chat <name> [action] [actionArgs...]").description("Syndicate chat \u2014 stream, send, log, members, add, remove, init, public").option("--markdown", "Send as rich markdown (for send)", false).option("--stdin", "Read send message from stdin instead of CLI arg (avoids shell quoting issues with $ chars and quotes)", false).option("--limit <n>", "Number of messages to show (for log)", "20").option("--force", "Recreate group even if one exists (for init)", false).option("--public", "Enable public chat \u2014 adds dashboard spectator (for init)", false).option("--description <text>", "New description (for rename)").option("--group-id <id>", "Explicit XMTP group ID (for publish-ens)").action(async (name, action, actionArgs, opts) => {
480
+ program.command("chat <name> [action] [actionArgs...]").description("Fund chat \u2014 stream, send, log, members, add, remove, init, public").option("--markdown", "Send as rich markdown (for send)", false).option("--stdin", "Read send message from stdin instead of CLI arg (avoids shell quoting issues with $ chars and quotes)", false).option("--limit <n>", "Number of messages to show (for log)", "20").option("--force", "Recreate group even if one exists (for init)", false).option("--public", "Enable public chat \u2014 adds dashboard spectator (for init)", false).option("--description <text>", "New description (for rename)").option("--group-id <id>", "Explicit XMTP group ID (for publish-ens)").action(async (name, action, actionArgs, opts) => {
480
481
  switch (action) {
481
482
  case "send": {
482
483
  let message = actionArgs[0];
@@ -563,4 +564,4 @@ function registerChatCommands(program) {
563
564
  export {
564
565
  registerChatCommands
565
566
  };
566
- //# sourceMappingURL=chat-JSSTSE4K.js.map
567
+ //# sourceMappingURL=chat-G5M3OK6M.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/commands/chat.ts"],"sourcesContent":["/**\n * Chat commands — sherwood chat <fund-name> [action] [args...]\n *\n * Uses XMTP for encrypted group messaging tied to funds.\n * Shells out to the @xmtp/cli binary for all XMTP operations.\n *\n * Commander can't dispatch subcommands when the parent has a positional <name> arg\n * (it always runs the parent action). So we use manual dispatch: a single .action()\n * that routes based on the [action] argument.\n *\n * Usage:\n * sherwood chat <name> — stream messages (default)\n * sherwood chat <name> send \"hello\" — send a text message\n * sherwood chat <name> send \"hello\" --markdown — send formatted markdown\n * sherwood chat <name> react <id> <emoji> — react to a message\n * sherwood chat <name> log [--limit 50] — show recent messages\n * sherwood chat <name> members — list group members\n * sherwood chat <name> add <address> — add member (creator only)\n * sherwood chat <name> init [--force] [--public] — create XMTP group + write ENS record\n * sherwood chat <name> public on/off — toggle dashboard spectator access\n * sherwood chat <name> rename <new-name> [--description \"...\"] — update group metadata (admin only)\n * sherwood chat <name> publish-ens [--group-id <id>] — write xmtpGroupId ENS text record (creator only, recovery for failed init)\n * sherwood chat <name> publish-metadata [--group-id <id>] — backfill xmtpGroupId into IPFS metadata (creator only; use when ENS write reverts)\n */\n\nimport { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { getAccount, formatContractError } from \"../lib/client.js\";\nimport { resolveFund, setTextRecord, getTextRecord } from \"../lib/ens.js\";\nimport { cacheGroupId, getCachedGroupId } from \"../lib/config.js\";\nimport { fetchMetadata, uploadMetadata } from \"../lib/ipfs.js\";\nimport * as factoryLib from \"../lib/factory.js\";\nimport { ENS } from \"../lib/addresses.js\";\nimport type { ChatEnvelope, MessageType } from \"../lib/types.js\";\nimport type { XmtpMessage } from \"../lib/xmtp.js\";\n\n// Lazy-load XMTP to avoid breaking non-chat commands when @xmtp/cli is missing\nasync function loadXmtp() {\n return import(\"../lib/xmtp.js\");\n}\n\n// ── Formatting ──\n\nfunction formatTimestamp(date: Date): string {\n return `${date.getHours().toString().padStart(2, \"0\")}:${date.getMinutes().toString().padStart(2, \"0\")}`;\n}\n\nfunction truncateAddress(addr: string): string {\n return `${addr.slice(0, 6)}...${addr.slice(-4)}`;\n}\n\nfunction colorByType(type: MessageType): (text: string) => string {\n switch (type) {\n case \"TRADE_EXECUTED\":\n return chalk.green;\n case \"RISK_ALERT\":\n return chalk.red;\n case \"TRADE_SIGNAL\":\n return chalk.yellow;\n case \"POSITION_UPDATE\":\n return chalk.cyan;\n case \"LP_REPORT\":\n return chalk.magenta;\n case \"X402_RESEARCH\":\n return chalk.cyan;\n case \"AGENT_REGISTERED\":\n case \"MEMBER_JOIN\":\n return chalk.blue;\n case \"RAGEQUIT_NOTICE\":\n return chalk.red;\n default:\n return chalk.white;\n }\n}\n\nfunction formatMessage(msg: XmtpMessage): string {\n const time = chalk.dim(`[${formatTimestamp(msg.sentAt)}]`);\n const sender = chalk.dim(truncateAddress(msg.senderInboxId));\n\n const text = msg.content;\n try {\n const envelope: ChatEnvelope = JSON.parse(text);\n const color = colorByType(envelope.type);\n const from = envelope.from ? truncateAddress(envelope.from) : sender;\n\n if (envelope.type === \"REACTION\") {\n const data = envelope.data as { reference?: string; emoji?: string } | undefined;\n return `${time} ${sender} reacted ${data?.emoji || \"?\"} to ${truncateAddress(data?.reference || \"?\")}`;\n }\n\n if (envelope.type === \"MESSAGE\") {\n if ((envelope.data as Record<string, unknown>)?.format === \"markdown\") {\n return `${time} ${chalk.dim(from)}\\n${envelope.text || \"\"}`;\n }\n return `${time} ${chalk.dim(from)}: ${envelope.text || \"\"}`;\n }\n\n if (envelope.type === \"AGENT_REGISTERED\") {\n return `${time} ${color(`[${envelope.type}]`)} Agent ${truncateAddress(envelope.agent?.address || \"?\")} registered`;\n }\n\n if (envelope.type === \"MEMBER_JOIN\") {\n return `${time} ${color(`[${envelope.type}]`)} ${truncateAddress(envelope.from || \"?\")} joined`;\n }\n\n if (envelope.type === \"X402_RESEARCH\") {\n const d = envelope.data as { provider?: string; queryType?: string; costUsdc?: string; attestationUid?: string } | undefined;\n const label = `${d?.provider || \"?\"} ${d?.queryType || \"?\"}`;\n return `${time} ${color(`[RESEARCH]`)} ${chalk.dim(from)}: ${label} ($${d?.costUsdc || \"?\"} USDC)`;\n }\n\n const summary = envelope.text || envelope.type;\n return `${time} ${color(`[${envelope.type}]`)} ${chalk.dim(from)}: ${summary}`;\n } catch {\n return `${time} ${sender}: ${text}`;\n }\n}\n\n// ── Action handlers ──\n\nasync function handleStream(name: string): Promise<void> {\n const spinner = ora(\"Connecting to chat...\").start();\n try {\n await resolveFund(name);\n const xmtp = await loadXmtp();\n const client = await xmtp.getXmtpClient();\n const group = await xmtp.getGroup(client, name);\n spinner.succeed(`Connected to ${name}.sherwoodagent.eth`);\n console.log(chalk.dim(\"Streaming messages... (Ctrl+C to exit)\\n\"));\n\n const cleanup = await xmtp.streamMessages(group, (msg) => {\n console.log(formatMessage(msg));\n });\n\n process.on(\"SIGINT\", async () => {\n console.log(chalk.dim(\"\\nDisconnecting...\"));\n cleanup();\n process.exit(0);\n });\n\n await new Promise(() => {});\n } catch (err) {\n spinner.fail(\"Failed to connect to chat\");\n console.error(chalk.red(formatContractError(err)));\n process.exit(1);\n }\n}\n\n/** Drain stdin into a single string. Used by `chat send --stdin` to bypass\n * shell expansion on dynamic messages (e.g. amounts containing `$`). */\nasync function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n }\n return Buffer.concat(chunks).toString('utf-8');\n}\n\nasync function handleSend(name: string, message: string, markdown: boolean): Promise<void> {\n const spinner = ora(\"Sending...\").start();\n try {\n const xmtp = await loadXmtp();\n const group = await xmtp.getGroup(\"\", name);\n\n if (markdown) {\n await xmtp.sendMarkdown(group, message);\n } else {\n const envelope: ChatEnvelope = {\n type: \"MESSAGE\",\n from: getAccount().address,\n text: message,\n timestamp: Math.floor(Date.now() / 1000),\n };\n await xmtp.sendEnvelope(group, envelope);\n }\n\n spinner.succeed(\"Message sent\");\n } catch (err) {\n spinner.fail(\"Failed to send message\");\n console.error(chalk.red(formatContractError(err)));\n process.exit(1);\n }\n}\n\nasync function handleReact(name: string, messageId: string, emoji: string): Promise<void> {\n const spinner = ora(\"Reacting...\").start();\n try {\n const xmtp = await loadXmtp();\n const group = await xmtp.getGroup(\"\", name);\n await xmtp.sendReaction(group, messageId, emoji);\n spinner.succeed(`Reacted ${emoji}`);\n } catch (err) {\n spinner.fail(\"Failed to send reaction\");\n console.error(chalk.red(formatContractError(err)));\n process.exit(1);\n }\n}\n\nasync function handleLog(name: string, limit: number): Promise<void> {\n const spinner = ora(\"Loading messages...\").start();\n try {\n const xmtp = await loadXmtp();\n const group = await xmtp.getGroup(\"\", name);\n const messages = await xmtp.getRecentMessages(group, limit);\n\n spinner.stop();\n console.log();\n console.log(chalk.bold(`Chat log: ${name}.sherwoodagent.eth`));\n console.log(chalk.dim(\"─\".repeat(50)));\n\n if (messages.length === 0) {\n console.log(chalk.dim(\" No messages yet\"));\n } else {\n for (const msg of messages.reverse()) {\n console.log(formatMessage(msg));\n }\n }\n console.log();\n } catch (err) {\n spinner.fail(\"Failed to load messages\");\n console.error(chalk.red(formatContractError(err)));\n process.exit(1);\n }\n}\n\nasync function handleMembers(name: string): Promise<void> {\n const spinner = ora(\"Loading members...\").start();\n try {\n const xmtp = await loadXmtp();\n const group = await xmtp.getGroup(\"\", name);\n const members = await xmtp.getMembers(group);\n\n spinner.stop();\n console.log();\n console.log(chalk.bold(`Members: ${name}.sherwoodagent.eth`));\n console.log(chalk.dim(\"─\".repeat(50)));\n\n for (const member of members) {\n const role = member.permissionLevel === \"super_admin\"\n ? chalk.yellow(\" (super admin)\")\n : member.permissionLevel === \"admin\"\n ? chalk.blue(\" (admin)\")\n : \"\";\n console.log(` ${member.inboxId}${role}`);\n }\n\n console.log(chalk.dim(`\\n Total: ${members.length} members`));\n console.log();\n } catch (err) {\n spinner.fail(\"Failed to load members\");\n console.error(chalk.red(formatContractError(err)));\n process.exit(1);\n }\n}\n\nasync function handleAdd(name: string, address: string): Promise<void> {\n const spinner = ora(\"Adding member...\").start();\n try {\n const xmtp = await loadXmtp();\n const group = await xmtp.getGroup(\"\", name);\n await xmtp.addMember(group, address);\n\n await xmtp.sendEnvelope(group, {\n type: \"MEMBER_JOIN\",\n from: address,\n fund: name,\n timestamp: Math.floor(Date.now() / 1000),\n });\n\n spinner.succeed(`Member added: ${address}`);\n } catch (err) {\n spinner.fail(\"Failed to add member\");\n console.error(chalk.red(formatContractError(err)));\n process.exit(1);\n }\n}\n\nasync function handleRemove(name: string, address: string): Promise<void> {\n const spinner = ora(\"Removing member...\").start();\n try {\n const xmtp = await loadXmtp();\n const group = await xmtp.getGroup(\"\", name);\n await xmtp.removeMember(group, address);\n spinner.succeed(`Member removed: ${address}`);\n } catch (err) {\n spinner.fail(\"Failed to remove member\");\n console.error(chalk.red(formatContractError(err)));\n process.exit(1);\n }\n}\n\n/**\n * Notify the spectator service to sync new groups.\n * Called after adding the spectator wallet to an XMTP group so the service\n * invalidates its cache, calls syncAll(), and discovers the new group.\n */\nasync function notifySpectatorSync(): Promise<void> {\n const spectatorUrl =\n process.env.SPECTATOR_URL || \"https://spectator.sherwood.sh\";\n try {\n const res = await fetch(`${spectatorUrl}/sync`, {\n method: \"POST\",\n signal: AbortSignal.timeout(8_000),\n });\n if (res.ok) {\n const data = (await res.json()) as { groups?: number };\n console.log(\n chalk.dim(\n ` Spectator synced — ${data.groups ?? \"?\"} groups discovered`,\n ),\n );\n }\n } catch {\n // Non-fatal — spectator will self-sync within 60 s via cache TTL\n console.log(\n chalk.dim(\" (Spectator sync skipped — will auto-discover within 60 s)\"),\n );\n }\n}\n\nasync function handleRename(\n name: string,\n newName?: string,\n newDescription?: string,\n): Promise<void> {\n if (newName === undefined && newDescription === undefined) {\n console.error(\n chalk.red(\n \"Usage: sherwood chat <name> rename [new-name] [--description \\\"...\\\"]\",\n ),\n );\n process.exit(1);\n }\n const spinner = ora(\"Updating group metadata...\").start();\n try {\n const xmtp = await loadXmtp();\n const group = await xmtp.getGroup(\"\", name);\n await xmtp.renameGroup(group, newName, newDescription);\n spinner.succeed(\n `Updated ${[\n newName !== undefined ? `name → \"${newName}\"` : null,\n newDescription !== undefined\n ? `description → \"${newDescription}\"`\n : null,\n ]\n .filter(Boolean)\n .join(\", \")}`,\n );\n } catch (err) {\n spinner.fail(\"Failed to update group metadata\");\n console.error(chalk.red(formatContractError(err)));\n process.exit(1);\n }\n}\n\nasync function handlePublishMetadata(\n name: string,\n groupIdOpt?: string,\n): Promise<void> {\n const spinner = ora(\"Updating fund metadata...\").start();\n try {\n const fund = await resolveFund(name);\n const callerAddress = getAccount().address.toLowerCase();\n if (fund.creator.toLowerCase() !== callerAddress) {\n spinner.fail(\"Only the fund creator can update metadata\");\n process.exit(1);\n }\n\n const xmtp = await loadXmtp();\n let groupId = groupIdOpt || getCachedGroupId(name);\n if (!groupId) {\n try {\n groupId = await xmtp.getGroup(\"\", name);\n } catch {\n // ignore\n }\n }\n if (!groupId) {\n spinner.fail(\n \"Could not determine group ID — pass --group-id <id> or run from a machine that has the group cached\",\n );\n process.exit(1);\n }\n\n spinner.text = \"Fetching current metadata...\";\n const info = await factoryLib.getFund(fund.id);\n let metadata;\n try {\n metadata = await fetchMetadata(info.metadataURI);\n } catch {\n metadata = {\n schema: \"sherwood/fund/v1\",\n name,\n description: \"\",\n chain: \"\",\n strategies: [],\n terms: {},\n links: {},\n };\n }\n metadata.xmtpGroupId = groupId;\n\n spinner.text = \"Pinning updated metadata to IPFS...\";\n const newURI = await uploadMetadata(metadata);\n\n spinner.text = \"Calling factory.updateMetadata...\";\n await factoryLib.updateMetadata(fund.id, newURI);\n\n spinner.succeed(`Metadata updated — xmtpGroupId = ${groupId}`);\n console.log(chalk.dim(` New URI: ${newURI}`));\n console.log(\n chalk.dim(\n \" Dashboard will resolve the group via metadata fallback on next page load.\",\n ),\n );\n } catch (err) {\n spinner.fail(\"Failed to update metadata\");\n console.error(chalk.red(formatContractError(err)));\n process.exit(1);\n }\n}\n\nasync function handlePublishEns(name: string, groupIdOpt?: string): Promise<void> {\n const spinner = ora(\"Publishing group ID to ENS...\").start();\n try {\n const fund = await resolveFund(name);\n const callerAddress = getAccount().address.toLowerCase();\n if (fund.creator.toLowerCase() !== callerAddress) {\n spinner.fail(\"Only the fund creator can write ENS records\");\n process.exit(1);\n }\n\n // Resolve group ID: explicit arg → local cache → existing ENS record (no-op)\n const xmtp = await loadXmtp();\n let groupId = groupIdOpt || getCachedGroupId(name);\n if (!groupId) {\n try {\n groupId = await xmtp.getGroup(\"\", name); // syncs DB + name-search fallback\n } catch {\n // ignore\n }\n }\n if (!groupId) {\n spinner.fail(\n \"Could not determine group ID — pass --group-id <id> or run from a machine that has the group cached\",\n );\n process.exit(1);\n }\n\n await setTextRecord(name, \"xmtpGroupId\", groupId, fund.vault);\n spinner.succeed(`Published xmtpGroupId → ${groupId} on ENS`);\n console.log(chalk.dim(\" Dashboard will pick up the group on next page load.\"));\n } catch (err) {\n spinner.fail(\"Failed to publish ENS record\");\n console.error(chalk.red(formatContractError(err)));\n process.exit(1);\n }\n}\n\nasync function handlePublic(name: string, on: boolean): Promise<void> {\n const xmtp = await loadXmtp();\n // Default to the canonical production spectator; `DASHBOARD_SPECTATOR_ADDRESS`\n // is an override hook for testing or future rotation. Earlier versions\n // of this command required the env var with no default — when callers\n // (cron, manual one-liners) set it to the wrong wallet, the agent's\n // own wallet got added \"as the spectator\" and the dashboard stayed\n // OFFLINE because the real spectator service was never in the group.\n // Single source of truth lives in xmtp.ts: resolveSpectatorAddress().\n const spectatorAddress = xmtp.resolveSpectatorAddress();\n const usingDefault =\n spectatorAddress === xmtp.DEFAULT_DASHBOARD_SPECTATOR_ADDRESS;\n\n const spinner = ora(`${on ? \"Enabling\" : \"Disabling\"} public chat...`).start();\n try {\n const group = await xmtp.getGroup(\"\", name);\n\n if (on) {\n await xmtp.addMember(group, spectatorAddress);\n spinner.succeed(\n `Public chat enabled — dashboard spectator added (${spectatorAddress}${usingDefault ? \", canonical\" : \", overridden via env\"})`,\n );\n await notifySpectatorSync();\n } else {\n await xmtp.removeMember(group, spectatorAddress);\n spinner.succeed(\n `Public chat disabled — dashboard spectator removed (${spectatorAddress})`,\n );\n }\n } catch (err) {\n spinner.fail(\"Failed to toggle public chat\");\n console.error(chalk.red(formatContractError(err)));\n process.exit(1);\n }\n}\n\nasync function handleInit(name: string, force: boolean, isPublic: boolean): Promise<void> {\n const spinner = ora(\"Initializing chat group...\").start();\n try {\n const fund = await resolveFund(name);\n const callerAddress = getAccount().address.toLowerCase();\n if (fund.creator.toLowerCase() !== callerAddress) {\n spinner.fail(\"Only the fund creator can initialize the chat group\");\n process.exit(1);\n }\n\n // Idempotency check\n if (!force) {\n const existingId = getCachedGroupId(name) || await getTextRecord(name, \"xmtpGroupId\");\n if (existingId) {\n spinner.succeed(\"XMTP group already exists for this fund\");\n console.log(chalk.dim(` Group ID: ${existingId}`));\n return;\n }\n }\n\n // Create the group\n spinner.text = \"Creating XMTP group...\";\n const xmtp = await loadXmtp();\n const client = await xmtp.getXmtpClient();\n const groupId = await xmtp.createFundGroup(client, name, isPublic);\n\n cacheGroupId(name, groupId);\n\n // Persist group ID. Strategy:\n // 1. ALWAYS write to IPFS metadata — canonical source on every chain.\n // The dashboard's resolver chain is `ENS text → metadata → null`, so\n // metadata being populated guarantees the dashboard works regardless\n // of ENS state. Necessary because the V1.5 vault has no `executeBatch`\n // (V-C3 removal), so the ENS `setText` call below currently reverts on\n // Base mainnet — without metadata, the dashboard would show OFFLINE.\n // 2. ADDITIONALLY try the ENS text record (best-effort). Fast resolution\n // path for chains where the vault has a writable executeBatch path\n // (HyperEVM today, or a future vault setEnsText helper). On failure,\n // we log a debug line and keep going — metadata fallback covers it.\n spinner.text = \"Saving group ID to fund metadata...\";\n try {\n const info = await factoryLib.getFund(fund.id);\n let metadata;\n try {\n metadata = await fetchMetadata(info.metadataURI);\n } catch {\n metadata = {\n schema: \"sherwood/fund/v1\",\n name,\n description: \"\",\n chain: \"\",\n strategies: [],\n terms: {},\n links: {},\n };\n }\n metadata.xmtpGroupId = groupId;\n const newURI = await uploadMetadata(metadata);\n await factoryLib.updateMetadata(fund.id, newURI);\n console.log(chalk.dim(`\\n Group ID saved to metadata: ${newURI}`));\n } catch (metaErr) {\n console.warn(chalk.yellow(\"\\n ⚠ Could not persist group ID to IPFS metadata\"));\n console.warn(chalk.dim(` ${metaErr instanceof Error ? metaErr.message : String(metaErr)}`));\n console.warn(chalk.dim(\" Dashboard may show OFFLINE until backfilled with `chat <name> publish-metadata`.\"));\n }\n\n // Best-effort ENS text record write. Currently reverts on Base mainnet\n // because the V1.5 vault has no owner-direct executeBatch path; metadata\n // above is the operative resolution source. Will succeed once a vault\n // setEnsText helper lands or on chains where the existing path works.\n const hasENS = ENS().L2_REGISTRY !== \"0x0000000000000000000000000000000000000000\";\n if (hasENS) {\n try {\n spinner.text = \"Writing group ID to ENS...\";\n await setTextRecord(name, \"xmtpGroupId\", groupId, fund.vault);\n console.log(chalk.dim(\" ENS text record written: xmtpGroupId\"));\n } catch {\n console.log(chalk.dim(\" ENS text record skipped (metadata fallback active)\"));\n }\n }\n\n spinner.succeed(`Chat group created for ${name}.sherwoodagent.eth`);\n console.log(chalk.dim(` Group ID: ${groupId}`));\n console.log(chalk.dim(` Stream: sherwood chat ${name}`));\n\n // Notify spectator to sync and discover the new public group\n if (isPublic) {\n await notifySpectatorSync();\n }\n } catch (err) {\n spinner.fail(\"Failed to initialize chat group\");\n console.error(chalk.red(formatContractError(err)));\n process.exit(1);\n }\n}\n\n// ── Command Registration ──\n\nexport function registerChatCommands(program: Command): void {\n program\n .command(\"chat <name> [action] [actionArgs...]\")\n .description(\"Fund chat — stream, send, log, members, add, remove, init, public\")\n .option(\"--markdown\", \"Send as rich markdown (for send)\", false)\n .option(\"--stdin\", \"Read send message from stdin instead of CLI arg (avoids shell quoting issues with $ chars and quotes)\", false)\n .option(\"--limit <n>\", \"Number of messages to show (for log)\", \"20\")\n .option(\"--force\", \"Recreate group even if one exists (for init)\", false)\n .option(\"--public\", \"Enable public chat — adds dashboard spectator (for init)\", false)\n .option(\"--description <text>\", \"New description (for rename)\")\n .option(\"--group-id <id>\", \"Explicit XMTP group ID (for publish-ens)\")\n .action(async (name: string, action: string | undefined, actionArgs: string[], opts: { markdown: boolean; stdin: boolean; limit: string; force: boolean; public: boolean; description?: string; groupId?: string }) => {\n switch (action) {\n case \"send\": {\n let message = actionArgs[0];\n if (opts.stdin) {\n // If stdin is a terminal, the user forgot to pipe — readStdin\n // would block forever waiting for EOF (Ctrl+D). Warn explicitly.\n if (process.stdin.isTTY) {\n console.error(chalk.yellow(\"--stdin specified but stdin is a terminal. Either pipe the message in or omit --stdin and pass it as an argument. Press Ctrl+D to send what you've typed, Ctrl+C to abort.\"));\n }\n // Read entire stdin into the message — sidesteps bash $-expansion\n // when callers (cron jobs, scripts) construct dynamic message text.\n message = await readStdin();\n if (!message.trim()) {\n console.error(chalk.red(\"--stdin given but stdin was empty\"));\n process.exit(1);\n }\n }\n if (!message) {\n console.error(chalk.red(\"Usage: sherwood chat <name> send <message> [--markdown]\\n echo \\\"$msg\\\" | sherwood chat <name> send --stdin\"));\n process.exit(1);\n }\n await handleSend(name, message, opts.markdown);\n break;\n }\n\n case \"react\": {\n const [messageId, emoji] = actionArgs;\n if (!messageId || !emoji) {\n console.error(chalk.red(\"Usage: sherwood chat <name> react <messageId> <emoji>\"));\n process.exit(1);\n }\n await handleReact(name, messageId, emoji);\n break;\n }\n\n case \"log\":\n await handleLog(name, parseInt(opts.limit, 10));\n break;\n\n case \"members\":\n await handleMembers(name);\n break;\n\n case \"add\": {\n const address = actionArgs[0];\n if (!address) {\n console.error(chalk.red(\"Usage: sherwood chat <name> add <address>\"));\n process.exit(1);\n }\n await handleAdd(name, address);\n break;\n }\n\n case \"remove\": {\n const removeAddr = actionArgs[0];\n if (!removeAddr) {\n console.error(chalk.red(\"Usage: sherwood chat <name> remove <address>\"));\n process.exit(1);\n }\n await handleRemove(name, removeAddr);\n break;\n }\n\n case \"init\":\n await handleInit(name, opts.force, opts.public);\n break;\n\n case \"rename\": {\n const newName = actionArgs[0]; // optional positional\n await handleRename(name, newName, opts.description);\n break;\n }\n\n case \"publish-ens\":\n await handlePublishEns(name, opts.groupId);\n break;\n\n case \"publish-metadata\":\n await handlePublishMetadata(name, opts.groupId);\n break;\n\n case \"public\": {\n const flag = actionArgs[0];\n if (flag !== \"on\" && flag !== \"off\") {\n console.error(chalk.red(\"Usage: sherwood chat <name> public on/off\"));\n process.exit(1);\n }\n await handlePublic(name, flag === \"on\");\n break;\n }\n\n case undefined:\n default:\n await handleStream(name);\n break;\n }\n });\n}\n"],"mappings":"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","names":[]}
@@ -1,25 +1,25 @@
1
1
  import {
2
2
  SHERWOOD
3
- } from "./chunk-GWMTAW6A.js";
3
+ } from "./chunk-RAITRCM7.js";
4
4
  import {
5
5
  getAccount,
6
6
  getPublicClient,
7
7
  waitForReceipt,
8
8
  writeContractWithRetry
9
- } from "./chunk-YJSCIQUZ.js";
9
+ } from "./chunk-WECQ6NVS.js";
10
10
  import {
11
11
  getChain
12
- } from "./chunk-2LRC7I33.js";
12
+ } from "./chunk-HYUUR6SC.js";
13
13
  import {
14
14
  SYNDICATE_FACTORY_ABI
15
- } from "./chunk-YZHZSBES.js";
15
+ } from "./chunk-BQMOE4FJ.js";
16
16
 
17
17
  // src/lib/factory.ts
18
18
  import { decodeEventLog } from "viem";
19
19
  function getFactoryAddress() {
20
20
  return SHERWOOD().FACTORY;
21
21
  }
22
- async function createSyndicate(params) {
22
+ async function createFund(params) {
23
23
  const client = getPublicClient();
24
24
  const hash = await writeContractWithRetry({
25
25
  account: getAccount(),
@@ -40,6 +40,11 @@ async function createSyndicate(params) {
40
40
  ]
41
41
  });
42
42
  const receipt = await waitForReceipt(hash);
43
+ if (receipt.status !== "success") {
44
+ throw new Error(
45
+ `createFund reverted on-chain (tx ${hash}). Most common cause: no prepared owner bond \u2014 run \`sherwood guardian prepare-owner-stake <amount>\` (min = swood.minOwnerStake) first.`
46
+ );
47
+ }
43
48
  for (const log of receipt.logs) {
44
49
  try {
45
50
  const event = decodeEventLog({
@@ -51,18 +56,18 @@ async function createSyndicate(params) {
51
56
  const args = event.args;
52
57
  return {
53
58
  hash,
54
- syndicateId: args.id,
59
+ fundId: args.id,
55
60
  vault: args.vault
56
61
  };
57
62
  }
58
63
  } catch {
59
64
  }
60
65
  }
61
- const count = await getSyndicateCount();
62
- const info = await getSyndicate(count);
66
+ const count = await getFundCount();
67
+ const info = await getFund(count);
63
68
  return {
64
69
  hash,
65
- syndicateId: count,
70
+ fundId: count,
66
71
  vault: info.vault
67
72
  };
68
73
  }
@@ -76,7 +81,7 @@ async function subdomainExists(subdomain) {
76
81
  });
77
82
  return id > 0n ? id : null;
78
83
  }
79
- async function getSyndicate(id) {
84
+ async function getFund(id) {
80
85
  const client = getPublicClient();
81
86
  const result = await client.readContract({
82
87
  address: getFactoryAddress(),
@@ -94,7 +99,7 @@ async function getSyndicate(id) {
94
99
  subdomain: result[6]
95
100
  };
96
101
  }
97
- async function getSyndicateCount() {
102
+ async function getFundCount() {
98
103
  const client = getPublicClient();
99
104
  return client.readContract({
100
105
  address: getFactoryAddress(),
@@ -102,7 +107,7 @@ async function getSyndicateCount() {
102
107
  functionName: "syndicateCount"
103
108
  });
104
109
  }
105
- async function getActiveSyndicates() {
110
+ async function getActiveFunds() {
106
111
  const client = getPublicClient();
107
112
  const result = await client.readContract({
108
113
  address: getFactoryAddress(),
@@ -119,24 +124,24 @@ async function getActiveSyndicates() {
119
124
  subdomain: s.subdomain
120
125
  }));
121
126
  }
122
- async function updateMetadata(syndicateId, metadataURI) {
127
+ async function updateMetadata(fundId, metadataURI) {
123
128
  const hash = await writeContractWithRetry({
124
129
  account: getAccount(),
125
130
  chain: getChain(),
126
131
  address: getFactoryAddress(),
127
132
  abi: SYNDICATE_FACTORY_ABI,
128
133
  functionName: "updateMetadata",
129
- args: [syndicateId, metadataURI]
134
+ args: [fundId, metadataURI]
130
135
  });
131
136
  await waitForReceipt(hash);
132
137
  return hash;
133
138
  }
134
139
 
135
140
  export {
136
- createSyndicate,
141
+ createFund,
137
142
  subdomainExists,
138
- getSyndicate,
139
- getActiveSyndicates,
143
+ getFund,
144
+ getActiveFunds,
140
145
  updateMetadata
141
146
  };
142
- //# sourceMappingURL=chunk-IL43IMOC.js.map
147
+ //# sourceMappingURL=chunk-3NMJ4LUL.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/factory.ts"],"sourcesContent":["/**\n * SyndicateFactory contract wrapper.\n *\n * Creates new fund vaults via the factory. Each fund = one vault proxy\n * with shared executor lib and vault implementation.\n */\n\nimport type { Address, Hex } from \"viem\";\nimport { parseUnits, formatUnits, decodeEventLog } from \"viem\";\nimport { getChain, getNetwork } from \"./network.js\";\nimport { getPublicClient, getAccount, writeContractWithRetry, waitForReceipt } from \"./client.js\";\nimport { SYNDICATE_FACTORY_ABI } from \"./abis.js\";\nimport { TOKENS, SHERWOOD } from \"./addresses.js\";\n\nexport interface FundInfo {\n id: bigint;\n vault: Address;\n creator: Address;\n metadataURI: string;\n createdAt: bigint;\n active: boolean;\n subdomain: string;\n}\n\nexport interface CreateFundParams {\n creatorAgentId: bigint;\n metadataURI: string;\n asset: Address;\n name: string;\n symbol: string;\n openDeposits: boolean;\n subdomain: string;\n}\n\nfunction getFactoryAddress(): Address {\n return SHERWOOD().FACTORY;\n}\n\nexport interface CreateFundResult {\n hash: Hex;\n fundId: bigint;\n vault: Address;\n}\n\n/**\n * Create a new fund via the factory.\n * Deploys a UUPS vault proxy, initializes it, and registers in the factory.\n * Waits for receipt and extracts vault address from SyndicateCreated event.\n */\nexport async function createFund(params: CreateFundParams): Promise<CreateFundResult> {\n const client = getPublicClient();\n\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: getFactoryAddress(),\n abi: SYNDICATE_FACTORY_ABI,\n functionName: \"createSyndicate\",\n args: [\n params.creatorAgentId,\n {\n metadataURI: params.metadataURI,\n asset: params.asset,\n name: params.name,\n symbol: params.symbol,\n openDeposits: params.openDeposits,\n subdomain: params.subdomain,\n },\n ],\n });\n\n // Wait for receipt and extract vault from SyndicateCreated event\n const receipt = await waitForReceipt(hash);\n if (receipt.status !== \"success\") {\n // Without this, a reverted create fell through to the factory-state\n // fallback and reported \"created\" with a zero vault (vnet e2e finding).\n throw new Error(\n `createFund reverted on-chain (tx ${hash}). Most common cause: no prepared owner bond — ` +\n `run \\`sherwood guardian prepare-owner-stake <amount>\\` (min = swood.minOwnerStake) first.`,\n );\n }\n\n // Parse SyndicateCreated event from receipt logs\n for (const log of receipt.logs) {\n try {\n const event = decodeEventLog({\n abi: SYNDICATE_FACTORY_ABI,\n data: log.data,\n topics: log.topics,\n });\n if (event.eventName === \"SyndicateCreated\") {\n const args = event.args as { id: bigint; vault: Address; creator: Address };\n return {\n hash,\n fundId: args.id,\n vault: args.vault,\n };\n }\n } catch {\n // Not our event, skip\n }\n }\n\n // Fallback: read from factory state (may lag on RPC replicas)\n const count = await getFundCount();\n const info = await getFund(count);\n\n return {\n hash,\n fundId: count,\n vault: info.vault,\n };\n}\n\n/**\n * Check if a subdomain is already registered. Returns the fund ID if found, null otherwise.\n */\nexport async function subdomainExists(subdomain: string): Promise<bigint | null> {\n const client = getPublicClient();\n const id = (await client.readContract({\n address: getFactoryAddress(),\n abi: SYNDICATE_FACTORY_ABI,\n functionName: \"subdomainToSyndicate\",\n args: [subdomain],\n })) as bigint;\n\n return id > 0n ? id : null;\n}\n\n/**\n * Get fund info by ID.\n */\nexport async function getFund(id: bigint): Promise<FundInfo> {\n const client = getPublicClient();\n const result = (await client.readContract({\n address: getFactoryAddress(),\n abi: SYNDICATE_FACTORY_ABI,\n functionName: \"syndicates\",\n args: [id],\n })) as [bigint, Address, Address, string, bigint, boolean, string];\n\n return {\n id: result[0],\n vault: result[1],\n creator: result[2],\n metadataURI: result[3],\n createdAt: result[4],\n active: result[5],\n subdomain: result[6],\n };\n}\n\n/**\n * Get the total number of funds created.\n */\nexport async function getFundCount(): Promise<bigint> {\n const client = getPublicClient();\n return client.readContract({\n address: getFactoryAddress(),\n abi: SYNDICATE_FACTORY_ABI,\n functionName: \"syndicateCount\",\n }) as Promise<bigint>;\n}\n\n/**\n * Get all active funds from the factory.\n */\nexport async function getActiveFunds(): Promise<FundInfo[]> {\n const client = getPublicClient();\n const result = (await client.readContract({\n address: getFactoryAddress(),\n abi: SYNDICATE_FACTORY_ABI,\n functionName: \"getAllActiveSyndicates\",\n })) as readonly {\n id: bigint;\n vault: Address;\n creator: Address;\n metadataURI: string;\n createdAt: bigint;\n active: boolean;\n subdomain: string;\n }[];\n\n return result.map((s) => ({\n id: s.id,\n vault: s.vault,\n creator: s.creator,\n metadataURI: s.metadataURI,\n createdAt: s.createdAt,\n active: s.active,\n subdomain: s.subdomain,\n }));\n}\n\n/**\n * Update fund metadata (creator only).\n */\nexport async function updateMetadata(fundId: bigint, metadataURI: string): Promise<Hex> {\n const hash = await writeContractWithRetry({\n account: getAccount(),\n chain: getChain(),\n address: getFactoryAddress(),\n abi: SYNDICATE_FACTORY_ABI,\n functionName: \"updateMetadata\",\n args: [fundId, metadataURI],\n });\n await waitForReceipt(hash);\n return hash;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAQA,SAAkC,sBAAsB;AA0BxD,SAAS,oBAA6B;AACpC,SAAO,SAAS,EAAE;AACpB;AAaA,eAAsB,WAAW,QAAqD;AACpF,QAAM,SAAS,gBAAgB;AAE/B,QAAM,OAAO,MAAM,uBAAuB;AAAA,IACxC,SAAS,WAAW;AAAA,IACpB,OAAO,SAAS;AAAA,IAChB,SAAS,kBAAkB;AAAA,IAC3B,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM;AAAA,MACJ,OAAO;AAAA,MACP;AAAA,QACE,aAAa,OAAO;AAAA,QACpB,OAAO,OAAO;AAAA,QACd,MAAM,OAAO;AAAA,QACb,QAAQ,OAAO;AAAA,QACf,cAAc,OAAO;AAAA,QACrB,WAAW,OAAO;AAAA,MACpB;AAAA,IACF;AAAA,EACF,CAAC;AAGD,QAAM,UAAU,MAAM,eAAe,IAAI;AACzC,MAAI,QAAQ,WAAW,WAAW;AAGhC,UAAM,IAAI;AAAA,MACR,oCAAoC,IAAI;AAAA,IAE1C;AAAA,EACF;AAGA,aAAW,OAAO,QAAQ,MAAM;AAC9B,QAAI;AACF,YAAM,QAAQ,eAAe;AAAA,QAC3B,KAAK;AAAA,QACL,MAAM,IAAI;AAAA,QACV,QAAQ,IAAI;AAAA,MACd,CAAC;AACD,UAAI,MAAM,cAAc,oBAAoB;AAC1C,cAAM,OAAO,MAAM;AACnB,eAAO;AAAA,UACL;AAAA,UACA,QAAQ,KAAK;AAAA,UACb,OAAO,KAAK;AAAA,QACd;AAAA,MACF;AAAA,IACF,QAAQ;AAAA,IAER;AAAA,EACF;AAGA,QAAM,QAAQ,MAAM,aAAa;AACjC,QAAM,OAAO,MAAM,QAAQ,KAAK;AAEhC,SAAO;AAAA,IACL;AAAA,IACA,QAAQ;AAAA,IACR,OAAO,KAAK;AAAA,EACd;AACF;AAKA,eAAsB,gBAAgB,WAA2C;AAC/E,QAAM,SAAS,gBAAgB;AAC/B,QAAM,KAAM,MAAM,OAAO,aAAa;AAAA,IACpC,SAAS,kBAAkB;AAAA,IAC3B,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM,CAAC,SAAS;AAAA,EAClB,CAAC;AAED,SAAO,KAAK,KAAK,KAAK;AACxB;AAKA,eAAsB,QAAQ,IAA+B;AAC3D,QAAM,SAAS,gBAAgB;AAC/B,QAAM,SAAU,MAAM,OAAO,aAAa;AAAA,IACxC,SAAS,kBAAkB;AAAA,IAC3B,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM,CAAC,EAAE;AAAA,EACX,CAAC;AAED,SAAO;AAAA,IACL,IAAI,OAAO,CAAC;AAAA,IACZ,OAAO,OAAO,CAAC;AAAA,IACf,SAAS,OAAO,CAAC;AAAA,IACjB,aAAa,OAAO,CAAC;AAAA,IACrB,WAAW,OAAO,CAAC;AAAA,IACnB,QAAQ,OAAO,CAAC;AAAA,IAChB,WAAW,OAAO,CAAC;AAAA,EACrB;AACF;AAKA,eAAsB,eAAgC;AACpD,QAAM,SAAS,gBAAgB;AAC/B,SAAO,OAAO,aAAa;AAAA,IACzB,SAAS,kBAAkB;AAAA,IAC3B,KAAK;AAAA,IACL,cAAc;AAAA,EAChB,CAAC;AACH;AAKA,eAAsB,iBAAsC;AAC1D,QAAM,SAAS,gBAAgB;AAC/B,QAAM,SAAU,MAAM,OAAO,aAAa;AAAA,IACxC,SAAS,kBAAkB;AAAA,IAC3B,KAAK;AAAA,IACL,cAAc;AAAA,EAChB,CAAC;AAUD,SAAO,OAAO,IAAI,CAAC,OAAO;AAAA,IACxB,IAAI,EAAE;AAAA,IACN,OAAO,EAAE;AAAA,IACT,SAAS,EAAE;AAAA,IACX,aAAa,EAAE;AAAA,IACf,WAAW,EAAE;AAAA,IACb,QAAQ,EAAE;AAAA,IACV,WAAW,EAAE;AAAA,EACf,EAAE;AACJ;AAKA,eAAsB,eAAe,QAAgB,aAAmC;AACtF,QAAM,OAAO,MAAM,uBAAuB;AAAA,IACxC,SAAS,WAAW;AAAA,IACpB,OAAO,SAAS;AAAA,IAChB,SAAS,kBAAkB;AAAA,IAC3B,KAAK;AAAA,IACL,cAAc;AAAA,IACd,MAAM,CAAC,QAAQ,WAAW;AAAA,EAC5B,CAAC;AACD,QAAM,eAAe,IAAI;AACzB,SAAO;AACT;","names":[]}
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  getAccount
3
- } from "./chunk-YJSCIQUZ.js";
3
+ } from "./chunk-WECQ6NVS.js";
4
4
  import {
5
5
  getVeniceApiKey,
6
6
  setVeniceApiKey
7
- } from "./chunk-2W4KGGPU.js";
7
+ } from "./chunk-GSC7PVEO.js";
8
8
 
9
9
  // src/lib/venice.ts
10
10
  import chalk from "chalk";
@@ -71,7 +71,7 @@ async function provisionApiKey() {
71
71
  signature,
72
72
  token,
73
73
  apiKeyType: "INFERENCE",
74
- description: "Sherwood syndicate agent"
74
+ description: "Sherwood fund agent"
75
75
  })
76
76
  });
77
77
  if (!keyRes.ok) {
@@ -186,4 +186,4 @@ export {
186
186
  chatCompletion,
187
187
  listModels
188
188
  };
189
- //# sourceMappingURL=chunk-UBAX22KA.js.map
189
+ //# sourceMappingURL=chunk-52U76TRE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/venice.ts"],"sourcesContent":["/**\n * Venice AI API integration — web3 key generation, validation, and inference.\n *\n * Key provisioning flow:\n * 1. GET /api_keys/generate_web3_key → validation token\n * 2. Sign token with agent wallet (EIP-191)\n * 3. POST /api_keys/generate_web3_key → API key\n *\n * Inference:\n * POST /chat/completions with Bearer auth → chat completion response\n *\n * The API key is stored in ~/.sherwood/config.json.\n * Venice requires the signing wallet to hold staked VVV (sVVV).\n */\n\nimport chalk from \"chalk\";\nimport { getAccount } from \"./client.js\";\nimport { setVeniceApiKey, getVeniceApiKey } from \"./config.js\";\n\nconst VENICE_API_BASE = \"https://api.venice.ai/api/v1\";\n\n// ── Retry policy for chatCompletion ──\n\nconst RETRY_MAX_ATTEMPTS = 3;\nconst RETRY_BASE_DELAYS_MS = [1000, 2000, 4000]; // 1s, 2s, 4s\nconst RETRY_JITTER_PCT = 0.2; // ±20%\nconst RETRYABLE_STATUS = new Set([429, 500, 502, 503, 504]);\n\n/**\n * Transient HTTP error raised by `chatCompletion` before retry logic kicks in.\n * Carries the response status so `shouldRetry` can inspect it.\n */\nclass VeniceHttpError extends Error {\n readonly status: number;\n readonly body: string;\n constructor(status: number, body: string) {\n super(`Venice inference failed: ${status} ${body}`);\n this.name = \"VeniceHttpError\";\n this.status = status;\n this.body = body;\n }\n}\n\n/**\n * Decide whether a failed `chatCompletion` HTTP attempt is worth retrying.\n * Retries: 429, 5xx, and network-class errors (fetch TypeError / ECONNRESET).\n * Never retries: AbortError (user/timeout), 4xx client errors, parse errors.\n */\nfunction shouldRetry(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n // User/caller abort or outer timeout — never retry\n if (err.name === \"AbortError\") return false;\n if (err instanceof VeniceHttpError) {\n return RETRYABLE_STATUS.has(err.status);\n }\n // Network-class: Node's fetch surfaces these as TypeError with a cause,\n // or occasionally the cause Error carries codes like ECONNRESET/ETIMEDOUT.\n if (err instanceof TypeError) return true;\n const cause = (err as { cause?: unknown }).cause;\n if (cause && typeof cause === \"object\") {\n const code = (cause as { code?: unknown }).code;\n if (typeof code === \"string\" &&\n [\"ECONNRESET\", \"ECONNREFUSED\", \"ETIMEDOUT\", \"EAI_AGAIN\", \"ENOTFOUND\", \"EPIPE\", \"UND_ERR_SOCKET\"].includes(code)) {\n return true;\n }\n }\n return false;\n}\n\nfunction jitter(delayMs: number): number {\n const spread = delayMs * RETRY_JITTER_PCT;\n return Math.max(0, Math.round(delayMs + (Math.random() * 2 - 1) * spread));\n}\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Provision a Venice API key via web3 wallet signature.\n * The wallet must hold sVVV for this to succeed.\n */\nexport async function provisionApiKey(): Promise<string> {\n const account = getAccount();\n\n // 1. Get validation token (unauthenticated per Venice swagger spec)\n const tokenRes = await fetch(`${VENICE_API_BASE}/api_keys/generate_web3_key`, {\n signal: AbortSignal.timeout(15_000),\n });\n if (!tokenRes.ok) {\n throw new Error(`Failed to get validation token: ${tokenRes.status} ${tokenRes.statusText}`);\n }\n const tokenData = await tokenRes.json();\n const token = tokenData?.data?.token;\n if (!token) {\n throw new Error(\"Venice API returned no validation token\");\n }\n\n // 2. Sign token with wallet (EIP-191)\n const signature = await account.signMessage({ message: token });\n\n // 3. Generate API key\n const keyRes = await fetch(`${VENICE_API_BASE}/api_keys/generate_web3_key`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n signal: AbortSignal.timeout(15_000),\n body: JSON.stringify({\n address: account.address,\n signature,\n token,\n apiKeyType: \"INFERENCE\",\n description: \"Sherwood fund agent\",\n }),\n });\n\n if (!keyRes.ok) {\n const body = await keyRes.text();\n throw new Error(`Failed to generate API key: ${keyRes.status} ${body}`);\n }\n\n const keyData = await keyRes.json();\n const apiKey = keyData?.data?.apiKey;\n if (!apiKey) {\n throw new Error(\"Venice API returned no API key\");\n }\n\n // Store in config\n setVeniceApiKey(apiKey);\n\n return apiKey;\n}\n\n/**\n * Check if the stored Venice API key is still valid.\n */\nexport async function checkApiKeyValid(): Promise<boolean> {\n const apiKey = getVeniceApiKey();\n if (!apiKey) return false;\n\n try {\n const res = await fetch(`${VENICE_API_BASE}/models`, {\n headers: { Authorization: `Bearer ${apiKey}` },\n signal: AbortSignal.timeout(15_000),\n });\n return res.ok;\n } catch {\n return false;\n }\n}\n\n// ── Inference ──\n\nexport interface ChatCompletionMessage {\n role: \"system\" | \"user\" | \"assistant\";\n content: string;\n}\n\nexport interface ChatCompletionOptions {\n model: string;\n messages: ChatCompletionMessage[];\n temperature?: number;\n maxTokens?: number;\n enableWebSearch?: boolean;\n disableThinking?: boolean;\n}\n\nexport interface ChatCompletionResult {\n content: string;\n model: string;\n usage: {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n };\n}\n\n/**\n * Call Venice chat completions API for private inference.\n * Requires a provisioned API key (run `sherwood venice provision` first).\n */\nexport async function chatCompletion(opts: ChatCompletionOptions): Promise<ChatCompletionResult> {\n const apiKey = getVeniceApiKey();\n if (!apiKey) {\n throw new Error(\"No Venice API key configured. Run 'sherwood venice provision' first.\");\n }\n\n const body: Record<string, unknown> = {\n model: opts.model,\n messages: opts.messages,\n };\n if (opts.temperature !== undefined) body.temperature = opts.temperature;\n if (opts.maxTokens !== undefined) body.max_tokens = opts.maxTokens;\n\n const veniceParams: Record<string, unknown> = {};\n if (opts.enableWebSearch) veniceParams.enable_web_search = \"on\";\n if (opts.disableThinking) veniceParams.disable_thinking = true;\n if (Object.keys(veniceParams).length > 0) body.venice_parameters = veniceParams;\n\n // Retry loop: exponential backoff with jitter on 429/5xx and network errors.\n // Caller-provided timeouts (e.g. Promise.race in the judge) still win — if\n // the outer timeout fires before retries exhaust, the promise rejects normally.\n let lastErr: unknown;\n let res: Response | undefined;\n for (let attempt = 1; attempt <= RETRY_MAX_ATTEMPTS; attempt++) {\n try {\n res = await fetch(`${VENICE_API_BASE}/chat/completions`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n signal: AbortSignal.timeout(120_000), // inference can be slow\n body: JSON.stringify(body),\n });\n if (!res.ok) {\n const errBody = await res.text();\n throw new VeniceHttpError(res.status, errBody);\n }\n lastErr = undefined;\n break; // success\n } catch (err) {\n lastErr = err;\n if (attempt >= RETRY_MAX_ATTEMPTS || !shouldRetry(err)) {\n throw err;\n }\n const baseDelay = RETRY_BASE_DELAYS_MS[attempt - 1] ?? RETRY_BASE_DELAYS_MS[RETRY_BASE_DELAYS_MS.length - 1];\n const delayMs = jitter(baseDelay);\n const reason = err instanceof VeniceHttpError ? `HTTP ${err.status}` : (err as Error).message || \"network\";\n console.error(chalk.dim(` [venice] retry ${attempt}/${RETRY_MAX_ATTEMPTS} after ${delayMs}ms — ${reason}`));\n await sleep(delayMs);\n }\n }\n\n if (!res || lastErr) {\n // Defensive — the loop either breaks on success or throws on final failure.\n throw lastErr ?? new Error(\"Venice inference failed: no response\");\n }\n\n const data = await res.json();\n const choice = data.choices?.[0];\n if (!choice) {\n throw new Error(\"Venice returned no choices\");\n }\n\n return {\n content: choice.message?.content ?? \"\",\n model: data.model ?? opts.model,\n usage: {\n promptTokens: data.usage?.prompt_tokens ?? 0,\n completionTokens: data.usage?.completion_tokens ?? 0,\n totalTokens: data.usage?.total_tokens ?? 0,\n },\n };\n}\n\n/**\n * List available Venice models.\n * Requires a provisioned API key.\n */\nexport async function listModels(): Promise<string[]> {\n const apiKey = getVeniceApiKey();\n if (!apiKey) {\n throw new Error(\"No Venice API key configured. Run 'sherwood venice provision' first.\");\n }\n\n const res = await fetch(`${VENICE_API_BASE}/models`, {\n headers: { Authorization: `Bearer ${apiKey}` },\n signal: AbortSignal.timeout(15_000),\n });\n\n if (!res.ok) {\n throw new Error(`Failed to list Venice models: ${res.status} ${res.statusText}`);\n }\n\n const data = await res.json();\n return (data.data ?? []).map((m: { id: string }) => m.id);\n}\n"],"mappings":"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","names":[]}
@@ -11,7 +11,7 @@ function loadSessionState() {
11
11
  }
12
12
  } catch {
13
13
  }
14
- return { version: 1, syndicates: {} };
14
+ return { version: 1, funds: {} };
15
15
  }
16
16
  function saveSessionState(state) {
17
17
  fs.mkdirSync(SESSION_DIR, { recursive: true });
@@ -19,11 +19,11 @@ function saveSessionState(state) {
19
19
  }
20
20
  function getSession(subdomain) {
21
21
  const state = loadSessionState();
22
- return state.syndicates[subdomain];
22
+ return state.funds[subdomain];
23
23
  }
24
24
  function updateSession(subdomain, update) {
25
25
  const state = loadSessionState();
26
- const existing = state.syndicates[subdomain] || {
26
+ const existing = state.funds[subdomain] || {
27
27
  subdomain,
28
28
  vault: "",
29
29
  governor: "",
@@ -34,23 +34,23 @@ function updateSession(subdomain, update) {
34
34
  totalMessagesProcessed: 0,
35
35
  totalEventsProcessed: 0
36
36
  };
37
- state.syndicates[subdomain] = { ...existing, ...update };
37
+ state.funds[subdomain] = { ...existing, ...update };
38
38
  saveSessionState(state);
39
39
  }
40
40
  function resetSession(subdomain, sinceBlock) {
41
41
  const state = loadSessionState();
42
42
  if (sinceBlock !== void 0) {
43
- if (state.syndicates[subdomain]) {
44
- state.syndicates[subdomain].lastBlockNumber = sinceBlock;
43
+ if (state.funds[subdomain]) {
44
+ state.funds[subdomain].lastBlockNumber = sinceBlock;
45
45
  saveSessionState(state);
46
46
  }
47
47
  } else {
48
- delete state.syndicates[subdomain];
48
+ delete state.funds[subdomain];
49
49
  saveSessionState(state);
50
50
  }
51
51
  }
52
52
  function getAllSessions() {
53
- return loadSessionState().syndicates;
53
+ return loadSessionState().funds;
54
54
  }
55
55
 
56
56
  export {
@@ -61,4 +61,4 @@ export {
61
61
  resetSession,
62
62
  getAllSessions
63
63
  };
64
- //# sourceMappingURL=chunk-W2ZUPR3W.js.map
64
+ //# sourceMappingURL=chunk-5DWB5Y7G.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/session.ts"],"sourcesContent":["/**\n * Session state management — ~/.sherwood/session.json\n *\n * Tracks per-fund cursors for XMTP messages and on-chain events.\n * Enables agents to catch up on what they missed between sessions.\n */\n\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nconst SESSION_DIR = path.join(os.homedir(), \".sherwood\");\nconst SESSION_PATH = path.join(SESSION_DIR, \"session.json\");\n\nexport interface FundSession {\n subdomain: string;\n vault: string; // vault address for event filtering\n governor: string; // governor address for proposal events\n // XMTP cursors\n lastMessageId: string;\n lastMessageTimestamp: number; // unix seconds\n // On-chain cursors\n lastBlockNumber: number;\n // Session metadata\n lastCheckAt: number; // unix seconds\n totalMessagesProcessed: number;\n totalEventsProcessed: number;\n}\n\ninterface SessionState {\n version: 1;\n funds: Record<string, FundSession>;\n}\n\nexport function loadSessionState(): SessionState {\n try {\n if (fs.existsSync(SESSION_PATH)) {\n return JSON.parse(fs.readFileSync(SESSION_PATH, \"utf-8\"));\n }\n } catch {\n // Corrupted file — start fresh\n }\n return { version: 1, funds: {} };\n}\n\nexport function saveSessionState(state: SessionState): void {\n fs.mkdirSync(SESSION_DIR, { recursive: true });\n fs.writeFileSync(SESSION_PATH, JSON.stringify(state, null, 2));\n}\n\nexport function getSession(subdomain: string): FundSession | undefined {\n const state = loadSessionState();\n return state.funds[subdomain];\n}\n\nexport function updateSession(\n subdomain: string,\n update: Partial<FundSession>,\n): void {\n const state = loadSessionState();\n const existing = state.funds[subdomain] || {\n subdomain,\n vault: \"\",\n governor: \"\",\n lastMessageId: \"\",\n lastMessageTimestamp: 0,\n lastBlockNumber: 0,\n lastCheckAt: 0,\n totalMessagesProcessed: 0,\n totalEventsProcessed: 0,\n };\n state.funds[subdomain] = { ...existing, ...update };\n saveSessionState(state);\n}\n\nexport function resetSession(\n subdomain: string,\n sinceBlock?: number,\n): void {\n const state = loadSessionState();\n if (sinceBlock !== undefined) {\n // Partial reset — just move the block cursor\n if (state.funds[subdomain]) {\n state.funds[subdomain].lastBlockNumber = sinceBlock;\n saveSessionState(state);\n }\n } else {\n // Full reset\n delete state.funds[subdomain];\n saveSessionState(state);\n }\n}\n\nexport function getAllSessions(): Record<string, FundSession> {\n return loadSessionState().funds;\n}\n"],"mappings":";AAOA,OAAO,QAAQ;AACf,OAAO,QAAQ;AACf,OAAO,UAAU;AAEjB,IAAM,cAAc,KAAK,KAAK,GAAG,QAAQ,GAAG,WAAW;AACvD,IAAM,eAAe,KAAK,KAAK,aAAa,cAAc;AAsBnD,SAAS,mBAAiC;AAC/C,MAAI;AACF,QAAI,GAAG,WAAW,YAAY,GAAG;AAC/B,aAAO,KAAK,MAAM,GAAG,aAAa,cAAc,OAAO,CAAC;AAAA,IAC1D;AAAA,EACF,QAAQ;AAAA,EAER;AACA,SAAO,EAAE,SAAS,GAAG,OAAO,CAAC,EAAE;AACjC;AAEO,SAAS,iBAAiB,OAA2B;AAC1D,KAAG,UAAU,aAAa,EAAE,WAAW,KAAK,CAAC;AAC7C,KAAG,cAAc,cAAc,KAAK,UAAU,OAAO,MAAM,CAAC,CAAC;AAC/D;AAEO,SAAS,WAAW,WAA4C;AACrE,QAAM,QAAQ,iBAAiB;AAC/B,SAAO,MAAM,MAAM,SAAS;AAC9B;AAEO,SAAS,cACd,WACA,QACM;AACN,QAAM,QAAQ,iBAAiB;AAC/B,QAAM,WAAW,MAAM,MAAM,SAAS,KAAK;AAAA,IACzC;AAAA,IACA,OAAO;AAAA,IACP,UAAU;AAAA,IACV,eAAe;AAAA,IACf,sBAAsB;AAAA,IACtB,iBAAiB;AAAA,IACjB,aAAa;AAAA,IACb,wBAAwB;AAAA,IACxB,sBAAsB;AAAA,EACxB;AACA,QAAM,MAAM,SAAS,IAAI,EAAE,GAAG,UAAU,GAAG,OAAO;AAClD,mBAAiB,KAAK;AACxB;AAEO,SAAS,aACd,WACA,YACM;AACN,QAAM,QAAQ,iBAAiB;AAC/B,MAAI,eAAe,QAAW;AAE5B,QAAI,MAAM,MAAM,SAAS,GAAG;AAC1B,YAAM,MAAM,SAAS,EAAE,kBAAkB;AACzC,uBAAiB,KAAK;AAAA,IACxB;AAAA,EACF,OAAO;AAEL,WAAO,MAAM,MAAM,SAAS;AAC5B,qBAAiB,KAAK;AAAA,EACxB;AACF;AAEO,SAAS,iBAA8C;AAC5D,SAAO,iBAAiB,EAAE;AAC5B;","names":[]}