@feralfile/cli 1.1.1
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 +96 -0
- package/config.json.example +96 -0
- package/dist/index.js +54 -0
- package/dist/src/ai-orchestrator/index.js +1019 -0
- package/dist/src/ai-orchestrator/registry.js +96 -0
- package/dist/src/commands/build.js +69 -0
- package/dist/src/commands/chat.js +189 -0
- package/dist/src/commands/config.js +68 -0
- package/dist/src/commands/device.js +278 -0
- package/dist/src/commands/helpers/config-files.js +62 -0
- package/dist/src/commands/helpers/device-discovery.js +111 -0
- package/dist/src/commands/helpers/playlist-display.js +161 -0
- package/dist/src/commands/helpers/prompt.js +65 -0
- package/dist/src/commands/helpers/ssh-helpers.js +44 -0
- package/dist/src/commands/play.js +110 -0
- package/dist/src/commands/publish.js +115 -0
- package/dist/src/commands/setup.js +225 -0
- package/dist/src/commands/sign.js +41 -0
- package/dist/src/commands/ssh.js +108 -0
- package/dist/src/commands/status.js +126 -0
- package/dist/src/commands/validate.js +18 -0
- package/dist/src/config.js +441 -0
- package/dist/src/intent-parser/index.js +1382 -0
- package/dist/src/intent-parser/utils.js +108 -0
- package/dist/src/logger.js +82 -0
- package/dist/src/main.js +459 -0
- package/dist/src/types.js +5 -0
- package/dist/src/utilities/address-validator.js +242 -0
- package/dist/src/utilities/device-default.js +36 -0
- package/dist/src/utilities/device-lookup.js +107 -0
- package/dist/src/utilities/device-normalize.js +62 -0
- package/dist/src/utilities/device-upsert.js +91 -0
- package/dist/src/utilities/domain-resolver.js +291 -0
- package/dist/src/utilities/ed25519-key-derive.js +155 -0
- package/dist/src/utilities/feed-fetcher.js +471 -0
- package/dist/src/utilities/ff1-compatibility.js +269 -0
- package/dist/src/utilities/ff1-device.js +250 -0
- package/dist/src/utilities/ff1-discovery.js +330 -0
- package/dist/src/utilities/functions.js +308 -0
- package/dist/src/utilities/index.js +469 -0
- package/dist/src/utilities/nft-indexer.js +1024 -0
- package/dist/src/utilities/playlist-builder.js +523 -0
- package/dist/src/utilities/playlist-publisher.js +131 -0
- package/dist/src/utilities/playlist-send.js +260 -0
- package/dist/src/utilities/playlist-signer.js +204 -0
- package/dist/src/utilities/playlist-signing-role.js +41 -0
- package/dist/src/utilities/playlist-source.js +128 -0
- package/dist/src/utilities/playlist-verifier.js +274 -0
- package/dist/src/utilities/ssh-access.js +145 -0
- package/dist/src/utils.js +48 -0
- package/docs/CONFIGURATION.md +206 -0
- package/docs/EXAMPLES.md +390 -0
- package/docs/FUNCTION_CALLING.md +96 -0
- package/docs/PROJECT_SPEC.md +228 -0
- package/docs/README.md +348 -0
- package/docs/RELEASING.md +73 -0
- package/package.json +76 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# ff-cli Project Spec
|
|
2
|
+
|
|
3
|
+
This document defines the current product role, boundaries, and constraints for `ff-cli`.
|
|
4
|
+
|
|
5
|
+
It is derived from the behavior and interfaces implemented in this repository as of March 2026. It serves as the planning entry point for substantial changes and should be updated as the CLI evolves.
|
|
6
|
+
|
|
7
|
+
## Why this doc exists
|
|
8
|
+
|
|
9
|
+
- Give future contributors and coding agents a stable current-state spec before implementation starts.
|
|
10
|
+
- Make the CLI's role in the broader FF1 and DP-1 system explicit.
|
|
11
|
+
- Record the constraints that should shape changes even when the codebase is refactored.
|
|
12
|
+
|
|
13
|
+
## Product summary
|
|
14
|
+
|
|
15
|
+
- Project: `ff-cli`
|
|
16
|
+
- Type: Node.js CLI
|
|
17
|
+
- System role: a control and integration surface for FF1 and DP-1 workflows
|
|
18
|
+
- Primary purpose: turn user intent or structured parameters into valid DP-1 playlists, then validate them and optionally sign, publish, and send them through FF1 and feed paths
|
|
19
|
+
|
|
20
|
+
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
|
+
|
|
22
|
+
## Strategic role
|
|
23
|
+
|
|
24
|
+
The CLI supports the broader Feral File goal of making it effortless to live with digital art every day.
|
|
25
|
+
|
|
26
|
+
Its value is reducing friction in the publish-to-play path:
|
|
27
|
+
|
|
28
|
+
- assemble playlists quickly
|
|
29
|
+
- keep outputs DP-1 conformant
|
|
30
|
+
- make FF1 playback and feed publishing easier to exercise
|
|
31
|
+
- provide deterministic tooling around model-assisted workflows
|
|
32
|
+
|
|
33
|
+
The CLI should strengthen the Gold Path, not invent a parallel product model.
|
|
34
|
+
|
|
35
|
+
## Users and primary use cases
|
|
36
|
+
|
|
37
|
+
Current likely users:
|
|
38
|
+
|
|
39
|
+
- internal engineers working on FF1, DP-1, feed, and device flows
|
|
40
|
+
- operators and launch teammates validating publish-to-play behavior
|
|
41
|
+
- advanced users or partners building and testing playlists
|
|
42
|
+
- developers using the CLI as a reference implementation for DP-1 and FF1 command flows
|
|
43
|
+
|
|
44
|
+
Primary use cases:
|
|
45
|
+
|
|
46
|
+
- build a playlist from structured JSON inputs
|
|
47
|
+
- build a playlist from natural-language prompts using model orchestration plus deterministic tools
|
|
48
|
+
- validate or verify a local or hosted DP-1 playlist
|
|
49
|
+
- sign a playlist with an Ed25519 key
|
|
50
|
+
- publish a validated playlist to a configured feed server
|
|
51
|
+
- send a playlist or direct media URL to a configured FF1 device
|
|
52
|
+
- manage local config and FF1 SSH access
|
|
53
|
+
- exercise compatibility checks against FF1 OS versions before risky commands
|
|
54
|
+
|
|
55
|
+
## Domain language
|
|
56
|
+
|
|
57
|
+
Use these terms consistently:
|
|
58
|
+
|
|
59
|
+
- `FF1`
|
|
60
|
+
- `FF1 device`
|
|
61
|
+
- `DP-1`
|
|
62
|
+
- `DP-1 envelope`
|
|
63
|
+
- `DP-1 conformance`
|
|
64
|
+
- `computational art playlist`
|
|
65
|
+
- `channel endorsement`
|
|
66
|
+
- `feed server`
|
|
67
|
+
- `playlist`
|
|
68
|
+
- `work`
|
|
69
|
+
|
|
70
|
+
## Product goals
|
|
71
|
+
|
|
72
|
+
The current code and internal context imply these practical goals:
|
|
73
|
+
|
|
74
|
+
- Make playlist creation and playback testing fast enough for daily use.
|
|
75
|
+
- Keep the path from intent to valid DP-1 output deterministic and inspectable.
|
|
76
|
+
- Preserve openness by relying on DP-1 as the compatibility layer instead of a CLI-specific format.
|
|
77
|
+
- Support FF1 as the reference playback target without making correctness depend on proprietary-only infrastructure.
|
|
78
|
+
- Serve as a reference surface for publish, verify, and play flows used elsewhere in the Feral File stack.
|
|
79
|
+
|
|
80
|
+
### Current behavior
|
|
81
|
+
|
|
82
|
+
The current implementation still depends on Feral File-operated infrastructure for some data retrieval paths, including the hardcoded production indexer endpoint used for NFT lookup.
|
|
83
|
+
|
|
84
|
+
### Design direction
|
|
85
|
+
|
|
86
|
+
Long-term interoperability should continue to reduce hard infrastructure coupling where practical, especially when a dependency blocks portability without adding protocol value.
|
|
87
|
+
|
|
88
|
+
## Non-goals
|
|
89
|
+
|
|
90
|
+
`ff-cli` should not become:
|
|
91
|
+
|
|
92
|
+
- the source of truth for exhibitions, channels, or artwork metadata
|
|
93
|
+
- the source of truth for ownership, passkeys, rights, or trust registry state
|
|
94
|
+
- a replacement for the mobile app as the primary user-facing controller
|
|
95
|
+
- a place to define new DP-1 protocol semantics by convenience
|
|
96
|
+
- a long-running backend service with hidden state
|
|
97
|
+
|
|
98
|
+
## Current system responsibilities
|
|
99
|
+
|
|
100
|
+
Based on the code today, the CLI is responsible for:
|
|
101
|
+
|
|
102
|
+
- loading configuration from `config.json`, `.env`, and defaults, with `config.json` taking precedence
|
|
103
|
+
- parsing natural-language requests into structured playlist requirements and settings
|
|
104
|
+
- orchestrating tool calls for feed fetches, address queries, contract-based NFT queries, domain resolution, playlist building, verification, publishing, and sending
|
|
105
|
+
- supporting a deterministic non-AI build path from structured JSON
|
|
106
|
+
- building DP-1 playlist envelopes from NFT metadata or direct media URLs
|
|
107
|
+
- validating and verifying playlist structure and signatures
|
|
108
|
+
- signing playlists when a private key is configured
|
|
109
|
+
- publishing validated playlists to configured feed servers
|
|
110
|
+
- discovering configured FF1 devices and sending playlists or direct media playback requests
|
|
111
|
+
- performing FF1 OS compatibility preflight checks before display and SSH flows
|
|
112
|
+
|
|
113
|
+
## Architecture boundaries
|
|
114
|
+
|
|
115
|
+
### What the CLI owns
|
|
116
|
+
|
|
117
|
+
- command-line UX and command routing
|
|
118
|
+
- local config loading and validation
|
|
119
|
+
- intent parsing and orchestration glue
|
|
120
|
+
- deterministic playlist assembly, verification, and signing helpers
|
|
121
|
+
- device and feed integration calls from the client side
|
|
122
|
+
|
|
123
|
+
### What the CLI depends on but does not own
|
|
124
|
+
|
|
125
|
+
- DP-1 protocol shape and evolution
|
|
126
|
+
- feed server behavior and data persistence
|
|
127
|
+
- FF1 runtime and OS behavior
|
|
128
|
+
- ownership and identity systems
|
|
129
|
+
- trust-path policy, licensing policy, and key registry policy
|
|
130
|
+
|
|
131
|
+
### Boundary rules
|
|
132
|
+
|
|
133
|
+
- The CLI may assemble, validate, and transmit DP-1 objects, but it should not silently fork the protocol.
|
|
134
|
+
- The CLI may call feed and device endpoints, but it should not become their compatibility abstraction layer of last resort.
|
|
135
|
+
- The CLI may use models for orchestration, but deterministic utilities remain the source of truth for output correctness.
|
|
136
|
+
- Trust-sensitive correctness must stay vendor-neutral and portable. The CLI can use cloud APIs for model orchestration, but the trust path cannot depend on cloud-specific guarantees.
|
|
137
|
+
- 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
|
+
|
|
139
|
+
## Functional shape
|
|
140
|
+
|
|
141
|
+
Today the CLI groups into these workflow areas:
|
|
142
|
+
|
|
143
|
+
### Setup and configuration
|
|
144
|
+
|
|
145
|
+
- `setup`
|
|
146
|
+
- `status`
|
|
147
|
+
- `config init|show|validate`
|
|
148
|
+
|
|
149
|
+
### Build and orchestration
|
|
150
|
+
|
|
151
|
+
- `chat`
|
|
152
|
+
- `build`
|
|
153
|
+
|
|
154
|
+
### DP-1 output integrity
|
|
155
|
+
|
|
156
|
+
- `verify`
|
|
157
|
+
- `validate`
|
|
158
|
+
- `sign`
|
|
159
|
+
|
|
160
|
+
### Delivery
|
|
161
|
+
|
|
162
|
+
- `play` (handles playlist files, playlist URLs, and media URLs)
|
|
163
|
+
- `publish`
|
|
164
|
+
|
|
165
|
+
### Device operations
|
|
166
|
+
|
|
167
|
+
- `ssh enable|disable`
|
|
168
|
+
|
|
169
|
+
## Deterministic-first behavior
|
|
170
|
+
|
|
171
|
+
The CLI supports model-assisted workflows, but the implementation posture should remain deterministic-first:
|
|
172
|
+
|
|
173
|
+
- models interpret intent
|
|
174
|
+
- utilities perform the real data fetching, playlist building, validation, signing, and delivery work
|
|
175
|
+
- invalid or malformed outputs should fail validation rather than being accepted because they were model-produced
|
|
176
|
+
|
|
177
|
+
## Trust, protocol, and rights assumptions
|
|
178
|
+
|
|
179
|
+
Important constraints from the broader FF system:
|
|
180
|
+
|
|
181
|
+
- DP-1 should evolve additively and remain forward-compatible where practical.
|
|
182
|
+
- Trust-path correctness must remain portable and key-controlled.
|
|
183
|
+
- Ownership and stewardship should not be confused with access gating in the CLI.
|
|
184
|
+
- The CLI may surface signatures, verification, and publishing, but it should not absorb licensing or identity policy that belongs elsewhere in the system.
|
|
185
|
+
|
|
186
|
+
## Reliability expectations
|
|
187
|
+
|
|
188
|
+
### Current behavior
|
|
189
|
+
|
|
190
|
+
- reliability matters more than novelty
|
|
191
|
+
- the publish-to-play path should stay simple and testable
|
|
192
|
+
- the CLI should help prove the path from canonical JSON to FF1 playback
|
|
193
|
+
- compatibility checks fail clearly when incompatibility is confirmed
|
|
194
|
+
- if FF1 OS version cannot be determined during preflight, the CLI currently proceeds and logs a warning instead of hard-blocking the command
|
|
195
|
+
|
|
196
|
+
### Design direction
|
|
197
|
+
|
|
198
|
+
- reliability matters more than novelty
|
|
199
|
+
- the publish-to-play path should stay simple and testable
|
|
200
|
+
- the CLI should help prove the path from canonical JSON to FF1 playback
|
|
201
|
+
- compatibility messaging should remain explicit enough that operators can distinguish confirmed incompatibility from uncertain device state
|
|
202
|
+
|
|
203
|
+
## Code and design constraints
|
|
204
|
+
|
|
205
|
+
- behavior changes should follow a spec-driven, test-first workflow when practical
|
|
206
|
+
- TypeScript is preferred for new or updated source
|
|
207
|
+
- comments should preserve durable maintenance context when the code encodes non-obvious design choices, trade-offs, invariants, or external constraints
|
|
208
|
+
- docs should be updated when user-facing behavior changes
|
|
209
|
+
- legacy compatibility paths should not be preserved unless explicitly required
|
|
210
|
+
|
|
211
|
+
## Verification expectations
|
|
212
|
+
|
|
213
|
+
The current repo verification path is:
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
npm run lint:fix
|
|
217
|
+
npm test
|
|
218
|
+
npm run build
|
|
219
|
+
ANTHROPIC_API_KEY=dummy node dist/index.js validate examples/sample-playlist.json
|
|
220
|
+
ANTHROPIC_API_KEY=dummy node dist/index.js config validate
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## Open questions
|
|
224
|
+
|
|
225
|
+
- Which CLI commands are considered stable public interface versus internal reference tooling?
|
|
226
|
+
- How much of the feed and trust workflow should remain directly exposed in the CLI?
|
|
227
|
+
- Which FF1 operations deserve stronger compatibility policies or broader smoke coverage?
|
|
228
|
+
- How much of the mobile app's long-term control model should also be mirrored in CLI form?
|
package/docs/README.md
ADDED
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
# ff-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
|
+
For project-level planning and future agentic work, see `./PROJECT_SPEC.md`.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm i -g @feralfile/cli
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
`npm` and `npx` require **Node.js 22 or newer** (see `package.json` `engines`). When a release raises the Node floor, that is a **breaking** change for Node 18/20 users; the GitHub Release for that version should say so explicitly (see `./RELEASING.md` for maintainer guidance).
|
|
14
|
+
|
|
15
|
+
## Install (curl)
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
curl -fsSL https://feralfile.com/ff-cli-install | bash
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Installs a prebuilt binary for macOS/Linux (no Node.js required).
|
|
22
|
+
|
|
23
|
+
## Configure
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
# Guided setup (recommended)
|
|
27
|
+
ff-cli setup
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
See the full configuration reference here: `./CONFIGURATION.md`.
|
|
31
|
+
|
|
32
|
+
During setup, you can pick FF1 devices to add. Use `ff-cli device add` to add more devices later, and `ff-cli device list` to see what's configured. The first device is the default for `play` commands (override with `-d`).
|
|
33
|
+
|
|
34
|
+
Manual config path:
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
ff-cli config init
|
|
38
|
+
ff-cli config validate
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### config.json structure (minimal)
|
|
42
|
+
|
|
43
|
+
```json
|
|
44
|
+
{
|
|
45
|
+
"defaultModel": "claude",
|
|
46
|
+
"models": {
|
|
47
|
+
"claude": {
|
|
48
|
+
"apiKey": "sk-ant-your-api-key-here",
|
|
49
|
+
"baseURL": "https://api.anthropic.com/v1/",
|
|
50
|
+
"model": "claude-sonnet-4-6",
|
|
51
|
+
"supportsFunctionCalling": true
|
|
52
|
+
},
|
|
53
|
+
"grok": {
|
|
54
|
+
"apiKey": "xai-your-api-key-here",
|
|
55
|
+
"baseURL": "https://api.x.ai/v1",
|
|
56
|
+
"model": "grok-beta",
|
|
57
|
+
"supportsFunctionCalling": true
|
|
58
|
+
},
|
|
59
|
+
"gpt": {
|
|
60
|
+
"apiKey": "sk-your-openai-key-here",
|
|
61
|
+
"baseURL": "https://api.openai.com/v1",
|
|
62
|
+
"model": "gpt-4o",
|
|
63
|
+
"supportsFunctionCalling": true
|
|
64
|
+
},
|
|
65
|
+
"gemini": {
|
|
66
|
+
"apiKey": "your-gemini-key-here",
|
|
67
|
+
"baseURL": "https://generativelanguage.googleapis.com/v1beta/openai/",
|
|
68
|
+
"model": "gemini-2.5-flash",
|
|
69
|
+
"supportsFunctionCalling": true
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"defaultDuration": 10,
|
|
73
|
+
"playlist": {
|
|
74
|
+
"privateKey": "your_ed25519_private_key_hex_or_base64_here"
|
|
75
|
+
},
|
|
76
|
+
"feed": { "baseURLs": ["https://dp1-feed-operator-api-prod.autonomy-system.workers.dev/api/v1"] },
|
|
77
|
+
"ff1Devices": {
|
|
78
|
+
"devices": [
|
|
79
|
+
{
|
|
80
|
+
"name": "Living Room Display",
|
|
81
|
+
"host": "http://192.168.1.100:1111"
|
|
82
|
+
}
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Environment variables (optional)
|
|
89
|
+
|
|
90
|
+
See `./CONFIGURATION.md` for environment variable mappings.
|
|
91
|
+
|
|
92
|
+
## Quick Start
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
# Chat
|
|
96
|
+
ff-cli chat
|
|
97
|
+
|
|
98
|
+
# Or natural language in one shot
|
|
99
|
+
ff-cli chat "Get 3 works from reas.eth" -o playlist.json
|
|
100
|
+
|
|
101
|
+
# Deterministic (no AI)
|
|
102
|
+
ff-cli build examples/params-example.json -o playlist.json
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
For development in this repo:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
npm run build
|
|
109
|
+
node dist/index.js chat
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
If you're running from source without a build, use:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
npm run dev -- chat
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Recommended Deterministic Flow (LLM + Tools)
|
|
119
|
+
|
|
120
|
+
The model orchestrates; deterministic tools keep us honest and DP1‑conformant.
|
|
121
|
+
|
|
122
|
+
1. Input: Share the essentials (contract + token IDs, or feed/URL names).
|
|
123
|
+
2. Orchestration: The LLM parses your prompt and calls tools that:
|
|
124
|
+
- Fetch NFT metadata via OSS libs (`viem` for Ethereum, `@taquito/taquito` for Tezos)
|
|
125
|
+
- Validate DP1 schema with `dp1-js`
|
|
126
|
+
- Build a DP1 playlist envelope deterministically
|
|
127
|
+
- Optionally sign with Ed25519 (canonical JSON via `dp1-js`)
|
|
128
|
+
3. Preview/send: Send to an FF1 on your LAN over HTTP (recommended). Point `ff1Devices.devices[].host` at a local relay if needed.
|
|
129
|
+
4. Publish: Optional feed/registry publishing via the `publish` command.
|
|
130
|
+
|
|
131
|
+
Notes:
|
|
132
|
+
|
|
133
|
+
- **Deterministic by design**: Validation rejects bad or hallucinated data; we loop until it's valid or stop.
|
|
134
|
+
- **OSS‑first**: `viem` and `@taquito/taquito`, with room for local caching.
|
|
135
|
+
- **Relay**: Swap the example host for a local Node/Hono relay; avoid vendor lock‑in.
|
|
136
|
+
|
|
137
|
+
## Commands (cheat sheet)
|
|
138
|
+
|
|
139
|
+
- `chat [content]` – AI-driven natural language playlists
|
|
140
|
+
- Options: `-o, --output <file>`, `-m, --model <name>`, `-d, --device <name>`, `-v, --verbose`
|
|
141
|
+
- `build [params.json]` – Deterministic build from JSON or stdin
|
|
142
|
+
- Options: `-o, --output <file>`, `-v, --verbose`
|
|
143
|
+
- `validate <file-or-url>` – Validate playlist structure only
|
|
144
|
+
- `verify <file-or-url>` – Validate structure and verify signatures. On failure, the CLI labels structure issues separately from signature verification. dp1-js uses `--public-key` (or a key derived from `playlist.privateKey` / `PLAYLIST_PRIVATE_KEY` when omitted) **only** for legacy flat `signature` verification; DP-1 v1.1.0 `signatures[]` envelopes are verified without relying on that argument. If deriving or normalizing key material fails, the CLI prints a warning on stderr and continues without it (legacy verification still requires a usable key when the playlist uses a flat `signature`). The derived key is emitted as PEM. Supported key forms: hex with optional `0x`, PEM, or 32-byte raw public key as hex or base64
|
|
145
|
+
- `sign <file>` – Sign playlist with a DP-1 v1.1.0 multi-signature envelope (private key string is forwarded to **`dp1-js`**; same hex or base64 PKCS#8 DER forms as `playlist.privateKey` in `./CONFIGURATION.md`). The command verifies the final envelope before writing output and refuses to persist tampered or otherwise unverifiable `signatures[]`.
|
|
146
|
+
- Options: `-k, --key <privateKey>`, `-r, --role <role>`, `-o, --output <file>`
|
|
147
|
+
- `play <source>` – Play a playlist file, playlist URL, or media URL on an FF1 device (runs `validate`-style structure checks before sending; use `verify` for signatures)
|
|
148
|
+
- Options: `-d, --device <name>`, `--skip-verify` (skip structure validation; not recommended)
|
|
149
|
+
- `publish <file>` – Publish a playlist to a feed server (`validate`-style structure checks before upload; use `verify` for signatures)
|
|
150
|
+
- Options: `-s, --server <index>` (server index if multiple configured)
|
|
151
|
+
- `ssh <enable|disable>` – Manage SSH access on an FF1 device
|
|
152
|
+
- Options: `-d, --device <name>`, `--pubkey <path>`, `--ttl <duration>`
|
|
153
|
+
- `device list` – List all configured FF1 devices
|
|
154
|
+
- `device add` – Add a new FF1 device (with mDNS discovery)
|
|
155
|
+
- Options: `--host <host>`, `--name <name>`
|
|
156
|
+
- `device remove <name>` – Remove a configured FF1 device
|
|
157
|
+
- `device default <name>` – Set the default FF1 device (used when `-d` is omitted)
|
|
158
|
+
- `config <init|show|validate>` – Manage configuration
|
|
159
|
+
|
|
160
|
+
## Usage Highlights
|
|
161
|
+
|
|
162
|
+
### Natural language (AI)
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
npm run dev -- chat "Get 3 works from reas.eth"
|
|
166
|
+
npm run dev -- chat "Get 3 works from einstein-rosen.tez"
|
|
167
|
+
npm run dev -- chat "Get tokens 52932,52457 from Ethereum contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0" -o playlist.json
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Feed playlists (for example `Unsupervised`, `Social Codes`) depend on your configured feed servers and network reachability.
|
|
171
|
+
Use exact or near-exact playlist titles for best results.
|
|
172
|
+
|
|
173
|
+
If you prompt with a bare EVM address (for example `from 0x...`), the CLI now tries owner-address lookup first, then automatically falls back to contract lookup when no owned tokens are found.
|
|
174
|
+
|
|
175
|
+
### One-shot complex prompt
|
|
176
|
+
|
|
177
|
+
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:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
# Mix sources, shuffle order, set per-item duration, and send to a named device
|
|
181
|
+
npm run dev -- chat "From Ethereum contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 get tokens 52932,52457 and from reas.eth get 2 works; shuffle the order; 7 seconds per item; send to device 'Living Room Display'." -o playlist.json -v
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
How it works (at a glance):
|
|
185
|
+
|
|
186
|
+
- The intent parser maps your text to `requirements` (what to fetch) and `playlistSettings` (e.g., `durationPerItem`, `preserveOrder=false` for shuffle, `deviceName`, `feedServer`).
|
|
187
|
+
- Deterministic tools fetch NFT metadata, build a DP‑1 playlist, and validate it.
|
|
188
|
+
- If `deviceName` is present, the CLI will send the validated playlist to that FF1 device.
|
|
189
|
+
- If `feedServer` is present (via "publish to my feed"), the CLI will publish the playlist to the selected feed server.
|
|
190
|
+
|
|
191
|
+
Use `--model claude|grok|gpt|gemini` to switch models, or set `defaultModel` in `config.json`.
|
|
192
|
+
|
|
193
|
+
### Natural language publishing
|
|
194
|
+
|
|
195
|
+
The intent parser recognizes publishing keywords and can both display and publish in one command:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
# Build and publish
|
|
199
|
+
npm run dev -- chat "Build playlist from Ethereum contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 with tokens 52932 and 52457; publish to my feed" -o playlist.json -v
|
|
200
|
+
|
|
201
|
+
# Display on Art Computer AND publish to feed
|
|
202
|
+
npm run dev -- chat "Get 3 from Unsupervised; shuffle; send to my Art Computer and publish to feed" -o playlist.json -v
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
For Feral File built playlists, you can reference titles listed in the repository:
|
|
206
|
+
`https://github.com/feral-file/dp1-feed/tree/main/playlists`
|
|
207
|
+
|
|
208
|
+
Example:
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
npm run dev -- chat "Get 3 from Unsupervised"
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Publishing keywords: "publish", "publish to my feed", "push to feed", "send to feed". The CLI will:
|
|
215
|
+
|
|
216
|
+
1. Detect the keyword and call `get_feed_servers`
|
|
217
|
+
2. If multiple servers → ask which one to use
|
|
218
|
+
3. Build → validate (structure) → publish automatically
|
|
219
|
+
4. Display playlist ID and server URL on success
|
|
220
|
+
|
|
221
|
+
If all configured feed servers are unreachable, the CLI now reports a feed availability error instead of "playlist not found".
|
|
222
|
+
|
|
223
|
+
### Deterministic (no AI)
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
npm run dev -- build params.json -o playlist.json
|
|
227
|
+
cat params.json | npm run dev -- build -o playlist.json
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
`params.json` should include `requirements` and optional `playlistSettings`. See `examples/params-example.json`.
|
|
231
|
+
|
|
232
|
+
### Validate, sign, and play
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
# Optional explicit validation (build flows already validate)
|
|
236
|
+
npm run dev -- validate playlist.json
|
|
237
|
+
|
|
238
|
+
# Sign (uses key and role from config, or overrides via --key / --role)
|
|
239
|
+
npm run dev -- sign playlist.json -o signed.json
|
|
240
|
+
|
|
241
|
+
# Play on configured default device (validates DP-1 structure by default)
|
|
242
|
+
npm run dev -- play playlist.json
|
|
243
|
+
|
|
244
|
+
# Play on a specific named device
|
|
245
|
+
npm run dev -- play playlist.json -d "Living Room Display"
|
|
246
|
+
|
|
247
|
+
# The play path performs a compatibility preflight check against the target FF1.
|
|
248
|
+
# If the device reports an unsupported FF1 OS version, the command fails with
|
|
249
|
+
# a clear version message before any cast request is sent.
|
|
250
|
+
# It also retries transient local-network errors (for example intermittent
|
|
251
|
+
# mDNS/Wi-Fi resolver failures) with a short backoff before returning a final error.
|
|
252
|
+
|
|
253
|
+
# Play a hosted DP-1 playlist
|
|
254
|
+
npm run dev -- play "https://cdn.example.com/playlist.json"
|
|
255
|
+
|
|
256
|
+
# Play a media URL directly
|
|
257
|
+
npm run dev -- play "https://example.com/video.mp4"
|
|
258
|
+
|
|
259
|
+
# Skip structure validation only if you must send a non-conformant payload (not recommended)
|
|
260
|
+
npm run dev -- play playlist.json --skip-verify
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### SSH access
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
# Enable SSH access for 30 minutes
|
|
267
|
+
ff-cli ssh enable --pubkey ~/.ssh/id_ed25519.pub --ttl 30m -d "Living Room Display"
|
|
268
|
+
|
|
269
|
+
# Disable SSH access
|
|
270
|
+
ff-cli ssh disable -d "Living Room Display"
|
|
271
|
+
|
|
272
|
+
# `ff-cli ssh` also performs the same FF1 OS compatibility preflight used by `play`.
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Publish to feed server
|
|
276
|
+
|
|
277
|
+
```bash
|
|
278
|
+
# Publish to first configured feed server
|
|
279
|
+
npm run dev -- publish playlist.json
|
|
280
|
+
|
|
281
|
+
# Publish to specific server (if multiple configured)
|
|
282
|
+
npm run dev -- publish playlist.json -s 0
|
|
283
|
+
npm run dev -- publish playlist.json -s 1
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
The `publish` command:
|
|
287
|
+
|
|
288
|
+
- Validates playlist structure (same as `validate`; does not verify signatures)
|
|
289
|
+
- Shows interactive server selection if multiple are configured
|
|
290
|
+
- Sends the validated playlist to the chosen feed server
|
|
291
|
+
- Returns the playlist ID on success
|
|
292
|
+
|
|
293
|
+
Configure feed servers in `config.json`:
|
|
294
|
+
|
|
295
|
+
```json
|
|
296
|
+
{
|
|
297
|
+
"feedServers": [
|
|
298
|
+
{
|
|
299
|
+
"baseUrl": "http://localhost:8787/api/v1",
|
|
300
|
+
"apiKey": "your-api-key-optional"
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
"baseUrl": "https://feed.example.com/api/v1",
|
|
304
|
+
"apiKey": "your-api-key-optional"
|
|
305
|
+
}
|
|
306
|
+
]
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
### FF1 device management
|
|
311
|
+
|
|
312
|
+
```bash
|
|
313
|
+
# List configured devices
|
|
314
|
+
ff-cli device list
|
|
315
|
+
|
|
316
|
+
# Add a device (interactive with mDNS discovery)
|
|
317
|
+
ff-cli device add
|
|
318
|
+
|
|
319
|
+
# Add a device non-interactively
|
|
320
|
+
ff-cli device add --host 192.168.1.100 --name kitchen
|
|
321
|
+
|
|
322
|
+
# Remove a device by name
|
|
323
|
+
ff-cli device remove kitchen
|
|
324
|
+
|
|
325
|
+
# Set the default device (used when -d is omitted)
|
|
326
|
+
ff-cli device default office
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Setup preserves existing devices when adding new ones. See selection rules and examples in `./CONFIGURATION.md`.
|
|
330
|
+
|
|
331
|
+
### Playlist signing (optional)
|
|
332
|
+
|
|
333
|
+
- Add `playlist.privateKey` (Ed25519 PKCS#8 DER as **hex** or **base64**, per `./CONFIGURATION.md`) and, optionally, `playlist.role` to `config.json`, or set `PLAYLIST_PRIVATE_KEY` and `PLAYLIST_ROLE`.
|
|
334
|
+
- The CLI passes that string to **`dp1-js`** for signing; the dependency decodes hex (`0x` optional) or base64 before loading the key.
|
|
335
|
+
- Signed playlists include a `signatures[]` envelope compliant with DP-1 v1.1.0 (via **`dp1-js`**).
|
|
336
|
+
|
|
337
|
+
## Constraints
|
|
338
|
+
|
|
339
|
+
- Max 20 items total across all requirements
|
|
340
|
+
- Per-source caps enforced in utilities
|
|
341
|
+
- Duration per item defaults to 10s (configurable)
|
|
342
|
+
|
|
343
|
+
## Links
|
|
344
|
+
|
|
345
|
+
- Function calling details: `./FUNCTION_CALLING.md`
|
|
346
|
+
- Examples: `./EXAMPLES.md`
|
|
347
|
+
- Release assets: `./RELEASING.md`
|
|
348
|
+
- DP1 spec: `https://github.com/display-protocol/dp1`
|
|
@@ -0,0 +1,73 @@
|
|
|
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
|
+
**macOS / Linux:**
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
./scripts/release/build-asset.sh
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
**Windows (PowerShell):**
|
|
14
|
+
|
|
15
|
+
```powershell
|
|
16
|
+
.\scripts\release\build-asset-windows.ps1
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
This produces (names vary by OS/arch):
|
|
20
|
+
|
|
21
|
+
- `release/ff-cli-darwin-arm64.tar.gz` (and `.sha256`) on macOS
|
|
22
|
+
- `release/ff-cli-linux-x64.tar.gz` (and `.sha256`) on Linux
|
|
23
|
+
- `release/ff-cli-windows-x64.zip` (and `.sha256`) on Windows
|
|
24
|
+
|
|
25
|
+
Run the appropriate script on each target platform and upload each pair to the GitHub release.
|
|
26
|
+
|
|
27
|
+
## GitHub Actions
|
|
28
|
+
|
|
29
|
+
- **Build** (`build.yml`): Trigger manually (Actions → Build → Run workflow) or on pull requests. Builds binaries on macOS, Linux, and Windows and uploads them as workflow artifacts for download.
|
|
30
|
+
- **Release** (`release.yml`): On **published** GitHub Releases, validates that `package.json` matches the tag, publishes to npm, then builds binaries and uploads assets. A GitHub Release marked as a pre-release publishes to the **`beta`** dist-tag; the version must also contain `beta`. A manual workflow dispatch can also publish a beta version when you need to bypass the normal release flow, but run it from `main`.
|
|
31
|
+
|
|
32
|
+
## npm Publish Requirements
|
|
33
|
+
|
|
34
|
+
- Set `NPM_TOKEN` in GitHub Actions secrets with an npm automation token.
|
|
35
|
+
- Ensure `package.json` version matches the release tag (e.g. tag `1.0.2` → `"version": "1.0.2"`). The release job fails fast when they differ.
|
|
36
|
+
- A **regular** (non-prerelease) GitHub Release publishes with the default dist-tag **`latest`**.
|
|
37
|
+
- A GitHub Release marked **Set as a pre-release** publishes to the **`beta`** dist-tag, and its version must contain `beta` so the package version stays aligned with the beta channel.
|
|
38
|
+
- Manual workflow dispatch runs publish to the **`beta`** dist-tag too, and the `version` input must contain `beta`, match `package.json`, and be dispatched from `main`.
|
|
39
|
+
- Example beta version: `1.0.18-beta.0`.
|
|
40
|
+
|
|
41
|
+
## Release notes and breaking changes
|
|
42
|
+
|
|
43
|
+
GitHub Release text (and any user-facing summary you publish with the version) should state compatibility changes in plain language. **Do not rely on `package.json` `engines` alone**; npm and installers surface it inconsistently, and operators skim release notes first.
|
|
44
|
+
|
|
45
|
+
### Node.js engine floor (breaking)
|
|
46
|
+
|
|
47
|
+
`package.json` declares `"engines": { "node": ">=22" }`. Raising the floor from Node 18 (or 20) is a **breaking change** for:
|
|
48
|
+
|
|
49
|
+
- global installs and `npx @feralfile/cli` on older runtimes
|
|
50
|
+
- CI jobs and images pinned to Node 18 or 20
|
|
51
|
+
- anyone developing from source without upgrading Node
|
|
52
|
+
|
|
53
|
+
**For the release that first ships this requirement**, copy or adapt the following into the GitHub Release description (and repeat in the upgrade section of internal comms if needed):
|
|
54
|
+
|
|
55
|
+
> **Breaking — Node.js:** ff-cli now requires **Node.js 22 or newer** (`package.json` `engines`). Node 18 and Node 20 are no longer supported. Upgrade Node on your machines and in CI, or stay on an older ff-cli version until you can migrate.
|
|
56
|
+
|
|
57
|
+
Later releases only need to repeat this block if the engine floor changes again.
|
|
58
|
+
|
|
59
|
+
## Installer Redirect
|
|
60
|
+
|
|
61
|
+
`https://feralfile.com/ff-cli-install` should redirect to:
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
https://raw.githubusercontent.com/feral-file/ff-cli/main/scripts/install.sh
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The installer script then fetches the release assets from GitHub Releases.
|
|
68
|
+
|
|
69
|
+
## Environment Overrides
|
|
70
|
+
|
|
71
|
+
- `FF_CLI_VERSION`: overrides the version label in logs
|
|
72
|
+
- `FF_CLI_NODE_VERSION`: Reserved in script headers for future use; current CI, npm `engines`, and release wrappers assume **Node.js 22+** (required by `dp1-js`).
|
|
73
|
+
- `FF_CLI_OUTPUT_DIR`: output directory (default: `./release`)
|