@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.
Files changed (58) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +96 -0
  3. package/config.json.example +96 -0
  4. package/dist/index.js +54 -0
  5. package/dist/src/ai-orchestrator/index.js +1019 -0
  6. package/dist/src/ai-orchestrator/registry.js +96 -0
  7. package/dist/src/commands/build.js +69 -0
  8. package/dist/src/commands/chat.js +189 -0
  9. package/dist/src/commands/config.js +68 -0
  10. package/dist/src/commands/device.js +278 -0
  11. package/dist/src/commands/helpers/config-files.js +62 -0
  12. package/dist/src/commands/helpers/device-discovery.js +111 -0
  13. package/dist/src/commands/helpers/playlist-display.js +161 -0
  14. package/dist/src/commands/helpers/prompt.js +65 -0
  15. package/dist/src/commands/helpers/ssh-helpers.js +44 -0
  16. package/dist/src/commands/play.js +110 -0
  17. package/dist/src/commands/publish.js +115 -0
  18. package/dist/src/commands/setup.js +225 -0
  19. package/dist/src/commands/sign.js +41 -0
  20. package/dist/src/commands/ssh.js +108 -0
  21. package/dist/src/commands/status.js +126 -0
  22. package/dist/src/commands/validate.js +18 -0
  23. package/dist/src/config.js +441 -0
  24. package/dist/src/intent-parser/index.js +1382 -0
  25. package/dist/src/intent-parser/utils.js +108 -0
  26. package/dist/src/logger.js +82 -0
  27. package/dist/src/main.js +459 -0
  28. package/dist/src/types.js +5 -0
  29. package/dist/src/utilities/address-validator.js +242 -0
  30. package/dist/src/utilities/device-default.js +36 -0
  31. package/dist/src/utilities/device-lookup.js +107 -0
  32. package/dist/src/utilities/device-normalize.js +62 -0
  33. package/dist/src/utilities/device-upsert.js +91 -0
  34. package/dist/src/utilities/domain-resolver.js +291 -0
  35. package/dist/src/utilities/ed25519-key-derive.js +155 -0
  36. package/dist/src/utilities/feed-fetcher.js +471 -0
  37. package/dist/src/utilities/ff1-compatibility.js +269 -0
  38. package/dist/src/utilities/ff1-device.js +250 -0
  39. package/dist/src/utilities/ff1-discovery.js +330 -0
  40. package/dist/src/utilities/functions.js +308 -0
  41. package/dist/src/utilities/index.js +469 -0
  42. package/dist/src/utilities/nft-indexer.js +1024 -0
  43. package/dist/src/utilities/playlist-builder.js +523 -0
  44. package/dist/src/utilities/playlist-publisher.js +131 -0
  45. package/dist/src/utilities/playlist-send.js +260 -0
  46. package/dist/src/utilities/playlist-signer.js +204 -0
  47. package/dist/src/utilities/playlist-signing-role.js +41 -0
  48. package/dist/src/utilities/playlist-source.js +128 -0
  49. package/dist/src/utilities/playlist-verifier.js +274 -0
  50. package/dist/src/utilities/ssh-access.js +145 -0
  51. package/dist/src/utils.js +48 -0
  52. package/docs/CONFIGURATION.md +206 -0
  53. package/docs/EXAMPLES.md +390 -0
  54. package/docs/FUNCTION_CALLING.md +96 -0
  55. package/docs/PROJECT_SPEC.md +228 -0
  56. package/docs/README.md +348 -0
  57. package/docs/RELEASING.md +73 -0
  58. package/package.json +76 -0
