@sage-protocol/cli 0.3.10 → 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.
- package/dist/cli/commands/personal.js +96 -10
- package/dist/cli/mcp-setup.md +35 -34
- package/package.json +1 -1
|
@@ -2,6 +2,7 @@ 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');
|
|
@@ -734,6 +735,10 @@ async function myLicensesAction(opts = {}) {
|
|
|
734
735
|
console.log(JSON.stringify(results, null, 2));
|
|
735
736
|
} else if (results.length === 0) {
|
|
736
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>');
|
|
737
742
|
} else {
|
|
738
743
|
results.forEach((item) => {
|
|
739
744
|
console.log(`🧾 ${item.receiptIdHex} — balance ${item.balance}`);
|
|
@@ -897,6 +902,32 @@ async function accessAction(creator, key, opts) {
|
|
|
897
902
|
|
|
898
903
|
let encryptedCid = resource?.encryptedCid || null;
|
|
899
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
|
+
|
|
900
931
|
if (!encryptedCid && opts.encryptedCid) {
|
|
901
932
|
encryptedCid = String(opts.encryptedCid);
|
|
902
933
|
}
|
|
@@ -912,9 +943,12 @@ async function accessAction(creator, key, opts) {
|
|
|
912
943
|
if (encryptedPayload && looksLikeCid(encryptedPayload)) {
|
|
913
944
|
try {
|
|
914
945
|
const resp = await axios.get(`${gateway}${encryptedPayload}`, { timeout: 10000 });
|
|
946
|
+
if (resp.status !== 200) {
|
|
947
|
+
throw new Error(`Status ${resp.status}`);
|
|
948
|
+
}
|
|
915
949
|
encryptedPayload = resp.data;
|
|
916
950
|
} catch (error) {
|
|
917
|
-
|
|
951
|
+
throw new Error(`Failed to fetch encrypted payload from IPFS via ${gateway}: ${error.message}`);
|
|
918
952
|
}
|
|
919
953
|
}
|
|
920
954
|
|
|
@@ -963,15 +997,66 @@ async function accessAction(creator, key, opts) {
|
|
|
963
997
|
}
|
|
964
998
|
}
|
|
965
999
|
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
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
|
+
}
|
|
975
1060
|
|
|
976
1061
|
if (opts.out) {
|
|
977
1062
|
outputPath = path.resolve(opts.out);
|
|
@@ -1112,6 +1197,7 @@ function register(program) {
|
|
|
1112
1197
|
.option('--out <file>', 'Write decrypted output to file')
|
|
1113
1198
|
.option('--skip-decrypt', 'Skip decryption and only report license status')
|
|
1114
1199
|
.option('--encrypted-cid <cid>', 'Override encrypted CID')
|
|
1200
|
+
.option('--manifest <cid>', 'Manifest CID to fetch encrypted content info from IPFS')
|
|
1115
1201
|
.option('--json', 'Emit machine-readable JSON report', false)
|
|
1116
1202
|
.action((creator, key, opts) => accessAction(creator, key, opts).catch((err) => { console.error(err.message); process.exit(1); }));
|
|
1117
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
|
|