@farthershore/cli 0.31.1 → 0.33.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 (4) hide show
  1. package/README.md +261 -34
  2. package/dist/index.js +111 -106
  3. package/dist/mcp.js +50 -46
  4. package/package.json +11 -4
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  Create and operate [FartherShore](https://farthershore.com) software businesses
4
4
  from the terminal.
5
5
 
6
- **Status: `0.31.1`.** Pre-1.0 — the command surface is stable but may still
6
+ **Status: `0.33.0`.** Pre-1.0 — the command surface is stable but may still
7
7
  change between minor versions. Pin an exact version in CI.
8
8
 
9
9
  FartherShore lets you define a software business as code, then sells, meters,
@@ -21,19 +21,19 @@ the explicitly agent-operable subset of the CLI surface.
21
21
  ## Install
22
22
 
23
23
  ```bash
24
- npm install -g @farthershore/cli@0.31.1
24
+ npm install -g @farthershore/cli@0.33.0
25
25
  ```
26
26
 
27
27
  Or run it directly with npx:
28
28
 
29
29
  ```bash
30
- npx -p @farthershore/cli@0.31.1 farthershore --help
30
+ npx -p @farthershore/cli@0.33.0 farthershore --help
31
31
  ```
32
32
 
33
33
  The package also ships an MCP stdio server for agents:
34
34
 
35
35
  ```bash
36
- npx -p @farthershore/cli@0.31.1 farthershore-mcp
36
+ npx -p @farthershore/cli@0.33.0 farthershore-mcp
37
37
  ```
38
38
 
39
39
  ## Authentication
@@ -131,14 +131,49 @@ write commands cover **operational** state that lives outside the manifest
131
131
 
132
132
  ## Environment variables
133
133
 
134
- | Variable | Description |
135
- | ---------------------- | --------------------------------------------------------------- |
136
- | `FARTHERSHORE_TOKEN` | Ephemeral organization-scoped MakerToken; never persisted |
137
- | `FARTHERSHORE_API_URL` | Platform Core API URL (default `https://core.farthershore.com`) |
138
- | `FARTHERSHORE_ENV` | Default environment scope when `--env` is omitted |
134
+ | Variable | Description |
135
+ | ----------------------------------------- | ------------------------------------------------------------------------ |
136
+ | `FARTHERSHORE_TOKEN` | Ephemeral organization-scoped MakerToken; never persisted |
137
+ | `FARTHERSHORE_API_URL` | Platform Core API URL (default `https://core.farthershore.com`) |
138
+ | `FARTHERSHORE_ENV` | Default environment scope when `--env` is omitted |
139
+ | `FARTHERSHORE_CONSUMER_TOKEN` | Ephemeral portal consumer session for `service-account`; never persisted |
140
+ | `FARTHERSHORE_ENVIRONMENT_ID` | Portal environment UUID fallback for `service-account` |
141
+ | `FARTHERSHORE_SUBSCRIBER_ORGANIZATION_ID` | Subscriber organization UUID fallback for `service-account` |
139
142
 
140
143
  ## Commands
141
144
 
145
+ ### Browse platform documentation (no login)
146
+
147
+ Docs are a read-only virtual filesystem: collections are root folders, sidebar
148
+ sections are directories, and pages are files. Listing a page shows its heading
149
+ anchors. Paths come from the published docs index, not your working directory.
150
+
151
+ ```bash
152
+ farthershore docs ls --format json
153
+ farthershore docs ls backend-sdk --format json
154
+ farthershore docs tree backend-sdk --format json
155
+ farthershore docs ls backend-sdk/connect-your-application --format json
156
+ farthershore docs read backend-sdk/connect-your-application/metering --format json
157
+ farthershore docs ls backend-sdk/connect-your-application/metering --format json
158
+ farthershore docs read backend/metering --section "choose-the-correct-metering-channel" --format json
159
+ farthershore docs search "runtime token" --collection backend-sdk --limit 10 --format json
160
+ farthershore docs collection backend-sdk --format json
161
+ ```
162
+
163
+ Use an anchor returned by `docs ls <page>` for `--section`. `read` also accepts the canonical slug or an
164
+ official docs URL with a `#heading` fragment, so links in skills can be used
165
+ directly. `get` aliases `read`; `list` aliases `ls`. A section includes all its
166
+ child headings and complete code fences. Full pages and collections are not
167
+ truncated; search results are bounded and include a total match count.
168
+
169
+ `farthershore docs --stage ls` selects stage; production is the default and
170
+ `--api-url` does not change the documentation origin. No credentials or
171
+ organization context are sent. JSON includes source URL and, for content reads,
172
+ the docs source commit. Human output is available with `--format table`.
173
+ The collection-aware `llms.txt` and corpus artifacts must be published first;
174
+ unavailable artifacts produce an error, not stale bundled guidance. Business
175
+ `knowledge` commands are separate authenticated resources.
176
+
142
177
  Run `farthershore <group> --help` for the full flag set of any command.
143
178
 
144
179
  Database-backed list commands use Core's shared query contract: repeat
@@ -205,6 +240,9 @@ farthershore business list --filter status=ACTIVE --sort updatedAt:desc --search
205
240
  farthershore business show weather-api --format json
206
241
  farthershore business show weather-api --env preview --format json
207
242
 
243
+ # Is the slug free? (normalized, blocked-word and collision checked)
244
+ farthershore business subdomain-check weather-api --format json
245
+
208
246
  farthershore business create weather-api \
209
247
  --display-name "Weather API" \
210
248
  --format json
@@ -219,7 +257,9 @@ Gather the product requirements, create the `business/` program, and author its
219
257
  plans, prices, limits, routes, and meters from scratch.
220
258
 
221
259
  `business update` changes platform-owned fields such as display name,
222
- description, icon, and logo (icon/logo accept PNG, JPEG, or WEBP). Plans,
260
+ description, icon, logo (icon/logo accept PNG, JPEG, or WEBP), and whether the
261
+ product is listed on the organization's public page
262
+ (`https://farthershore.io/organization/<org-slug>`, listed by default). Plans,
223
263
  prices, limits, routes, and meters are repo-controlled and must be changed
224
264
  through the Business SDK code path.
225
265
 
@@ -232,6 +272,8 @@ farthershore business update weather-api \
232
272
  --format json
233
273
  farthershore business update weather-api \
234
274
  --clear-icon --clear-logo --format json
275
+ farthershore business update weather-api \
276
+ --unlist-from-org-page --format json
235
277
  ```
236
278
 
237
279
  `business publish` enforces the same go-live gates as the dashboard and returns
@@ -239,6 +281,31 @@ stable remediation errors when a prerequisite is missing.
239
281
  `business rollback` enqueues a rollback of the specified prior publish workflow
240
282
  and requires the exact `business:rollback` permission.
241
283
 
284
+ `business rbac` reads a business's Managed-RBAC state — the platform-owned
285
+ `rbacEnabled` flag. `business rbac enable` / `disable` toggle that flag (like
286
+ `docsEnabled`, it is platform-owned and never repo-authored); once enabled,
287
+ subscriber organizations manage roles in their portal. Both toggles are
288
+ idempotent. Subscriber role and assignment state is kept server-side on
289
+ disable, so re-enabling is a pure flag flip.
290
+
291
+ ```bash
292
+ farthershore business rbac weather-api --format json
293
+ farthershore business rbac enable weather-api --format json
294
+ farthershore business rbac disable weather-api --format json
295
+ ```
296
+
297
+ `business rbac subjects list` lists the custom permission vocabulary: subjects
298
+ whose `<subject>:<verb>` permissions are grantable to subscriber roles
299
+ alongside the route-derived catalog. Subjects are **repo-owned** — declared via
300
+ a permission-carrying `fs.group(id, routes, { permission: { verbs, escalatory,
301
+ description } })` in the business repo's `business/` folder and synced from the
302
+ accepted spec. To change them, edit the group declaration, run
303
+ `farthershore validate`, and push; there are no CLI write commands.
304
+
305
+ ```bash
306
+ farthershore business rbac subjects list weather-api --format json
307
+ ```
308
+
242
309
  ### `farthershore apply-timeline`
243
310
 
244
311
  Inspect repo-backed applies — PRs, pushes, releases, checks, semantic diffs,
@@ -269,20 +336,150 @@ to them. Built-in and custom roles use the same list contract.
269
336
  ```bash
270
337
  farthershore organization role list <organizationId> --filter builtIn=true --sort name --search security --format json
271
338
  farthershore organization members <organizationId> --filter roleKey=auditor --sort email:asc --search person --format json
339
+
340
+ # Primary owner only; hands ultimate authority to another existing member.
341
+ farthershore organization ownership-transfer <organizationId> <newOwnerUserId> --yes --format json
342
+ ```
343
+
344
+ Selecting the default organization is a local credential concern, not an API
345
+ call: `farthershore auth organization use <id-or-slug>` changes the stored
346
+ default, and `--org <id>` overrides it for one command.
347
+
348
+ ### `farthershore token`
349
+
350
+ Create and administer organization-owned MakerTokens. These commands require a
351
+ signed-in user CLI session (`farthershore login`); an existing MakerToken cannot
352
+ list, mint, approve, rotate, revoke, or otherwise administer credentials. The
353
+ entire group is CLI-only and is deliberately absent from `farthershore-mcp`.
354
+
355
+ ```bash
356
+ # Exact permissions a human may delegate — read this before choosing --permissions.
357
+ farthershore token permission-catalog --org --format json
358
+
359
+ # Omit --businesses to snapshot ALL current and future org businesses.
360
+ farthershore token create deploy-bot --org \
361
+ --permissions '["business:read","business:publish"]' \
362
+ --businesses business_1,business_2 \
363
+ --idempotency-key org-token-create-2026-08-11 \
364
+ --format json
365
+
366
+ farthershore token list --org --format json
367
+ farthershore token approvals --org --format json
368
+ farthershore token approve <approvalId> --org --format json
369
+ farthershore token approve <approvalId> --org \
370
+ --permissions '["business:read"]' --format json # trim on approval
371
+ farthershore token deny <approvalId> --org --format json
372
+ farthershore token update <tokenId> --org \
373
+ --permissions '["business:read"]' \
374
+ --idempotency-key org-token-update-2026-08-11 --format json
375
+ farthershore token rotate <tokenId> --org --format json
376
+ farthershore token revoke <tokenId> --org --yes --format json
377
+ ```
378
+
379
+ Creation and updates that exceed the caller's live authority return
380
+ `data.status: "PENDING"`, an approval id, and **no plaintext credential**. A
381
+ direct ACTIVE create, an approved CREATE, or a rotation returns `data.token`
382
+ exactly once; store it immediately. Human output follows the same rule: it
383
+ prints plaintext only for an ACTIVE one-time-secret response and says explicitly
384
+ when a PENDING request minted nothing.
385
+
386
+ Create and update accept `--idempotency-key`. Reuse the same key when repeating
387
+ the same logical request after an interrupted invocation. If omitted, the CLI
388
+ generates a key and keeps it stable across its automatic transient retries.
389
+
390
+ ### `farthershore stripe`
391
+
392
+ Read the Stripe Connect account a business bills through (a per-business
393
+ override when one exists, otherwise the organization default) and remove a
394
+ per-business override. Both require a signed-in owner session; a MakerToken is
395
+ rejected. Connecting Stripe is a browser-only onboarding handshake with Stripe,
396
+ so there is deliberately no `stripe connect` command — do it from the
397
+ dashboard and confirm with `stripe status`.
398
+
399
+ ```bash
400
+ farthershore stripe status weather-api --format json
401
+ farthershore stripe disconnect weather-api --yes --format json
402
+ ```
403
+
404
+ `stripe disconnect` is refused while any subscription on the business is still
405
+ money-bearing.
406
+
407
+ ### `farthershore service-account`
408
+
409
+ Manage service accounts owned by a subscriber organization. This is a separate
410
+ subscriber-plane trust boundary: it requires a current identity-provider portal
411
+ consumer session in `FARTHERSHORE_CONSUMER_TOKEN`, plus the exact environment
412
+ and subscriber organization context. The consumer bearer has no argv flag and
413
+ is never exchanged or persisted by the CLI. A builder login or MakerToken cannot
414
+ substitute for it.
415
+
416
+ ```bash
417
+ export FARTHERSHORE_CONSUMER_TOKEN='<current portal session token>'
418
+ export FARTHERSHORE_ENVIRONMENT_ID='<environment UUID>'
419
+ export FARTHERSHORE_SUBSCRIBER_ORGANIZATION_ID='<subscriber organization UUID>'
420
+
421
+ farthershore service-account list <businessId> --format json
422
+ farthershore service-account create <businessId> deploy-bot \
423
+ --permissions '["route:read","route:write"]' \
424
+ --scopes '["production"]' \
425
+ --idempotency-key sa-create-2026-08-11 --format json
426
+ farthershore service-account update <businessId> <serviceAccountId> \
427
+ --permissions '["route:read"]' \
428
+ --idempotency-key sa-update-2026-08-11 --format json
429
+ farthershore service-account approvals <businessId> --format json
430
+ farthershore service-account approve <businessId> <approvalId> \
431
+ --permissions '["route:read"]' --format json # optional trim
432
+ farthershore service-account deny <businessId> <approvalId> --format json
433
+ farthershore service-account rotate <businessId> <serviceAccountId> --format json
434
+ farthershore service-account revoke <businessId> <serviceAccountId> --yes --format json
435
+ ```
436
+
437
+ Pass `--environment-id` and `--subscriber-organization` to override the two
438
+ context environment variables for one command. PENDING create/update responses
439
+ never print `plaintext`. ACTIVE creates
440
+ and rotations print the one-time key once. Create/update idempotency follows the
441
+ same explicit-key or generated stable in-flight retry behavior as org tokens.
442
+
443
+ This group is direct CLI-only and deliberately has no MCP projection: the MCP
444
+ operation registry carries builder principals, not portal consumer sessions.
445
+
446
+ ### `farthershore limit`
447
+
448
+ Manage subscriber-owned usage limits with a portal consumer session. `list`
449
+ reads the current limits; `set` creates a limit when `--limit-id` is omitted and
450
+ updates that limit when `--limit-id` is present; `remove` deletes a limit.
451
+
452
+ ```bash
453
+ farthershore limit list <business-id> --format json
454
+ farthershore limit set <business-id> \
455
+ --quantity requests --mode BLOCK --scope ORG --units 10000 \
456
+ --format json
457
+ farthershore limit set <business-id> \
458
+ --limit-id <limit-id> --mode NOTIFY --units 20000 \
459
+ --notify-at 0.8 --format json
460
+ farthershore limit remove <business-id> <limit-id> --format json
272
461
  ```
273
462
 
463
+ Changing a limit's scope, subject, or quantity requires removing and recreating
464
+ the limit with the new target.
465
+
466
+ Every `limit` command requires `FARTHERSHORE_CONSUMER_TOKEN`, containing the
467
+ current portal consumer session token. Pass `--environment-id` and
468
+ `--subscriber-organization`, or set their respective fallbacks
469
+ `FARTHERSHORE_ENVIRONMENT_ID` and
470
+ `FARTHERSHORE_SUBSCRIBER_ORGANIZATION_ID`. These subscriber-portal credentials
471
+ are separate from the organization-scoped MakerToken used by the rest of the
472
+ CLI and are never persisted automatically.
473
+
274
474
  ### `farthershore plan`
275
475
 
276
- Read code-managed plans and operate live subscriber migrations. The CLI does not
476
+ Read code-managed plans. The CLI does not
277
477
  create, update, or delete plan definitions — edit the Business SDK program for
278
478
  that.
279
479
 
280
480
  ```bash
281
481
  farthershore plan list weather-api # table (default in TTY)
282
482
  farthershore plan list weather-api --format json
283
-
284
- # Migrate live subscribers after a repo-authored plan version is released
285
- farthershore plan migrate weather-api pro --from 1 --to head --policy next_renewal --format json
286
483
  ```
287
484
 
288
485
  ### `farthershore frontend`
@@ -342,17 +539,18 @@ across billing, edge credentials, and subscriptions.
342
539
 
343
540
  ### `farthershore variables`
344
541
 
345
- Manage write-only private secrets with one exclusive delivery phase. `BUILD`
346
- values enter only the isolated managed build and are leak-scanned from its
347
- artifact. `RUNTIME` values stay out of builds and are injected only by Gateway
348
- for compiled, granted integrations.
542
+ Manage platform-owned variables. The name is the class: an `FS_PUBLIC_` prefix
543
+ makes a value public (inlined into the frontend bundle, readable by every
544
+ visitor); any other name is a write-only secret — available to the isolated
545
+ managed build (leak-scanned from its artifact) and injected by Gateway for any
546
+ compiled integration that references it.
349
547
 
350
548
  ```bash
351
549
  farthershore variables list weather-api --format json
352
550
  printf '%s' "$SENTRY_AUTH_TOKEN" | farthershore variables set weather-api \
353
- SENTRY_AUTH_TOKEN --delivery build --format json
354
- printf '%s' "$POSTHOG_SECRET" | farthershore variables set weather-api \
355
- POSTHOG_SECRET --delivery runtime --format json
551
+ SENTRY_AUTH_TOKEN --format json
552
+ printf '%s' "$POSTHOG_PROJECT_KEY" | farthershore variables set weather-api \
553
+ FS_PUBLIC_POSTHOG_KEY --format json
356
554
  farthershore variables revoke weather-api POSTHOG_SECRET --yes --format json
357
555
  farthershore variables rm weather-api POSTHOG_SECRET --yes --format json
358
556
  ```
@@ -387,7 +585,7 @@ Pair the token with
387
585
  your upstream:
388
586
 
389
587
  ```ts
390
- import { fartherShore, withUsage } from "@farthershore/backend";
588
+ import { fartherShore } from "@farthershore/backend";
391
589
 
392
590
  const fs = fartherShore.initFromEnv();
393
591
 
@@ -395,7 +593,7 @@ export async function POST(request: Request) {
395
593
  const url = new URL(request.url);
396
594
  const body = await request.clone().arrayBuffer();
397
595
 
398
- await fs.verifyRequest({
596
+ const ctx = await fs.verifyRequest({
399
597
  method: request.method,
400
598
  path: url.pathname,
401
599
  query: url.search,
@@ -404,17 +602,19 @@ export async function POST(request: Request) {
404
602
  });
405
603
 
406
604
  const result = await runWorkflow(await request.json());
407
- return withUsage(request, Response.json(result), {
408
- tokens_used: result.tokensUsed,
605
+ await ctx.report({
606
+ meter: "tokens_used",
607
+ values: { tokens_used: result.tokensUsed },
409
608
  });
609
+ return Response.json(result);
410
610
  }
411
611
  ```
412
612
 
413
613
  ### `farthershore webhook`
414
614
 
415
- Provision outbound webhook endpoints and inspect delivery health. If the business
416
- declares webhooks under `business/`, writes return
417
- `409 MANAGED_BY_CODE` so the repo stays canonical.
615
+ Provision outbound webhook endpoints and inspect delivery health. Endpoints are
616
+ platform-owned operate records: they never live in the managed repo, so these
617
+ writes work the same for every business regardless of repo linkage.
418
618
 
419
619
  ```bash
420
620
  farthershore webhook list weather-api --format json
@@ -424,11 +624,38 @@ farthershore webhook create weather-api \
424
624
  --format json
425
625
  farthershore webhook update weather-api <webhookId> --disable --format json
426
626
  farthershore webhook test weather-api <webhookId> --format json
627
+ farthershore webhook trigger weather-api <webhookId> --type payment.failed --format json
427
628
  farthershore webhook deliveries weather-api <webhookId> --limit 20 --format json
629
+ farthershore webhook rotate weather-api <webhookId> --format json
428
630
  farthershore webhook delete weather-api <webhookId> --yes --format json
429
631
  ```
430
632
 
431
- `webhook create` returns the signing secret once; store it in the receiving app.
633
+ `webhook create` and `webhook rotate` return the signing secret once; store it
634
+ in the receiving app. In human mode they also print it as an
635
+ `FS_WEBHOOK_SECRET=` line plus a `createWebhookHandler` snippet.
636
+
637
+ `webhook test` sends the plain `webhook.test` ping. `webhook trigger --type`
638
+ sends a signed, realistic sample of one catalog event (the deliveries log
639
+ records it under that type) so every handler branch can be exercised locally.
640
+
641
+ For a receiver on your machine, `webhook listen` is the Stripe-CLI-style loop:
642
+ it opens a Cloudflare quick tunnel to `--forward-to`, creates a temporary
643
+ endpoint on it, prints the endpoint id / tunnel URL / (with `--print-secret`)
644
+ the `FS_WEBHOOK_SECRET=` line, tails deliveries as
645
+ `time type status responseStatus id`, and deletes the endpoint on Ctrl-C.
646
+
647
+ ```bash
648
+ farthershore webhook listen weather-api \
649
+ --forward-to http://localhost:3000/webhooks/farthershore \
650
+ --print-secret --trigger payment.failed
651
+ farthershore webhook listen weather-api --forward-to localhost:3000/webhooks \
652
+ --events subscription.created,payment.failed --format json
653
+ ```
654
+
655
+ `listen` needs `cloudflared` — bundled as an optional
656
+ `@farthershore/cloudflared-<platform>` dependency, or on your PATH. It has no
657
+ MCP tool (long-running, process-owning). A listener killed hard leaves an
658
+ endpoint with a `*.trycloudflare.com` URL; `webhook delete --yes` removes it.
432
659
 
433
660
  ### `farthershore promo-code`
434
661
 
@@ -455,12 +682,12 @@ Use `--all-plans` to clear plan scoping.
455
682
  Install or refresh the platform-verified skills bundle together. The platform
456
683
  pins this immutable release, and CI plus a daily repository check compare it to
457
684
  GitHub's latest stable release so the guidance cannot silently drift.
458
- This command requires `@farthershore/cli` 0.31.1 or newer.
685
+ This command requires `@farthershore/cli` 0.33.0 or newer.
459
686
 
460
687
  ```bash
461
688
  farthershore skills install --help
462
689
  # If the command is unavailable, upgrade to the required CLI release:
463
- npm install -g @farthershore/cli@0.31.1
690
+ npm install -g @farthershore/cli@0.33.0
464
691
  farthershore skills install
465
692
  ```
466
693
 
@@ -512,9 +739,9 @@ The MCP server (`farthershore-mcp`) projects its tools from the same operation
512
739
  registry that defines the CLI commands. Every MCP tool has a CLI sibling, but
513
740
  not every CLI command is exposed through MCP. Tool names use the `fs_*` prefix
514
741
  and cover only operations explicitly marked agent-operable in that registry.
515
- Organization, role, member, and invitation administration requires a live-user
516
- CLI session and is not projected into MCP; audit logs, notifications, and apply
517
- timelines are also CLI-only.
742
+ Organization, role, member, invitation, and org MakerToken administration
743
+ requires a live-user CLI session and is not projected into MCP; audit logs,
744
+ notifications, and apply timelines are also CLI-only.
518
745
 
519
746
  ```bash
520
747
  farthershore-mcp