@sherwoodagent/cli 0.72.3 → 0.73.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chat-G5M3OK6M.js → chat-ONGVCWAP.js} +2 -2
- package/dist/{chunk-ZYXFKVYF.js → chunk-XDGCHURW.js} +17 -1
- package/dist/chunk-XDGCHURW.js.map +1 -0
- package/dist/index.js +35 -23
- package/dist/index.js.map +1 -1
- package/dist/{ipfs-VGWTUORE.js → ipfs-RWSTXTZM.js} +4 -2
- package/dist/{research-6VEEPEPP.js → research-2AFNVV7X.js} +2 -2
- package/dist/{session-PURMITWE.js → session-6FMZMPCE.js} +2 -2
- package/package.json +1 -1
- package/dist/chunk-ZYXFKVYF.js.map +0 -1
- /package/dist/{chat-G5M3OK6M.js.map → chat-ONGVCWAP.js.map} +0 -0
- /package/dist/{ipfs-VGWTUORE.js.map → ipfs-RWSTXTZM.js.map} +0 -0
- /package/dist/{research-6VEEPEPP.js.map → research-2AFNVV7X.js.map} +0 -0
- /package/dist/{session-PURMITWE.js.map → session-6FMZMPCE.js.map} +0 -0
|
@@ -24,7 +24,7 @@ import "./chunk-BQMOE4FJ.js";
|
|
|
24
24
|
import {
|
|
25
25
|
fetchMetadata,
|
|
26
26
|
uploadMetadata
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-XDGCHURW.js";
|
|
28
28
|
|
|
29
29
|
// src/commands/chat.ts
|
|
30
30
|
import chalk from "chalk";
|
|
@@ -564,4 +564,4 @@ function registerChatCommands(program) {
|
|
|
564
564
|
export {
|
|
565
565
|
registerChatCommands
|
|
566
566
|
};
|
|
567
|
-
//# sourceMappingURL=chat-
|
|
567
|
+
//# sourceMappingURL=chat-ONGVCWAP.js.map
|
|
@@ -58,6 +58,21 @@ async function fetchMetadata(ipfsURI) {
|
|
|
58
58
|
}
|
|
59
59
|
return await response.json();
|
|
60
60
|
}
|
|
61
|
+
function mergeFundMetadata(current, overrides) {
|
|
62
|
+
const base = { ...current ?? {} };
|
|
63
|
+
const name = overrides.name || base.name || overrides.subdomain;
|
|
64
|
+
const description = overrides.description || base.description || `${name} \u2014 a Sherwood fund on ${overrides.subdomain}.sherwoodagent.eth`;
|
|
65
|
+
return {
|
|
66
|
+
...base,
|
|
67
|
+
schema: base.schema || "sherwood/fund/v1",
|
|
68
|
+
name,
|
|
69
|
+
description,
|
|
70
|
+
chain: base.chain || overrides.defaultChain,
|
|
71
|
+
strategies: base.strategies ?? [],
|
|
72
|
+
terms: base.terms ?? {},
|
|
73
|
+
links: base.links ?? {}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
61
76
|
async function resolveMetadataSummary(uri) {
|
|
62
77
|
try {
|
|
63
78
|
if (uri.startsWith("data:application/json;base64,")) {
|
|
@@ -76,6 +91,7 @@ export {
|
|
|
76
91
|
pinJSON,
|
|
77
92
|
uploadMetadata,
|
|
78
93
|
fetchMetadata,
|
|
94
|
+
mergeFundMetadata,
|
|
79
95
|
resolveMetadataSummary
|
|
80
96
|
};
|
|
81
|
-
//# sourceMappingURL=chunk-
|
|
97
|
+
//# sourceMappingURL=chunk-XDGCHURW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/lib/ipfs.ts"],"sourcesContent":["/**\n * IPFS metadata upload/fetch via Sherwood API.\n *\n * Uploads go through the server-side API at sherwood.sh/api/ipfs/upload\n * which holds the Pinata JWT. CLI and app only need the gateway URL for reads.\n */\n\nexport interface FundMetadata {\n schema: string;\n name: string;\n description: string;\n logo?: string;\n chain: string;\n xmtpGroupId?: string;\n strategies: {\n id: string;\n name: string;\n description: string;\n protocols: string[];\n riskLevel: string;\n }[];\n terms: {\n minDeposit?: string;\n minDepositFormatted?: string;\n feeModel?: string;\n lockPeriod?: number;\n };\n links: {\n moltbook?: string;\n dashboard?: string;\n github?: string;\n };\n}\n\nconst DEFAULT_PINATA_GATEWAY = \"https://sherwood.mypinata.cloud\";\n// www is canonical — the apex 307-redirects to it (an extra hop that has been\n// observed slow/flaky on cold starts; vnet e2e finding).\nconst DEFAULT_UPLOAD_API = \"https://www.sherwood.sh/api/ipfs/upload\";\n\nfunction getUploadApiUrl(): string {\n return process.env.SHERWOOD_API_URL\n ? `${process.env.SHERWOOD_API_URL}/api/ipfs/upload`\n : DEFAULT_UPLOAD_API;\n}\n\nfunction getPinataGateway(): string {\n return process.env.PINATA_GATEWAY || DEFAULT_PINATA_GATEWAY;\n}\n\n/**\n * Upload JSON to IPFS via the Sherwood API (server-side Pinata).\n * Returns the IPFS URI (ipfs://Qm...).\n */\nasync function uploadToIPFS(content: Record<string, unknown>, name: string): Promise<string> {\n const url = getUploadApiUrl();\n\n // Transient \"fetch failed\" / cold-start 5xx from the pin API shouldn't kill\n // a propose flow — retry briefly before surfacing (vnet e2e finding).\n const attempts = 3;\n let lastErr: unknown;\n for (let i = 0; i < attempts; i++) {\n try {\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ content, name }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n // 4xx won't improve on retry; 5xx might.\n if (response.status < 500) throw new Error(`IPFS upload failed (${response.status}): ${text}`);\n lastErr = new Error(`IPFS upload failed (${response.status}): ${text}`);\n } else {\n const result = (await response.json()) as { ipfsHash: string };\n return `ipfs://${result.ipfsHash}`;\n }\n } catch (err) {\n if (err instanceof Error && err.message.startsWith(\"IPFS upload failed (4\")) throw err;\n lastErr = err;\n }\n if (i < attempts - 1) await new Promise((r) => setTimeout(r, 2000 * (i + 1)));\n }\n throw lastErr instanceof Error ? lastErr : new Error(`IPFS upload failed: ${String(lastErr)}`);\n}\n\n/**\n * Pin arbitrary JSON to IPFS.\n * Used for research results and other generic JSON payloads.\n * Returns the IPFS URI (ipfs://Qm...).\n */\nexport async function pinJSON(content: Record<string, unknown>, name: string): Promise<string> {\n return uploadToIPFS(content, name);\n}\n\n/**\n * Upload fund metadata to IPFS.\n * Returns the IPFS URI (ipfs://Qm...).\n */\nexport async function uploadMetadata(metadata: FundMetadata): Promise<string> {\n const name = `sherwood-fund-${metadata.name.toLowerCase().replace(/\\s+/g, \"-\")}`;\n return uploadToIPFS(metadata as unknown as Record<string, unknown>, name);\n}\n\n/**\n * Fetch and parse metadata from an IPFS URI.\n * Supports ipfs:// protocol URIs and raw CIDs.\n */\nexport async function fetchMetadata(ipfsURI: string): Promise<FundMetadata> {\n const gateway = getPinataGateway();\n let cid: string;\n\n if (ipfsURI.startsWith(\"ipfs://\")) {\n cid = ipfsURI.slice(7);\n } else if (ipfsURI.startsWith(\"Qm\") || ipfsURI.startsWith(\"bafy\")) {\n cid = ipfsURI;\n } else {\n throw new Error(`Invalid IPFS URI: ${ipfsURI}`);\n }\n\n const url = `${gateway}/ipfs/${cid}`;\n const response = await fetch(url);\n\n if (!response.ok) {\n throw new Error(`Failed to fetch metadata from ${url} (${response.status})`);\n }\n\n return (await response.json()) as FundMetadata;\n}\n\n/**\n * Merge flag-driven overrides onto the fund's CURRENT metadata.\n *\n * `update-metadata` used to rebuild the JSON from scratch, silently dropping\n * any field not re-supplied by a flag — notably `xmtpGroupId`, which is the\n * ONLY group-discovery path for the dashboard on ENS-less chains (issue #458).\n *\n * Semantics: flags (`name`/`description`) win; everything else on `current`\n * (`xmtpGroupId`, `terms`, `links`, `strategies`, and any unknown keys) is\n * preserved. Unknown keys survive because the spread of `current` is a runtime\n * copy of every own-enumerable property, not just the ones in `FundMetadata`.\n * Pass `current = null` (e.g. when the fetch failed) to fall back to the old\n * build-from-scratch behavior.\n */\nexport function mergeFundMetadata(\n current: Partial<FundMetadata> | null | undefined,\n overrides: {\n name?: string;\n description?: string;\n subdomain: string;\n defaultChain: string;\n },\n): FundMetadata {\n const base = { ...(current ?? {}) } as Partial<FundMetadata> & Record<string, unknown>;\n const name = overrides.name || base.name || overrides.subdomain;\n const description =\n overrides.description ||\n base.description ||\n `${name} — a Sherwood fund on ${overrides.subdomain}.sherwoodagent.eth`;\n return {\n ...base,\n schema: base.schema || \"sherwood/fund/v1\",\n name,\n description,\n chain: base.chain || overrides.defaultChain,\n strategies: base.strategies ?? [],\n terms: base.terms ?? {},\n links: base.links ?? {},\n };\n}\n\n/**\n * Resolve a metadata URI (ipfs:// or data: base64) to name + description.\n * Returns null on any error — callers should treat enrichment as best-effort.\n */\nexport async function resolveMetadataSummary(\n uri: string,\n): Promise<{ name: string; description: string } | null> {\n try {\n if (uri.startsWith(\"data:application/json;base64,\")) {\n const b64 = uri.slice(\"data:application/json;base64,\".length);\n const json = JSON.parse(Buffer.from(b64, \"base64\").toString(\"utf-8\"));\n return { name: json.name || \"\", description: json.description || \"\" };\n }\n const meta = await fetchMetadata(uri);\n return { name: meta.name, description: meta.description };\n } catch {\n return null;\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
|
@@ -171,8 +171,9 @@ import {
|
|
|
171
171
|
} from "./chunk-BQMOE4FJ.js";
|
|
172
172
|
import {
|
|
173
173
|
fetchMetadata,
|
|
174
|
+
mergeFundMetadata,
|
|
174
175
|
uploadMetadata
|
|
175
|
-
} from "./chunk-
|
|
176
|
+
} from "./chunk-XDGCHURW.js";
|
|
176
177
|
|
|
177
178
|
// src/index.ts
|
|
178
179
|
import { config as loadDotenv } from "dotenv";
|
|
@@ -1180,13 +1181,17 @@ var ROBINHOOD_L2 = {
|
|
|
1180
1181
|
slug: "robinhood-l2",
|
|
1181
1182
|
// V2 redeploy (chain 46630): fresh core contracts + a full guardian layer
|
|
1182
1183
|
// (registry + sWOOD) and a deployed StrategyFactory for the keyless
|
|
1183
|
-
// clone+init path (#387).
|
|
1184
|
+
// clone+init path (#387). Post-#421 per-vault-governor redeploy — kept in
|
|
1185
|
+
// sync with the canonical source of truth contracts/chains/46630.json (and
|
|
1186
|
+
// the app's app/src/lib/contracts.ts ROBINHOOD_TESTNET_ADDRESSES). A stale
|
|
1187
|
+
// factory here made /api/v1/funds?chain=46630 read the old deployment and
|
|
1188
|
+
// return {count: 0} while the UI listed funds (issue #459).
|
|
1184
1189
|
sherwood: {
|
|
1185
|
-
factory: "
|
|
1186
|
-
guardianRegistry: "
|
|
1187
|
-
vaultImpl: "
|
|
1188
|
-
batchExecutorLib: "
|
|
1189
|
-
strategyFactory: "
|
|
1190
|
+
factory: "0xB9E71Fb33075328d6e94eCFFf8a8629D6d057cce",
|
|
1191
|
+
guardianRegistry: "0x57f0fa384d0d7e2F234535d1235440312866872B",
|
|
1192
|
+
vaultImpl: "0x189160156d470B9ce8A55206DE19Ea60D2638ec6",
|
|
1193
|
+
batchExecutorLib: "0xd83dc3A79Bb41a02Ca7aC812c0f52212C1BdBC1B",
|
|
1194
|
+
strategyFactory: "0xE1D082ef1CE17f9C6a46e97928337267BFF0C309"
|
|
1190
1195
|
},
|
|
1191
1196
|
// No ERC-8004 registry and no EAS path on Robinhood L2.
|
|
1192
1197
|
identityRegistry: ZERO_ADDRESS,
|
|
@@ -3739,7 +3744,7 @@ function registerStrategyTemplateCommands(strategy2) {
|
|
|
3739
3744
|
process.exit(1);
|
|
3740
3745
|
}
|
|
3741
3746
|
const { propose: propose2 } = await import("./governor-RRBTDGDX.js");
|
|
3742
|
-
const { pinJSON } = await import("./ipfs-
|
|
3747
|
+
const { pinJSON } = await import("./ipfs-RWSTXTZM.js");
|
|
3743
3748
|
const { parseDuration: parseDuration2 } = await import("./governor-RRBTDGDX.js");
|
|
3744
3749
|
const strategyDuration = parseDuration2(opts.duration);
|
|
3745
3750
|
const metaSpinner = ora("Pinning metadata to IPFS...").start();
|
|
@@ -10331,7 +10336,7 @@ try {
|
|
|
10331
10336
|
} catch {
|
|
10332
10337
|
}
|
|
10333
10338
|
var require2 = createRequire(import.meta.url);
|
|
10334
|
-
var CLI_VERSION = "0.
|
|
10339
|
+
var CLI_VERSION = "0.73.1";
|
|
10335
10340
|
async function loadXmtp() {
|
|
10336
10341
|
return import("./xmtp-M32JSE4I.js");
|
|
10337
10342
|
}
|
|
@@ -10798,18 +10803,25 @@ fund.command("update-metadata").description("Update fund metadata (creator only)
|
|
|
10798
10803
|
spinner.fail(`Fund #${opts.id} not found.`);
|
|
10799
10804
|
process.exit(1);
|
|
10800
10805
|
}
|
|
10801
|
-
|
|
10802
|
-
|
|
10806
|
+
spinner.text = W6("Fetching current metadata...");
|
|
10807
|
+
let current = null;
|
|
10808
|
+
try {
|
|
10809
|
+
current = await fetchMetadata(info.metadataURI);
|
|
10810
|
+
} catch (fetchErr) {
|
|
10811
|
+
console.warn(
|
|
10812
|
+
chalk16.yellow(
|
|
10813
|
+
" \u26A0 Could not fetch current metadata \u2014 rebuilding from flags (unknown fields like xmtpGroupId may be dropped)"
|
|
10814
|
+
)
|
|
10815
|
+
);
|
|
10816
|
+
console.warn(DIM6(` ${fetchErr instanceof Error ? fetchErr.message : String(fetchErr)}`));
|
|
10817
|
+
}
|
|
10803
10818
|
spinner.text = W6("Uploading metadata to IPFS...");
|
|
10804
|
-
const metadata = {
|
|
10805
|
-
|
|
10806
|
-
|
|
10807
|
-
|
|
10808
|
-
|
|
10809
|
-
|
|
10810
|
-
terms: {},
|
|
10811
|
-
links: {}
|
|
10812
|
-
};
|
|
10819
|
+
const metadata = mergeFundMetadata(current, {
|
|
10820
|
+
name: opts.name,
|
|
10821
|
+
description: opts.description,
|
|
10822
|
+
subdomain: info.subdomain,
|
|
10823
|
+
defaultChain: getChain().name
|
|
10824
|
+
});
|
|
10813
10825
|
metadataURI = await uploadMetadata(metadata);
|
|
10814
10826
|
spinner.text = W6("Updating on-chain metadata...");
|
|
10815
10827
|
}
|
|
@@ -11655,7 +11667,7 @@ ${info.name} (${info.type})`);
|
|
|
11655
11667
|
}
|
|
11656
11668
|
});
|
|
11657
11669
|
try {
|
|
11658
|
-
const { registerChatCommands } = await import("./chat-
|
|
11670
|
+
const { registerChatCommands } = await import("./chat-ONGVCWAP.js");
|
|
11659
11671
|
registerChatCommands(program);
|
|
11660
11672
|
} catch {
|
|
11661
11673
|
program.command("chat <name> [action] [actionArgs...]").description("Fund chat (XMTP) \u2014 requires @xmtp/cli").action(() => {
|
|
@@ -11665,7 +11677,7 @@ try {
|
|
|
11665
11677
|
process.exit(1);
|
|
11666
11678
|
});
|
|
11667
11679
|
}
|
|
11668
|
-
var { registerSessionCommands } = await import("./session-
|
|
11680
|
+
var { registerSessionCommands } = await import("./session-6FMZMPCE.js");
|
|
11669
11681
|
registerSessionCommands(program);
|
|
11670
11682
|
registerVeniceCommands(program);
|
|
11671
11683
|
registerAllowanceCommands(program);
|
|
@@ -11674,7 +11686,7 @@ registerProposalCommands(program);
|
|
|
11674
11686
|
registerQueueCommands(program);
|
|
11675
11687
|
registerGovernorCommands(program);
|
|
11676
11688
|
registerGuardianCommands(program);
|
|
11677
|
-
var { registerResearchCommands } = await import("./research-
|
|
11689
|
+
var { registerResearchCommands } = await import("./research-2AFNVV7X.js");
|
|
11678
11690
|
registerResearchCommands(program);
|
|
11679
11691
|
var { registerAgentCommands } = await import("./agent-6IRZUPFT.js");
|
|
11680
11692
|
registerAgentCommands(program);
|