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.
@@ -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/reduce position | `create_order` | opposite `side` | [trading](references/trading.md) |
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 — MANDATORY STEPS
68
+ ## Closing vs Reducing a Position
68
69
 
69
- Closing a position is the most error-prone operation. Follow these steps exactly:
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
- ### Step 1: Query the current position
72
- Call `list_orders` (or `get_order` if you have the order ID) to get:
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
- ### Step 2: Create the closing order
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
- ### Step 3: Verify
84
- Call `list_orders` to confirm the position is closed or reduced.
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 LONG position:**
89
- 1. `list_orders` → finds: side=LONG, margin=60, symbol=JBTC
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 close the position without checking current margin" | WRONG. Always call `list_orders` first to get the exact side and margin before closing. |
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, close, reduce, or add size to perpetual positions.
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
- ### Closing a Position MANDATORY STEPS
62
+ ### Reducing a Position (Partial Close)
62
63
 
63
- Closing a position means creating a reverse order. You **MUST** query the current position first.
64
+ A **partial** close uses `create_order` only a **full** close uses
65
+ `close_position` (see section 2).
64
66
 
65
- **Why query first?** The margin amount must match the current position for a full close. Guessing wrong leads to partial closes or over-allocation.
66
-
67
- **Required flow:**
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
- **Close a long position (use opposite side with same margin):**
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. Add PPO Protection — `protect_order`
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
- ## 3. Take-Profit — `set_take_profit`
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
- ## 4. Stop-Loss — `set_stop_loss`
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
- ## 5. PPO (Perpetual Put Option) Details
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" | Close order without `ppo` | `{ side: <opposite>, symbol, margin: <full> }` |
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.
@@ -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
- To close, create an order with the **opposite side** and the **same margin** as your existing position.
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
- # Full close: if your position is LONG with 100 USDC margin
82
- jv order create --side short --symbol JBTC --margin 100
83
+ # Close a single position by order ID
84
+ jv order close --order-id 99
83
85
 
84
- # Partial close: reduce by half
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
- Always check your current position first with `jv orders list --pretty` to confirm the exact side and margin.
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
- | `JV_BASE_RPC_URL` | Base chain RPC | Built-in |
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,6 +1,6 @@
1
1
  {
2
2
  "name": "jaspervault_cli",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "description": "JasperVault CLI for interacting with the JasperVault Manager API",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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,4 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare const PLATFORMS: readonly ["openclaw", "cursor", "claude", "all"];
3
- export type Platform = (typeof PLATFORMS)[number];
4
- export declare function registerInitCommand(program: Command): void;
@@ -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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"}
@@ -1,4 +0,0 @@
1
- import { Command } from 'commander';
2
- export declare const PLATFORMS: readonly ["openclaw", "cursor", "claude", "all"];
3
- export type Platform = (typeof PLATFORMS)[number];
4
- export declare function registerSkillCommand(program: Command): void;