@nearform/fling 0.8.0 → 0.10.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.
Files changed (3) hide show
  1. package/README.md +134 -25
  2. package/dist/cli.js +2204 -388
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -38,13 +38,64 @@ This does everything a new machine needs:
38
38
  sign-in providers, its login page, to choose one) and an API key is
39
39
  stored in `~/.fling/config.json` (mode 0600). This is skipped if you're already signed in.
40
40
  The server becomes your current one; logins to other Flings are kept.
41
+ When you are already signed in, it reads the server's `/.well-known/fling` again, so the CLI
42
+ knows the release it runs now.
41
43
  2. **Adds Fling to Claude Code.** If `claude` is on your PATH, setup installs the Fling plugin
42
- (skill + MCP server) from the `nearform/fling` marketplace, or updates it if it's already
43
- installed. `--scope project|local` installs it for this project only (default `user`).
44
+ (skill + MCP server) from the `nearform/fling` marketplace. `--scope project|local` installs it
45
+ for this project only (default `user`). When the plugin is already installed, setup refreshes
46
+ it instead (`claude plugin marketplace update fling`, then `claude plugin update fling@fling`)
47
+ and says which version it went from and to; restart Claude Code (or run `/reload-plugins`)
48
+ after an update. A refresh that fails is reported and leaves the installed plugin as it was;
49
+ it doesn't fail setup.
44
50
  3. **Adds Fling to Claude Desktop.** If Claude Desktop is installed (macOS, Windows), setup
45
- downloads `fling.mcpb` and opens it, and Claude Desktop asks you to confirm.
51
+ downloads the `fling.mcpb` of the CLI's own version and opens it, and Claude Desktop asks you
52
+ to confirm. That is the server's copy when the server runs the same release, otherwise the one
53
+ attached to the CLI's GitHub Release (the server's copy if that download fails). Running setup
54
+ again updates an older extension in place.
46
55
 
