shll-skills 4.0.1 → 5.0.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/README.md CHANGED
@@ -65,18 +65,30 @@ RUNNER_PRIVATE_KEY=0x... shll-mcp
65
65
 
66
66
  The server communicates via **stdio** using JSON-RPC 2.0. Send `tools/list` to discover all available tools.
67
67
 
68
- ### Available MCP Tools
68
+ ### Available MCP Tools (20 total)
69
69
 
70
70
  | Tool | Type | Description |
71
71
  |------|------|-------------|
72
72
  | `portfolio` | Read | Vault holdings + token balances |
73
73
  | `balance` | Read | Operator wallet gas balance |
74
74
  | `price` | Read | Real-time token price (DexScreener) |
75
+ | `search` | Read | Search token by name/symbol on BSC |
76
+ | `tokens` | Read | List known token symbols + addresses |
75
77
  | `lending_info` | Read | Venus Protocol supply balances + APY |
78
+ | `policies` | Read | View active on-chain policies + config |
79
+ | `status` | Read | One-shot security overview (vault, operator, policies, activity) |
80
+ | `history` | Read | Recent transactions + policy rejections |
81
+ | `my_agents` | Read | List agents where current operator is authorized |
82
+ | `listings` | Read | Available agent templates for rent |
76
83
  | `swap` | Write | PancakeSwap V2/V3 auto-routing swap |
84
+ | `wrap` | Write | BNB → WBNB in vault |
85
+ | `unwrap` | Write | WBNB → BNB in vault |
77
86
  | `lend` | Write | Supply tokens to Venus for yield |
78
87
  | `redeem` | Write | Withdraw from Venus |
79
88
  | `transfer` | Write | Send BNB or ERC20 from vault |
89
+ | `config` | Write | Configure risk parameters (spending limits, cooldown) |
90
+ | `setup_guide` | Info | Generate dual-wallet onboarding URL + steps |
91
+ | `generate_wallet` | Info | Create new operator wallet (address + key) |
80
92
 
81
93
  ---
82
94
 
