@@ -131,2 +131,3 @@ "use strict"; | ||
| async function sendPlaylistToDevice({ playlist, deviceName, }) { | ||
| let device; | ||
| try { | ||
@@ -147,3 +148,3 @@ // Validate input | ||
| } | ||
| const device = resolved.device; | ||
| device = resolved.device; | ||
| const compatibility = await (0, ff1_compatibility_1.assertFF1CommandCompatibility)(device, 'displayPlaylist'); | ||
@@ -203,5 +204,8 @@ if (!compatibility.compatible) { | ||
| if (!response) { | ||
| const deviceLabel = device.name || device.host; | ||
| return { | ||
| success: false, | ||
| error: 'Failed to send playlist to device after retries', | ||
| error: `Could not reach device "${deviceLabel}" at ${device.host}`, | ||
| details: 'Check that the device is powered on and reachable on your network. ' + | ||
| 'If the device IP changed (e.g. after a factory reset), run: ff1 setup', | ||
| }; | ||
@@ -233,8 +237,18 @@ } | ||
| catch (error) { | ||
| logger.error(`Error sending playlist to device: ${error.message}`); | ||
| const errorMessage = error.message; | ||
| logger.error(`Error sending playlist to device: ${errorMessage}`); | ||
| if (device && isTransientDeviceNetworkError(error)) { | ||
| const deviceLabel = device.name || device.host; | ||
| return { | ||
| success: false, | ||
| error: `Could not reach device "${deviceLabel}" at ${device.host}`, | ||
| details: 'Check that the device is powered on and reachable on your network. ' + | ||
| 'If the device IP changed (e.g. after a factory reset), run: ff1 setup', | ||
| }; | ||
| } | ||
| return { | ||
| success: false, | ||
| error: error.message, | ||
| error: errorMessage, | ||
| }; | ||
| } | ||
| } |
@@ -113,3 +113,3 @@ # Configuration Guide | ||
| Configure devices you want to send playlists to. | ||
| Configure devices you want to play content on. | ||
@@ -138,7 +138,7 @@ - `ff1Devices.devices` (array of objects): | ||
| - `send` and `ssh` perform a compatibility preflight before sending commands to FF1. The CLI gets the device version by calling `POST /api/cast` with `{ "command": "getDeviceStatus", "request": {} }` and reads `message.installedVersion` from the response. | ||
| - `play` and `ssh` perform a compatibility preflight before sending commands to FF1. The CLI gets the device version by calling `POST /api/cast` with `{ "command": "getDeviceStatus", "request": {} }` and reads `message.installedVersion` from the response. | ||
| - Minimum supported FF1 OS versions: | ||
| - `send` (`displayPlaylist`): `1.0.0` or newer | ||
| - `play` (`displayPlaylist`): `1.0.0` or newer | ||
| - `ssh` (`sshAccess`): `1.0.9` or newer | ||
@@ -157,6 +157,6 @@ | ||
| # Send to first device | ||
| npm run dev -- send playlist.json | ||
| npm run dev -- play playlist.json | ||
| # Send to a specific device by exact name | ||
| npm run dev -- send playlist.json -d "Living Room Display" | ||
| # Play on a specific device by exact name | ||
| npm run dev -- play playlist.json -d "Living Room Display" | ||
| ``` | ||
@@ -163,0 +163,0 @@ |
@@ -162,4 +162,3 @@ # FF1-CLI Project Spec | ||
| - `send` | ||
| - `play` | ||
| - `play` (handles playlist files, playlist URLs, and media URLs) | ||
| - `publish` | ||
@@ -166,0 +165,0 @@ |
+14
-15
@@ -30,3 +30,3 @@ # FF1-CLI Documentation | ||
| During setup, you can pick FF1 devices to add. Use `ff1 device add` to add more devices later, and `ff1 device list` to see what's configured. The first device is the default for `send`/`play` commands (override with `-d`). | ||
| During setup, you can pick FF1 devices to add. Use `ff1 device add` to add more devices later, and `ff1 device list` to see what's configured. The first device is the default for `play` commands (override with `-d`). | ||
@@ -136,8 +136,6 @@ Manual config path: | ||
| - Options: `-o, --output <file>`, `-v, --verbose` | ||
| - `play <url>` – Send a media URL directly to an FF1 device | ||
| - Options: `-d, --device <name>`, `--skip-verify` | ||
| - `validate <file-or-url>` / `verify <file-or-url>` – Validate a DP1 playlist file | ||
| - `sign <file>` – Sign playlist with Ed25519 | ||
| - Options: `-k, --key <base64>`, `-o, --output <file>` | ||
| - `send <file>` – Send a local or hosted DP-1 playlist to an FF1 device | ||
| - `play <source>` – Play a playlist file, playlist URL, or media URL on an FF1 device | ||
| - Options: `-d, --device <name>`, `--skip-verify` | ||
@@ -227,3 +225,3 @@ - `publish <file>` – Publish a playlist to a feed server | ||
| ### Validate, sign, and send | ||
| ### Validate, sign, and play | ||
@@ -237,17 +235,18 @@ ```bash | ||
| # Send to configured default device (verifies by default) | ||
| npm run dev -- send playlist.json | ||
| # Play on configured default device (verifies by default) | ||
| npm run dev -- play playlist.json | ||
| # Send to a specific named device | ||
| npm run dev -- send playlist.json -d "Living Room Display" | ||
| # Play on a specific named device | ||
| npm run dev -- play playlist.json -d "Living Room Display" | ||
| # The send path now performs a compatibility preflight check against the target FF1. | ||
| # The play path performs a compatibility preflight check against the target FF1. | ||
| # If the device reports an unsupported FF1 OS version, the command fails with | ||
| # a clear version message before any cast request is sent. | ||
| # The send path also retries transient local-network errors (for example intermittent | ||
| # It also retries transient local-network errors (for example intermittent | ||
| # mDNS/Wi-Fi resolver failures) with a short backoff before returning a final error. | ||
| # Send a hosted DP-1 playlist | ||
| npm run dev -- send "https://cdn.example.com/playlist.json" | ||
| # Play a direct URL | ||
| # Play a hosted DP-1 playlist | ||
| npm run dev -- play "https://cdn.example.com/playlist.json" | ||
| # Play a media URL directly | ||
| npm run dev -- play "https://example.com/video.mp4" --skip-verify | ||
@@ -265,3 +264,3 @@ ``` | ||
| # `ff1 ssh` also performs the same FF1 OS compatibility preflight used by `send`. | ||
| # `ff1 ssh` also performs the same FF1 OS compatibility preflight used by `play`. | ||
| ``` | ||
@@ -268,0 +267,0 @@ |
+1
-1
| { | ||
| "name": "ff1-cli", | ||
| "version": "1.0.12", | ||
| "version": "1.0.16", | ||
| "description": "CLI to fetch NFT information and build DP1 playlists using Grok API", | ||
@@ -5,0 +5,0 @@ "main": "dist/index.js", |
+21
-3
@@ -50,3 +50,3 @@ # FF1-CLI | ||
| ```bash | ||
| npm install | ||
| npm ci | ||
| npm run dev -- setup | ||
@@ -65,2 +65,19 @@ npm run dev -- chat | ||
| ## Verification | ||
| GitHub Actions runs `.github/workflows/ci.yml` for pull requests, pushes to `main`/`master`, and reusable `workflow_call` jobs. CI uses Node.js 22, installs dependencies with `npm ci`, sets `GROK_API_KEY=dummy`, and runs the repo-wide verification entrypoint: | ||
| ```bash | ||
| GROK_API_KEY=dummy npm run verify | ||
| ``` | ||
| Run the same command locally before opening a PR. It checks formatting, lint, tests, TypeScript build, playlist validation smoke, and config validation smoke without mutating source files. | ||
| Other GitHub Actions workflows: | ||
| - `.github/workflows/build.yml` builds release assets when called by release automation or manually dispatched. | ||
| - `.github/workflows/release.yml` reuses CI, verifies the release version, publishes npm, uploads assets, and checks the published release. | ||
| - `.github/workflows/dependency-review.yml` reviews dependency changes on pull requests. | ||
| - `.github/workflows/codeql.yml` runs CodeQL analysis on pull requests and pushes to `main`/`master`. | ||
| ## Scripts | ||
@@ -71,5 +88,6 @@ | ||
| npm run build # Build TypeScript | ||
| npm run lint:fix # Lint + fix | ||
| npm run check # Format check + lint + tests | ||
| npm run smoke # Build + CLI smoke checks | ||
| npm run verify # Format + lint + test + smoke | ||
| npm run verify # CI-equivalent validation entrypoint | ||
| npm run lint:fix # Optional mutating lint fix; review changes before committing | ||
| ``` | ||
@@ -76,0 +94,0 @@ |
Sorry, the diff of this file is too big to display
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
493826
0.24%95
23.38%