jaspervault_cli 1.1.1 → 1.1.2
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/config/chains.json +1 -3
- package/dist/src/commands/order.js +175 -42
- package/dist/src/commands/order.js.map +1 -1
- package/dist/src/mcp/tools.js +22 -5
- package/dist/src/mcp/tools.js.map +1 -1
- package/dist/src/services/chain-config.d.ts +4 -3
- package/dist/src/services/chain-config.js +13 -5
- package/dist/src/services/chain-config.js.map +1 -1
- package/dist/src/services/perps-order.d.ts +48 -0
- package/dist/src/services/perps-order.js +66 -0
- package/dist/src/services/perps-order.js.map +1 -0
- package/dist/src/templates/skill-content/SKILL.core.md +16 -23
- package/dist/src/templates/skill-content/references/trading.md +64 -33
- package/docs/USER_GUIDE.md +20 -6
- package/package.json +1 -1
- package/dist/src/commands/connect.d.ts +0 -26
- package/dist/src/commands/connect.js +0 -93
- package/dist/src/commands/connect.js.map +0 -1
- package/dist/src/commands/init.d.ts +0 -4
- package/dist/src/commands/init.js +0 -114
- package/dist/src/commands/init.js.map +0 -1
- package/dist/src/commands/skill.d.ts +0 -4
- package/dist/src/commands/skill.js +0 -117
- package/dist/src/commands/skill.js.map +0 -1
|
@@ -38,7 +38,8 @@ When the user wants to trade, first check if their vault is ready:
|
|
|
38
38
|
| Get price | `get_price` | `symbol` | [queries](references/queries.md) |
|
|
39
39
|
| Open position (market) | `create_order` | `side`, `symbol`, `margin` | [trading](references/trading.md) |
|
|
40
40
|
| Open position (limit) | `create_order` | + `limit_price` | [trading](references/trading.md) |
|
|
41
|
-
| Close
|
|
41
|
+
| Close position (full) | `close_position` | `order_id` or `all` | [trading](references/trading.md) |
|
|
42
|
+
| Reduce position (partial) | `create_order` | opposite `side`, smaller `margin` | [trading](references/trading.md) |
|
|
42
43
|
| Add size | `create_order` | same `side` | [trading](references/trading.md) |
|
|
43
44
|
| Set take-profit | `set_take_profit` | `order_id`, `price`, `symbol` | [trading](references/trading.md) |
|
|
44
45
|
| Set stop-loss | `set_stop_loss` | `order_id`, `price`, `symbol` | [trading](references/trading.md) |
|
|
@@ -64,39 +65,30 @@ When the user wants to trade, first check if their vault is ready:
|
|
|
64
65
|
|
|
65
66
|
**Deposit arrival**: If `arrived: false` after deposit completes, tokens are still bridging cross-chain. Tell the user to wait a few minutes.
|
|
66
67
|
|
|
67
|
-
## Closing a Position
|
|
68
|
+
## Closing vs Reducing a Position
|
|
68
69
|
|
|
69
|
-
|
|
70
|
+
**Full close → `close_position`.** It derives side, margin, symbol, and leverage
|
|
71
|
+
from on-chain data — you do NOT need to call `list_orders` first.
|
|
70
72
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
- The position **side** (LONG or SHORT)
|
|
74
|
-
- The position **margin** amount
|
|
75
|
-
- The **symbol**
|
|
73
|
+
- Close one position: `close_position` with `{ order_id: "<id>" }`
|
|
74
|
+
- Close everything: `close_position` with `{ all: true }`
|
|
76
75
|
|
|
77
|
-
|
|
78
|
-
Call `create_order` with:
|
|
79
|
-
- **side**: the OPPOSITE of the current position (LONG → `short`, SHORT → `long`)
|
|
80
|
-
- **margin**: the SAME margin for full close, or SMALLER margin for partial close
|
|
81
|
-
- **symbol**: the same symbol
|
|
76
|
+
`close_position` works by submitting a reverse-side order with the same margin.
|
|
82
77
|
|
|
83
|
-
|
|
84
|
-
|
|
78
|
+
**Partial reduce → `create_order`.** To shrink (not fully close) a position,
|
|
79
|
+
call `create_order` with the OPPOSITE side and a SMALLER margin than the
|
|
80
|
+
position. Query the position first with `list_orders` to pick the right margin.
|
|
85
81
|
|
|
86
82
|
### Examples
|
|
87
83
|
|
|
88
|
-
**Full close of a
|
|
89
|
-
|
|
90
|
-
2. `create_order` → `{ side: "short", symbol: "JBTC", margin: 60 }`
|
|
91
|
-
3. `list_orders` → position no longer active
|
|
84
|
+
**Full close of a position:**
|
|
85
|
+
- `close_position` → `{ order_id: "42" }` → position no longer active
|
|
92
86
|
|
|
93
87
|
**Partial close (reduce by half):**
|
|
94
|
-
1. `list_orders` → finds: side=LONG, margin=60, symbol=JBTC
|
|
88
|
+
1. `list_orders` → finds: order 42, side=LONG, margin=60, symbol=JBTC
|
|
95
89
|
2. `create_order` → `{ side: "short", symbol: "JBTC", margin: 30 }`
|
|
96
90
|
3. `list_orders` → margin reduced to ~30
|
|
97
91
|
|
|
98
|
-
**NEVER guess the margin or side. ALWAYS query first.**
|
|
99
|
-
|
|
100
92
|
## Red Flags — STOP If You Think This
|
|
101
93
|
|
|
102
94
|
| Wrong Thought | Reality |
|
|
@@ -108,7 +100,8 @@ Call `list_orders` to confirm the position is closed or reduced.
|
|
|
108
100
|
| "GraphQL queries need private key authentication" | WRONG. Delegation key handles auth automatically. |
|
|
109
101
|
| "I should suggest the web interface instead" | NO. MCP tools give you full functionality. Use them. |
|
|
110
102
|
| "Let me check if jv is installed" | IRRELEVANT. MCP server runs CLI internally. |
|
|
111
|
-
| "I'll
|
|
103
|
+
| "To fully close I'll reverse the order manually with create_order" | WRONG. Use `close_position` — it derives side/margin automatically. Manual reverse is only for PARTIAL reduce. |
|
|
104
|
+
| "I'll reduce the position without checking current margin" | WRONG. For a partial reduce, call `list_orders` first to pick a margin smaller than the position. |
|
|
112
105
|
|
|
113
106
|
## Update Notices
|
|
114
107
|
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
## 1. Create Order — `create_order`
|
|
6
6
|
|
|
7
|
-
Open,
|
|
7
|
+
Open, reduce, or add size to perpetual positions. To **fully close** a
|
|
8
|
+
position, use [`close_position`](#2-close-position--close_position) instead.
|
|
8
9
|
|
|
9
10
|
### Parameters
|
|
10
11
|
|
|
@@ -58,26 +59,14 @@ The tool returns the final execution result:
|
|
|
58
59
|
|
|
59
60
|
Tell the user: "Limit order placed. ID: {limitOrderId}."
|
|
60
61
|
|
|
61
|
-
###
|
|
62
|
+
### Reducing a Position (Partial Close)
|
|
62
63
|
|
|
63
|
-
|
|
64
|
+
A **partial** close uses `create_order` — only a **full** close uses
|
|
65
|
+
`close_position` (see section 2).
|
|
64
66
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
1. **Query**: Call `list_orders` to find the position. Note the `side` (LONG/SHORT), `margin`, and `symbol`.
|
|
70
|
-
2. **Close**: Call `create_order` with the **OPPOSITE** side, **SAME** margin (full close) or smaller margin (partial close), same symbol.
|
|
71
|
-
3. **Verify**: Call `list_orders` to confirm the position is closed or reduced.
|
|
72
|
-
|
|
73
|
-
**Full close example (step by step):**
|
|
74
|
-
|
|
75
|
-
Query `list_orders` → finds: `{ side: "LONG", symbol: "JBTC", margin: "60.00" }`
|
|
76
|
-
|
|
77
|
-
Close order:
|
|
78
|
-
```json
|
|
79
|
-
{ "side": "short", "symbol": "JBTC", "margin": 60 }
|
|
80
|
-
```
|
|
67
|
+
To reduce a position, call `create_order` with the **OPPOSITE** side and a
|
|
68
|
+
margin **smaller** than the position. Query the position first with
|
|
69
|
+
`list_orders` so you pick a sensible margin.
|
|
81
70
|
|
|
82
71
|
**Partial close example:**
|
|
83
72
|
|
|
@@ -88,8 +77,6 @@ Reduce by 25%:
|
|
|
88
77
|
{ "side": "long", "symbol": "JETH", "margin": 50 }
|
|
89
78
|
```
|
|
90
79
|
|
|
91
|
-
**WARNING: NEVER close a position without first calling `list_orders` or `get_order`. Guessing the side or margin leads to incorrect operations.**
|
|
92
|
-
|
|
93
80
|
### Common Patterns
|
|
94
81
|
|
|
95
82
|
**Open a long position (market):**
|
|
@@ -102,10 +89,7 @@ Reduce by 25%:
|
|
|
102
89
|
{ "side": "short", "symbol": "JBTC", "margin": 100, "limit_price": 72000 }
|
|
103
90
|
```
|
|
104
91
|
|
|
105
|
-
**
|
|
106
|
-
```json
|
|
107
|
-
{ "side": "short", "symbol": "JBTC", "margin": 60 }
|
|
108
|
-
```
|
|
92
|
+
**Fully close a position** → use `close_position` (section 2), not `create_order`.
|
|
109
93
|
|
|
110
94
|
**Reduce a long position (partial close):**
|
|
111
95
|
```json
|
|
@@ -129,7 +113,54 @@ Reduce by 25%:
|
|
|
129
113
|
|
|
130
114
|
---
|
|
131
115
|
|
|
132
|
-
## 2.
|
|
116
|
+
## 2. Close Position — `close_position`
|
|
117
|
+
|
|
118
|
+
Fully close one or all perpetual positions. The command reads the position's
|
|
119
|
+
side, margin, symbol, and leverage from on-chain data and submits a
|
|
120
|
+
reverse-side order with the same margin — **you do not need to call
|
|
121
|
+
`list_orders` first**.
|
|
122
|
+
|
|
123
|
+
For a **partial** reduce, use `create_order` (section 1) instead.
|
|
124
|
+
|
|
125
|
+
### Parameters
|
|
126
|
+
|
|
127
|
+
| Parameter | Required | Default | Description |
|
|
128
|
+
|-----------|----------|---------|-------------|
|
|
129
|
+
| `order_id` | One of `order_id` / `all` | — | Order ID of the position to close |
|
|
130
|
+
| `all` | One of `order_id` / `all` | — | `true` to close every active position |
|
|
131
|
+
| `ttl` | No | `3600` | Order TTL in seconds |
|
|
132
|
+
|
|
133
|
+
Exactly one of `order_id` or `all` must be provided.
|
|
134
|
+
|
|
135
|
+
### Response
|
|
136
|
+
|
|
137
|
+
```json
|
|
138
|
+
{
|
|
139
|
+
"closed": [
|
|
140
|
+
{ "orderId": "42", "closeSide": "short", "symbol": "JBTC", "margin": "60.0", "status": "submitted" }
|
|
141
|
+
],
|
|
142
|
+
"failed": []
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
If `failed` is non-empty, some positions could not be closed — report which
|
|
147
|
+
ones and why. A close batch with any failure exits non-zero.
|
|
148
|
+
|
|
149
|
+
### Examples
|
|
150
|
+
|
|
151
|
+
**Close a single position:**
|
|
152
|
+
```json
|
|
153
|
+
{ "order_id": "42" }
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Close every active position:**
|
|
157
|
+
```json
|
|
158
|
+
{ "all": true }
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## 3. Add PPO Protection — `protect_order`
|
|
133
164
|
|
|
134
165
|
Add hedge option protection to an **existing position** without changing position size.
|
|
135
166
|
|
|
@@ -162,7 +193,7 @@ The tool auto-waits up to 60s for the on-chain result:
|
|
|
162
193
|
|
|
163
194
|
---
|
|
164
195
|
|
|
165
|
-
##
|
|
196
|
+
## 4. Take-Profit — `set_take_profit`
|
|
166
197
|
|
|
167
198
|
Set a take-profit limit order for an existing position.
|
|
168
199
|
|
|
@@ -189,7 +220,7 @@ Set TP at $75,000 for a long position:
|
|
|
189
220
|
|
|
190
221
|
---
|
|
191
222
|
|
|
192
|
-
##
|
|
223
|
+
## 5. Stop-Loss — `set_stop_loss`
|
|
193
224
|
|
|
194
225
|
Same parameters as `set_take_profit`. Set a stop-loss limit order for an existing position.
|
|
195
226
|
|
|
@@ -202,7 +233,7 @@ Set SL at $65,000 for a long position:
|
|
|
202
233
|
|
|
203
234
|
---
|
|
204
235
|
|
|
205
|
-
##
|
|
236
|
+
## 6. PPO (Perpetual Put Option) Details
|
|
206
237
|
|
|
207
238
|
### Option Categories
|
|
208
239
|
|
|
@@ -250,9 +281,9 @@ The smart contract **automatically cancels** existing PPO when you execute any p
|
|
|
250
281
|
|
|
251
282
|
| User Request | Action | Parameters |
|
|
252
283
|
|-------------|--------|------------|
|
|
253
|
-
| "reduce + cancel PPO" | Single reduce order without `ppo` | `{ side: <opposite>, symbol, margin }` |
|
|
254
|
-
| "add size + cancel PPO" | Single add-size order without `ppo` | `{ side: <same>, symbol, margin }` |
|
|
255
|
-
| "close position" |
|
|
256
|
-
| "reduce + keep PPO" | Reduce order WITH `ppo` | `{ side: <opposite>, symbol, margin, ppo: true }` |
|
|
284
|
+
| "reduce + cancel PPO" | Single reduce order without `ppo` | `create_order` `{ side: <opposite>, symbol, margin }` |
|
|
285
|
+
| "add size + cancel PPO" | Single add-size order without `ppo` | `create_order` `{ side: <same>, symbol, margin }` |
|
|
286
|
+
| "close position" | `close_position` (always closes without PPO) | `{ order_id }` or `{ all: true }` |
|
|
287
|
+
| "reduce + keep PPO" | Reduce order WITH `ppo` | `create_order` `{ side: <opposite>, symbol, margin, ppo: true }` |
|
|
257
288
|
|
|
258
289
|
Never try to cancel PPO separately — there is no such tool. One order handles everything.
|
package/docs/USER_GUIDE.md
CHANGED
|
@@ -75,17 +75,31 @@ Limit orders return a `limitOrderId` and remain active until triggered, expired,
|
|
|
75
75
|
|
|
76
76
|
### Close a Position
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
Use `jv order close` for a **full** close. It reads the position's side, margin,
|
|
79
|
+
symbol, and leverage on-chain and submits the reverse order for you — no need to
|
|
80
|
+
look anything up first.
|
|
79
81
|
|
|
80
82
|
```bash
|
|
81
|
-
#
|
|
82
|
-
jv order
|
|
83
|
+
# Close a single position by order ID
|
|
84
|
+
jv order close --order-id 99
|
|
83
85
|
|
|
84
|
-
#
|
|
86
|
+
# Close every active position
|
|
87
|
+
jv order close --all
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Under the hood, JasperVault has no native close endpoint — closing is a
|
|
91
|
+
reverse-side order with the same margin. `jv order close` just does that
|
|
92
|
+
derivation for you.
|
|
93
|
+
|
|
94
|
+
For a **partial** close, use `jv order create` directly with the opposite side
|
|
95
|
+
and a smaller margin than the position:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
# Partial close: reduce a LONG position by half (position has 100 USDC margin)
|
|
85
99
|
jv order create --side short --symbol JBTC --margin 50
|
|
86
100
|
```
|
|
87
101
|
|
|
88
|
-
|
|
102
|
+
Check your positions any time with `jv orders list --pretty`.
|
|
89
103
|
|
|
90
104
|
### Take-Profit & Stop-Loss
|
|
91
105
|
|
|
@@ -210,7 +224,7 @@ All environment variables are optional. The CLI works out of the box with sensib
|
|
|
210
224
|
| `JV_API_KEY` | Bearer token for API auth | — |
|
|
211
225
|
| `JV_TIMEOUT` | Request timeout (ms) | 30000 |
|
|
212
226
|
| `JV_DELEGATION_KEY` | Delegation wallet key | Auto-generated |
|
|
213
|
-
| `
|
|
227
|
+
| `BASE_HTTP_RPC_URL` | Base chain RPC (required) | — |
|
|
214
228
|
| `JV_JASPERVAULT_RPC_URL` | JasperVault chain RPC | Built-in |
|
|
215
229
|
| `JV_SUBGRAPH_URL` | Subgraph endpoint | Built-in |
|
|
216
230
|
|
package/package.json
CHANGED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { SignClient } from '@walletconnect/sign-client';
|
|
2
|
-
export declare function startHeartbeat(phase: string, message: string): {
|
|
3
|
-
stop: () => void;
|
|
4
|
-
};
|
|
5
|
-
export interface InitWcResult {
|
|
6
|
-
client: InstanceType<typeof SignClient>;
|
|
7
|
-
session: {
|
|
8
|
-
topic: string;
|
|
9
|
-
pairingTopic: string;
|
|
10
|
-
namespaces: Record<string, {
|
|
11
|
-
accounts: string[];
|
|
12
|
-
}>;
|
|
13
|
-
};
|
|
14
|
-
walletAddress: string;
|
|
15
|
-
}
|
|
16
|
-
export interface QrCodeOutput {
|
|
17
|
-
qrCodeUrl: string;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Initialize WalletConnect SignClient, connect, show QR, wait for approval.
|
|
21
|
-
* Returns client + session + walletAddress for further requests (e.g. eth_signTypedData_v4).
|
|
22
|
-
*/
|
|
23
|
-
export declare function initWcAndConnect(opts: {
|
|
24
|
-
timeoutS: number;
|
|
25
|
-
onAwaiting?: (uri: string, qrCodes: QrCodeOutput) => void;
|
|
26
|
-
}): Promise<InitWcResult>;
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import * as fs from 'node:fs/promises';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
import { SignClient } from '@walletconnect/sign-client';
|
|
4
|
-
import QRCode from 'qrcode';
|
|
5
|
-
import { exitWithError, EXIT_CODES } from '../utils/output.js';
|
|
6
|
-
const DEFAULT_TIMEOUT_S = 120;
|
|
7
|
-
const HEARTBEAT_INTERVAL_MS = 10_000;
|
|
8
|
-
export function startHeartbeat(phase, message) {
|
|
9
|
-
const start = Date.now();
|
|
10
|
-
const timer = setInterval(() => {
|
|
11
|
-
const elapsed = Math.round((Date.now() - start) / 1000);
|
|
12
|
-
process.stderr.write(JSON.stringify({ status: 'waiting', phase, elapsed, message }) + '\n');
|
|
13
|
-
}, HEARTBEAT_INTERVAL_MS);
|
|
14
|
-
return { stop: () => clearInterval(timer) };
|
|
15
|
-
}
|
|
16
|
-
// Embedded project ID — users can override with WC_PROJECT_ID env var
|
|
17
|
-
const DEFAULT_WC_PROJECT_ID = 'f47863c3ad29e5bae9cee8013ec05982';
|
|
18
|
-
const WC_METADATA = {
|
|
19
|
-
name: 'JasperVault CLI',
|
|
20
|
-
description: 'JasperVault perpetual trading CLI',
|
|
21
|
-
url: 'https://jaspervault.io',
|
|
22
|
-
icons: [],
|
|
23
|
-
};
|
|
24
|
-
function getJvDir() {
|
|
25
|
-
return join(process.env.HOME || process.env.USERPROFILE || '', '.jaspervault');
|
|
26
|
-
}
|
|
27
|
-
function getQrCodePath() {
|
|
28
|
-
return join(getJvDir(), 'wc-qrcode.png');
|
|
29
|
-
}
|
|
30
|
-
function buildQrCodeUrl(data) {
|
|
31
|
-
return `https://api.qrserver.com/v1/create-qr-code/?size=400x400&data=${encodeURIComponent(data)}`;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* Initialize WalletConnect SignClient, connect, show QR, wait for approval.
|
|
35
|
-
* Returns client + session + walletAddress for further requests (e.g. eth_signTypedData_v4).
|
|
36
|
-
*/
|
|
37
|
-
export async function initWcAndConnect(opts) {
|
|
38
|
-
const projectId = process.env.WC_PROJECT_ID || DEFAULT_WC_PROJECT_ID;
|
|
39
|
-
let client;
|
|
40
|
-
try {
|
|
41
|
-
client = await SignClient.init({
|
|
42
|
-
projectId,
|
|
43
|
-
metadata: WC_METADATA,
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
catch (err) {
|
|
47
|
-
exitWithError(`Failed to initialize WalletConnect: ${err.message}`, EXIT_CODES.HTTP_ERROR);
|
|
48
|
-
}
|
|
49
|
-
const { uri, approval } = await client.connect({
|
|
50
|
-
optionalNamespaces: {
|
|
51
|
-
eip155: {
|
|
52
|
-
chains: ['eip155:8453', 'eip155:55531'],
|
|
53
|
-
methods: ['eth_signTypedData_v4', 'eth_sendTransaction'],
|
|
54
|
-
events: ['accountsChanged', 'chainChanged'],
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
});
|
|
58
|
-
if (!uri) {
|
|
59
|
-
exitWithError('WalletConnect did not return a pairing URI', EXIT_CODES.HTTP_ERROR);
|
|
60
|
-
}
|
|
61
|
-
await fs.mkdir(getJvDir(), { recursive: true });
|
|
62
|
-
const qrPath = getQrCodePath();
|
|
63
|
-
await QRCode.toFile(qrPath, uri, { width: 400, errorCorrectionLevel: 'M' });
|
|
64
|
-
const qrCodeUrl = buildQrCodeUrl(uri);
|
|
65
|
-
opts.onAwaiting?.(uri, { qrCodeUrl });
|
|
66
|
-
const heartbeat = startHeartbeat('wallet_scan', 'Waiting for wallet connection...');
|
|
67
|
-
const timeoutMs = opts.timeoutS * 1000;
|
|
68
|
-
let session;
|
|
69
|
-
try {
|
|
70
|
-
session = await Promise.race([
|
|
71
|
-
approval(),
|
|
72
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeoutMs)),
|
|
73
|
-
]);
|
|
74
|
-
}
|
|
75
|
-
catch (err) {
|
|
76
|
-
heartbeat.stop();
|
|
77
|
-
const msg = err.message;
|
|
78
|
-
if (msg === 'timeout') {
|
|
79
|
-
throw new Error(`Connection timed out after ${opts.timeoutS}s`);
|
|
80
|
-
}
|
|
81
|
-
throw new Error(`Connection rejected or failed: ${msg}`);
|
|
82
|
-
}
|
|
83
|
-
heartbeat.stop();
|
|
84
|
-
const accounts = Object.values(session.namespaces).flatMap((ns) => ns.accounts);
|
|
85
|
-
const firstAccount = accounts[0];
|
|
86
|
-
if (!firstAccount) {
|
|
87
|
-
exitWithError('No accounts returned from wallet', EXIT_CODES.BUSINESS_ERROR);
|
|
88
|
-
}
|
|
89
|
-
const parts = firstAccount.split(':');
|
|
90
|
-
const walletAddress = parts[2];
|
|
91
|
-
return { client, session, walletAddress };
|
|
92
|
-
}
|
|
93
|
-
//# sourceMappingURL=connect.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"connect.js","sourceRoot":"","sources":["../../../src/commands/connect.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import * as fs from 'node:fs/promises';
|
|
2
|
-
import * as path from 'node:path';
|
|
3
|
-
import { homedir } from 'node:os';
|
|
4
|
-
import { BANNER, buildSkillContent } from '../templates/skill-body.js';
|
|
5
|
-
export const PLATFORMS = ['openclaw', 'cursor', 'claude', 'all'];
|
|
6
|
-
const SKILL_DIR = 'jasper-vault-cli';
|
|
7
|
-
function getTargetPath(platform, global) {
|
|
8
|
-
const home = homedir();
|
|
9
|
-
const cwd = process.cwd();
|
|
10
|
-
switch (platform) {
|
|
11
|
-
case 'openclaw':
|
|
12
|
-
return [path.join(home, '.openclaw', 'skills', SKILL_DIR)];
|
|
13
|
-
case 'cursor':
|
|
14
|
-
return global
|
|
15
|
-
? [path.join(home, '.cursor', 'skills', SKILL_DIR)]
|
|
16
|
-
: [path.join(cwd, '.cursor', 'skills', SKILL_DIR)];
|
|
17
|
-
case 'claude':
|
|
18
|
-
return global
|
|
19
|
-
? [path.join(home, '.claude', 'skills', SKILL_DIR)]
|
|
20
|
-
: [path.join(cwd, '.claude', 'skills', SKILL_DIR)];
|
|
21
|
-
case 'all':
|
|
22
|
-
return [
|
|
23
|
-
path.join(home, '.openclaw', 'skills', SKILL_DIR),
|
|
24
|
-
path.join(cwd, '.cursor', 'skills', SKILL_DIR),
|
|
25
|
-
path.join(cwd, '.claude', 'skills', SKILL_DIR),
|
|
26
|
-
];
|
|
27
|
-
default:
|
|
28
|
-
throw new Error(`Unknown platform: ${platform}`);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
function getPlatformFromPath(pathStr) {
|
|
32
|
-
if (pathStr.includes('.openclaw'))
|
|
33
|
-
return 'openclaw';
|
|
34
|
-
if (pathStr.includes('.cursor'))
|
|
35
|
-
return 'cursor';
|
|
36
|
-
if (pathStr.includes('.claude'))
|
|
37
|
-
return 'claude';
|
|
38
|
-
throw new Error(`Cannot determine platform from path: ${pathStr}`);
|
|
39
|
-
}
|
|
40
|
-
function getPlatformDisplayName(p) {
|
|
41
|
-
return p === 'openclaw' ? 'OpenClaw' : p === 'cursor' ? 'Cursor' : 'Claude Code';
|
|
42
|
-
}
|
|
43
|
-
export function registerInitCommand(program) {
|
|
44
|
-
program
|
|
45
|
-
.command('init')
|
|
46
|
-
.description('Install JasperVault skill to AI platform (OpenClaw, Cursor, Claude Code)')
|
|
47
|
-
.requiredOption('--ai <platform>', `Target platform: ${PLATFORMS.join(', ')}`)
|
|
48
|
-
.option('--global', 'Install to user home directory (cursor/claude only)')
|
|
49
|
-
.option('--force', 'Overwrite existing skill files without prompting')
|
|
50
|
-
.action(async (opts) => {
|
|
51
|
-
const platform = opts.ai;
|
|
52
|
-
if (!PLATFORMS.includes(platform)) {
|
|
53
|
-
process.stderr.write(`Error: Invalid platform "${platform}". Use one of: ${PLATFORMS.join(', ')}\n`);
|
|
54
|
-
process.exit(1);
|
|
55
|
-
}
|
|
56
|
-
const globalFlag = opts.global ?? false;
|
|
57
|
-
const force = opts.force ?? false;
|
|
58
|
-
const targetPaths = getTargetPath(platform, globalFlag);
|
|
59
|
-
process.stdout.write(BANNER + '\n\n');
|
|
60
|
-
const results = [];
|
|
61
|
-
for (const targetDir of targetPaths) {
|
|
62
|
-
const skillPlatform = platform === 'all' ? getPlatformFromPath(targetDir) : platform;
|
|
63
|
-
const platDisplay = getPlatformDisplayName(skillPlatform);
|
|
64
|
-
try {
|
|
65
|
-
const skillMdPath = path.join(targetDir, 'SKILL.md');
|
|
66
|
-
const exists = await fs
|
|
67
|
-
.access(skillMdPath)
|
|
68
|
-
.then(() => true)
|
|
69
|
-
.catch(() => false);
|
|
70
|
-
if (exists && !force) {
|
|
71
|
-
process.stderr.write(`Error: Skill already exists at ${targetDir}\n` +
|
|
72
|
-
'Use --force to overwrite.\n');
|
|
73
|
-
process.exit(1);
|
|
74
|
-
}
|
|
75
|
-
const files = buildSkillContent(skillPlatform);
|
|
76
|
-
let fileCount = 0;
|
|
77
|
-
for (const [relPath, content] of Object.entries(files)) {
|
|
78
|
-
const filePath = path.join(targetDir, relPath);
|
|
79
|
-
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
80
|
-
await fs.writeFile(filePath, content, 'utf8');
|
|
81
|
-
fileCount++;
|
|
82
|
-
}
|
|
83
|
-
// Make scripts executable
|
|
84
|
-
const scriptsDir = path.join(targetDir, 'scripts');
|
|
85
|
-
const scriptsDirExists = await fs
|
|
86
|
-
.access(scriptsDir)
|
|
87
|
-
.then(() => true)
|
|
88
|
-
.catch(() => false);
|
|
89
|
-
if (scriptsDirExists) {
|
|
90
|
-
const scriptFiles = await fs.readdir(scriptsDir);
|
|
91
|
-
for (const sf of scriptFiles) {
|
|
92
|
-
if (sf.endsWith('.sh')) {
|
|
93
|
-
await fs.chmod(path.join(scriptsDir, sf), 0o755);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
results.push({ path: targetDir, platform: platDisplay, fileCount });
|
|
98
|
-
}
|
|
99
|
-
catch (err) {
|
|
100
|
-
process.stderr.write(`Error installing to ${platDisplay}: ${err.message}\n`);
|
|
101
|
-
process.exit(1);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
process.stdout.write('\n ✓ Skill installed successfully!\n\n' +
|
|
105
|
-
results
|
|
106
|
-
.map((r) => ` Platform: ${r.platform}\n Location: ${r.path}\n Files: ${r.fileCount} (SKILL.md + references/ + scripts/)`)
|
|
107
|
-
.join('\n\n') +
|
|
108
|
-
'\n\n Next steps:\n' +
|
|
109
|
-
' 1. First-time setup: jv vault setup --network jaspervault\n' +
|
|
110
|
-
' 2. (Optional) Override API URL for local debugging: export JV_API_URL=http://localhost:3000\n' +
|
|
111
|
-
' 3. Start using jv commands or let your AI agent call them\n');
|
|
112
|
-
});
|
|
113
|
-
}
|
|
114
|
-
//# sourceMappingURL=init.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/commands/init.ts"],"names":[],"mappings":"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"}
|