@feralfile/cli 1.6.0 → 2.0.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/README.md +6 -11
- package/config.json.example +0 -65
- package/dist/index.js +1 -3
- package/dist/package.json +3 -4
- package/dist/src/commands/config.js +15 -13
- package/dist/src/commands/play.js +55 -0
- package/dist/src/commands/setup.js +1 -73
- package/dist/src/commands/status.js +0 -13
- package/dist/src/config.js +3 -126
- package/dist/src/main.js +2 -361
- package/dist/src/utilities/ff1-device.js +55 -0
- package/dist/src/utilities/playlist-builder.js +59 -16
- package/docs/CONFIGURATION.md +0 -34
- package/docs/EXAMPLES.md +206 -215
- package/docs/PROJECT_SPEC.md +20 -18
- package/docs/README.md +51 -104
- package/package.json +3 -4
- package/dist/src/ai-orchestrator/index.js +0 -1040
- package/dist/src/ai-orchestrator/registry.js +0 -96
- package/dist/src/commands/chat.js +0 -189
- package/dist/src/intent-parser/index.js +0 -1393
- package/dist/src/intent-parser/utils.js +0 -116
- package/docs/FUNCTION_CALLING.md +0 -100
package/docs/EXAMPLES.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Examples
|
|
2
2
|
|
|
3
|
-
Copy‑pasteable commands that work with the current CLI.
|
|
3
|
+
Copy‑pasteable commands that work with the current CLI. ff-cli is deterministic: there's no built-in chat. Natural language belongs in your coding agent (Claude Code, Codex), which drives these commands via the `ff-control` skill. No LLM API key required.
|
|
4
4
|
|
|
5
5
|
## Setup
|
|
6
6
|
|
|
@@ -16,190 +16,249 @@ npm run dev -- config init
|
|
|
16
16
|
npm run dev -- config validate
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
##
|
|
19
|
+
## Use with a coding agent
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
`skills/ff-control/SKILL.md`
|
|
21
|
+
ff-cli ships a [Claude Code](https://docs.claude.com/en/docs/claude-code) / Codex skill at `skills/ff-control/SKILL.md`. Once installed, ask your agent in plain language ("Get 3 works from reas.eth and play on Living Room", "Build a playlist from this Objkt URL and publish to my feed") and it translates the request into `ff-cli find` or `ff-cli build` and runs the validate → play/publish flow for you.
|
|
24
22
|
|
|
25
23
|
Recommended local install path:
|
|
26
24
|
|
|
27
25
|
```bash
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
git clone --depth=1 https://github.com/feral-file/ff-cli /tmp/ff-cli \
|
|
27
|
+
&& mkdir -p ~/.claude/skills \
|
|
28
|
+
&& cp -r /tmp/ff-cli/skills/ff-control ~/.claude/skills/
|
|
30
29
|
```
|
|
31
30
|
|
|
32
|
-
|
|
31
|
+
The rest of this doc shows the deterministic commands the skill (or you) drives directly.
|
|
33
32
|
|
|
34
|
-
|
|
33
|
+
## Find an artwork
|
|
35
34
|
|
|
36
|
-
|
|
35
|
+
`ff-cli find` resolves a marketplace URL, raw `chain:contract:tokenId`, or wallet address into a playable DP-1 playlist. Sources: Art Blocks, Objkt, fxhash, OpenSea, SuperRare, Feral File, Neort, Verse, raw on-chain coordinates, and wallet addresses.
|
|
37
36
|
|
|
38
37
|
```bash
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
# Paste a URL and play it on your FF1
|
|
39
|
+
npm run dev -- find https://www.artblocks.io/collection/ringers-by-dmitri-cherniak --play
|
|
40
|
+
|
|
41
|
+
# Tezos / hic et nunc via Objkt (the alias resolves to a KT1 contract)
|
|
42
|
+
npm run dev -- find https://objkt.com/tokens/hicetnunc/111068 --play
|
|
43
|
+
|
|
44
|
+
# Feral File artwork (public id may be hex or numeric)
|
|
45
|
+
npm run dev -- find https://feralfile.com/exhibitions/artwork/f0240e04d64717e319584957f6a83954b029254ad1260b6320472ea8c0c5b1cf --play
|
|
46
|
+
|
|
47
|
+
# Save without playing
|
|
48
|
+
npm run dev -- find ethereum:0xababababab20053426ad1c782de9ea8444358070:5001410 -o send-receive.json
|
|
49
|
+
|
|
50
|
+
# Single on-chain token by coordinates
|
|
51
|
+
npm run dev -- find ethereum:0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0:52932 -o token.json
|
|
52
|
+
|
|
53
|
+
# Tezos token by coordinates
|
|
54
|
+
npm run dev -- find tezos:KT1BcNnzWze3vCviwiETYNwcFSwjv6RihZEQ:22 -o tez-token.json
|
|
55
|
+
|
|
56
|
+
# Wallet address (owner lookup); cap the number of tokens with --limit
|
|
57
|
+
npm run dev -- find 0xaeE022552B539dB18297D7481b6D547C622488B3 -l 10 -o wallet.json
|
|
58
|
+
|
|
59
|
+
# Limit a large series to the first N tokens
|
|
60
|
+
npm run dev -- find https://www.artblocks.io/collection/ringers-by-dmitri-cherniak -l 5 -o ringers.json
|
|
61
|
+
|
|
62
|
+
# Build and publish to a configured feed server
|
|
63
|
+
npm run dev -- find https://objkt.com/tokens/hicetnunc/111068 --publish
|
|
64
|
+
|
|
65
|
+
# Build, play on a named device, and skip interactive prompts
|
|
66
|
+
npm run dev -- find https://objkt.com/tokens/hicetnunc/111068 --play -d "Living Room Display" -y
|
|
41
67
|
```
|
|
42
68
|
|
|
43
|
-
|
|
69
|
+
OpenSea and Verse accept both item and collection/series URLs:
|
|
44
70
|
|
|
45
71
|
```bash
|
|
46
|
-
#
|
|
47
|
-
npm run dev
|
|
72
|
+
# OpenSea collection (Ethereum); slug resolved from the public page, no API key
|
|
73
|
+
npm run dev -- find https://opensea.io/collection/your-collection-slug -l 5 -o opensea.json
|
|
48
74
|
|
|
49
|
-
#
|
|
50
|
-
npm run dev --
|
|
51
|
-
|
|
52
|
-
npm run dev -- chat "Get tokens 52932,52457 from Ethereum contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0" -v
|
|
53
|
-
npm run dev -- chat "Make a playlist of 10 works from 0xaeE022552B539dB18297D7481b6D547C622488B3" -v
|
|
75
|
+
# Verse series
|
|
76
|
+
npm run dev -- find https://verse.works/series/your-series-slug -l 5 -o verse.json
|
|
77
|
+
```
|
|
54
78
|
|
|
55
|
-
|
|
56
|
-
npm run dev -- chat "your request" --model grok
|
|
57
|
-
npm run dev -- chat "your request" --model gpt
|
|
58
|
-
npm run dev -- chat "your request" --model gemini
|
|
79
|
+
Run `npm run dev -- find --help` for the full input list and options.
|
|
59
80
|
|
|
60
|
-
|
|
61
|
-
```
|
|
81
|
+
## Build from structured params
|
|
62
82
|
|
|
63
|
-
|
|
83
|
+
Use `ff-cli build` when you already have the contract, token IDs, feed names, or artwork ids and want explicit control over ordering, durations, and title. The input is a JSON object with `requirements` and optional `playlistSettings`.
|
|
64
84
|
|
|
65
85
|
```bash
|
|
66
|
-
# From file
|
|
86
|
+
# From a file
|
|
67
87
|
npm run dev -- build examples/params-example.json -o playlist.json
|
|
68
88
|
|
|
69
89
|
# From stdin
|
|
70
90
|
cat examples/params-example.json | npm run dev -- build -o playlist.json
|
|
71
91
|
```
|
|
72
92
|
|
|
73
|
-
|
|
93
|
+
Each requirement has a `type`:
|
|
94
|
+
|
|
95
|
+
- `build_playlist` — `blockchain`, `contractAddress`, `tokenIds`, optional `quantity`
|
|
96
|
+
- `feral_file_artwork` — `artworkId` (a Feral File public artwork id or `/exhibitions/artwork/{id}` URL)
|
|
97
|
+
- `query_address` — `ownerAddress`, optional `quantity` (random selection)
|
|
98
|
+
- `fetch_feed` — `playlistName`, `quantity`
|
|
99
|
+
|
|
100
|
+
`playlistSettings` may set `title`, `durationPerItem`, `preserveOrder` (set `false` to shuffle), and `deviceName`.
|
|
101
|
+
|
|
102
|
+
### From a contract + token IDs
|
|
74
103
|
|
|
75
104
|
```bash
|
|
76
|
-
cat > /tmp/
|
|
105
|
+
cat > /tmp/eth-tokens.json <<'JSON'
|
|
77
106
|
{
|
|
78
107
|
"requirements": [
|
|
79
108
|
{
|
|
80
|
-
"type": "
|
|
81
|
-
"
|
|
109
|
+
"type": "build_playlist",
|
|
110
|
+
"blockchain": "ethereum",
|
|
111
|
+
"contractAddress": "0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0",
|
|
112
|
+
"tokenIds": ["52932", "52457"]
|
|
82
113
|
}
|
|
83
114
|
],
|
|
84
115
|
"playlistSettings": {
|
|
85
|
-
"title": "
|
|
116
|
+
"title": "ETH Tokens",
|
|
117
|
+
"preserveOrder": false,
|
|
118
|
+
"durationPerItem": 7
|
|
86
119
|
}
|
|
87
120
|
}
|
|
88
121
|
JSON
|
|
89
122
|
|
|
90
|
-
npm run dev -- build /tmp/
|
|
123
|
+
npm run dev -- build /tmp/eth-tokens.json -o playlist-eth.json -v
|
|
91
124
|
```
|
|
92
125
|
|
|
93
|
-
|
|
126
|
+
Tezos works the same way with `"blockchain": "tezos"` and a `KT1...` contract:
|
|
94
127
|
|
|
95
128
|
```bash
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
129
|
+
cat > /tmp/tez-tokens.json <<'JSON'
|
|
130
|
+
{
|
|
131
|
+
"requirements": [
|
|
132
|
+
{
|
|
133
|
+
"type": "build_playlist",
|
|
134
|
+
"blockchain": "tezos",
|
|
135
|
+
"contractAddress": "KT1BcNnzWze3vCviwiETYNwcFSwjv6RihZEQ",
|
|
136
|
+
"tokenIds": ["22", "8"]
|
|
137
|
+
}
|
|
138
|
+
],
|
|
139
|
+
"playlistSettings": { "title": "Tezos Tokens", "preserveOrder": false }
|
|
140
|
+
}
|
|
141
|
+
JSON
|
|
101
142
|
|
|
102
|
-
|
|
103
|
-
npm run dev -- chat "Build playlist from Ethereum address 0xaeE022552B539dB18297D7481b6D547C622488B3 and 2 from Unsupervised" --model gpt -v
|
|
143
|
+
npm run dev -- build /tmp/tez-tokens.json -o playlist-tez.json -v
|
|
104
144
|
```
|
|
105
145
|
|
|
106
|
-
###
|
|
107
|
-
|
|
108
|
-
The CLI can parse rich requests and do it all in one go: fetch, build a DP‑1 playlist, shuffle, set durations, and send to a named device.
|
|
146
|
+
### From a wallet address
|
|
109
147
|
|
|
110
148
|
```bash
|
|
111
|
-
|
|
112
|
-
|
|
149
|
+
cat > /tmp/wallet.json <<'JSON'
|
|
150
|
+
{
|
|
151
|
+
"requirements": [
|
|
152
|
+
{
|
|
153
|
+
"type": "query_address",
|
|
154
|
+
"ownerAddress": "0xaeE022552B539dB18297D7481b6D547C622488B3",
|
|
155
|
+
"quantity": 5
|
|
156
|
+
}
|
|
157
|
+
],
|
|
158
|
+
"playlistSettings": { "title": "From a wallet", "preserveOrder": false }
|
|
159
|
+
}
|
|
160
|
+
JSON
|
|
161
|
+
|
|
162
|
+
npm run dev -- build /tmp/wallet.json -o playlist-wallet.json -v
|
|
113
163
|
```
|
|
114
164
|
|
|
115
|
-
|
|
165
|
+
### From a feed playlist
|
|
116
166
|
|
|
117
|
-
|
|
118
|
-
`https://github.com/feral-file/dp1-feed/tree/main/playlists`
|
|
167
|
+
Feed playlist queries require reachable feed servers in your config. Reference exhibition titles from the official playlist repository: `https://github.com/feral-file/dp1-feed/tree/main/playlists`.
|
|
119
168
|
|
|
120
169
|
```bash
|
|
121
|
-
|
|
122
|
-
|
|
170
|
+
cat > /tmp/feed.json <<'JSON'
|
|
171
|
+
{
|
|
172
|
+
"requirements": [
|
|
173
|
+
{ "type": "fetch_feed", "playlistName": "Unsupervised", "quantity": 3 }
|
|
174
|
+
],
|
|
175
|
+
"playlistSettings": { "title": "From a feed", "preserveOrder": false }
|
|
176
|
+
}
|
|
177
|
+
JSON
|
|
123
178
|
|
|
124
|
-
|
|
125
|
-
npm run dev -- chat "Get 3 from Unsupervised and 2 from reas.eth" -v -o playlist.json
|
|
179
|
+
npm run dev -- build /tmp/feed.json -o playlist-feed.json -v
|
|
126
180
|
```
|
|
127
181
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
- Feed playlist queries require reachable feed servers in your config.
|
|
131
|
-
- If no feeds are reachable, feed playlist examples will fail even if the title exists.
|
|
132
|
-
- Bare EVM prompts (`from 0x...`) now fall back from owner lookup to contract lookup when needed.
|
|
133
|
-
|
|
134
|
-
## Natural Language: Display and Publish
|
|
135
|
-
|
|
136
|
-
The CLI recognizes publishing keywords like "publish", "publish to my feed", "push to feed", "send to feed" and automatically publishes after building.
|
|
137
|
-
|
|
138
|
-
### Basic Publishing
|
|
182
|
+
### From a Feral File artwork
|
|
139
183
|
|
|
140
184
|
```bash
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
185
|
+
cat > /tmp/ff-artwork.json <<'JSON'
|
|
186
|
+
{
|
|
187
|
+
"requirements": [
|
|
188
|
+
{
|
|
189
|
+
"type": "feral_file_artwork",
|
|
190
|
+
"artworkId": "https://feralfile.com/exhibitions/artwork/f0240e04d64717e319584957f6a83954b029254ad1260b6320472ea8c0c5b1cf"
|
|
191
|
+
}
|
|
192
|
+
],
|
|
193
|
+
"playlistSettings": { "title": "Feral File Artwork" }
|
|
194
|
+
}
|
|
195
|
+
JSON
|
|
151
196
|
|
|
152
|
-
|
|
153
|
-
npm run dev chat
|
|
154
|
-
# Then type: "publish the playlist ./playlist-temp.json"
|
|
197
|
+
npm run dev -- build /tmp/ff-artwork.json -o playlist.json
|
|
155
198
|
```
|
|
156
199
|
|
|
157
|
-
###
|
|
200
|
+
### Mixing sources in one playlist
|
|
201
|
+
|
|
202
|
+
Combine multiple requirements; shuffle with `preserveOrder: false` and set per-item timing with `durationPerItem`.
|
|
158
203
|
|
|
159
204
|
```bash
|
|
160
|
-
|
|
161
|
-
|
|
205
|
+
cat > /tmp/mixed.json <<'JSON'
|
|
206
|
+
{
|
|
207
|
+
"requirements": [
|
|
208
|
+
{
|
|
209
|
+
"type": "build_playlist",
|
|
210
|
+
"blockchain": "tezos",
|
|
211
|
+
"contractAddress": "KT1BcNnzWze3vCviwiETYNwcFSwjv6RihZEQ",
|
|
212
|
+
"tokenIds": ["22", "8"]
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
"type": "build_playlist",
|
|
216
|
+
"blockchain": "ethereum",
|
|
217
|
+
"contractAddress": "0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0",
|
|
218
|
+
"tokenIds": ["52932", "52457"]
|
|
219
|
+
},
|
|
220
|
+
{ "type": "fetch_feed", "playlistName": "Unsupervised", "quantity": 3 },
|
|
221
|
+
{ "type": "query_address", "ownerAddress": "reas.eth", "quantity": 1 }
|
|
222
|
+
],
|
|
223
|
+
"playlistSettings": {
|
|
224
|
+
"title": "Mixed",
|
|
225
|
+
"preserveOrder": false,
|
|
226
|
+
"durationPerItem": 6,
|
|
227
|
+
"deviceName": "Living Room Display"
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
JSON
|
|
162
231
|
|
|
163
|
-
|
|
164
|
-
npm run dev -- chat "Get 5 from Unsupervised, shuffle, display on 'Living Room', and publish to feed" -v
|
|
232
|
+
npm run dev -- build /tmp/mixed.json -o playlist-mixed.json -v
|
|
165
233
|
```
|
|
166
234
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
**Mode 1: Build and Publish** (when sources are mentioned)
|
|
170
|
-
|
|
171
|
-
1. Intent parser detects "publish" keywords with sources/requirements
|
|
172
|
-
2. Calls `get_feed_servers` to retrieve configured servers
|
|
173
|
-
3. If 1 server → uses it automatically; if 2+ servers → asks user to pick
|
|
174
|
-
4. Builds playlist → validates structure → publishes automatically
|
|
235
|
+
## Validate / Sign / Play
|
|
175
236
|
|
|
176
|
-
|
|
237
|
+
```bash
|
|
238
|
+
# Validate playlist structure
|
|
239
|
+
npm run dev -- validate playlist.json
|
|
240
|
+
npm run dev -- validate "https://cdn.example.com/playlist.json"
|
|
177
241
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
3. If 1 server → uses it automatically; if 2+ servers → asks user to pick
|
|
181
|
-
4. Publishes the playlist from `./playlist.json` (or specified path)
|
|
242
|
+
# Validate structure AND verify signatures
|
|
243
|
+
npm run dev -- verify playlist.json
|
|
182
244
|
|
|
183
|
-
|
|
245
|
+
# Sign playlist (uses key/role from config, or override via --key / --role)
|
|
246
|
+
npm run dev -- sign playlist.json -o signed.json
|
|
184
247
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
- Publishing status: `✓ Published to feed server`
|
|
188
|
-
- Playlist ID: `Playlist ID: 84e028f8-...`
|
|
248
|
+
# Play on the configured default device
|
|
249
|
+
npm run dev -- play playlist.json
|
|
189
250
|
|
|
190
|
-
|
|
251
|
+
# Play on a specific named device
|
|
252
|
+
npm run dev -- play signed.json -d "Living Room Display"
|
|
191
253
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
npm run dev -- validate playlist.json
|
|
195
|
-
npm run dev -- validate "https://cdn.example.com/playlist.json"
|
|
254
|
+
# Play a hosted DP-1 playlist
|
|
255
|
+
npm run dev -- play "https://cdn.example.com/playlist.json"
|
|
196
256
|
|
|
197
|
-
#
|
|
198
|
-
npm run dev --
|
|
257
|
+
# Play a media URL directly
|
|
258
|
+
npm run dev -- play "https://example.com/video.mp4"
|
|
199
259
|
|
|
200
|
-
#
|
|
201
|
-
npm run dev --
|
|
202
|
-
npm run dev -- send "https://cdn.example.com/playlist.json" -d "Living Room Display"
|
|
260
|
+
# Skip verification only if you must send a non-conformant payload (not recommended)
|
|
261
|
+
npm run dev -- play playlist.json --skip-verify
|
|
203
262
|
```
|
|
204
263
|
|
|
205
264
|
## Publish to Feed Server
|
|
@@ -240,9 +299,9 @@ npm run dev -- publish --help
|
|
|
240
299
|
|
|
241
300
|
### Flow
|
|
242
301
|
|
|
243
|
-
1. **
|
|
302
|
+
1. **Verify** - Playlist structure and signatures checked; unsigned or broken playlists are rejected
|
|
244
303
|
2. **Select Server** - If multiple servers, choose which one (interactive or via `-s` flag)
|
|
245
|
-
3. **Publish** - Send
|
|
304
|
+
3. **Publish** - Send the verified playlist to the selected feed server
|
|
246
305
|
4. **Confirm** - Returns playlist ID and server details
|
|
247
306
|
|
|
248
307
|
### Example Output
|
|
@@ -287,11 +346,11 @@ Select server (0-based index): 0
|
|
|
287
346
|
Failed to publish: {"error":"unauthorized","message":"Invalid API key"}
|
|
288
347
|
```
|
|
289
348
|
|
|
290
|
-
##
|
|
349
|
+
## Complete Flow (build → validate → sign → play → publish)
|
|
291
350
|
|
|
292
351
|
```bash
|
|
293
|
-
# 1.
|
|
294
|
-
npm run dev --
|
|
352
|
+
# 1. Build a playlist (via find or build)
|
|
353
|
+
npm run dev -- find https://objkt.com/tokens/hicetnunc/111068 -o playlist.json
|
|
295
354
|
|
|
296
355
|
# 2. Validate it
|
|
297
356
|
npm run dev -- validate playlist.json
|
|
@@ -299,13 +358,38 @@ npm run dev -- validate playlist.json
|
|
|
299
358
|
# 3. Sign it
|
|
300
359
|
npm run dev -- sign playlist.json -o signed.json
|
|
301
360
|
|
|
302
|
-
# 4.
|
|
303
|
-
npm run dev --
|
|
361
|
+
# 4. Play it on a device
|
|
362
|
+
npm run dev -- play signed.json -d "Living Room Display"
|
|
304
363
|
|
|
305
|
-
# 5. Publish to feed server
|
|
364
|
+
# 5. Publish to a feed server
|
|
306
365
|
npm run dev -- publish signed.json -s 0
|
|
307
366
|
```
|
|
308
367
|
|
|
368
|
+
`ff-cli find` can collapse build + play + publish into one command:
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
npm run dev -- find https://objkt.com/tokens/hicetnunc/111068 --play -d "Living Room Display" --publish
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
## FF1 device management
|
|
375
|
+
|
|
376
|
+
```bash
|
|
377
|
+
# List configured devices
|
|
378
|
+
npm run dev -- device list
|
|
379
|
+
|
|
380
|
+
# Add a device interactively (with mDNS discovery)
|
|
381
|
+
npm run dev -- device add
|
|
382
|
+
|
|
383
|
+
# Add a device non-interactively
|
|
384
|
+
npm run dev -- device add --host 192.168.1.100 --name kitchen
|
|
385
|
+
|
|
386
|
+
# Remove a device by name
|
|
387
|
+
npm run dev -- device remove kitchen
|
|
388
|
+
|
|
389
|
+
# Set the default device (used when -d is omitted)
|
|
390
|
+
npm run dev -- device default office
|
|
391
|
+
```
|
|
392
|
+
|
|
309
393
|
## Troubleshooting
|
|
310
394
|
|
|
311
395
|
```bash
|
|
@@ -314,100 +398,7 @@ npm run dev -- config show
|
|
|
314
398
|
|
|
315
399
|
# Reinitialize config
|
|
316
400
|
npm run dev -- config init
|
|
317
|
-
```
|
|
318
401
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
- Format:
|
|
323
|
-
```bash
|
|
324
|
-
npm run dev -- chat "Compose a playlist from Ethereum contract <0x...> with tokens <id> and <id>; [shuffle|mix]; [send to device|send to '<device>']" -o <output.json> -v
|
|
325
|
-
```
|
|
326
|
-
- Example:
|
|
327
|
-
```bash
|
|
328
|
-
npm run dev -- chat "Compose a playlist from Ethereum contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 with tokens 52932 and 52457; mix them up; send to device" -o playlist-eth.json -v
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
- **TEZ contract + token IDs (shuffle, named device)**
|
|
332
|
-
- Format:
|
|
333
|
-
```bash
|
|
334
|
-
npm run dev -- chat "Build a playlist from Tezos contract <KT1...> with tokens <id> and <id>; shuffle; send to '<device>'" -o <output.json> -v
|
|
335
|
-
```
|
|
336
|
-
- Example:
|
|
337
|
-
```bash
|
|
338
|
-
npm run dev -- chat "Build a playlist from Tezos contract KT1BcNnzWze3vCviwiETYNwcFSwjv6RihZEQ with tokens 22 and 8; shuffle; send to 'Living Room'" -o playlist-tez.json -v
|
|
339
|
-
```
|
|
340
|
-
|
|
341
|
-
- **Owner address (ENS → ETH), shuffled**
|
|
342
|
-
- Format:
|
|
343
|
-
```bash
|
|
344
|
-
npm run dev -- chat "Create a playlist from address <ens> (<n> items); [shuffle|mix]; [send/push to my device]" -o <output.json> -v
|
|
345
|
-
```
|
|
346
|
-
- Example:
|
|
347
|
-
```bash
|
|
348
|
-
npm run dev -- chat "Create a playlist from address reas.eth (5 items); shuffle; push to my device" -o playlist-ens.json -v
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
- **Owner address (Tezos tz1), shuffled**
|
|
352
|
-
- Format:
|
|
353
|
-
```bash
|
|
354
|
-
npm run dev -- chat "Create a playlist from Tezos address <tz1...> (<n> items); [shuffle|mix]; [send to device]" -o <output.json> -v
|
|
355
|
-
```
|
|
356
|
-
- Example:
|
|
357
|
-
```bash
|
|
358
|
-
npm run dev -- chat "Create a playlist from Tezos address tz1VSUr8wwNhLAzempoch5d6hLRiTh8Cjcjb (3 items); mix them up; send to device" -o playlist-tz1.json -v
|
|
359
|
-
```
|
|
360
|
-
|
|
361
|
-
- **Feed playlists (named), shuffled**
|
|
362
|
-
- Format:
|
|
363
|
-
```bash
|
|
364
|
-
npm run dev -- chat "[Create|Build] a playlist from feed '<name>' (<n> items); shuffle; [send to device]" -o <output.json> -v
|
|
365
|
-
```
|
|
366
|
-
- Examples:
|
|
367
|
-
```bash
|
|
368
|
-
npm run dev -- chat "Create a playlist from feed 'Unsupervised' (3 items); shuffle; send to device" -o playlist-feed1.json -v
|
|
369
|
-
npm run dev -- chat "Build a playlist from feed 'Unsupervised' (3 items); shuffle; send to device" -o playlist-feed2.json -v
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
- **Mixed in one prompt (ETH + TEZ + feed + ENS), shuffled, named device**
|
|
373
|
-
- Format:
|
|
374
|
-
```bash
|
|
375
|
-
npm run dev -- chat "Compose a playlist: Tezos <KT1...> tokens <id>, <id>; Ethereum <0x...> tokens <id>, <id>; <n> from '<feed>'; <m> from <ens>; shuffle; send to '<device>'" -o <output.json> -v
|
|
376
|
-
```
|
|
377
|
-
- Example:
|
|
378
|
-
```bash
|
|
379
|
-
npm run dev -- chat "Compose a playlist: Tezos KT1BcNnzWze3vCviwiETYNwcFSwjv6RihZEQ tokens 22, 8; Ethereum 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 tokens 52932, 52457; 3 from 'Unsupervised'; 1 from reas.eth; shuffle; send to 'Living Room'" -o playlist-mixed.json -v
|
|
380
|
-
```
|
|
381
|
-
|
|
382
|
-
- **Multiple instructions in one prompt (incremental), shuffled**
|
|
383
|
-
- Format:
|
|
384
|
-
```bash
|
|
385
|
-
npm run dev -- chat "Create a playlist from Ethereum contract <0x...> tokens <id>, <id>; then add <n> from '<feed>'; then add <m> from <ens>; shuffle; [send/push to my device]" -o <output.json> -v
|
|
386
|
-
```
|
|
387
|
-
- Example:
|
|
388
|
-
```bash
|
|
389
|
-
npm run dev -- chat "Create a playlist from Ethereum contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 tokens 52932, 52457; then add 2 from 'Unsupervised'; then add 1 from reas.eth; shuffle; push to my device" -o playlist-multi.json -v
|
|
390
|
-
```
|
|
391
|
-
|
|
392
|
-
- **Synonym variants for the same ETH case**
|
|
393
|
-
- Format:
|
|
394
|
-
```bash
|
|
395
|
-
npm run dev -- chat "[Build|Create|Compose] a playlist from Ethereum contract <0x...> tokens <id> and <id>; send to device" -o <output.json> -v
|
|
396
|
-
```
|
|
397
|
-
- Examples:
|
|
398
|
-
```bash
|
|
399
|
-
npm run dev -- chat "Build a playlist from Ethereum contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 tokens 52932 and 52457; send to device" -o playlist-eth-build.json -v
|
|
400
|
-
npm run dev -- chat "Create a playlist from Ethereum contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 tokens 52932 and 52457; send to device" -o playlist-eth-create.json -v
|
|
401
|
-
```
|
|
402
|
-
|
|
403
|
-
- **Device targeting: generic vs named**
|
|
404
|
-
- Format:
|
|
405
|
-
```bash
|
|
406
|
-
npm run dev -- chat "Compose a playlist from <ens/address> (<n> items); send to device" -o <output.json> -v
|
|
407
|
-
npm run dev -- chat "Compose a playlist from <ens/address> (<n> items); send to '<device>'" -o <output.json> -v
|
|
408
|
-
```
|
|
409
|
-
- Examples:
|
|
410
|
-
```bash
|
|
411
|
-
npm run dev -- chat "Compose a playlist from reas.eth (3 items); send to device" -o playlist-generic-device.json -v
|
|
412
|
-
npm run dev -- chat "Compose a playlist from reas.eth (3 items); send to 'Living Room'" -o playlist-named-device.json -v
|
|
413
|
-
```
|
|
402
|
+
# Validate configuration
|
|
403
|
+
npm run dev -- config validate
|
|
404
|
+
```
|
package/docs/PROJECT_SPEC.md
CHANGED
|
@@ -15,7 +15,9 @@ It is derived from the behavior and interfaces implemented in this repository as
|
|
|
15
15
|
- Project: `ff-cli`
|
|
16
16
|
- Type: Node.js CLI
|
|
17
17
|
- System role: a control and integration surface for FF1 and DP-1 workflows
|
|
18
|
-
- Primary purpose: turn
|
|
18
|
+
- Primary purpose: turn resolved sources or structured parameters into valid DP-1 playlists deterministically, then validate them and optionally sign, publish, and play them through FF1 and feed paths
|
|
19
|
+
|
|
20
|
+
There is no built-in natural-language interface and no model orchestration. Natural language belongs in the user's coding agent (Claude Code, Codex), which drives ff-cli's deterministic commands via the `ff-control` skill. ff-cli requires no LLM API key.
|
|
19
21
|
|
|
20
22
|
In the Feral File architecture bands, `ff-cli` sits primarily in the presentation and control layer. It is not the canonical source of truth for exhibitions, ownership, device runtime, or protocol evolution. It is a practical operator and developer surface that bridges those systems.
|
|
21
23
|
|
|
@@ -28,7 +30,7 @@ Its value is reducing friction in the publish-to-play path:
|
|
|
28
30
|
- assemble playlists quickly
|
|
29
31
|
- keep outputs DP-1 conformant
|
|
30
32
|
- make FF1 playback and feed publishing easier to exercise
|
|
31
|
-
- provide deterministic tooling
|
|
33
|
+
- provide deterministic tooling that agents and scripts can drive reliably
|
|
32
34
|
|
|
33
35
|
The CLI should strengthen the Gold Path, not invent a parallel product model.
|
|
34
36
|
|
|
@@ -44,11 +46,11 @@ Current likely users:
|
|
|
44
46
|
Primary use cases:
|
|
45
47
|
|
|
46
48
|
- build a playlist from structured JSON inputs
|
|
47
|
-
-
|
|
49
|
+
- resolve a marketplace URL, on-chain coordinates, or a wallet address into a playlist (`find`)
|
|
48
50
|
- validate or verify a local or hosted DP-1 playlist
|
|
49
51
|
- sign a playlist with an Ed25519 key
|
|
50
52
|
- publish a validated playlist to a configured feed server
|
|
51
|
-
-
|
|
53
|
+
- play a playlist or direct media URL on a configured FF1 device
|
|
52
54
|
- manage local config and FF1 SSH access
|
|
53
55
|
- exercise compatibility checks against FF1 OS versions before risky commands
|
|
54
56
|
|
|
@@ -100,9 +102,9 @@ Long-term interoperability should continue to reduce hard infrastructure couplin
|
|
|
100
102
|
Based on the code today, the CLI is responsible for:
|
|
101
103
|
|
|
102
104
|
- loading configuration from `config.json`, `.env`, and defaults, with `config.json` taking precedence
|
|
103
|
-
-
|
|
104
|
-
-
|
|
105
|
-
- supporting a deterministic
|
|
105
|
+
- resolving marketplace URLs, on-chain coordinates, and wallet addresses into playlists (`find`)
|
|
106
|
+
- running feed fetches, address queries, contract-based NFT queries, domain resolution, playlist building, verification, publishing, and playback
|
|
107
|
+
- supporting a deterministic build path from structured JSON (`build`)
|
|
106
108
|
- building DP-1 playlist envelopes from NFT metadata or direct media URLs
|
|
107
109
|
- validating and verifying playlist structure and signatures
|
|
108
110
|
- signing playlists when a private key is configured
|
|
@@ -116,7 +118,7 @@ Based on the code today, the CLI is responsible for:
|
|
|
116
118
|
|
|
117
119
|
- command-line UX and command routing
|
|
118
120
|
- local config loading and validation
|
|
119
|
-
-
|
|
121
|
+
- source resolution (`find`) and structured-params handling (`build`)
|
|
120
122
|
- deterministic playlist assembly, verification, and signing helpers
|
|
121
123
|
- device and feed integration calls from the client side
|
|
122
124
|
|
|
@@ -132,8 +134,8 @@ Based on the code today, the CLI is responsible for:
|
|
|
132
134
|
|
|
133
135
|
- The CLI may assemble, validate, and transmit DP-1 objects, but it should not silently fork the protocol.
|
|
134
136
|
- The CLI may call feed and device endpoints, but it should not become their compatibility abstraction layer of last resort.
|
|
135
|
-
-
|
|
136
|
-
- Trust-sensitive correctness must stay vendor-neutral and portable
|
|
137
|
+
- Deterministic utilities remain the source of truth for output correctness; the CLI does not interpret natural language or orchestrate models.
|
|
138
|
+
- Trust-sensitive correctness must stay vendor-neutral and portable; the trust path cannot depend on cloud-specific guarantees.
|
|
137
139
|
- Current implementation note: some retrieval paths still use Feral File-operated services directly, so portability here is an intended direction rather than a fully achieved property.
|
|
138
140
|
|
|
139
141
|
## Functional shape
|
|
@@ -146,9 +148,9 @@ Today the CLI groups into these workflow areas:
|
|
|
146
148
|
- `status`
|
|
147
149
|
- `config init|show|validate`
|
|
148
150
|
|
|
149
|
-
### Build
|
|
151
|
+
### Build
|
|
150
152
|
|
|
151
|
-
- `
|
|
153
|
+
- `find`
|
|
152
154
|
- `build`
|
|
153
155
|
|
|
154
156
|
### DP-1 output integrity
|
|
@@ -168,11 +170,11 @@ Today the CLI groups into these workflow areas:
|
|
|
168
170
|
|
|
169
171
|
## Deterministic-first behavior
|
|
170
172
|
|
|
171
|
-
The CLI
|
|
173
|
+
The CLI is deterministic end to end. There is no natural-language interface; any natural-language layer lives in the user's coding agent, which drives these commands:
|
|
172
174
|
|
|
173
|
-
-
|
|
174
|
-
- utilities perform the real
|
|
175
|
-
- invalid or malformed outputs
|
|
175
|
+
- commands map directly to source resolution, data fetching, playlist building, validation, signing, and delivery
|
|
176
|
+
- utilities perform the real work and are the source of truth for output correctness
|
|
177
|
+
- invalid or malformed outputs fail validation rather than being passed through
|
|
176
178
|
|
|
177
179
|
## Trust, protocol, and rights assumptions
|
|
178
180
|
|
|
@@ -216,8 +218,8 @@ The current repo verification path is:
|
|
|
216
218
|
npm run lint:fix
|
|
217
219
|
npm test
|
|
218
220
|
npm run build
|
|
219
|
-
|
|
220
|
-
|
|
221
|
+
node dist/index.js validate examples/sample-playlist.json
|
|
222
|
+
node dist/index.js config validate
|
|
221
223
|
```
|
|
222
224
|
|
|
223
225
|
## Open questions
|