@feralfile/cli 1.1.1 → 1.2.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 +26 -0
- package/dist/index.js +4 -2
- package/dist/package.json +84 -0
- package/dist/src/ai-orchestrator/index.js +14 -2
- package/dist/src/commands/build.js +3 -3
- package/dist/src/commands/chat.js +3 -3
- package/dist/src/commands/config.js +2 -2
- package/dist/src/commands/device.js +6 -6
- package/dist/src/commands/find.js +502 -0
- package/dist/src/commands/helpers/device-discovery.js +1 -1
- package/dist/src/commands/play.js +52 -11
- package/dist/src/commands/setup.js +1 -1
- package/dist/src/commands/status.js +2 -2
- package/dist/src/intent-parser/index.js +16 -5
- package/dist/src/intent-parser/utils.js +7 -2
- package/dist/src/main.js +61 -17
- package/dist/src/utilities/ab-marketplace.js +95 -0
- package/dist/src/utilities/feral-file-artwork.js +89 -0
- package/dist/src/utilities/ff-marketplace.js +115 -0
- package/dist/src/utilities/ff1-device.js +4 -4
- package/dist/src/utilities/functions.js +1 -1
- package/dist/src/utilities/fxhash-marketplace.js +146 -0
- package/dist/src/utilities/index.js +80 -1
- package/dist/src/utilities/marketplace-url.js +373 -0
- package/dist/src/utilities/neort-marketplace.js +102 -0
- package/dist/src/utilities/nft-indexer.js +22 -14
- package/dist/src/utilities/objkt-marketplace.js +77 -0
- package/dist/src/utilities/playlist-publisher.js +9 -42
- package/dist/src/utilities/raster-client.js +252 -0
- package/dist/src/utilities/user-agent.js +20 -0
- package/docs/CONFIGURATION.md +3 -1
- package/docs/EXAMPLES.md +23 -0
- package/docs/FUNCTION_CALLING.md +3 -1
- package/docs/README.md +11 -10
- package/docs/RELEASING.md +92 -22
- package/package.json +9 -1
package/docs/EXAMPLES.md
CHANGED
|
@@ -70,12 +70,35 @@ npm run dev -- build examples/params-example.json -o playlist.json
|
|
|
70
70
|
cat examples/params-example.json | npm run dev -- build -o playlist.json
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
+
Build from a Feral File public artwork id or artwork URL:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
cat > /tmp/ff-artwork.json <<'JSON'
|
|
77
|
+
{
|
|
78
|
+
"requirements": [
|
|
79
|
+
{
|
|
80
|
+
"type": "feral_file_artwork",
|
|
81
|
+
"artworkId": "https://feralfile.com/exhibitions/artwork/f0240e04d64717e319584957f6a83954b029254ad1260b6320472ea8c0c5b1cf"
|
|
82
|
+
}
|
|
83
|
+
],
|
|
84
|
+
"playlistSettings": {
|
|
85
|
+
"title": "Feral File Artwork"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
JSON
|
|
89
|
+
|
|
90
|
+
npm run dev -- build /tmp/ff-artwork.json -o playlist.json
|
|
91
|
+
```
|
|
92
|
+
|
|
73
93
|
## AI‑Orchestrated Deterministic Flow (prompts)
|
|
74
94
|
|
|
75
95
|
```bash
|
|
76
96
|
# Show tool‑call progress and validation
|
|
77
97
|
npm run dev -- chat "Build a playlist of my works from reas.eth plus 3 from Unsupervised" -v -o playlist.json
|
|
78
98
|
|
|
99
|
+
# Build from a Feral File artwork URL
|
|
100
|
+
npm run dev -- chat "Build a playlist from https://feralfile.com/exhibitions/artwork/f0240e04d64717e319584957f6a83954b029254ad1260b6320472ea8c0c5b1cf" -v -o playlist.json
|
|
101
|
+
|
|
79
102
|
# Switch model if desired
|
|
80
103
|
npm run dev -- chat "Build playlist from Ethereum address 0xaeE022552B539dB18297D7481b6D547C622488B3 and 2 from Unsupervised" --model gpt -v
|
|
81
104
|
```
|
package/docs/FUNCTION_CALLING.md
CHANGED
|
@@ -24,8 +24,9 @@ Key files:
|
|
|
24
24
|
Defined in `src/ai-orchestrator/index.js` as tool schemas for OpenAI‑compatible clients.
|
|
25
25
|
|
|
26
26
|
- `query_requirement(requirement, duration)`
|
|
27
|
-
- Types: `build_playlist`, `fetch_feed`, `query_address`
|
|
27
|
+
- Types: `build_playlist`, `feral_file_artwork`, `fetch_feed`, `query_address`
|
|
28
28
|
- For `build_playlist`: requires `blockchain`, `contractAddress`, `tokenIds`, optional `quantity`
|
|
29
|
+
- For `feral_file_artwork`: requires `artworkId`, either a Feral File public artwork id or `/exhibitions/artwork/{id}` URL
|
|
29
30
|
- For `query_address`: requires `ownerAddress`, optional `quantity` (random selection)
|
|
30
31
|
- For `fetch_feed`: requires `playlistName`, `quantity`
|
|
31
32
|
|
|
@@ -65,6 +66,7 @@ Two options are available:
|
|
|
65
66
|
{
|
|
66
67
|
"requirements": [
|
|
67
68
|
{ "type": "fetch_feed", "playlistName": "Social Codes", "quantity": 3 },
|
|
69
|
+
{ "type": "feral_file_artwork", "artworkId": "https://feralfile.com/exhibitions/artwork/..." },
|
|
68
70
|
{
|
|
69
71
|
"type": "build_playlist",
|
|
70
72
|
"blockchain": "ethereum",
|
package/docs/README.md
CHANGED
|
@@ -144,9 +144,9 @@ Notes:
|
|
|
144
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
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
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 `
|
|
148
|
-
- Options: `-d, --device <name>`, `--skip-verify` (skip
|
|
149
|
-
- `publish <file>` – Publish a playlist to a feed server (`
|
|
147
|
+
- `play <source>` – Play a playlist file, playlist URL, or media URL on an FF1 device (runs `verify` before sending; only the CLI-synthesized media URL fallback is auto-signed when a signing key is configured; use `--skip-verify` to bypass the gate)
|
|
148
|
+
- Options: `-d, --device <name>`, `--skip-verify` (skip signature verification; not recommended)
|
|
149
|
+
- `publish <file>` – Publish a playlist to a feed server (runs `verify` before upload and rejects unsigned or broken playlists)
|
|
150
150
|
- Options: `-s, --server <index>` (server index if multiple configured)
|
|
151
151
|
- `ssh <enable|disable>` – Manage SSH access on an FF1 device
|
|
152
152
|
- Options: `-d, --device <name>`, `--pubkey <path>`, `--ttl <duration>`
|
|
@@ -184,8 +184,8 @@ npm run dev -- chat "From Ethereum contract 0xb932a70A57673d89f4acfFBE830E8ed7f7
|
|
|
184
184
|
How it works (at a glance):
|
|
185
185
|
|
|
186
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
|
|
188
|
-
- If `deviceName` is present, the CLI will send the
|
|
187
|
+
- Deterministic tools fetch NFT metadata, build a DP‑1 playlist, and verify it.
|
|
188
|
+
- If `deviceName` is present, the CLI will send the verified playlist to that FF1 device.
|
|
189
189
|
- If `feedServer` is present (via "publish to my feed"), the CLI will publish the playlist to the selected feed server.
|
|
190
190
|
|
|
191
191
|
Use `--model claude|grok|gpt|gemini` to switch models, or set `defaultModel` in `config.json`.
|
|
@@ -215,7 +215,7 @@ Publishing keywords: "publish", "publish to my feed", "push to feed", "send to f
|
|
|
215
215
|
|
|
216
216
|
1. Detect the keyword and call `get_feed_servers`
|
|
217
217
|
2. If multiple servers → ask which one to use
|
|
218
|
-
3. Build →
|
|
218
|
+
3. Build → verify → publish automatically
|
|
219
219
|
4. Display playlist ID and server URL on success
|
|
220
220
|
|
|
221
221
|
If all configured feed servers are unreachable, the CLI now reports a feed availability error instead of "playlist not found".
|
|
@@ -238,7 +238,7 @@ npm run dev -- validate playlist.json
|
|
|
238
238
|
# Sign (uses key and role from config, or overrides via --key / --role)
|
|
239
239
|
npm run dev -- sign playlist.json -o signed.json
|
|
240
240
|
|
|
241
|
-
# Play on configured default device (
|
|
241
|
+
# Play on configured default device (verifies playlists; only media URL fallbacks may be auto-signed)
|
|
242
242
|
npm run dev -- play playlist.json
|
|
243
243
|
|
|
244
244
|
# Play on a specific named device
|
|
@@ -256,7 +256,7 @@ npm run dev -- play "https://cdn.example.com/playlist.json"
|
|
|
256
256
|
# Play a media URL directly
|
|
257
257
|
npm run dev -- play "https://example.com/video.mp4"
|
|
258
258
|
|
|
259
|
-
# Skip
|
|
259
|
+
# Skip signature verification only if you must send a non-conformant payload (not recommended)
|
|
260
260
|
npm run dev -- play playlist.json --skip-verify
|
|
261
261
|
```
|
|
262
262
|
|
|
@@ -285,9 +285,10 @@ npm run dev -- publish playlist.json -s 1
|
|
|
285
285
|
|
|
286
286
|
The `publish` command:
|
|
287
287
|
|
|
288
|
-
-
|
|
288
|
+
- Verifies playlist signatures before upload
|
|
289
|
+
- Rejects unsigned or broken playlists
|
|
289
290
|
- Shows interactive server selection if multiple are configured
|
|
290
|
-
- Sends the
|
|
291
|
+
- Sends the verified playlist to the chosen feed server
|
|
291
292
|
- Returns the playlist ID on success
|
|
292
293
|
|
|
293
294
|
Configure feed servers in `config.json`:
|
package/docs/RELEASING.md
CHANGED
|
@@ -1,8 +1,57 @@
|
|
|
1
|
-
# Releasing
|
|
1
|
+
# Releasing ff-cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
How releases happen, how to cut one, and what to do when things go sideways.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Cut a release (day-to-day)
|
|
6
|
+
|
|
7
|
+
1. **Bump `package.json` version** on `main` (or via a `chore: bump version to X.Y.Z` PR — the project has used both patterns).
|
|
8
|
+
2. **Push to `main`** so the tag created in step 3 points at the bump commit.
|
|
9
|
+
3. **Create a GitHub Release** with the tag equal to the version (e.g. tag `1.2.0` → `"version": "1.2.0"`). Use `gh release create 1.2.0 --title "v1.2.0" --notes "..."` or the web UI.
|
|
10
|
+
4. **The `release.yml` workflow fires automatically**, verifies tag == `package.json` version, runs CI, publishes to npm via OIDC, builds binary assets, uploads them to the release, and verifies the package landed on npm.
|
|
11
|
+
|
|
12
|
+
That's it. No tokens, no manual `npm publish`. The whole thing takes ~4 minutes end-to-end.
|
|
13
|
+
|
|
14
|
+
### Beta releases
|
|
15
|
+
|
|
16
|
+
For pre-release versions (e.g. `1.2.0-beta.0`):
|
|
17
|
+
|
|
18
|
+
- Mark the GitHub Release as a **pre-release**, and the version string in `package.json` must contain `beta`. Publishes go to the `beta` dist-tag.
|
|
19
|
+
- Or use **workflow dispatch** (Actions → Release → Run workflow) from `main` with a `version` input that contains `beta` and matches `package.json`.
|
|
20
|
+
|
|
21
|
+
## How publishing actually works
|
|
22
|
+
|
|
23
|
+
The `publish-npm` job in `release.yml` authenticates to npm via **GitHub Actions OIDC** (npm Trusted Publishing). Key pieces:
|
|
24
|
+
|
|
25
|
+
| Piece | Why |
|
|
26
|
+
|---|---|
|
|
27
|
+
| `permissions: id-token: write` on the job | Lets GitHub Actions mint an OIDC token at runtime. |
|
|
28
|
+
| `node-version: '24'` (only this job) | Node 22's bundled npm 10.x doesn't support OIDC publishing. Node 24 ships with npm 11.x. The package's `engines: node >=22` floor for consumers is unrelated. |
|
|
29
|
+
| `npm publish --provenance` | Generates a SLSA provenance attestation signed via sigstore, then submits the package + attestation to npm. |
|
|
30
|
+
| `package.json` `"repository": { "url": "git+https://github.com/feral-file/ff-cli.git" }` | npm cross-checks this against the provenance ("built from feral-file/ff-cli") and rejects the publish if it doesn't match. |
|
|
31
|
+
| **No `NPM_TOKEN` secret** | OIDC replaces the token entirely. The old secret is deleted; do not re-add. |
|
|
32
|
+
|
|
33
|
+
The trust relationship lives at https://www.npmjs.com/package/@feralfile/cli/access — publisher: GitHub Actions, org `feral-file`, repo `ff-cli`, workflow `release.yml`. Changing the workflow filename, repo, or org will break publishes until the trust config is updated.
|
|
34
|
+
|
|
35
|
+
## Bootstrapping a brand-new npm package
|
|
36
|
+
|
|
37
|
+
You will probably never do this again for `@feralfile/cli`, but if you ever publish a new scoped package (`@feralfile/something-else`), the chicken-and-egg sequence is:
|
|
38
|
+
|
|
39
|
+
1. **First publish must come from a logged-in human** (npm Trusted Publishing can only be configured against an existing package). Run `npm publish --access public` locally as a user with publish rights to the org. If your account has 2FA, pass `--otp 123456` inline — the browser auth flow needs a real TTY that `gh`/Claude/CI doesn't provide.
|
|
40
|
+
2. **Configure the trusted publisher** at `https://www.npmjs.com/package/<name>/access` once the package exists. Fields: Publisher = GitHub Actions, Organization = `feral-file`, Repository = `<repo>`, Workflow filename = `release.yml`.
|
|
41
|
+
3. **Confirm `package.json` has a matching `repository.url`** before letting CI publish, or `--provenance` will 422.
|
|
42
|
+
4. **Cut a small follow-up release through CI** to confirm the OIDC path works end-to-end before relying on it.
|
|
43
|
+
5. **Optionally harden**: flip "Publishing access" to "Require 2FA and disallow tokens" so the only way to publish is via the trusted publisher in CI — no laptops, no automation tokens.
|
|
44
|
+
|
|
45
|
+
## GitHub Actions workflows
|
|
46
|
+
|
|
47
|
+
- **`ci.yml`** — formatting, lint, tests, build on Node 22 across ubuntu/macos/windows. Called by `release.yml` and runs on PRs / pushes to `main`.
|
|
48
|
+
- **`build.yml`** — builds prebuilt binaries (macOS/Linux/Windows) and uploads them as workflow artifacts. Triggered manually or from `release.yml`.
|
|
49
|
+
- **`release.yml`** — orchestrates a release. Verifies version, runs CI, publishes to npm (Node 24 + OIDC + provenance), builds binaries, uploads release assets, verifies the package and assets are live. Triggers on published GitHub Releases or manual dispatch (beta only).
|
|
50
|
+
- **`codeql.yml`**, **`dependency-review.yml`** — security scanning.
|
|
51
|
+
|
|
52
|
+
## Binary release assets
|
|
53
|
+
|
|
54
|
+
The curl installer (`https://feralfile.com/ff-cli-install`) downloads prebuilt binaries from GitHub Releases. The release workflow builds and uploads them automatically. To build one locally:
|
|
6
55
|
|
|
7
56
|
**macOS / Linux:**
|
|
8
57
|
|
|
@@ -16,28 +65,12 @@ The curl installer downloads prebuilt binaries from GitHub Releases. Build one a
|
|
|
16
65
|
.\scripts\release\build-asset-windows.ps1
|
|
17
66
|
```
|
|
18
67
|
|
|
19
|
-
|
|
68
|
+
Produces (names vary by OS/arch):
|
|
20
69
|
|
|
21
70
|
- `release/ff-cli-darwin-arm64.tar.gz` (and `.sha256`) on macOS
|
|
22
71
|
- `release/ff-cli-linux-x64.tar.gz` (and `.sha256`) on Linux
|
|
23
72
|
- `release/ff-cli-windows-x64.zip` (and `.sha256`) on Windows
|
|
24
73
|
|
|
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
74
|
## Release notes and breaking changes
|
|
42
75
|
|
|
43
76
|
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.
|
|
@@ -56,7 +89,7 @@ GitHub Release text (and any user-facing summary you publish with the version) s
|
|
|
56
89
|
|
|
57
90
|
Later releases only need to repeat this block if the engine floor changes again.
|
|
58
91
|
|
|
59
|
-
## Installer
|
|
92
|
+
## Installer redirect
|
|
60
93
|
|
|
61
94
|
`https://feralfile.com/ff-cli-install` should redirect to:
|
|
62
95
|
|
|
@@ -66,8 +99,45 @@ https://raw.githubusercontent.com/feral-file/ff-cli/main/scripts/install.sh
|
|
|
66
99
|
|
|
67
100
|
The installer script then fetches the release assets from GitHub Releases.
|
|
68
101
|
|
|
69
|
-
## Environment
|
|
102
|
+
## Environment overrides
|
|
70
103
|
|
|
71
104
|
- `FF_CLI_VERSION`: overrides the version label in logs
|
|
72
105
|
- `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
106
|
- `FF_CLI_OUTPUT_DIR`: output directory (default: `./release`)
|
|
107
|
+
|
|
108
|
+
## Troubleshooting
|
|
109
|
+
|
|
110
|
+
### `404 Not Found - PUT https://registry.npmjs.org/@feralfile%2fcli`
|
|
111
|
+
|
|
112
|
+
npm hides "you don't have publish access" as a 404. Check:
|
|
113
|
+
|
|
114
|
+
1. The trusted publisher at https://www.npmjs.com/package/@feralfile/cli/access matches the *running* workflow: organization, repository, workflow filename, environment (or lack thereof).
|
|
115
|
+
2. The job has `permissions: id-token: write`.
|
|
116
|
+
3. You're not somehow still passing an `NPM_TOKEN` / `NODE_AUTH_TOKEN` env var — that flips npm into token-auth mode, and if the token isn't authorized for the scope you'll 404.
|
|
117
|
+
|
|
118
|
+
### `422 Unprocessable Entity ... "repository.url" is "", expected to match "https://github.com/feral-file/ff-cli" from provenance`
|
|
119
|
+
|
|
120
|
+
The SLSA provenance attestation records the source repo; npm requires `package.json`'s `repository.url` to match before accepting the publish. Add:
|
|
121
|
+
|
|
122
|
+
```json
|
|
123
|
+
"repository": {
|
|
124
|
+
"type": "git",
|
|
125
|
+
"url": "git+https://github.com/feral-file/ff-cli.git"
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### `npm error code MODULE_NOT_FOUND ... Cannot find module 'promise-retry'`
|
|
130
|
+
|
|
131
|
+
You're trying to `npm install -g npm@latest` on top of a running npm. It overwrites its own files mid-execution and corrupts. Don't upgrade in place — use a Node version that already ships the npm you need. The `publish-npm` job runs Node 24 specifically for this reason.
|
|
132
|
+
|
|
133
|
+
### `EOTP — This operation requires a one-time password`
|
|
134
|
+
|
|
135
|
+
You're publishing manually from a laptop, and your npm account has 2FA enforced. Either pass `--otp 123456` inline (TOTP code from your authenticator), or run `npm publish` directly in a real terminal where the browser auth flow can complete. **CI never hits this** — OIDC is its own auth path and bypasses 2FA.
|
|
136
|
+
|
|
137
|
+
### `Version mismatch: package.json is X but tag is Y`
|
|
138
|
+
|
|
139
|
+
The `verify-version` job catches this. Fix `package.json` to match the tag and create a new release tag, or delete and recreate the release with the correct tag.
|
|
140
|
+
|
|
141
|
+
### Release fired but never reached npm
|
|
142
|
+
|
|
143
|
+
The tag is consumed even when publish fails (you can't republish the same version). Bump to the next patch version and cut a fresh release. Optionally `gh release delete <tag> --cleanup-tag` to remove the never-published tag from the release page.
|
package/package.json
CHANGED
|
@@ -1,7 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@feralfile/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "CLI for building DP-1 playlists of digital art using AI (Claude, Grok, ChatGPT, Gemini)",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/feral-file/ff-cli.git"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/feral-file/ff-cli#readme",
|
|
10
|
+
"bugs": {
|
|
11
|
+
"url": "https://github.com/feral-file/ff-cli/issues"
|
|
12
|
+
},
|
|
5
13
|
"main": "dist/index.js",
|
|
6
14
|
"bin": {
|
|
7
15
|
"ff-cli": "dist/index.js"
|