@sage-protocol/cli 0.3.9 → 0.4.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.
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"RPC_URL": "https://sepolia.base.org",
|
|
8
8
|
"LIBRARY_REGISTRY_ADDRESS": "0x032F2E93549640a319163Ba600fc50bA1AFBE50F",
|
|
9
9
|
"SUBDAO_FACTORY_ADDRESS": "0x6bb6A83149F84Df0584aC863e5fE3416AFb214aC",
|
|
10
|
-
"SUBGRAPH_URL": "https://api.goldsky.com/api/public/project_cmhxp0fppsbdd01q56xp2gqw9/subgraphs/sxxx-protocol/1.0.
|
|
10
|
+
"SUBGRAPH_URL": "https://api.goldsky.com/api/public/project_cmhxp0fppsbdd01q56xp2gqw9/subgraphs/sxxx-protocol/1.0.1/gn",
|
|
11
11
|
"PINATA_JWT": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySW5mb3JtYXRpb24iOnsiaWQiOiI4ODE2MWM1Ni05NTYzLTQyNTUtYTU4Ni0xMzBiMTUyMWIxNmIiLCJlbWFpbCI6InRlcnJlbmV0d2VsbHM0N0BnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwicGluX3BvbGljeSI6eyJyZWdpb25zIjpbeyJkZXNpcmVkUmVwbGljYXRpb25Db3VudCI6MSwiaWQiOiJGUkExIn0seyJkZXNpcmVkUmVwbGljYXRpb25Db3VudCI6MSwiaWQiOiJOWUMxIn1dLCJ2ZXJzaW9uIjoxfSwibWZhX2VuYWJsZWQiOmZhbHNlLCJzdGF0dXMiOiJBQ1RJVkUifSwiYXV0aGVudGljYXRpb25UeXBlIjoic2NvcGVkS2V5Iiwic2NvcGVkS2V5S2V5IjoiMDRjZWY4NzE5OTg1ODE1M2U5Y2IiLCJzY29wZWRLZXlTZWNyZXQiOiJmNDFjMDVhZTNjN2EzMTliOTAxZjhiNGI3YjMxMDljMThmNjgyZmRkZGY3OGU1ZmZkZjQ4MTM4OTQ0OWUyOGVjIiwiZXhwIjoxNzk1NTMzNTA4fQ.tQKFU7aZ3EKb7RkB99QTaWVduaaKaKjEa1nk43aeSlo"
|
|
12
12
|
}
|
|
13
13
|
}
|
|
@@ -2,11 +2,13 @@ const fs = require('fs');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const axios = require('axios');
|
|
4
4
|
const { getAddress, id, parseUnits, formatUnits, Contract, MaxUint256 } = require('ethers');
|
|
5
|
+
const { decryptAesGcm, fromB64 } = require('../utils/aes');
|
|
5
6
|
const sdk = require('@sage-protocol/sdk');
|
|
6
7
|
const { formatJson } = require('../utils/format');
|
|
7
8
|
const { getProvider, getWallet } = require('../utils/provider');
|
|
8
9
|
const { loadAbi } = require('../utils/abi-loader');
|
|
9
10
|
const { buildAccessControlConditions, receiptIdToHex } = require('../utils/personal-helpers');
|
|
11
|
+
const { buildNodeAuthSig } = require('../utils/lit');
|
|
10
12
|
const ConfigManager = require('../config');
|
|
11
13
|
|
|
12
14
|
if (ConfigManager && typeof ConfigManager.loadEnv === 'function') {
|
|
@@ -114,7 +116,7 @@ async function createAction(opts) {
|
|
|
114
116
|
try { return contract.interface.parseLog(l); } catch (_) { return null; }
|
|
115
117
|
}).find(Boolean);
|
|
116
118
|
const out = {
|
|
117
|
-
txHash: receipt.
|
|
119
|
+
txHash: receipt.hash,
|
|
118
120
|
registry: evt && evt.args ? evt.args.registry : undefined,
|
|
119
121
|
policy,
|
|
120
122
|
};
|
|
@@ -140,7 +142,7 @@ async function setPriceAction(key, price, opts) {
|
|
|
140
142
|
key,
|
|
141
143
|
price,
|
|
142
144
|
priceWei: priceWei.toString(),
|
|
143
|
-
txHash: receipt.
|
|
145
|
+
txHash: receipt.hash,
|
|
144
146
|
};
|
|
145
147
|
if (opts && opts.json) {
|
|
146
148
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -172,7 +174,7 @@ async function sellAction(key, price, opts = {}) {
|
|
|
172
174
|
const tx = await facet.createPersonalRegistry(policy);
|
|
173
175
|
const rcpt = await tx.wait();
|
|
174
176
|
if (!opts.json) {
|
|
175
|
-
console.log(`📚 Personal registry created (policy=${policy}) -> tx ${rcpt.
|
|
177
|
+
console.log(`📚 Personal registry created (policy=${policy}) -> tx ${rcpt.hash}`);
|
|
176
178
|
}
|
|
177
179
|
}
|
|
178
180
|
|
|
@@ -244,10 +246,12 @@ async function sellAction(key, price, opts = {}) {
|
|
|
244
246
|
throw new Error('Lit encryption helpers not available. Ensure @lit-protocol/encryption is installed.');
|
|
245
247
|
}
|
|
246
248
|
|
|
247
|
-
const litNetwork = opts.litNetwork || process.env.LIT_NETWORK || '
|
|
248
|
-
const client = new LitNodeClient({ litNetwork });
|
|
249
|
+
const litNetwork = opts.litNetwork || process.env.LIT_NETWORK || 'datil-test';
|
|
250
|
+
const client = new LitNodeClient({ litNetwork, debug: false });
|
|
249
251
|
await client.connect();
|
|
250
252
|
|
|
253
|
+
const litChain = await inferLitChain(provider, opts.chain);
|
|
254
|
+
|
|
251
255
|
let sessionSigs = null;
|
|
252
256
|
if (opts.session) {
|
|
253
257
|
sessionSigs = loadJsonFile(opts.session, '--session');
|
|
@@ -261,13 +265,14 @@ async function sellAction(key, price, opts = {}) {
|
|
|
261
265
|
authSig = loadJsonFile(opts.authSig, '--auth-sig');
|
|
262
266
|
} else if (process.env.LIT_AUTH_SIG) {
|
|
263
267
|
authSig = loadJsonFile(process.env.LIT_AUTH_SIG, 'LIT_AUTH_SIG');
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
|
|
268
|
+
} else {
|
|
269
|
+
// Auto-generate authSig from connected wallet
|
|
270
|
+
if (!opts.json) {
|
|
271
|
+
console.log('🔐 Generating Lit auth signature from wallet...');
|
|
272
|
+
}
|
|
273
|
+
authSig = await buildNodeAuthSig(wallet, litChain);
|
|
267
274
|
}
|
|
268
275
|
}
|
|
269
|
-
|
|
270
|
-
const litChain = await inferLitChain(provider, opts.chain);
|
|
271
276
|
const accessConditions = buildAccessControlConditions(receiptAddress, receiptId, litChain);
|
|
272
277
|
|
|
273
278
|
const encResp = await encryptUint8Array({
|
|
@@ -328,12 +333,12 @@ async function sellAction(key, price, opts = {}) {
|
|
|
328
333
|
const marketplace = new Contract(marketplaceAddress, marketplaceAbi, wallet);
|
|
329
334
|
const priceTx = await marketplace.setPrice(keyHash, priceWei);
|
|
330
335
|
const priceReceipt = await priceTx.wait();
|
|
331
|
-
result.txHash = priceReceipt.
|
|
336
|
+
result.txHash = priceReceipt.hash;
|
|
332
337
|
|
|
333
338
|
if (opts.json) {
|
|
334
339
|
console.log(JSON.stringify(result, null, 2));
|
|
335
340
|
} else {
|
|
336
|
-
console.log(`✅ Listed ${key} for ${price} SXXX (${priceReceipt.
|
|
341
|
+
console.log(`✅ Listed ${key} for ${price} SXXX (tx: ${priceReceipt.hash})`);
|
|
337
342
|
if (result.encryptedCid) {
|
|
338
343
|
console.log(`🔒 Encrypted CID: ${result.encryptedCid}`);
|
|
339
344
|
console.log(`🗃️ Manifest CID: ${result.manifestCid}`);
|
|
@@ -430,7 +435,48 @@ async function listAction(opts = {}) {
|
|
|
430
435
|
let personalResourceMap = new Map();
|
|
431
436
|
|
|
432
437
|
if (!explicitKeys.length && subgraphUrl) {
|
|
433
|
-
|
|
438
|
+
// First try to get all listings (PriceSet events)
|
|
439
|
+
const listingsQuery = `
|
|
440
|
+
query($creator: Bytes!, $first: Int!) {
|
|
441
|
+
personalListings(where: { creator: $creator, listed: true }, first: $first, orderBy: updatedAt, orderDirection: desc) {
|
|
442
|
+
id
|
|
443
|
+
creator
|
|
444
|
+
key
|
|
445
|
+
price
|
|
446
|
+
listed
|
|
447
|
+
createdAt
|
|
448
|
+
updatedAt
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
`;
|
|
452
|
+
try {
|
|
453
|
+
const listingsData = await subgraphQuery(subgraphUrl, listingsQuery, {
|
|
454
|
+
creator: creatorAddress.toLowerCase(),
|
|
455
|
+
first: limit,
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
for (const listing of listingsData?.personalListings || []) {
|
|
459
|
+
const keyHash = String(listing.key);
|
|
460
|
+
const idKey = `hash:${keyHash}`;
|
|
461
|
+
if (!entries.has(idKey)) {
|
|
462
|
+
entries.set(idKey, {
|
|
463
|
+
type: 'hash',
|
|
464
|
+
keyHash,
|
|
465
|
+
priceFromListing: listing.price ? BigInt(String(listing.price)) : null,
|
|
466
|
+
listedAt: listing.createdAt ? Number(listing.createdAt) : null,
|
|
467
|
+
updatedAt: listing.updatedAt ? Number(listing.updatedAt) : null,
|
|
468
|
+
});
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
} catch (listingError) {
|
|
472
|
+
// PersonalListing entity may not exist yet, fall back to purchases
|
|
473
|
+
if (!listingError.message?.includes('Cannot query field')) {
|
|
474
|
+
console.warn(`⚠️ Listings query: ${listingError.message}`);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// Also fetch purchases for additional metadata
|
|
479
|
+
const purchasesQuery = `
|
|
434
480
|
query($creator: Bytes!, $first: Int!) {
|
|
435
481
|
licensePurchases(where: { creator: $creator }, first: $first, orderBy: blockTimestamp, orderDirection: desc) {
|
|
436
482
|
key
|
|
@@ -444,7 +490,7 @@ async function listAction(opts = {}) {
|
|
|
444
490
|
}
|
|
445
491
|
`;
|
|
446
492
|
try {
|
|
447
|
-
const data = await subgraphQuery(subgraphUrl,
|
|
493
|
+
const data = await subgraphQuery(subgraphUrl, purchasesQuery, {
|
|
448
494
|
creator: creatorAddress.toLowerCase(),
|
|
449
495
|
first: limit,
|
|
450
496
|
});
|
|
@@ -452,7 +498,15 @@ async function listAction(opts = {}) {
|
|
|
452
498
|
for (const purchase of data?.licensePurchases || []) {
|
|
453
499
|
const keyHash = String(purchase.key);
|
|
454
500
|
const idKey = `hash:${keyHash}`;
|
|
455
|
-
|
|
501
|
+
const existing = entries.get(idKey);
|
|
502
|
+
if (existing) {
|
|
503
|
+
// Enrich existing listing with purchase data
|
|
504
|
+
existing.receiptId = purchase.receiptId ? BigInt(String(purchase.receiptId)) : existing.receiptId;
|
|
505
|
+
existing.lastBuyer = purchase.buyer ? getAddress(purchase.buyer) : existing.lastBuyer;
|
|
506
|
+
existing.lastPurchaseAt = purchase.blockTimestamp ? Number(purchase.blockTimestamp) : existing.lastPurchaseAt;
|
|
507
|
+
existing.encryptedCid = purchase.encryptedCid || existing.encryptedCid;
|
|
508
|
+
existing.metadata = purchase.metadata || existing.metadata;
|
|
509
|
+
} else {
|
|
456
510
|
entries.set(idKey, {
|
|
457
511
|
type: 'hash',
|
|
458
512
|
keyHash,
|
|
@@ -501,7 +555,10 @@ async function listAction(opts = {}) {
|
|
|
501
555
|
}
|
|
502
556
|
|
|
503
557
|
if (!entries.size) {
|
|
504
|
-
console.log('ℹ️ No listings found.
|
|
558
|
+
console.log('ℹ️ No listings found.');
|
|
559
|
+
console.log(' Use --key <name> to check a specific listing by key.');
|
|
560
|
+
console.log(' Example: sage personal list --mine --key "my-prompt"');
|
|
561
|
+
console.log(' Note: Listings appear in subgraph after first purchase.');
|
|
505
562
|
return [];
|
|
506
563
|
}
|
|
507
564
|
|
|
@@ -678,6 +735,10 @@ async function myLicensesAction(opts = {}) {
|
|
|
678
735
|
console.log(JSON.stringify(results, null, 2));
|
|
679
736
|
} else if (results.length === 0) {
|
|
680
737
|
console.log('ℹ️ No active personal licenses found for this holder.');
|
|
738
|
+
console.log('');
|
|
739
|
+
console.log(' If you recently purchased a license, the subgraph may still be syncing.');
|
|
740
|
+
console.log(' To check a specific license directly on-chain, use:');
|
|
741
|
+
console.log(' sage personal premium access <creator> <key>');
|
|
681
742
|
} else {
|
|
682
743
|
results.forEach((item) => {
|
|
683
744
|
console.log(`🧾 ${item.receiptIdHex} — balance ${item.balance}`);
|
|
@@ -751,7 +812,7 @@ async function buyAction(creator, key, expectedPriceArg, opts = {}) {
|
|
|
751
812
|
const approveTx = await sxxx.approve(marketplaceAddress, approveAmount);
|
|
752
813
|
const approveReceipt = await approveTx.wait();
|
|
753
814
|
if (!opts.json) {
|
|
754
|
-
console.log(`✅ SXXX approval tx ${approveReceipt.
|
|
815
|
+
console.log(`✅ SXXX approval tx ${approveReceipt.hash}`);
|
|
755
816
|
}
|
|
756
817
|
}
|
|
757
818
|
|
|
@@ -778,7 +839,7 @@ async function buyAction(creator, key, expectedPriceArg, opts = {}) {
|
|
|
778
839
|
: sdk.personal.computeReceiptId(creatorAddress, key);
|
|
779
840
|
|
|
780
841
|
const result = {
|
|
781
|
-
txHash: receipt.
|
|
842
|
+
txHash: receipt.hash,
|
|
782
843
|
creator: creatorAddress,
|
|
783
844
|
buyer: buyerAddress,
|
|
784
845
|
key,
|
|
@@ -841,6 +902,32 @@ async function accessAction(creator, key, opts) {
|
|
|
841
902
|
|
|
842
903
|
let encryptedCid = resource?.encryptedCid || null;
|
|
843
904
|
let metadata = resource?.metadata || null;
|
|
905
|
+
let manifestObj = null;
|
|
906
|
+
|
|
907
|
+
// If --manifest provided, fetch manifest from IPFS and extract encryptedCid
|
|
908
|
+
if (opts.manifest) {
|
|
909
|
+
const gateway = resolveGateway(opts.gateway);
|
|
910
|
+
try {
|
|
911
|
+
if (!opts.json) {
|
|
912
|
+
console.log(`📥 Fetching manifest from IPFS: ${opts.manifest}`);
|
|
913
|
+
}
|
|
914
|
+
const manifestResp = await axios.get(`${gateway}${opts.manifest}`, { timeout: 15000 });
|
|
915
|
+
const manifest = manifestResp.data;
|
|
916
|
+
manifestObj = manifest;
|
|
917
|
+
if (manifest?.encryptedCid) {
|
|
918
|
+
encryptedCid = manifest.encryptedCid;
|
|
919
|
+
if (!opts.json) {
|
|
920
|
+
console.log(`✅ Found encryptedCid in manifest: ${encryptedCid}`);
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
if (manifest?.metadata && !metadata) {
|
|
924
|
+
metadata = manifest.metadata;
|
|
925
|
+
}
|
|
926
|
+
} catch (err) {
|
|
927
|
+
console.warn(`⚠️ Failed to fetch manifest: ${err?.message || err}`);
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
|
|
844
931
|
if (!encryptedCid && opts.encryptedCid) {
|
|
845
932
|
encryptedCid = String(opts.encryptedCid);
|
|
846
933
|
}
|
|
@@ -856,9 +943,12 @@ async function accessAction(creator, key, opts) {
|
|
|
856
943
|
if (encryptedPayload && looksLikeCid(encryptedPayload)) {
|
|
857
944
|
try {
|
|
858
945
|
const resp = await axios.get(`${gateway}${encryptedPayload}`, { timeout: 10000 });
|
|
946
|
+
if (resp.status !== 200) {
|
|
947
|
+
throw new Error(`Status ${resp.status}`);
|
|
948
|
+
}
|
|
859
949
|
encryptedPayload = resp.data;
|
|
860
950
|
} catch (error) {
|
|
861
|
-
|
|
951
|
+
throw new Error(`Failed to fetch encrypted payload from IPFS via ${gateway}: ${error.message}`);
|
|
862
952
|
}
|
|
863
953
|
}
|
|
864
954
|
|
|
@@ -879,10 +969,12 @@ async function accessAction(creator, key, opts) {
|
|
|
879
969
|
|
|
880
970
|
if (!opts.skipDecrypt && payloadObject) {
|
|
881
971
|
const { LitNodeClient } = requireLit();
|
|
882
|
-
const litNetwork = opts.litNetwork || process.env.LIT_NETWORK || '
|
|
883
|
-
const client = new LitNodeClient({ litNetwork });
|
|
972
|
+
const litNetwork = opts.litNetwork || process.env.LIT_NETWORK || 'datil-test';
|
|
973
|
+
const client = new LitNodeClient({ litNetwork, debug: false });
|
|
884
974
|
await client.connect();
|
|
885
975
|
|
|
976
|
+
const litChain = await inferLitChain(provider, opts.chain);
|
|
977
|
+
|
|
886
978
|
let sessionSigs = null;
|
|
887
979
|
if (opts.session) {
|
|
888
980
|
sessionSigs = loadJsonFile(opts.session, '--session');
|
|
@@ -891,22 +983,80 @@ async function accessAction(creator, key, opts) {
|
|
|
891
983
|
}
|
|
892
984
|
|
|
893
985
|
let authSig = null;
|
|
894
|
-
if (
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
986
|
+
if (!sessionSigs) {
|
|
987
|
+
if (opts.authSig) {
|
|
988
|
+
authSig = loadJsonFile(opts.authSig, '--auth-sig');
|
|
989
|
+
} else if (process.env.LIT_AUTH_SIG) {
|
|
990
|
+
authSig = loadJsonFile(process.env.LIT_AUTH_SIG, 'LIT_AUTH_SIG');
|
|
991
|
+
} else {
|
|
992
|
+
// Auto-generate authSig from connected wallet
|
|
993
|
+
if (!opts.json) {
|
|
994
|
+
console.log('🔐 Generating Lit auth signature from wallet...');
|
|
995
|
+
}
|
|
996
|
+
authSig = await buildNodeAuthSig(wallet, litChain);
|
|
997
|
+
}
|
|
898
998
|
}
|
|
899
999
|
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
1000
|
+
// Check for Hybrid Encryption (Sage Personal Manifest)
|
|
1001
|
+
if (payloadObject.type === 'sage-personal-encrypted' && payloadObject.enc === 'aes-256-gcm') {
|
|
1002
|
+
if (!manifestObj || !manifestObj.lit) {
|
|
1003
|
+
throw new Error('Hybrid encryption detected but no Manifest provided (use --manifest <cid>).');
|
|
1004
|
+
}
|
|
1005
|
+
if (!opts.json) console.log('🔐 Decrypting hybrid content (Lit + AES-GCM)...');
|
|
1006
|
+
|
|
1007
|
+
const litParams = manifestObj.lit;
|
|
1008
|
+
const condition = litParams.evmContractConditions?.[0] || {
|
|
1009
|
+
conditionType: 'evmContract',
|
|
1010
|
+
contractAddress: receiptAddress,
|
|
1011
|
+
functionName: 'balanceOf',
|
|
1012
|
+
functionParams: [':userAddress', receiptId.toString()],
|
|
1013
|
+
functionAbi: {
|
|
1014
|
+
inputs: [{ internalType: 'address', name: 'account', type: 'address' }, { internalType: 'uint256', name: 'id', type: 'uint256' }],
|
|
1015
|
+
name: 'balanceOf',
|
|
1016
|
+
outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],
|
|
1017
|
+
stateMutability: 'view',
|
|
1018
|
+
type: 'function',
|
|
1019
|
+
},
|
|
1020
|
+
chain: litChain,
|
|
1021
|
+
returnValueTest: { comparator: '>', value: '0' },
|
|
1022
|
+
};
|
|
1023
|
+
|
|
1024
|
+
const request = {
|
|
1025
|
+
unifiedAccessControlConditions: [condition],
|
|
1026
|
+
chain: litChain,
|
|
1027
|
+
ciphertext: litParams.encryptedSymmetricKey,
|
|
1028
|
+
dataToEncryptHash: litParams.dataToEncryptHash,
|
|
1029
|
+
authSig,
|
|
1030
|
+
sessionSigs,
|
|
1031
|
+
};
|
|
1032
|
+
|
|
1033
|
+
const response = await client.decrypt(request);
|
|
1034
|
+
if (!response || !response.decryptedData) {
|
|
1035
|
+
throw new Error('[personal] Lit decryption of symmetric key failed');
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
// response.decryptedData is Uint8Array
|
|
1039
|
+
const symmetricKey = response.decryptedData;
|
|
1040
|
+
|
|
1041
|
+
decrypted = decryptAesGcm(
|
|
1042
|
+
fromB64(payloadObject.ciphertext),
|
|
1043
|
+
Buffer.from(symmetricKey),
|
|
1044
|
+
fromB64(payloadObject.iv),
|
|
1045
|
+
fromB64(payloadObject.tag)
|
|
1046
|
+
);
|
|
1047
|
+
|
|
1048
|
+
} else {
|
|
1049
|
+
// Legacy/Direct Lit Decryption
|
|
1050
|
+
decrypted = await sdk.personal.decryptWithLit({
|
|
1051
|
+
encryptedCid: payloadObject,
|
|
1052
|
+
receiptId,
|
|
1053
|
+
chain: litChain,
|
|
1054
|
+
receiptAddress,
|
|
1055
|
+
litClient: client,
|
|
1056
|
+
sessionSigs: sessionSigs || undefined,
|
|
1057
|
+
authSig: authSig || undefined,
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
910
1060
|
|
|
911
1061
|
if (opts.out) {
|
|
912
1062
|
outputPath = path.resolve(opts.out);
|
|
@@ -1047,6 +1197,7 @@ function register(program) {
|
|
|
1047
1197
|
.option('--out <file>', 'Write decrypted output to file')
|
|
1048
1198
|
.option('--skip-decrypt', 'Skip decryption and only report license status')
|
|
1049
1199
|
.option('--encrypted-cid <cid>', 'Override encrypted CID')
|
|
1200
|
+
.option('--manifest <cid>', 'Manifest CID to fetch encrypted content info from IPFS')
|
|
1050
1201
|
.option('--json', 'Emit machine-readable JSON report', false)
|
|
1051
1202
|
.action((creator, key, opts) => accessAction(creator, key, opts).catch((err) => { console.error(err.message); process.exit(1); }));
|
|
1052
1203
|
|
package/dist/cli/mcp-setup.md
CHANGED
|
@@ -18,10 +18,10 @@ Create or update your `.env` file with the required configuration:
|
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
20
|
# Subgraph (preferred) + Blockchain
|
|
21
|
-
SUBGRAPH_URL=https://api.goldsky.com/api/public/project_cmhxp0fppsbdd01q56xp2gqw9/subgraphs/sxxx-protocol/1.0.
|
|
22
|
-
RPC_URL=https://sepolia.
|
|
23
|
-
LIBRARY_REGISTRY_ADDRESS=
|
|
24
|
-
SUBDAO_FACTORY_ADDRESS=
|
|
21
|
+
SUBGRAPH_URL=https://api.goldsky.com/api/public/project_cmhxp0fppsbdd01q56xp2gqw9/subgraphs/sxxx-protocol/1.0.2/gn
|
|
22
|
+
RPC_URL=https://base-sepolia.publicnode.com
|
|
23
|
+
LIBRARY_REGISTRY_ADDRESS=0x419Cd79d58db6A5aE1900dd7F0c1b8d153FfaD06
|
|
24
|
+
SUBDAO_FACTORY_ADDRESS=0xED573E7e4c00fE325f846B961Df3352807eA3807
|
|
25
25
|
|
|
26
26
|
# Optional: Custom IPFS Gateway
|
|
27
27
|
IPFS_GATEWAY=https://ipfs.io/ipfs
|
|
@@ -65,10 +65,10 @@ You should see a JSON response listing the available tools.
|
|
|
65
65
|
"command": "node",
|
|
66
66
|
"args": ["/absolute/path/to/sage-protocol/cli/mcp-server-stdio.js"],
|
|
67
67
|
"env": {
|
|
68
|
-
"SUBGRAPH_URL": "https://api.goldsky.com/api/public/project_cmhxp0fppsbdd01q56xp2gqw9/subgraphs/sxxx-protocol/1.0.
|
|
69
|
-
"RPC_URL": "https://sepolia.
|
|
70
|
-
"LIBRARY_REGISTRY_ADDRESS": "
|
|
71
|
-
"SUBDAO_FACTORY_ADDRESS": "
|
|
68
|
+
"SUBGRAPH_URL": "https://api.goldsky.com/api/public/project_cmhxp0fppsbdd01q56xp2gqw9/subgraphs/sxxx-protocol/1.0.2/gn",
|
|
69
|
+
"RPC_URL": "https://base-sepolia.publicnode.com",
|
|
70
|
+
"LIBRARY_REGISTRY_ADDRESS": "0x419Cd79d58db6A5aE1900dd7F0c1b8d153FfaD06",
|
|
71
|
+
"SUBDAO_FACTORY_ADDRESS": "0xED573E7e4c00fE325f846B961Df3352807eA3807"
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
}
|
|
@@ -97,36 +97,37 @@ Can you search for on-chain prompts related to "real estate"?
|
|
|
97
97
|
or
|
|
98
98
|
|
|
99
99
|
```
|
|
100
|
-
Please list all available
|
|
100
|
+
Please list all available DAOs in the Sage Protocol.
|
|
101
101
|
```
|
|
102
102
|
|
|
103
103
|
## Available MCP Tools
|
|
104
104
|
|
|
105
|
-
Your Sage Protocol MCP Server provides these tools
|
|
106
|
-
|
|
107
|
-
###
|
|
108
|
-
-
|
|
109
|
-
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
-
|
|
118
|
-
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
-
|
|
123
|
-
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
###
|
|
127
|
-
-
|
|
128
|
-
-
|
|
129
|
-
|
|
105
|
+
Your Sage Protocol MCP Server provides these tools. For the full list, see `docs/development/mcp-config.md`.
|
|
106
|
+
|
|
107
|
+
### Quick Workflow (recommended)
|
|
108
|
+
- `quick_create_prompt` - Create a new prompt (handles library creation automatically)
|
|
109
|
+
- `quick_iterate_prompt` - Update an existing prompt with automatic backup
|
|
110
|
+
- `quick_test_prompt` / `test_prompt` - Test a prompt with variable substitution
|
|
111
|
+
- `improve_prompt` - Analyze a prompt and suggest improvements
|
|
112
|
+
- `rename_prompt` - Rename a prompt's key/display name
|
|
113
|
+
- `help` - Get help on Sage MCP workflows
|
|
114
|
+
|
|
115
|
+
### Discovery & Search
|
|
116
|
+
- `search_prompts` - Unified search across local and on-chain sources
|
|
117
|
+
- `search_onchain_prompts` - Search directly from on-chain registries
|
|
118
|
+
- `trending_prompts` - List trending prompts
|
|
119
|
+
- `list_prompts` - List prompts from local libraries
|
|
120
|
+
- `get_prompt` - Retrieve a specific prompt by key
|
|
121
|
+
- `get_prompt_content` - Fetch full content from IPFS by CID
|
|
122
|
+
- `list_libraries` - Page through libraries (local or on-chain)
|
|
123
|
+
- `list_subdaos` - List all available DAOs
|
|
124
|
+
- `get_library_manifests` - Get executed library manifests
|
|
125
|
+
|
|
126
|
+
### Publishing & Governance
|
|
127
|
+
- `suggest_subdaos_for_library` - Recommend DAOs for publishing
|
|
128
|
+
- `generate_publishing_commands` - Generate CLI commands to publish
|
|
129
|
+
- `publish_manifest_flow` - Validate → Push → Proposal payload (no signing)
|
|
130
|
+
- `list_proposals` - List active proposals for a DAO
|
|
130
131
|
|
|
131
132
|
## Troubleshooting
|
|
132
133
|
|