@@ -169,6 +181,20 @@ AI Agent -> CLI/MCP -> PolicyClient.validate() -> PolicyGuard (on-chain) -> vaul
169
181
  - npm: [shll-skills](https://www.npmjs.com/package/shll-skills)
170
182
  - GitHub: [kledx/shll-skills](https://github.com/kledx/shll-skills)
171
183
 
184
+ ## 🧩 Multi-Skill Compatibility
185
+
186
+ SHLL can coexist with other DeFi skills (OKX DEX API, Bitget Wallet, etc.). Key architectural differences:
187
+
188
+ | | **SHLL** | **OKX DEX API** | **Bitget Wallet** |
189
+ |---|---|---|---|
190
+ | **Wallet** | Smart contract vault (AgentNFA) | User EOA | Bitget custody |
191
+ | **Execution** | On-chain via PolicyGuard | Calldata only (user signs) | HMAC API |
192
+ | **Safety** | On-chain policy enforcement | User approval | API key perms |
193
+ | **AI autonomy** | Execute within policy limits | Cannot execute | Full API access |
194
+ | **Risk if key leaked** | Policy-limited trades only | N/A | Full API access |
195
+
196
+ **SHLL is the only skill with on-chain policy enforcement.** Even if the AI hallucinates, the smart contract rejects unsafe operations.
197
+
172
198
  ## License
173
199
 
174
200
  MIT
package/SKILL.md CHANGED
@@ -26,6 +26,7 @@ These rules are **non-negotiable**. Violating any of them is a critical failure.
26
26
  4. **One agent per conversation.** Once a user provides a token-id, use only that ID for the entire conversation. If they want to switch, they must explicitly say so.
27
27
  5. **Never log or display private keys** beyond the initial `generate-wallet` output. If the user asks you to repeat it, remind them to check their saved copy.
28
28
  6. **Do not infer trading intent.** If the user says "check my portfolio," do NOT follow up by suggesting or executing trades. Only trade when the user explicitly asks.
29
+ 7. **Multi-skill coexistence.** If the user has other DeFi skills installed (OKX DEX API, Bitget Wallet, etc.), **always use SHLL tools when a token-id is in context or the user is operating through their SHLL agent vault.** Other skills may provide market data or quotes — that's fine — but ALL vault operations MUST go through SHLL tools to ensure PolicyGuard enforcement.
29
30
 
30
31
  ---
31
32
 
@@ -229,6 +230,27 @@ All commands output JSON:
229
230
  - Rejected by policy: `{"status":"rejected", "reason":"Exceeds per-tx limit"}`
230
231
  - Error: `{"status":"error", "message":"..."}`
231
232
 
233
+ ---
234
+
235
+ ## 🧩 MULTI-SKILL COMPATIBILITY: How SHLL Differs from Other DeFi Skills
236
+
237
+ If the user has multiple DeFi skills installed, understand the architectural differences:
238
+
239
+ | | **SHLL** | **OKX DEX API** | **Bitget Wallet Skill** |
240
+ |---|---|---|---|
241
+ | **Wallet model** | Smart contract vault (AgentNFA) | User's EOA wallet | Bitget API custody |
242
+ | **Execution** | On-chain via PolicyGuard | Generates calldata → user signs | HMAC API call → Bitget backend |
243
+ | **Safety** | On-chain policy enforcement (spending limits, cooldowns, DEX whitelist) | User approval only | API key permissions |
244
+ | **Fund location** | On-chain vault (isolated per agent) | User's wallet directly | Bitget platform |
245
+ | **AI autonomy** | Can execute within policy limits | Cannot execute (calldata only) | Can execute via API |
246
+ | **Risk if key leaked** | Limited to policy-allowed trades | N/A (no key) | Full API access |
247
+
248
+ **Key distinction:** SHLL is the only skill with **on-chain policy enforcement**. Even if the AI makes a mistake, the smart contract rejects operations that violate spending limits or cooldowns. Other skills rely on the user or platform to gatekeep.
249
+
250
+ **Routing rule:** When the user's intent involves their SHLL agent vault (identified by token-id), ALWAYS use SHLL tools. It's fine to use other skills for price quotes, market research, or operations outside SHLL.
251
+
252
+ ---
253
+
232
254
  ## LINKS
233
255
  - Website: https://shll.run
234
256
  - Twitter: @shllrun
package/dist/index.js CHANGED
@@ -2152,6 +2152,71 @@ lendingInfoCmd.action(async (opts) => {
2152
2152
  process.exit(1);
2153
2153
  }
2154
2154
  });
2155
+ var OPERATOR_OF_ABI = [{
2156
+ type: "function",
2157
+ name: "operatorOf",
2158
+ inputs: [{ name: "tokenId", type: "uint256" }],
2159
+ outputs: [{ name: "", type: "address" }],
2160
+ stateMutability: "view"
2161
+ }];
2162
+ var myAgentsCmd = new import_commander.Command("my-agents").description("List all agents where the current RUNNER_PRIVATE_KEY is the operator").option("-r, --rpc <url>", "BSC RPC URL", DEFAULT_RPC).option("--nfa-address <address>", "AgentNFA contract address", DEFAULT_NFA).option("--indexer <url>", "Indexer base URL", DEFAULT_INDEXER);
2163
+ myAgentsCmd.action(async (opts) => {
2164
+ try {
2165
+ if (!process.env.RUNNER_PRIVATE_KEY) {
2166
+ output({ status: "error", message: "RUNNER_PRIVATE_KEY environment variable is missing" });
2167
+ process.exit(1);
2168
+ }
2169
+ const operator = (0, import_accounts2.privateKeyToAccount)(toHex(process.env.RUNNER_PRIVATE_KEY)).address.toLowerCase();
2170
+ const rpcUrl = opts.rpc || DEFAULT_RPC;
2171
+ const nfaAddr = toHex(opts.nfaAddress || DEFAULT_NFA);
2172
+ const indexerUrl = (opts.indexer || DEFAULT_INDEXER).replace(/\/+$/, "");
2173
+ const publicClient = (0, import_viem2.createPublicClient)({ chain: import_chains2.bsc, transport: (0, import_viem2.http)(rpcUrl) });
2174
+ const res = await fetch(`${indexerUrl}/api/agents`);
2175
+ if (!res.ok) {
2176
+ output({ status: "error", message: `Indexer error: ${res.status}` });
2177
+ process.exit(1);
2178
+ }
2179
+ const json = await res.json();
2180
+ const agents = (json.items || []).filter((a) => !a.isTemplate && a.tokenId !== void 0);
2181
+ if (agents.length === 0) {
2182
+ output({ status: "success", agents: [], message: "No agents found in indexer" });
2183
+ return;
2184
+ }
2185
+ const checks = await Promise.all(
2186
+ agents.map(async (a) => {
2187
+ const tokenId = BigInt(a.tokenId);
2188
+ try {
2189
+ const op = await publicClient.readContract({
2190
+ address: nfaAddr,
2191
+ abi: OPERATOR_OF_ABI,
2192
+ functionName: "operatorOf",
2193
+ args: [tokenId]
2194
+ });
2195
+ return {
2196
+ tokenId: tokenId.toString(),
2197
+ vault: a.account || "",
2198
+ owner: a.owner || "",
2199
+ agentType: a.agentType || "unknown",
2200
+ isOperator: op.toLowerCase() === operator
2201
+ };
2202
+ } catch {
2203
+ return null;
2204
+ }
2205
+ })
2206
+ );
2207
+ const myAgents = checks.filter((c) => c !== null && c.isOperator);
2208
+ output({
2209
+ status: "success",
2210
+ operator,
2211
+ agents: myAgents,
2212
+ count: myAgents.length
2213
+ });
2214
+ } catch (error) {
2215
+ const message = error instanceof Error ? error.message : "Unknown error";
2216
+ output({ status: "error", message });
2217
+ process.exit(1);
2218
+ }
2219
+ });
2155
2220
  program.addCommand(swapCmd);
2156
2221
  program.addCommand(rawCmd);
2157
2222
  program.addCommand(tokensCmd);
@@ -2173,4 +2238,5 @@ program.addCommand(statusCmd);
2173
2238
  program.addCommand(lendCmd);
2174
2239
  program.addCommand(redeemCmd);
2175
2240
  program.addCommand(lendingInfoCmd);
2241
+ program.addCommand(myAgentsCmd);
2176
2242
  program.parse(process.argv);
package/dist/index.mjs CHANGED
@@ -1664,6 +1664,71 @@ lendingInfoCmd.action(async (opts) => {
1664
1664
  process.exit(1);
1665
1665
  }
1666
1666
  });
