@sage-protocol/cli 0.8.15 → 0.8.16
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.
Potentially problematic release.
This version of @sage-protocol/cli might be problematic. Click here for more details.
- package/README.md +111 -221
- package/dist/cli/commands/ipfs.js +1 -1
- package/dist/cli/ipfs-manager.js +119 -13
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,295 +1,185 @@
|
|
|
1
1
|
# Sage CLI
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
CLI for the Sage Protocol. Install AI prompts and skills, create prompt libraries, and publish with on-chain governance.
|
|
4
4
|
|
|
5
5
|
```bash
|
|
6
6
|
npm i -g @sage-protocol/cli
|
|
7
|
-
sage --help
|
|
8
7
|
```
|
|
9
8
|
|
|
10
|
-
##
|
|
9
|
+
## Zero-Config Start (Privy Default)
|
|
11
10
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Create a wallet-owned library for your prompts without DAO overhead:
|
|
11
|
+
**Privy wallet is the default** - no local keystore or seed phrase needed. Just install and go:
|
|
15
12
|
|
|
16
13
|
```bash
|
|
17
|
-
#
|
|
18
|
-
|
|
19
|
-
# App ID is baked in; no secret is required when using the web relay (default)
|
|
20
|
-
sage wallet connect
|
|
21
|
-
|
|
22
|
-
# 2. Create a personal library
|
|
23
|
-
sage library vault create --name "My Prompts"
|
|
14
|
+
# Install a skill immediately
|
|
15
|
+
sage install build-web3
|
|
24
16
|
|
|
25
|
-
#
|
|
26
|
-
sage
|
|
17
|
+
# Or connect your wallet first (opens browser)
|
|
18
|
+
sage wallet connect
|
|
27
19
|
|
|
28
|
-
#
|
|
29
|
-
sage
|
|
20
|
+
# Get testnet tokens
|
|
21
|
+
sage sxxx faucet
|
|
30
22
|
```
|
|
31
23
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
Create a governed library with token-based voting:
|
|
24
|
+
## Install Skills & Prompts
|
|
35
25
|
|
|
36
26
|
```bash
|
|
37
|
-
#
|
|
38
|
-
sage
|
|
39
|
-
|
|
40
|
-
# 2. Or step-by-step:
|
|
41
|
-
sage prompts init # Initialize workspace
|
|
42
|
-
sage prompts new my-prompt # Create a prompt
|
|
43
|
-
sage prompts publish # Upload and propose update
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
### Install Prompts from Others
|
|
27
|
+
# From the Sage platform
|
|
28
|
+
sage install build-web3
|
|
29
|
+
sage install solidity-audit
|
|
47
30
|
|
|
48
|
-
|
|
49
|
-
# From a DAO
|
|
31
|
+
# From a DAO library
|
|
50
32
|
sage install 0x1234...abcd
|
|
51
|
-
sage install my-library
|
|
52
33
|
|
|
53
34
|
# From IPFS
|
|
54
|
-
sage install
|
|
35
|
+
sage install bafkrei...
|
|
55
36
|
|
|
56
37
|
# From GitHub
|
|
57
38
|
sage install github:user/repo
|
|
58
|
-
```
|
|
59
39
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
### Library Management
|
|
65
|
-
|
|
66
|
-
| Command | Description |
|
|
67
|
-
|---------|-------------|
|
|
68
|
-
| `sage library quickstart` | Create library + DAO in one command |
|
|
69
|
-
| `sage library info` | Show library info for a DAO |
|
|
70
|
-
| `sage library fork <source>` | Fork an existing library |
|
|
71
|
-
| `sage library personal create` | Create a personal (wallet-owned) library |
|
|
72
|
-
| `sage library personal list` | List your personal libraries |
|
|
73
|
-
| `sage library personal push` | Push files to a personal library |
|
|
74
|
-
| `sage library personal delete` | Delete a personal library |
|
|
75
|
-
| `sage library vault ...` | Alias for personal libraries (clearer SIWE vault naming) |
|
|
76
|
-
|
|
77
|
-
### Prompt Workspace
|
|
78
|
-
|
|
79
|
-
| Command | Description |
|
|
80
|
-
|---------|-------------|
|
|
81
|
-
| `sage prompts init` | Initialize a prompt workspace |
|
|
82
|
-
| `sage prompts new <key>` | Create a new prompt/skill |
|
|
83
|
-
| `sage prompts list` | List all prompts in workspace |
|
|
84
|
-
| `sage prompts publish` | Build manifest and propose update |
|
|
85
|
-
| `sage prompts sync` | Sync with on-chain state |
|
|
86
|
-
| `sage prompts import <source>` | Import from GitHub/on-chain |
|
|
87
|
-
| `sage prompts search <query>` | Search prompts |
|
|
88
|
-
|
|
89
|
-
### Personal Prompts
|
|
90
|
-
|
|
91
|
-
| Command | Description |
|
|
92
|
-
|---------|-------------|
|
|
93
|
-
| `sage personal create` | Create a personal registry |
|
|
94
|
-
| `sage personal publish <key>` | Publish a free prompt |
|
|
95
|
-
| `sage personal list` | List personal prompts |
|
|
96
|
-
| `sage personal premium publish` | Publish paid content |
|
|
97
|
-
| `sage personal premium buy` | Purchase a license |
|
|
98
|
-
| `sage personal premium access` | Decrypt purchased content |
|
|
99
|
-
| `sage personal my-licenses` | View owned licenses |
|
|
100
|
-
|
|
101
|
-
### Wallet & Config
|
|
102
|
-
|
|
103
|
-
| Command | Description |
|
|
104
|
-
|---------|-------------|
|
|
105
|
-
| `sage wallet connect` | Connect a wallet (Cast, Privy, WalletConnect) |
|
|
106
|
-
| `sage wallet balance` | Show wallet balance |
|
|
107
|
-
| `sage config show` | Show current configuration |
|
|
108
|
-
| `sage config ipfs onboard` | Configure IPFS/pinning |
|
|
109
|
-
| `sage secret set <name>` | Store a secret in keychain |
|
|
40
|
+
# List what you have installed
|
|
41
|
+
sage list
|
|
42
|
+
```
|
|
110
43
|
|
|
111
|
-
|
|
44
|
+
## Create a Personal Library
|
|
112
45
|
|
|
113
|
-
|
|
46
|
+
No governance overhead - just publish under your wallet:
|
|
114
47
|
|
|
115
48
|
```bash
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
PRIVY_APP_ID=your_app_id
|
|
119
|
-
PRIVY_APP_SECRET=your_app_secret
|
|
120
|
-
EOF
|
|
121
|
-
```
|
|
49
|
+
# Create library
|
|
50
|
+
sage library personal create --name "My Prompts"
|
|
122
51
|
|
|
123
|
-
|
|
52
|
+
# Push your prompts
|
|
53
|
+
sage library personal push <libraryId> --from-dir ./prompts
|
|
124
54
|
|
|
125
|
-
|
|
126
|
-
|
|
55
|
+
# List your libraries
|
|
56
|
+
sage library personal list
|
|
127
57
|
```
|
|
128
58
|
|
|
129
|
-
|
|
59
|
+
## Create a Governed DAO Library
|
|
130
60
|
|
|
131
|
-
|
|
132
|
-
|---------|-------------|
|
|
133
|
-
| `sage gov propose` | Create a governance proposal |
|
|
134
|
-
| `sage gov vote <proposalId>` | Vote on a proposal |
|
|
135
|
-
| `sage gov queue <proposalId>` | Queue a passed proposal |
|
|
136
|
-
| `sage gov execute <proposalId>` | Execute a queued proposal |
|
|
137
|
-
| `sage proposals list` | List proposals for current DAO |
|
|
138
|
-
|
|
139
|
-
### Reputation
|
|
140
|
-
|
|
141
|
-
| Command | Description |
|
|
142
|
-
|---------|-------------|
|
|
143
|
-
| `sage reputation check <address>` | Check trust signals (badges, contributions) |
|
|
144
|
-
| `sage reputation status <address>` | Author metrics (revenue, purchases, consumers) |
|
|
145
|
-
| `sage reputation leaderboard` | Top authors by revenue |
|
|
146
|
-
| `sage reputation achievements <address>` | Achievement badges earned |
|
|
147
|
-
|
|
148
|
-
## Personal/Vault Libraries
|
|
149
|
-
|
|
150
|
-
Personal libraries are wallet-owned collections that don't require DAO governance. They're ideal for:
|
|
151
|
-
|
|
152
|
-
- **Individual creators** who want to publish prompts under their own identity
|
|
153
|
-
- **Quick iteration** without governance delays
|
|
154
|
-
- **Premium content** with on-chain licensing via Lit Protocol
|
|
155
|
-
|
|
156
|
-
### Create and Manage
|
|
61
|
+
For team/community libraries with on-chain voting:
|
|
157
62
|
|
|
158
63
|
```bash
|
|
159
|
-
#
|
|
160
|
-
sage library
|
|
161
|
-
|
|
162
|
-
# View your libraries
|
|
163
|
-
sage library vault list
|
|
64
|
+
# One command: scan prompts, upload, create DAO, register
|
|
65
|
+
sage library quickstart --name "Team Library" --from-dir ./prompts
|
|
164
66
|
|
|
165
|
-
#
|
|
166
|
-
sage
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
sage library vault info lib_abc123
|
|
170
|
-
|
|
171
|
-
# Delete a library
|
|
172
|
-
sage library vault delete lib_abc123
|
|
67
|
+
# Or step-by-step
|
|
68
|
+
sage prompts init
|
|
69
|
+
sage prompts new my-prompt
|
|
70
|
+
sage prompts publish
|
|
173
71
|
```
|
|
174
72
|
|
|
175
|
-
|
|
73
|
+
## First-Time Setup (Optional)
|
|
176
74
|
|
|
177
|
-
|
|
75
|
+
Privy handles auth automatically. For advanced setup:
|
|
178
76
|
|
|
179
77
|
```bash
|
|
180
|
-
#
|
|
181
|
-
sage
|
|
182
|
-
|
|
183
|
-
--price 100 \
|
|
184
|
-
--name "Advanced Prompt" \
|
|
185
|
-
--description "High-value prompt template"
|
|
186
|
-
|
|
187
|
-
# Check pricing
|
|
188
|
-
sage personal premium price <creator> <key>
|
|
189
|
-
|
|
190
|
-
# Buy a license
|
|
191
|
-
sage personal premium buy <creator> <key> --auto-approve
|
|
192
|
-
|
|
193
|
-
# Access purchased content
|
|
194
|
-
sage personal premium access <creator> <key> --out decrypted.md
|
|
195
|
-
|
|
196
|
-
# View your licenses
|
|
197
|
-
sage personal my-licenses
|
|
78
|
+
sage init # Interactive setup wizard
|
|
79
|
+
sage doctor # Check your environment
|
|
80
|
+
sage wizard # Guided tutorial
|
|
198
81
|
```
|
|
199
82
|
|
|
200
|
-
##
|
|
201
|
-
|
|
202
|
-
The CLI uses the Sage IPFS worker by default:
|
|
203
|
-
|
|
204
|
-
- **Gateway**: `https://ipfs.dev.sageprotocol.io/ipfs`
|
|
205
|
-
- **Worker**: `https://api.sageprotocol.io`
|
|
83
|
+
## Claude Code Integration
|
|
206
84
|
|
|
207
85
|
```bash
|
|
208
|
-
#
|
|
209
|
-
sage
|
|
210
|
-
|
|
211
|
-
# Upload content
|
|
212
|
-
sage ipfs upload ./my-file.md
|
|
213
|
-
|
|
214
|
-
# Pin existing content
|
|
215
|
-
sage ipfs pin <cid>
|
|
86
|
+
# Init with skill support
|
|
87
|
+
sage init --with-skill
|
|
216
88
|
|
|
217
|
-
#
|
|
218
|
-
sage
|
|
89
|
+
# Install skills for Claude Code
|
|
90
|
+
sage install build-web3
|
|
91
|
+
sage prompts import-skill solidity-audit
|
|
219
92
|
```
|
|
220
93
|
|
|
221
|
-
|
|
94
|
+
---
|
|
222
95
|
|
|
223
|
-
|
|
224
|
-
# Show credit balance
|
|
225
|
-
sage ipfs credits
|
|
96
|
+
## Command Reference
|
|
226
97
|
|
|
227
|
-
|
|
228
|
-
sage ipfs buy-credits
|
|
98
|
+
### Installation & Skills
|
|
229
99
|
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
100
|
+
| Command | Description |
|
|
101
|
+
|---------|-------------|
|
|
102
|
+
| `sage install <source>` | Install from DAO, IPFS, or GitHub |
|
|
103
|
+
| `sage list` | List installed prompts/skills |
|
|
104
|
+
| `sage update [key]` | Update installed content |
|
|
105
|
+
| `sage skill add <path>` | Add local skill to Claude Code |
|
|
233
106
|
|
|
234
|
-
|
|
107
|
+
### Wallet & Tokens
|
|
235
108
|
|
|
236
|
-
|
|
109
|
+
| Command | Description |
|
|
110
|
+
|---------|-------------|
|
|
111
|
+
| `sage wallet` | Show wallet info (Privy default) |
|
|
112
|
+
| `sage wallet connect` | Connect wallet (opens browser) |
|
|
113
|
+
| `sage sxxx faucet` | Get testnet SXXX tokens |
|
|
114
|
+
| `sage sxxx balance` | Check SXXX balance |
|
|
115
|
+
| `sage sxxx delegate-self` | Enable voting power |
|
|
237
116
|
|
|
238
|
-
|
|
239
|
-
# Show all config
|
|
240
|
-
sage config show --all
|
|
117
|
+
### Libraries
|
|
241
118
|
|
|
242
|
-
|
|
243
|
-
|
|
119
|
+
| Command | Description |
|
|
120
|
+
|---------|-------------|
|
|
121
|
+
| `sage library personal create` | Create wallet-owned library |
|
|
122
|
+
| `sage library personal push` | Push content to library |
|
|
123
|
+
| `sage library personal list` | List your libraries |
|
|
124
|
+
| `sage library quickstart` | Create DAO library in one command |
|
|
244
125
|
|
|
245
|
-
|
|
246
|
-
sage config profile list
|
|
247
|
-
sage config profile use <name>
|
|
248
|
-
```
|
|
126
|
+
### Prompts
|
|
249
127
|
|
|
250
|
-
|
|
128
|
+
| Command | Description |
|
|
129
|
+
|---------|-------------|
|
|
130
|
+
| `sage prompts init` | Initialize workspace |
|
|
131
|
+
| `sage prompts new <key>` | Create new prompt |
|
|
132
|
+
| `sage prompts publish` | Publish to DAO |
|
|
133
|
+
| `sage prompts sync` | Sync with on-chain state |
|
|
251
134
|
|
|
252
|
-
|
|
135
|
+
### DAO & Governance
|
|
253
136
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
sage
|
|
257
|
-
sage
|
|
258
|
-
sage
|
|
259
|
-
|
|
137
|
+
| Command | Description |
|
|
138
|
+
|---------|-------------|
|
|
139
|
+
| `sage dao list` | List DAOs |
|
|
140
|
+
| `sage dao info <addr>` | Show DAO details |
|
|
141
|
+
| `sage proposals inbox` | Active proposals |
|
|
142
|
+
| `sage gov vote <id>` | Vote on proposal |
|
|
260
143
|
|
|
261
|
-
|
|
144
|
+
### IPFS
|
|
262
145
|
|
|
263
|
-
|
|
146
|
+
| Command | Description |
|
|
147
|
+
|---------|-------------|
|
|
148
|
+
| `sage ipfs upload <file>` | Upload to IPFS |
|
|
149
|
+
| `sage ipfs download <cid>` | Download (prompts, skills, raw) |
|
|
150
|
+
| `sage ipfs pins` | List pinned content |
|
|
264
151
|
|
|
265
|
-
|
|
152
|
+
### Config
|
|
266
153
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
154
|
+
| Command | Description |
|
|
155
|
+
|---------|-------------|
|
|
156
|
+
| `sage config show` | Show configuration |
|
|
157
|
+
| `sage context` | Show DAO context |
|
|
158
|
+
| `sage doctor` | Diagnose environment |
|
|
270
159
|
|
|
271
|
-
|
|
272
|
-
```
|
|
273
|
-
.claude/
|
|
274
|
-
├── skills/build-web3/
|
|
275
|
-
│ ├── SKILL.md
|
|
276
|
-
│ └── workflows/
|
|
277
|
-
└── commands/build-web3.md
|
|
160
|
+
## Aliases
|
|
278
161
|
|
|
279
|
-
|
|
280
|
-
|
|
162
|
+
| Full | Short |
|
|
163
|
+
|------|-------|
|
|
164
|
+
| `sage library` | `sage l` |
|
|
165
|
+
| `sage governance` | `sage gov` |
|
|
166
|
+
| `sage wallet` | `sage w` |
|
|
167
|
+
| `sage sxxx` | `sage token` |
|
|
168
|
+
|
|
169
|
+
## Premium Content
|
|
281
170
|
|
|
282
|
-
|
|
171
|
+
Sell encrypted prompts with Lit Protocol licensing:
|
|
283
172
|
|
|
284
173
|
```bash
|
|
285
|
-
sage
|
|
286
|
-
sage
|
|
174
|
+
sage personal premium publish my-prompt --file ./prompt.md --price 100
|
|
175
|
+
sage personal premium buy <creator> <key>
|
|
176
|
+
sage personal premium access <creator> <key> --out decrypted.md
|
|
287
177
|
```
|
|
288
178
|
|
|
289
|
-
##
|
|
179
|
+
## Links
|
|
290
180
|
|
|
291
|
-
- [
|
|
292
|
-
- [
|
|
181
|
+
- [Documentation](https://docs.sageprotocol.io)
|
|
182
|
+
- [GitHub](https://github.com/sage-protocol/cli)
|
|
293
183
|
|
|
294
184
|
## License
|
|
295
185
|
|
|
@@ -321,7 +321,7 @@ function register(program) {
|
|
|
321
321
|
)
|
|
322
322
|
.addCommand(
|
|
323
323
|
new Command('download')
|
|
324
|
-
.description('Download
|
|
324
|
+
.description('Download content from IPFS (prompts, skills, libraries, or raw files)')
|
|
325
325
|
.argument('<cid>', 'IPFS CID to download')
|
|
326
326
|
.option('-o, --output <file>', 'Output file path')
|
|
327
327
|
.option('-g, --gateway <url>', 'Preferred IPFS gateway (reads)', process.env.SAGE_IPFS_GATEWAY)
|
package/dist/cli/ipfs-manager.js
CHANGED
|
@@ -533,32 +533,138 @@ class IPFSManager {
|
|
|
533
533
|
|
|
534
534
|
async downloadPrompt(cid, outputPath) {
|
|
535
535
|
try {
|
|
536
|
-
const downloaded = await withSpinner('Downloading
|
|
536
|
+
const downloaded = await withSpinner('Downloading content from IPFS', async () => {
|
|
537
537
|
let prompt = this.prompts.get(cid);
|
|
538
|
+
let contentType = 'prompt';
|
|
539
|
+
|
|
538
540
|
if (!prompt) {
|
|
541
|
+
// First try to fetch as JSON (prompt/skill format)
|
|
539
542
|
const data = await this.#withBackoff(() => this.client.downloadJson({ cid }).catch(() => null), { retries: Number(process.env.SAGE_IPFS_FETCH_RETRIES || 2), baseMs: Number(process.env.SAGE_IPFS_FETCH_BACKOFF_MS || 400) });
|
|
543
|
+
|
|
540
544
|
if (data) {
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
545
|
+
// Detect content type based on structure
|
|
546
|
+
if (data.skills && Array.isArray(data.skills)) {
|
|
547
|
+
// Library manifest with skills
|
|
548
|
+
contentType = 'library';
|
|
549
|
+
prompt = {
|
|
550
|
+
name: data.name || 'Downloaded Library',
|
|
551
|
+
description: data.description || 'Library manifest from IPFS',
|
|
552
|
+
content: JSON.stringify(data, null, 2),
|
|
553
|
+
timestamp: data.timestamp || Date.now(),
|
|
554
|
+
filePath: 'ipfs-download',
|
|
555
|
+
metadata: { type: 'library', skillCount: data.skills.length, promptCount: data.prompts?.length || 0 }
|
|
556
|
+
};
|
|
557
|
+
} else if (data.content && (data.content.includes('# ') || data.content.includes('```'))) {
|
|
558
|
+
// Skill format (markdown content)
|
|
559
|
+
contentType = 'skill';
|
|
560
|
+
prompt = {
|
|
561
|
+
name: data.name || data.key || 'Downloaded Skill',
|
|
562
|
+
description: data.description || 'Skill from IPFS',
|
|
563
|
+
content: data.content,
|
|
564
|
+
timestamp: data.timestamp || Date.now(),
|
|
565
|
+
filePath: 'ipfs-download',
|
|
566
|
+
metadata: { type: 'skill', tags: data.tags }
|
|
567
|
+
};
|
|
568
|
+
} else if (data.name && data.content) {
|
|
569
|
+
// Standard prompt format
|
|
570
|
+
contentType = 'prompt';
|
|
571
|
+
prompt = {
|
|
572
|
+
name: data.name,
|
|
573
|
+
description: data.description || 'Downloaded from IPFS',
|
|
574
|
+
content: data.content,
|
|
575
|
+
timestamp: data.timestamp || Date.now(),
|
|
576
|
+
filePath: 'ipfs-download',
|
|
577
|
+
};
|
|
578
|
+
} else {
|
|
579
|
+
// Unknown JSON structure - save as raw JSON
|
|
580
|
+
contentType = 'json';
|
|
581
|
+
prompt = {
|
|
582
|
+
name: 'Downloaded Content',
|
|
583
|
+
description: 'Raw JSON from IPFS',
|
|
584
|
+
content: JSON.stringify(data, null, 2),
|
|
585
|
+
timestamp: Date.now(),
|
|
586
|
+
filePath: 'ipfs-download',
|
|
587
|
+
metadata: { type: 'json', keys: Object.keys(data) }
|
|
588
|
+
};
|
|
589
|
+
}
|
|
548
590
|
this.prompts.set(cid, prompt);
|
|
591
|
+
} else {
|
|
592
|
+
// Try to fetch as raw text via gateway
|
|
593
|
+
const gatewayUrls = this.buildGatewayUrls(cid);
|
|
594
|
+
let rawContent = null;
|
|
595
|
+
|
|
596
|
+
for (const url of gatewayUrls) {
|
|
597
|
+
try {
|
|
598
|
+
const axios = require('axios');
|
|
599
|
+
const response = await axios.get(url, { timeout: 15000, responseType: 'text' });
|
|
600
|
+
if (response.data) {
|
|
601
|
+
rawContent = typeof response.data === 'string' ? response.data : JSON.stringify(response.data);
|
|
602
|
+
break;
|
|
603
|
+
}
|
|
604
|
+
} catch (_) {
|
|
605
|
+
// Try next gateway
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
if (rawContent) {
|
|
610
|
+
contentType = 'raw';
|
|
611
|
+
prompt = {
|
|
612
|
+
name: 'Downloaded Content',
|
|
613
|
+
description: 'Raw content from IPFS',
|
|
614
|
+
content: rawContent,
|
|
615
|
+
timestamp: Date.now(),
|
|
616
|
+
filePath: 'ipfs-download',
|
|
617
|
+
metadata: { type: 'raw', size: rawContent.length }
|
|
618
|
+
};
|
|
619
|
+
this.prompts.set(cid, prompt);
|
|
620
|
+
}
|
|
549
621
|
}
|
|
550
622
|
}
|
|
551
|
-
|
|
552
|
-
|
|
623
|
+
|
|
624
|
+
if (!prompt) {
|
|
625
|
+
throw new Error(`Content with CID ${cid} not found. The CID may be invalid or the content may have expired.`);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// Determine file extension based on content type
|
|
629
|
+
let extension = '.txt';
|
|
630
|
+
if (contentType === 'skill') extension = '.md';
|
|
631
|
+
else if (contentType === 'library' || contentType === 'json') extension = '.json';
|
|
632
|
+
|
|
633
|
+
const safeName = prompt.name.replace(/[^a-zA-Z0-9-_]/g, '-').toLowerCase();
|
|
634
|
+
const finalOutputPath = outputPath || `${safeName}${extension}`;
|
|
553
635
|
fs.writeFileSync(finalOutputPath, prompt.content);
|
|
554
|
-
|
|
636
|
+
|
|
637
|
+
return { prompt, finalOutputPath, contentType };
|
|
555
638
|
}, { successText: () => 'Downloaded' });
|
|
556
|
-
|
|
639
|
+
|
|
640
|
+
// Show appropriate output based on content type
|
|
641
|
+
const typeLabels = {
|
|
642
|
+
prompt: '📝 Prompt',
|
|
643
|
+
skill: '🛠️ Skill',
|
|
644
|
+
library: '📚 Library',
|
|
645
|
+
json: '📄 JSON',
|
|
646
|
+
raw: '📦 Raw Content'
|
|
647
|
+
};
|
|
648
|
+
|
|
649
|
+
this.log(`${typeLabels[downloaded.contentType] || '📄 Content'}: ${downloaded.prompt.name}`);
|
|
557
650
|
this.log('📄 Description:', downloaded.prompt.description);
|
|
558
651
|
this.log('📁 Saved to:', downloaded.finalOutputPath);
|
|
652
|
+
|
|
653
|
+
// Show helpful hints based on content type
|
|
654
|
+
if (downloaded.contentType === 'skill') {
|
|
655
|
+
this.log(colors.yellow('\n💡 Tip: To install this skill, run:'));
|
|
656
|
+
this.log(` sage skill add ${downloaded.finalOutputPath}`);
|
|
657
|
+
} else if (downloaded.contentType === 'library') {
|
|
658
|
+
const meta = downloaded.prompt.metadata || {};
|
|
659
|
+
this.log(`📊 Contains: ${meta.promptCount || 0} prompts, ${meta.skillCount || 0} skills`);
|
|
660
|
+
} else if (downloaded.contentType === 'raw') {
|
|
661
|
+
this.log(colors.yellow('\n⚠️ Note: This content is not in Sage prompt/skill format.'));
|
|
662
|
+
this.log(' It has been saved as raw text.');
|
|
663
|
+
}
|
|
664
|
+
|
|
559
665
|
return downloaded.finalOutputPath;
|
|
560
666
|
} catch (error) {
|
|
561
|
-
console.error('❌ Failed to download
|
|
667
|
+
console.error('❌ Failed to download content:', error.message);
|
|
562
668
|
throw error;
|
|
563
669
|
}
|
|
564
670
|
}
|