ff1-cli 1.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/LICENSE +21 -0
- package/README.md +65 -0
- package/config.json.example +78 -0
- package/dist/index.js +627 -0
- package/dist/src/ai-orchestrator/index.js +870 -0
- package/dist/src/ai-orchestrator/registry.js +96 -0
- package/dist/src/config.js +352 -0
- package/dist/src/intent-parser/index.js +1342 -0
- package/dist/src/intent-parser/utils.js +108 -0
- package/dist/src/logger.js +72 -0
- package/dist/src/main.js +393 -0
- package/dist/src/types.js +5 -0
- package/dist/src/utilities/address-validator.js +242 -0
- package/dist/src/utilities/domain-resolver.js +291 -0
- package/dist/src/utilities/feed-fetcher.js +387 -0
- package/dist/src/utilities/ff1-device.js +176 -0
- package/dist/src/utilities/functions.js +325 -0
- package/dist/src/utilities/index.js +372 -0
- package/dist/src/utilities/nft-indexer.js +1013 -0
- package/dist/src/utilities/playlist-builder.js +522 -0
- package/dist/src/utilities/playlist-publisher.js +131 -0
- package/dist/src/utilities/playlist-send.js +241 -0
- package/dist/src/utilities/playlist-signer.js +171 -0
- package/dist/src/utilities/playlist-verifier.js +156 -0
- package/dist/src/utils.js +48 -0
- package/docs/CONFIGURATION.md +178 -0
- package/docs/EXAMPLES.md +331 -0
- package/docs/FUNCTION_CALLING.md +92 -0
- package/docs/README.md +267 -0
- package/docs/RELEASING.md +22 -0
- package/package.json +75 -0
package/docs/README.md
ADDED
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
# FF1-CLI Documentation
|
|
2
|
+
|
|
3
|
+
Build DP-1 (Display Protocol 1) playlists from NFT data with either natural language (AI‑driven) or deterministic parameters. This doc covers install, config, and day‑to‑day usage.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm i -g ff1-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Install (curl)
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
curl -fsSL https://feralfile.com/ff1-cli-install | bash
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Installs a prebuilt binary for macOS/Linux (no Node.js required).
|
|
18
|
+
|
|
19
|
+
## Configure
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Create example config and edit API keys
|
|
23
|
+
ff1 config init
|
|
24
|
+
|
|
25
|
+
# Validate configuration
|
|
26
|
+
ff1 config validate
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
See the full configuration reference here: `./CONFIGURATION.md`.
|
|
30
|
+
|
|
31
|
+
### config.json structure (minimal)
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"defaultModel": "grok",
|
|
36
|
+
"models": {
|
|
37
|
+
"grok": {
|
|
38
|
+
"apiKey": "xai-your-api-key-here",
|
|
39
|
+
"baseURL": "https://api.x.ai/v1",
|
|
40
|
+
"model": "grok-beta",
|
|
41
|
+
"supportsFunctionCalling": true
|
|
42
|
+
},
|
|
43
|
+
"chatgpt": {
|
|
44
|
+
"apiKey": "sk-your-openai-key-here",
|
|
45
|
+
"baseURL": "https://api.openai.com/v1",
|
|
46
|
+
"model": "gpt-4o",
|
|
47
|
+
"supportsFunctionCalling": true
|
|
48
|
+
},
|
|
49
|
+
"gemini": {
|
|
50
|
+
"apiKey": "your-gemini-key-here",
|
|
51
|
+
"baseURL": "https://generativelanguage.googleapis.com/v1beta/openai/",
|
|
52
|
+
"model": "gemini-2.0-flash-exp",
|
|
53
|
+
"supportsFunctionCalling": true
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"defaultDuration": 10,
|
|
57
|
+
"playlist": {
|
|
58
|
+
"privateKey": "your_ed25519_private_key_base64_here"
|
|
59
|
+
},
|
|
60
|
+
"feed": { "baseURLs": ["https://feed.feralfile.com/api/v1"] },
|
|
61
|
+
"ff1Devices": {
|
|
62
|
+
"devices": [
|
|
63
|
+
{
|
|
64
|
+
"name": "Living Room Display",
|
|
65
|
+
"host": "http://192.168.1.100:1111",
|
|
66
|
+
"apiKey": "",
|
|
67
|
+
"topicID": ""
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Environment variables (optional)
|
|
75
|
+
|
|
76
|
+
See `./CONFIGURATION.md` for environment variable mappings.
|
|
77
|
+
|
|
78
|
+
## Quick Start
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# Chat
|
|
82
|
+
ff1 chat
|
|
83
|
+
|
|
84
|
+
# Or natural language in one shot
|
|
85
|
+
ff1 chat "Get tokens 1,2,3 from Ethereum contract 0xabc" -o playlist.json
|
|
86
|
+
|
|
87
|
+
# Deterministic (no AI)
|
|
88
|
+
ff1 build examples/params-example.json -o playlist.json
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
For development in this repo:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
npm run build
|
|
95
|
+
node dist/index.js chat
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
If you're running from source without a build, use:
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
npm run dev -- chat
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Recommended Deterministic Flow (LLM + Tools)
|
|
105
|
+
|
|
106
|
+
The model orchestrates; deterministic tools keep us honest and DP1‑conformant.
|
|
107
|
+
|
|
108
|
+
1. Input: Share the essentials (contract + token IDs, or feed/URL names).
|
|
109
|
+
2. Orchestration: The LLM parses your prompt and calls tools that:
|
|
110
|
+
- Fetch NFT metadata via OSS libs (`viem` for Ethereum, `@taquito/taquito` for Tezos)
|
|
111
|
+
- Validate DP1 schema with `dp1-js`
|
|
112
|
+
- Build a DP1 playlist envelope deterministically
|
|
113
|
+
- Optionally sign with Ed25519 (canonical JSON via `dp1-js`)
|
|
114
|
+
3. Preview/send: Send to an FF1 on your LAN over HTTP (recommended). Point `ff1Devices.devices[].host` at a local relay if needed.
|
|
115
|
+
4. Publish: Optional feed/registry publishing via the `publish` command.
|
|
116
|
+
|
|
117
|
+
Notes:
|
|
118
|
+
|
|
119
|
+
- **Deterministic by design**: Validation rejects bad or hallucinated data; we loop until it's valid or stop.
|
|
120
|
+
- **OSS‑first**: `viem` and `@taquito/taquito`, with room for local caching.
|
|
121
|
+
- **Relay**: Swap the example host for a local Node/Hono relay; avoid vendor lock‑in.
|
|
122
|
+
|
|
123
|
+
## Commands (cheat sheet)
|
|
124
|
+
|
|
125
|
+
- `chat [content]` – AI-driven natural language playlists
|
|
126
|
+
- Options: `-o, --output <file>`, `-m, --model <name>`, `-v, --verbose`
|
|
127
|
+
- `build [params.json]` – Deterministic build from JSON or stdin
|
|
128
|
+
- Options: `-o, --output <file>`, `-v, --verbose`
|
|
129
|
+
- `play <url>` – Send a media URL directly to an FF1 device
|
|
130
|
+
- Options: `-d, --device <name>`, `--skip-verify`
|
|
131
|
+
- `validate <file>` / `verify <file>` – Validate a DP1 playlist file
|
|
132
|
+
- `sign <file>` – Sign playlist with Ed25519
|
|
133
|
+
- Options: `-k, --key <base64>`, `-o, --output <file>`
|
|
134
|
+
- `send <file>` – Send playlist to an FF1 device
|
|
135
|
+
- Options: `-d, --device <name>`, `--skip-verify`
|
|
136
|
+
- `publish <file>` – Publish a playlist to a feed server
|
|
137
|
+
- Options: `-s, --server <index>` (server index if multiple configured)
|
|
138
|
+
- `config <init|show|validate>` – Manage configuration
|
|
139
|
+
|
|
140
|
+
## Usage Highlights
|
|
141
|
+
|
|
142
|
+
### Natural language (AI)
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
npm run dev -- chat "Get token 42 from Tezos contract KT1abc"
|
|
146
|
+
npm run dev -- chat "Get tokens 100-105 from Ethereum contract 0xdef" -o playlist.json
|
|
147
|
+
npm run dev -- chat "Get 3 from Social Codes and 2 from 0xabc" -v
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### One-shot complex prompt
|
|
151
|
+
|
|
152
|
+
The model reads your request via the intent parser and turns it into structured `requirements` and `playlistSettings` (including shuffle, durations, and device). You can do everything in one line:
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
# Mix sources, shuffle order, set per-item duration, and send to a named device
|
|
156
|
+
npm run dev -- chat "From Ethereum contract 0xabc get tokens 1,2 and from Tezos KT1xyz get token 42; shuffle the order; 7 seconds per item; send to device 'Living Room Display'." -o playlist.json -v
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
How it works (at a glance):
|
|
160
|
+
|
|
161
|
+
- The intent parser maps your text to `requirements` (what to fetch) and `playlistSettings` (e.g., `durationPerItem`, `preserveOrder=false` for shuffle, `deviceName`, `feedServer`).
|
|
162
|
+
- Deterministic tools fetch NFT metadata, build a DP‑1 playlist, and validate it.
|
|
163
|
+
- If `deviceName` is present, the CLI will send the validated playlist to that FF1 device.
|
|
164
|
+
- If `feedServer` is present (via "publish to my feed"), the CLI will publish the playlist to the selected feed server.
|
|
165
|
+
|
|
166
|
+
Use `--model grok|chatgpt|gemini` to switch models, or set `defaultModel` in `config.json`.
|
|
167
|
+
|
|
168
|
+
### Natural language publishing
|
|
169
|
+
|
|
170
|
+
The intent parser recognizes publishing keywords and can both display and publish in one command:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
# Build and publish
|
|
174
|
+
npm run dev -- chat "Build playlist from Ethereum contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 with tokens 52932 and 52457; publish to my feed" -o playlist.json -v
|
|
175
|
+
|
|
176
|
+
# Display on FF1 AND publish to feed
|
|
177
|
+
npm run dev -- chat "Get tokens 1,2 from 0xabc; shuffle; send to my FF1 and publish to feed" -o playlist.json -v
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Publishing keywords: "publish", "publish to my feed", "push to feed", "send to feed". The CLI will:
|
|
181
|
+
|
|
182
|
+
1. Detect the keyword and call `get_feed_servers`
|
|
183
|
+
2. If multiple servers → ask which one to use
|
|
184
|
+
3. Build → verify → publish automatically
|
|
185
|
+
4. Display playlist ID and server URL on success
|
|
186
|
+
|
|
187
|
+
### Deterministic (no AI)
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
npm run dev -- build params.json -o playlist.json
|
|
191
|
+
cat params.json | npm run dev -- build -o playlist.json
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
`params.json` should include `requirements` and optional `playlistSettings`. See `examples/params-example.json`.
|
|
195
|
+
|
|
196
|
+
### Validate, sign, and send
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
# Validate
|
|
200
|
+
npm run dev -- validate playlist.json
|
|
201
|
+
|
|
202
|
+
# Sign (uses key from config or override via --key)
|
|
203
|
+
npm run dev -- sign playlist.json -o signed.json
|
|
204
|
+
|
|
205
|
+
# Send to device (verifies by default)
|
|
206
|
+
npm run dev -- send playlist.json -d "Living Room Display"
|
|
207
|
+
|
|
208
|
+
# Play a direct URL
|
|
209
|
+
npm run dev -- play "https://example.com/video.mp4" -d "Living Room Display" --skip-verify
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
### Publish to feed server
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
# Publish to first configured feed server
|
|
216
|
+
npm run dev -- publish playlist.json
|
|
217
|
+
|
|
218
|
+
# Publish to specific server (if multiple configured)
|
|
219
|
+
npm run dev -- publish playlist.json -s 0
|
|
220
|
+
npm run dev -- publish playlist.json -s 1
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
The `publish` command:
|
|
224
|
+
|
|
225
|
+
- Validates the playlist against DP-1 spec
|
|
226
|
+
- Shows interactive server selection if multiple are configured
|
|
227
|
+
- Sends the validated playlist to the chosen feed server
|
|
228
|
+
- Returns the playlist ID on success
|
|
229
|
+
|
|
230
|
+
Configure feed servers in `config.json`:
|
|
231
|
+
|
|
232
|
+
```json
|
|
233
|
+
{
|
|
234
|
+
"feedServers": [
|
|
235
|
+
{
|
|
236
|
+
"baseUrl": "http://localhost:8787/api/v1",
|
|
237
|
+
"apiKey": "your-api-key-optional"
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
"baseUrl": "https://feed.example.com/api/v1",
|
|
241
|
+
"apiKey": "your-api-key-optional"
|
|
242
|
+
}
|
|
243
|
+
]
|
|
244
|
+
}
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
### FF1 device configuration
|
|
248
|
+
|
|
249
|
+
See selection rules and examples in `./CONFIGURATION.md`.
|
|
250
|
+
|
|
251
|
+
### Playlist signing (optional)
|
|
252
|
+
|
|
253
|
+
- Add `playlist.privateKey` (base64 Ed25519) to `config.json` or set `PLAYLIST_PRIVATE_KEY`.
|
|
254
|
+
- Signed playlists include a `signature` field compliant with DP1 (via `dp1-js`).
|
|
255
|
+
|
|
256
|
+
## Constraints
|
|
257
|
+
|
|
258
|
+
- Max 20 items total across all requirements
|
|
259
|
+
- Per-source caps enforced in utilities
|
|
260
|
+
- Duration per item defaults to 10s (configurable)
|
|
261
|
+
|
|
262
|
+
## Links
|
|
263
|
+
|
|
264
|
+
- Function calling details: `./FUNCTION_CALLING.md`
|
|
265
|
+
- Examples: `./EXAMPLES.md`
|
|
266
|
+
- Release assets: `./RELEASING.md`
|
|
267
|
+
- DP1 spec: `https://github.com/display-protocol/dp1`
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Releasing Binary Assets
|
|
2
|
+
|
|
3
|
+
The curl installer downloads prebuilt binaries from GitHub Releases. Build one asset per OS/arch and upload both the archive and its `.sha256` checksum.
|
|
4
|
+
|
|
5
|
+
## Build a Release Asset (local)
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
./scripts/release/build-asset.sh
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
This produces:
|
|
12
|
+
|
|
13
|
+
- `release/ff1-cli-darwin-x64.tar.gz`
|
|
14
|
+
- `release/ff1-cli-darwin-x64.tar.gz.sha256`
|
|
15
|
+
|
|
16
|
+
The exact filename depends on the OS/arch you build on. Run the script on each target platform (macOS + Linux, x64/arm64) and upload each pair to the GitHub release.
|
|
17
|
+
|
|
18
|
+
## Environment Overrides
|
|
19
|
+
|
|
20
|
+
- `FF1_CLI_VERSION`: overrides the version label in logs
|
|
21
|
+
- `FF1_CLI_NODE_VERSION`: Node version to bundle (default: 20.12.2)
|
|
22
|
+
- `FF1_CLI_OUTPUT_DIR`: output directory (default: `./release`)
|
package/package.json
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "ff1-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CLI to fetch NFT information and build DP1 playlists using Grok API",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ff1": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"docs",
|
|
12
|
+
"config.json.example",
|
|
13
|
+
"README.md",
|
|
14
|
+
"LICENSE"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc",
|
|
18
|
+
"bundle": "node build.js",
|
|
19
|
+
"bundle:dev": "node build.js --dev",
|
|
20
|
+
"release:asset": "./scripts/release/build-asset.sh",
|
|
21
|
+
"start": "node dist/index.js",
|
|
22
|
+
"dev": "tsx index.ts",
|
|
23
|
+
"prepublishOnly": "npm run build",
|
|
24
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
25
|
+
"lint": "eslint .",
|
|
26
|
+
"lint:fix": "eslint . --fix",
|
|
27
|
+
"format": "prettier --write \"**/*.{js,ts}\"",
|
|
28
|
+
"format:check": "prettier --check \"**/*.{js,ts}\""
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=18"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"keywords": [
|
|
37
|
+
"nft",
|
|
38
|
+
"playlist",
|
|
39
|
+
"dp1",
|
|
40
|
+
"grok",
|
|
41
|
+
"cli"
|
|
42
|
+
],
|
|
43
|
+
"author": "",
|
|
44
|
+
"license": "MIT",
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@lancedb/lancedb": "^0.22.1",
|
|
47
|
+
"@mozilla/readability": "^0.6.0",
|
|
48
|
+
"@xenova/transformers": "^2.17.2",
|
|
49
|
+
"axios": "^1.6.2",
|
|
50
|
+
"chalk": "^4.1.2",
|
|
51
|
+
"cheerio": "^1.0.0-rc.12",
|
|
52
|
+
"commander": "^11.1.0",
|
|
53
|
+
"dotenv": "^16.3.1",
|
|
54
|
+
"dp1-js": "^1.1.0",
|
|
55
|
+
"fuzzysort": "^3.1.0",
|
|
56
|
+
"jsdom": "^27.0.0",
|
|
57
|
+
"openai": "^4.58.1",
|
|
58
|
+
"ora": "^5.4.1",
|
|
59
|
+
"puppeteer": "^24.22.3",
|
|
60
|
+
"viem": "^2.38.2"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@types/jsdom": "^27.0.0",
|
|
64
|
+
"@types/node": "^24.7.1",
|
|
65
|
+
"@typescript-eslint/eslint-plugin": "^8.46.0",
|
|
66
|
+
"@typescript-eslint/parser": "^8.46.0",
|
|
67
|
+
"esbuild": "^0.25.10",
|
|
68
|
+
"eslint": "^9.36.0",
|
|
69
|
+
"eslint-config-prettier": "^10.1.8",
|
|
70
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
71
|
+
"prettier": "^3.6.2",
|
|
72
|
+
"tsx": "^4.20.6",
|
|
73
|
+
"typescript": "^5.9.3"
|
|
74
|
+
}
|
|
75
|
+
}
|