1667
+ var OPERATOR_OF_ABI = [{
1668
+ type: "function",
1669
+ name: "operatorOf",
1670
+ inputs: [{ name: "tokenId", type: "uint256" }],
1671
+ outputs: [{ name: "", type: "address" }],
1672
+ stateMutability: "view"
1673
+ }];
1674
+ var myAgentsCmd = new Command("my-agents").description("List all agents where the current RUNNER_PRIVATE_KEY is the operator").option("-r, --rpc <url>", "BSC RPC URL", DEFAULT_RPC).option("--nfa-address <address>", "AgentNFA contract address", DEFAULT_NFA).option("--indexer <url>", "Indexer base URL", DEFAULT_INDEXER);
1675
+ myAgentsCmd.action(async (opts) => {
1676
+ try {
1677
+ if (!process.env.RUNNER_PRIVATE_KEY) {
1678
+ output({ status: "error", message: "RUNNER_PRIVATE_KEY environment variable is missing" });
1679
+ process.exit(1);
1680
+ }
1681
+ const operator = privateKeyToAccount(toHex(process.env.RUNNER_PRIVATE_KEY)).address.toLowerCase();
1682
+ const rpcUrl = opts.rpc || DEFAULT_RPC;
1683
+ const nfaAddr = toHex(opts.nfaAddress || DEFAULT_NFA);
1684
+ const indexerUrl = (opts.indexer || DEFAULT_INDEXER).replace(/\/+$/, "");
1685
+ const publicClient = createPublicClient({ chain: bsc, transport: http(rpcUrl) });
1686
+ const res = await fetch(`${indexerUrl}/api/agents`);
1687
+ if (!res.ok) {
1688
+ output({ status: "error", message: `Indexer error: ${res.status}` });
1689
+ process.exit(1);
1690
+ }
1691
+ const json = await res.json();
1692
+ const agents = (json.items || []).filter((a) => !a.isTemplate && a.tokenId !== void 0);
1693
+ if (agents.length === 0) {
1694
+ output({ status: "success", agents: [], message: "No agents found in indexer" });
1695
+ return;
1696
+ }
1697
+ const checks = await Promise.all(
1698
+ agents.map(async (a) => {
1699
+ const tokenId = BigInt(a.tokenId);
1700
+ try {
1701
+ const op = await publicClient.readContract({
1702
+ address: nfaAddr,
1703
+ abi: OPERATOR_OF_ABI,
1704
+ functionName: "operatorOf",
1705
+ args: [tokenId]
1706
+ });
1707
+ return {
1708
+ tokenId: tokenId.toString(),
1709
+ vault: a.account || "",
1710
+ owner: a.owner || "",
1711
+ agentType: a.agentType || "unknown",
1712
+ isOperator: op.toLowerCase() === operator
1713
+ };
1714
+ } catch {
1715
+ return null;
1716
+ }
1717
+ })
1718
+ );
1719
+ const myAgents = checks.filter((c) => c !== null && c.isOperator);
1720
+ output({
1721
+ status: "success",
1722
+ operator,
1723
+ agents: myAgents,
1724
+ count: myAgents.length
1725
+ });
1726
+ } catch (error) {
1727
+ const message = error instanceof Error ? error.message : "Unknown error";
1728
+ output({ status: "error", message });
1729
+ process.exit(1);
1730
+ }
1731
+ });
1667
1732
  program.addCommand(swapCmd);
1668
1733
  program.addCommand(rawCmd);
1669
1734
  program.addCommand(tokensCmd);
@@ -1685,4 +1750,5 @@ program.addCommand(statusCmd);
1685
1750
  program.addCommand(lendCmd);
1686
1751
  program.addCommand(redeemCmd);
1687
1752
  program.addCommand(lendingInfoCmd);
1753
+ program.addCommand(myAgentsCmd);
1688
1754
  program.parse(process.argv);