47
- On a terminal it asks before steps 2 and 3. With `--yes` it does them without asking.
56
+ On a terminal it asks before installing the plugin and before step 3. With `--yes` it does them
57
+ without asking. Refreshing an installed plugin needs no question.
58
+
59
+ ### Staying up to date
60
+
61
+ Every Fling publishes the release it runs (`release` in `/.well-known/fling`). After a command, when
62
+ the server it used runs a newer release than the CLI, the CLI prints one line on stderr:
63
+
64
+ ```
65
+ ▲ Fling 0.9.0 is out (this CLI is 0.8.0). Update: npm i -g @nearform/fling@latest && fling setup
66
+ ```
67
+
68
+ It compares with the metadata the CLI already holds, so it never makes a request of its own. The
69
+ stored release stays current because every server response says which release the server runs (the
70
+ `Fling-Release` header): when it differs from the stored one, the CLI stores the new release. That
71
+ needs both the server and the CLI on a release after 0.8.0; with an older server, the stored release
72
+ changes only at sign-in, when `fling setup` reads the metadata again, and when a command needs a
73
+ feature the stored copy lacks. It says it at most once a day per server, remembering when in
74
+ `update-check.json` in the config directory. It says nothing under `--json`, when stderr isn't a
75
+ terminal, when `CI` is set, or when `FLING_NO_UPDATE_CHECK` is set (to anything). A server older
76
+ than the CLI says nothing either. The MCP server tells Claude instead (see [Claude Code plugin and
77
+ MCP](#claude-code-plugin-and-mcp)).
78
+
79
+ ### When something doesn't work
80
+
81
+ `fling doctor` checks the setup and prints one line per check, `✔` ok, `▲` warning or `✖` problem,
82
+ each warning and problem with its fix:
83
+
84
+ - **CLI:** its version, Node.js against the versions it supports, the latest version on npm
85
+ (skipped when npm can't be reached), and whether `fling` on your PATH is this CLI.
86
+ - **Config:** where it lives (`FLING_CONFIG_DIR`), whether the config file is private (mode 0600:
87
+ it holds your API keys), and whether `FLING_URL` or `FLING_API_KEY` is in effect (named, never
88
+ shown).
89
+ - **Each Fling** you signed in to, the current one marked: whether its `/.well-known/fling`
90
+ answers, the release it runs against the CLI's, whether your API key is still accepted, and the
91
+ features it reports.
92
+ - **Claude Code:** `claude` on your PATH, the Fling plugin (installed, enabled, its version against
93
+ the CLI's) and the `fling` marketplace.
94
+ - **Claude Desktop:** whether the extension is installed, enabled, and its version.
95
+
96
+ It only reads: it changes nothing, and each request has a short timeout. `--json` prints
97
+ `{ ok, checks: [{ area, id, status, message, fix?, server? }] }`. The exit code is 1 when any check
98
+ is a problem.
48
99
 
49
100
  To sign in only, use `fling login <url>` (the URL is remembered: later `fling login` needs none).
50
101
  There is no default server: until you log in, commands say to run `fling login <url>`.
@@ -94,7 +145,9 @@ What you can fling:
94
145
  - **A single `.html`/`.htm` file**, served as the site's `index.html`.
95
146
  - **A `.zip`**: extracted (paths that would escape the folder are refused), `__MACOSX/` and dotfiles
96
147
  skipped (dotfiles such as `.env` are listed), and a single top-level folder unwrapped.
97
- - **Any other file** (`.pdf`, `.svg`, `.png`, `.md`…), served next to a small generated `index.html`
148
+ - **A single Markdown file** (`.md`, `.markdown`), on a Fling that renders Markdown (the
149
+ `markdown` capability): its rendered page is the site's home page.
150
+ - **Any other file** (`.pdf`, `.svg`, `.png`…), served next to a small generated `index.html`
98
151
  that shows it (images, PDF, video, audio) or links to it.
99
152
 
100
153
  A file's default site name comes from its name, without the extension or a browser's ` (1)`
@@ -105,21 +158,23 @@ does; see below).
105
158
 
106
159
  - Re-fling to update. Identical content is a no-op, and content you deployed before is restored
107
160
  instantly without uploading.
108
- - **Publish one folder of a site** with `--path` (and `--name`): `fling deploy ./report --name
109
- changelog --path 30-10-26` serves the report at `https://changelog.<sites domain>/30-10-26/` and
110
- keeps every other file of the site. Only the folder's files are uploaded; the server copies the
111
- rest into the new version (at most 1,000 files, else `too_large`: deploy the whole site). If
112
- someone else publishes the site in between, the deploy runs once more on top of theirs. `fling
113
- versions` shows where each one went (PATH), and rolling back removes it. On a Fling without path
114
- publishing (`pathPublish`) the CLI refuses rather than replace the whole site.
161
+ - **Publish one folder of a site as its Path** with `--path` (and `--name`): `fling deploy ./plan
162
+ --name payments-plans --path PAY-412` serves the plan at `https://payments-plans.<sites
163
+ domain>/PAY-412/`. A Path is one top-level folder with its own versions, rollback, owners and
164
+ publishers; publishing it never touches the rest of the site or its other Paths, so teammates
165
+ publishing different Paths never collide. The first publish makes the Path, with you as its
166
+ owner. `--path` takes one folder: nested folders (`reports/2026`) are refused, so publish them as
167
+ part of their top-level folder. A folder pulled with `fling pull --path` deploys back to its
168
+ Path. On a Fling without path publishing (`pathPublish`) the CLI refuses rather than replace the
169
+ whole site. See [Paths](#paths).
115
170
  - **Change a site you can open** with `fling pull <name> [dir]`: it downloads the current version
116
171
  into `dir` (default `./<name>`) with a site link, `.fling-site.json`, naming the server, the site
117
172
  and the version pulled. `fling deploy <dir>` then publishes to that site on that version and
118
173
  uploads only what changed (`3 changed, 1 removed`). If someone published the site since you
119
174
  pulled, it stops (`base_changed`) rather than overwrite their work: pull again into another
120
175
  folder and redo your change, or `fling deploy <dir> --force` to replace what they published.
121
- `--path <folder>` pulls one folder of the site; `--version-id <id>` another version (owners and
122
- publishers). Anyone signed in who can open the site may pull it; only its owners and publishers
176
+ `--path <folder>` pulls one of the site's Paths, its files at the top of `dir`; `--version-id
177
+ <id>` another version (owners and publishers). Anyone signed in who can open the site may pull it; only its owners and publishers
123
178
  may deploy. A folder that isn't empty needs `--force`. On a Fling without the `pull` capability
124
179
  the CLI says so.
125
180
  - **Fling never publishes dotfiles, gitignored files, secret files (keys, certs, credentials) or
@@ -201,15 +256,15 @@ and a taken name fails (exit 1) with suggestions rather than picking another nam
201
256
  |---|---|
202
257
  | `fling ls [--archived] [--sort updated\|created\|name]` | your sites, last updated first (`created`: newest first; `name`: A–Z) |
203
258
  | `fling ls --shared [--sort …]` | the restricted sites others have shared with you: owner, and how (your address or a group) |
204
- | `fling info <name>` / `fling versions <name>` | details and version history, with who published each version and, for a path publish, the folder (PATH) |
259
+ | `fling info <name>` / `fling versions <name> [--path <folder>]` | details and version history, with who published each version; `--path`: a Path's own versions |
205
260
  | `fling pull <name> [dir] [--path <folder>] [--version-id <id>] [--force]` | download a site's files to change them; `fling deploy <dir>` publishes on the version pulled |
206
- | `fling files <name> [versionId]` | the files in the live version (or an earlier one) |
207
- | `fling rollback <name> <versionId>` | serve an earlier version |
261
+ | `fling files <name> [versionId] [--path <folder>]` | the files in the live version (or an earlier one), or a Path's |
262
+ | `fling rollback <name> <versionId> [--path <folder>]` | serve an earlier version (of the site, or of one Path) |
208
263
  | `fling share <name> [--refresh] [--revoke]` | public share link: print or create it, rotate it, or remove it |
209
264
  | `fling visibility <name> private\|public` | require sign-in, or not (private again: the access it had) |
210
265
  | `fling access <name> [--only-me \| --members \| --public] [--add <emails>] [--remove <emails>] [--group <slugs>] [--remove-group <slugs>] [--clear]` | who can open a site: only you, listed people and groups, everyone signed in, or anyone |
211
- | `fling owners <name> [--add <emails>] [--remove <emails>] [--set <emails>] [--group <slugs>] [--remove-group <slugs>]` | who owns a site, or change it |
212
- | `fling publishers <name> [--add …] [--remove …] [--set …] [--group …] [--remove-group …]` | who publishes a site without owning it, or change it |
266
+ | `fling owners <name> [--add <emails>] [--remove <emails>] [--set <emails>] [--group <slugs>] [--remove-group <slugs>] [--path <folder>]` | who owns a site (or a Path), or change it |
267
+ | `fling publishers <name> [--add …] [--remove …] [--set …] [--group …] [--remove-group …] [--path <folder>]` | who publishes a site (or a Path) without owning it, or change it |
213
268
  | `fling archive <name>` / `fling unarchive <name>` | take offline and keep the files, or bring back |
214
269
  | `fling rm <name> [--yes]` | delete permanently |
215
270
 
@@ -287,6 +342,46 @@ admin for an admin's view), and `fling info` its Owners, Publishers and You. As
287
342
  commands print `{ name, role, owners, publishers }`, each list `{ emails: [{ email, known, guest?
288
343
  }], groups: [{ slug, name, size }] }`.
289
344
 
345
+ ### Paths
346
+
347
+ A **Path** is a top-level folder of a site published on its own, such as one plan per ticket on a
348
+ team's site: `fling deploy ./plan --name payments-plans --path PAY-412`. Each Path has its own
349
+ versions, rollback, owners and publishers, and is served at `<site>/<folder>/`. Who can open it is
350
+ the site's. Its owners and publishers, and the site's owners, can publish it, roll it back and
351
+ change it; the site's publishers can make new Paths. On a Fling with Paths (the `paths`
352
+ capability):
353
+
354
+ ```sh
355
+ fling paths payments-plans # its Paths: folder, title, version, state, can you publish, updated
356
+ fling versions payments-plans --path PAY-412 # the Path's own versions (* = live)
357
+ fling files payments-plans --path PAY-412 # the files of its live version (or give a version id)
358
+ fling rollback payments-plans <versionId> --path PAY-412 # roll back only the Path
359
+ fling owners payments-plans --path PAY-412 --add cat@example.com
360
+ fling publishers payments-plans --path PAY-412 --add bob@example.com
361
+ fling paths archive payments-plans PAY-412 # take it off the site (404), keep its versions; `paths unarchive` brings it back
362
+ fling paths delete payments-plans PAY-412 # delete it and its versions (asks first unless --yes)
363
+ fling pull payments-plans --path PAY-412 # its files, to change and deploy back to the Path
364
+ ```
365
+
366
+ **The home page.** A site's home page (its root `index.html`) can list its Paths, three ways:
367
+
368
+ - **Default**: with no `index.html` of its own, the site's home page is a listing of its live
369
+ Paths. A site whose first publish is a Path gets one. Nothing to do.
370
+ - **Custom**: your own `index.html` with a Paths block, which Fling fills with the live Paths
371
+ whenever one changes (and serves as JSON at `/_fling-paths.json`). `fling paths init [dir]
372
+ --template plans|docs|reports|minimal [--title T]` writes a starter (it never replaces an
373
+ `index.html` without `--force`); adapt it, keeping the block, check it with `fling paths check
374
+ [dir|file]` (errors exit 1, warnings are printed), then deploy the folder as the site root,
375
+ without `--path`. The block is the bare marker `<!-- fling:paths -->` (Fling's default list,
376
+ styled by your page) or a template, `<!-- fling:paths sort=updated --> <a href="{{href}}">{{title}}</a>
377
+ <!-- fling:empty --> None yet. <!-- /fling:paths -->`, whose item repeats per Path with
378
+ `{{href}} {{folder}} {{title}} {{updated}} {{date}} {{version}}`. Options: `sort=updated|oldest|folder|folder-desc`,
379
+ `nocontrols`, `nostyle`; `<!-- fling:paths-controls -->` places the search and sort controls.
380
+ - **None**: an `index.html` without a Paths block lists no Paths, and a deploy says so.
381
+
382
+ With `--json`, `fling paths` prints `{ name, paths: [{ folder, title, url, currentVersionId,
383
+ archived, owners?, publishers?, canPublish, createdAt, updatedAt }] }`.
384
+
290
385
  ### Groups
291
386
 
292
387
  A group is a named list of people, such as a team, that anyone signed in can use in a site's
@@ -346,8 +441,10 @@ fling responses my-app --format csv -o labels.csv # the export: json, j
346
441
  - `fling deploy` checks the file against the folder's pages and stops on errors. After the deploy
347
442
  it lists each form and the pages it applies to (`forms` in `--json`). Without the file, it ends
348
443
  with one line on adding a form (`formsHint` in `--json`; `--quiet` leaves it out).
349
- - Without the file, deploying a whole site removes its forms. A `--path` deploy keeps them, and so
350
- does a pulled folder, unless it was pulled with a `fling.forms.json` you have since deleted.
444
+ - Without the file, deploying a whole site removes its forms. A pulled folder keeps them, unless it
445
+ was pulled with a `fling.forms.json` you have since deleted. Forms are the site's: a `--path`
446
+ deploy leaves them as they are and refuses a folder with `fling.forms.json`. Deploy the forms with
447
+ the site's root, with `paths` patterns that reach the Path's pages (`PAY-412/**`).
351
448
  - `fling pull` writes the site's `fling.forms.json` back into the folder.
352
449
  - On a form with `"visibility": "own"`, reviewers see only their own answers; the site's owners see
353
450
  everyone's.
@@ -382,7 +479,8 @@ another server (a remembered one brings its key; see [Several Flings](#several-f
382
479
  Environment: `FLING_API_KEY`, `FLING_URL`, `FLING_CONFIG_DIR`, `FLING_DEBUG`, `FLING_DOWNLOADS_DIR`
383
480
  (where the MCP server looks for files given by name first), `FLING_ADD_SERVER` (a Fling the MCP
384
481
  server adds to the remembered ones when it starts), `FLING_NO_WAIT=1` (after a deploy or a new share
385
- link, don't wait the few seconds it takes to reach every edge).
482
+ link, don't wait the few seconds it takes to reach every edge), `FLING_NO_UPDATE_CHECK` (never say
483
+ that a newer Fling release is out; see [Staying up to date](#staying-up-to-date)).
386
484
 
387
485
  ## Claude Code plugin and MCP
388
486
 
@@ -422,14 +520,14 @@ accepts).
422
520
  The MCP tools:
423
521
 
424
522
  - `fling_deploy`: a folder, `.html`, `.zip` or other file on this computer, by path or just its
425
- name (looked up like the CLI does). `sitePath` (with `name`) publishes it into that folder of the
426
- site and keeps the rest, like `--path`. A folder pulled with `fling pull` or `fling_pull` deploys
523
+ name (looked up like the CLI does). `sitePath` (with `name`) publishes it as that Path of the
524
+ site, the rest untouched, like `--path`. A folder pulled with `fling pull` or `fling_pull` deploys
427
525
  on the version pulled, like the CLI; `force: true` publishes over whatever is live.
428
526
  - `fling_pull`: downloads a site into a folder on this computer (default
429
527
  `~/Documents/Claude/fling/<name>`) to change it and deploy it again with `fling_deploy`.
430
528
  - `fling_read_files`: a site's files inline, a page at a time, for reading without a download.
431
529
  - `fling_publish`: files passed inline, for content Claude wrote in the conversation. It has the same
432
- definition as the remote connector's tool; `path` publishes them into that folder of the site;
530
+ definition as the remote connector's tool; `path` publishes them as that Path of the site;
433
531
  `base` (a version from `fling_read_files`) sends only the files that changed, and `remove` names
434
532
  files to delete.
435
533
  - `fling_find_files`: recent `.html`/`.zip` files and folders with an `index.html` in those folders,
@@ -439,6 +537,12 @@ The MCP tools:
439
537
  Fling, including a new one, which becomes current only if none is.
440
538
  - `fling_servers`: lists the Flings on this computer (address, name, who is signed in, which is
441
539
  current), read when called. `{use: <server>}` makes one current, the same as `fling use`.
540
+ - `fling_doctor`: the checks of `fling doctor`, read-only, as lines and data. Claude calls it when
541
+ something about Fling doesn't work (sign-in, tools missing, versions) and tells you the fixes.
542
+ - `fling_paths` (a site's Paths, and what its home page does with them) where a Fling has Paths,
543
+ and `fling_paths_template` and `fling_paths_check` (a starter home page with a Paths block, and
544
+ its check), which need no Fling. `fling_info`, `fling_files` and `fling_rollback` take `path` to
545
+ act on one Path.
442
546
  - `fling_check_name`, `fling_list`, `fling_info`, `fling_files`, `fling_share`,
443
547
  `fling_set_visibility`, `fling_archive`, `fling_rollback`, `fling_delete` (needs
444
548
  `confirm: true`), `fling_whoami`, the comment tools when a Fling has comments, the forms tools when it has forms
@@ -454,6 +558,11 @@ The MCP tools:
454
558
 
455
559
  Results that give URLs (deploys, publishes, comments) end with the Fling they went to.
456
560
 
561
+ **Updates.** When a Fling the MCP server knows runs a newer release than it, its instructions say
562
+ so, and so does the first `fling_publish` or `fling_deploy` result of the session on that Fling.
563
+ Claude then suggests the update command (`npm i -g @nearform/fling@latest && fling setup`, then
564
+ restart Claude): inside Claude you never see the CLI's own update line.
565
+
457
566
  The MCP server never prompts:
458
567
 
459
568
  - **Names.** Without a `name`, `fling_deploy` uses the generated name and fails with suggestions if