@@ -0,0 +1,390 @@
1
+ # Examples
2
+
3
+ Copy‑pasteable commands that work with the current CLI.
4
+
5
+ ## Setup
6
+
7
+ ```bash
8
+ npm install
9
+ npm run dev -- setup
10
+ ```
11
+
12
+ Manual config path:
13
+
14
+ ```bash
15
+ npm run dev -- config init
16
+ npm run dev -- config validate
17
+ ```
18
+
19
+ ## OpenClaw skill prompt
20
+
21
+ If you want OpenClaw to run ff-cli end-to-end without confirmation, start from:
22
+
23
+ `skills/ff-control/SKILL.md`
24
+
25
+ Recommended local install path:
26
+
27
+ ```bash
28
+ mkdir -p ~/.openclaw/skills
29
+ ln -sfn ~/Work/ff-cli/skills/ff-control ~/.openclaw/skills/ff-control
30
+ ```
31
+
32
+ Compatibility copy (same prompt):
33
+
34
+ `examples/openclaw-ff-skill.md`
35
+
36
+ Paste that prompt into your OpenClaw skill config, then test with plain requests like:
37
+
38
+ ```bash
39
+ "Get 3 works from reas.eth and send to Living Room"
40
+ "Get 3 from Unsupervised and publish to my feed"
41
+ ```
42
+
43
+ ## Natural Language
44
+
45
+ ```bash
46
+ # Interactive chat
47
+ npm run dev chat
48
+
49
+ # One-shot requests
50
+ npm run dev -- chat "Get 3 works from reas.eth" -o playlist.json
51
+ npm run dev -- chat "Get 3 works from einstein-rosen.tez"
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
54
+
55
+ # Switch model
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
59
+
60
+ # Model names must match keys in config.json under `models`.
61
+ ```
62
+
63
+ ## Deterministic Build (no AI)
64
+
65
+ ```bash
66
+ # From file
67
+ npm run dev -- build examples/params-example.json -o playlist.json
68
+
69
+ # From stdin
70
+ cat examples/params-example.json | npm run dev -- build -o playlist.json
71
+ ```
72
+
73
+ ## AI‑Orchestrated Deterministic Flow (prompts)
74
+
75
+ ```bash
76
+ # Show tool‑call progress and validation
77
+ npm run dev -- chat "Build a playlist of my works from reas.eth plus 3 from Unsupervised" -v -o playlist.json
78
+
79
+ # Switch model if desired
80
+ npm run dev -- chat "Build playlist from Ethereum address 0xaeE022552B539dB18297D7481b6D547C622488B3 and 2 from Unsupervised" --model gpt -v
81
+ ```
82
+
83
+ ### One‑shot complex prompt
84
+
85
+ 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.
86
+
87
+ ```bash
88
+ # Example: combine sources, shuffle, set 6s per item, and send to device
89
+ npm run dev -- chat "Get tokens 52932,52457 from contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 and 2 from reas.eth; shuffle; 6 seconds each; send to 'Living Room Display'." -o playlist.json -v
90
+ ```
91
+
92
+ ## Feral File Built Playlists
93
+
94
+ Use exhibition titles from the official playlist repository:
95
+ `https://github.com/feral-file/dp1-feed/tree/main/playlists`
96
+
97
+ ```bash
98
+ # Fetch from a built playlist title
99
+ npm run dev -- chat "Get 3 from Unsupervised" -v
100
+
101
+ # Mix a built playlist with wallet/domain sources
102
+ npm run dev -- chat "Get 3 from Unsupervised and 2 from reas.eth" -v -o playlist.json
103
+ ```
104
+
105
+ Notes:
106
+
107
+ - Feed playlist queries require reachable feed servers in your config.
108
+ - If no feeds are reachable, feed playlist examples will fail even if the title exists.
109
+ - Bare EVM prompts (`from 0x...`) now fall back from owner lookup to contract lookup when needed.
110
+
111
+ ## Natural Language: Display and Publish
112
+
113
+ The CLI recognizes publishing keywords like "publish", "publish to my feed", "push to feed", "send to feed" and automatically publishes after building.
114
+
115
+ ### Basic Publishing
116
+
117
+ ```bash
118
+ # Build and publish
119
+ npm run dev -- chat "Build playlist from Ethereum contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 with tokens 52932 and 52457; publish to my feed" -o playlist.json -v
120
+
121
+ # With feed selection (if multiple servers configured)
122
+ # The CLI will ask: "Which feed server? 1) https://dp1-feed-operator-api-prod.autonomy-system.workers.dev/api/v1 2) http://localhost:8787"
123
+ npm run dev -- chat "Get 3 from Unsupervised and publish to feed" -v
124
+
125
+ # Publish existing playlist (defaults to ./playlist.json)
126
+ npm run dev chat
127
+ # Then type: "publish playlist"
128
+
129
+ # Publish specific playlist file
130
+ npm run dev chat
131
+ # Then type: "publish the playlist ./playlist-temp.json"
132
+ ```
133
+
134
+ ### Combined: Display + Publish
135
+
136
+ ```bash
137
+ # Display on Art Computer AND publish to feed
138
+ npm run dev -- chat "Build playlist from contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 with tokens 52932 and 52457; mix them up; send to my Art Computer and publish to my feed" -o playlist.json -v
139
+
140
+ # With explicit device name
141
+ npm run dev -- chat "Get 5 from Unsupervised, shuffle, display on 'Living Room', and publish to feed" -v
142
+ ```
143
+
144
+ ### How It Works
145
+
146
+ **Mode 1: Build and Publish** (when sources are mentioned)
147
+
148
+ 1. Intent parser detects "publish" keywords with sources/requirements
149
+ 2. Calls `get_feed_servers` to retrieve configured servers
150
+ 3. If 1 server → uses it automatically; if 2+ servers → asks user to pick
151
+ 4. Builds playlist → validates structure → publishes automatically
152
+
153
+ **Mode 2: Publish Existing File** (e.g., "publish playlist")
154
+
155
+ 1. Intent parser detects "publish playlist" or similar phrases
156
+ 2. Calls `get_feed_servers` to retrieve configured servers
157
+ 3. If 1 server → uses it automatically; if 2+ servers → asks user to pick
158
+ 4. Publishes the playlist from `./playlist.json` (or specified path)
159
+
160
+ Output shows:
161
+
162
+ - Playlist build progress (Mode 1 only)
163
+ - Device sending (if requested): `✓ Sent to device: Living Room`
164
+ - Publishing status: `✓ Published to feed server`
165
+ - Playlist ID: `Playlist ID: 84e028f8-...`
166
+
167
+ ## Validate / Sign / Send
168
+
169
+ ```bash
170
+ # Validate playlist
171
+ npm run dev -- validate playlist.json
172
+ npm run dev -- validate "https://cdn.example.com/playlist.json"
173
+
174
+ # Sign playlist
175
+ npm run dev -- sign playlist.json -o signed.json
176
+
177
+ # Send to device
178
+ npm run dev -- send playlist.json -d "Living Room Display"
179
+ npm run dev -- send "https://cdn.example.com/playlist.json" -d "Living Room Display"
180
+ ```
181
+
182
+ ## Publish to Feed Server
183
+
184
+ Publish validated playlists to a DP-1 feed server for sharing and discovery.
185
+
186
+ ### Configuration
187
+
188
+ Add feed servers to `config.json`:
189
+
190
+ ```json
191
+ {
192
+ "feedServers": [
193
+ {
194
+ "baseUrl": "http://localhost:8787/api/v1",
195
+ "apiKey": "your-api-key"
196
+ },
197
+ {
198
+ "baseUrl": "https://feed.example.com/api/v1",
199
+ "apiKey": "your-api-key"
200
+ }
201
+ ]
202
+ }
203
+ ```
204
+
205
+ ### Publish Commands
206
+
207
+ ```bash
208
+ # Interactive: list servers and ask which to use
209
+ npm run dev -- publish playlist.json
210
+
211
+ # Direct: publish to specific server (server index 0)
212
+ npm run dev -- publish playlist.json -s 0
213
+
214
+ # Show help
215
+ npm run dev -- publish --help
216
+ ```
217
+
218
+ ### Flow
219
+
220
+ 1. **Validate** - Playlist structure checked (`validate`-style parse; use `verify` for signatures)
221
+ 2. **Select Server** - If multiple servers, choose which one (interactive or via `-s` flag)
222
+ 3. **Publish** - Send validated playlist to selected feed server
223
+ 4. **Confirm** - Returns playlist ID and server details
224
+
225
+ ### Example Output
226
+
227
+ ```
228
+ $ npm run dev -- publish playlist.json
229
+
230
+ 📡 Publishing playlist to feed server...
231
+
232
+ Multiple feed servers found. Select one:
233
+ 0: http://localhost:8787/api/v1
234
+ 1: https://feed.example.com/api/v1
235
+
236
+ Select server (0-based index): 0
237
+
238
+ ✅ Playlist published successfully!
239
+ Playlist ID: 84e028f8-ea12-4779-a496-64f95f0486cd
240
+ Server: http://localhost:8787/api/v1
241
+ Status: Published to feed server (created)
242
+ ```
243
+
244
+ ### Error Handling
245
+
246
+ **Validation failed:**
247
+
248
+ ```
249
+ ❌ Failed to publish playlist
250
+ Playlist validation failed: dpVersion: Required; id: Required
251
+ ```
252
+
253
+ **File not found:**
254
+
255
+ ```
256
+ ❌ Failed to publish playlist
257
+ Playlist file not found: /path/to/playlist.json
258
+ ```
259
+
260
+ **API error:**
261
+
262
+ ```
263
+ ❌ Failed to publish playlist
264
+ Failed to publish: {"error":"unauthorized","message":"Invalid API key"}
265
+ ```
266
+
267
+ ## Validate / Sign / Send / Publish (Complete Flow)
268
+
269
+ ```bash
270
+ # 1. Create a playlist (via chat or build)
271
+ npm run dev -- chat "Get 3 works from reas.eth" -o playlist.json
272
+
273
+ # 2. Validate it
274
+ npm run dev -- validate playlist.json
275
+
276
+ # 3. Sign it
277
+ npm run dev -- sign playlist.json -o signed.json
278
+
279
+ # 4. Send to device
280
+ npm run dev -- send signed.json -d "My Display"
281
+
282
+ # 5. Publish to feed server
283
+ npm run dev -- publish signed.json -s 0
284
+ ```
285
+
286
+ ## Troubleshooting
287
+
288
+ ```bash
289
+ # Show current configuration
290
+ npm run dev -- config show
291
+
292
+ # Reinitialize config
293
+ npm run dev -- config init
294
+ ```
295
+
296
+ ### Natural‑language one‑shot examples (proven)
297
+
298
+ - **ETH contract + token IDs (shuffle/mix, generic device)**
299
+ - Format:
300
+ ```bash
301
+ 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
302
+ ```
303
+ - Example:
304
+ ```bash
305
+ 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
306
+ ```
307
+
308
+ - **TEZ contract + token IDs (shuffle, named device)**
309
+ - Format:
310
+ ```bash
311
+ npm run dev -- chat "Build a playlist from Tezos contract <KT1...> with tokens <id> and <id>; shuffle; send to '<device>'" -o <output.json> -v
312
+ ```
313
+ - Example:
314
+ ```bash
315
+ 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
316
+ ```
317
+
318
+ - **Owner address (ENS → ETH), shuffled**
319
+ - Format:
320
+ ```bash
321
+ npm run dev -- chat "Create a playlist from address <ens> (<n> items); [shuffle|mix]; [send/push to my device]" -o <output.json> -v
322
+ ```
323
+ - Example:
324
+ ```bash
325
+ npm run dev -- chat "Create a playlist from address reas.eth (5 items); shuffle; push to my device" -o playlist-ens.json -v
326
+ ```
327
+
328
+ - **Owner address (Tezos tz1), shuffled**
329
+ - Format:
330
+ ```bash
331
+ npm run dev -- chat "Create a playlist from Tezos address <tz1...> (<n> items); [shuffle|mix]; [send to device]" -o <output.json> -v
332
+ ```
333
+ - Example:
334
+ ```bash
335
+ npm run dev -- chat "Create a playlist from Tezos address tz1VSUr8wwNhLAzempoch5d6hLRiTh8Cjcjb (3 items); mix them up; send to device" -o playlist-tz1.json -v
336
+ ```
337
+
338
+ - **Feed playlists (named), shuffled**
339
+ - Format:
340
+ ```bash
341
+ npm run dev -- chat "[Create|Build] a playlist from feed '<name>' (<n> items); shuffle; [send to device]" -o <output.json> -v
342
+ ```
343
+ - Examples:
344
+ ```bash
345
+ npm run dev -- chat "Create a playlist from feed 'Unsupervised' (3 items); shuffle; send to device" -o playlist-feed1.json -v
346
+ npm run dev -- chat "Build a playlist from feed 'Unsupervised' (3 items); shuffle; send to device" -o playlist-feed2.json -v
347
+ ```
348
+
349
+ - **Mixed in one prompt (ETH + TEZ + feed + ENS), shuffled, named device**
350
+ - Format:
351
+ ```bash
352
+ 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
353
+ ```
354
+ - Example:
355
+ ```bash
356
+ 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
357
+ ```
358
+
359
+ - **Multiple instructions in one prompt (incremental), shuffled**
360
+ - Format:
361
+ ```bash
362
+ 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
363
+ ```
364
+ - Example:
365
+ ```bash
366
+ 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
367
+ ```
368
+
369
+ - **Synonym variants for the same ETH case**
370
+ - Format:
371
+ ```bash
372
+ npm run dev -- chat "[Build|Create|Compose] a playlist from Ethereum contract <0x...> tokens <id> and <id>; send to device" -o <output.json> -v
373
+ ```
374
+ - Examples:
375
+ ```bash
376
+ npm run dev -- chat "Build a playlist from Ethereum contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 tokens 52932 and 52457; send to device" -o playlist-eth-build.json -v
377
+ npm run dev -- chat "Create a playlist from Ethereum contract 0xb932a70A57673d89f4acfFBE830E8ed7f75Fb9e0 tokens 52932 and 52457; send to device" -o playlist-eth-create.json -v
378
+ ```
379
+
380
+ - **Device targeting: generic vs named**
381
+ - Format:
382
+ ```bash
383
+ npm run dev -- chat "Compose a playlist from <ens/address> (<n> items); send to device" -o <output.json> -v
384
+ npm run dev -- chat "Compose a playlist from <ens/address> (<n> items); send to '<device>'" -o <output.json> -v
385
+ ```
386
+ - Examples:
387
+ ```bash
388
+ npm run dev -- chat "Compose a playlist from reas.eth (3 items); send to device" -o playlist-generic-device.json -v
389
+ npm run dev -- chat "Compose a playlist from reas.eth (3 items); send to 'Living Room'" -o playlist-named-device.json -v
390
+ ```
@@ -0,0 +1,96 @@
1
+ # Function Calling Architecture
2
+
3
+ How ff-cli uses AI function calling to build playlists deterministically. The model orchestrates function calls; tools enforce schema and assemble the DP-1 envelope.
4
+
5
+ ## Overview
6
+
7
+ Natural language requests become structured parameters. An AI orchestrator then calls functions to fetch items, build a DP-1 playlist, validate structure (`verify_playlist`), optionally sign, and send to a device.
8
+
9
+ Pipeline:
10
+
11
+ ```
12
+ Intent Parser → Orchestrator (function calls) → Utilities → DP-1 Playlist
13
+ ```
14
+
15
+ Key files:
16
+
17
+ - `src/intent-parser/` – Parses user text into `requirements` + `playlistSettings`
18
+ - `src/ai-orchestrator/index.js` – Function schemas and orchestration logic
19
+ - `src/utilities/` – Concrete implementations used by the orchestrator
20
+ - `src/main.ts` – Bridges CLI commands to parser/orchestrator/utilities
21
+
22
+ ## Function Schemas (AI‑visible)
23
+
24
+ Defined in `src/ai-orchestrator/index.js` as tool schemas for OpenAI‑compatible clients.
25
+
26
+ - `query_requirement(requirement, duration)`
27
+ - Types: `build_playlist`, `fetch_feed`, `query_address`
28
+ - For `build_playlist`: requires `blockchain`, `contractAddress`, `tokenIds`, optional `quantity`
29
+ - For `query_address`: requires `ownerAddress`, optional `quantity` (random selection)
30
+ - For `fetch_feed`: requires `playlistName`, `quantity`
31
+
32
+ - `search_feed_playlist(playlistName)` → fuzzy-match across configured feeds
33
+ - `fetch_feed_playlist_items(playlistName, quantity, duration)`
34
+ - `build_playlist(items, title?, slug?, shuffle?)` → returns DP-1 playlist
35
+ - `verify_playlist(playlist)` → DP-1 parse/structure validation only (must precede send; use CLI `verify` for signatures)
36
+ - `verify_addresses(addresses[])` → validates Ethereum (0x...) and Tezos (tz.../KT1) address formats
37
+ - `send_to_device(playlist, deviceName?)`
38
+ - `resolve_domains(domains[], displayResults?)` → ENS/TNS resolution
39
+
40
+ Notes enforced by the orchestrator:
41
+
42
+ - Always pass complete requirement objects (no truncating addresses/token IDs)
43
+ - Resolve domains (`.eth`, `.tez`) before `query_address`
44
+ - Build, then `verify_playlist` (structure) before sending to devices
45
+ - Shuffle is controlled by `playlistSettings.preserveOrder`
46
+
47
+ ## Implementations (server‑side)
48
+
49
+ Located in `src/utilities/` and wired in `src/ai-orchestrator/index.js`:
50
+
51
+ - `buildDP1Playlist({ items, title, slug })` → `src/utilities/playlist-builder.js`
52
+ - `sendPlaylistToDevice({ playlist, deviceName })` → `src/utilities/ff1-device.ts`
53
+ - `resolveDomains({ domains, displayResults })` → `src/utilities/domain-resolver.ts`
54
+ - `verifyPlaylist({ playlist })` in `functions.js` → delegates to `validatePlaylist` in `playlist-verifier.ts` (structure/parse only)
55
+ - `verifyAddresses({ addresses })` → `src/utilities/functions.js` (uses `address-validator.ts`)
56
+ - Feed utilities: `feed-fetcher.js`
57
+
58
+ ## Deterministic Paths
59
+
60
+ Two options are available:
61
+
62
+ 1. No-AI deterministic build (recommended for automation): Use CLI `build` command with a JSON file or stdin containing:
63
+
64
+ ```json
65
+ {
66
+ "requirements": [
67
+ { "type": "fetch_feed", "playlistName": "Social Codes", "quantity": 3 },
68
+ {
69
+ "type": "build_playlist",
70
+ "blockchain": "ethereum",
71
+ "contractAddress": "0x...",
72
+ "tokenIds": ["1", "2"],
73
+ "quantity": 2
74
+ }
75
+ ],
76
+ "playlistSettings": { "durationPerItem": 10, "preserveOrder": true, "title": "My Mix" }
77
+ }
78
+ ```
79
+
80
+ This path bypasses the intent parser/orchestrator and calls utilities directly. Validation and sensible defaults are applied in `src/main.ts`.
81
+
82
+ 2. AI‑orchestrated deterministic build (recommended for prompts): Use `chat` with `--verbose` to see tool calls. The orchestrator enforces complete requirement objects, then runs `verify_playlist` (structure only) before sending.
83
+
84
+ ## Extending Functionality (OSS‑first)
85
+
86
+ 1. Add a new function in `src/utilities/` (prefer OSS libs: `viem` for Ethereum, `@taquito/taquito` for Tezos; add local caching where it helps)
87
+ 2. Export and wire it in `src/utilities/index.js`
88
+ 3. Add a corresponding schema in `src/ai-orchestrator/index.js`
89
+ 4. Update this doc if user‑facing behavior changes
90
+ 5. Run `npm run lint:fix`
91
+
92
+ ## Validation & Constraints
93
+
94
+ - Verify via `dp1-js` for DP-1 conformance (canonical JSON + Ed25519 signing supported)
95
+ - Enforce max item counts and ordering/shuffle rules during build
96
+ - Batch domain resolution; report failures without crashing the flow