@farthershore/cli 0.33.2 → 0.33.4
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 +105 -48
- package/dist/index.js +136 -106
- package/dist/mcp.js +84 -57
- package/package.json +6 -6
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.33.
|
|
6
|
+
**Status: `0.33.4`.** 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.33.
|
|
24
|
+
npm install -g @farthershore/cli@0.33.4
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
Or run it directly with npx:
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
|
-
npx -p @farthershore/cli@0.33.
|
|
30
|
+
npx -p @farthershore/cli@0.33.4 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.33.
|
|
36
|
+
npx -p @farthershore/cli@0.33.4 farthershore-mcp
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
## Authentication
|
|
@@ -88,7 +88,8 @@ Create a managed business repo, author the business, validate it, and push:
|
|
|
88
88
|
|
|
89
89
|
```bash
|
|
90
90
|
# 1. Create the managed repo. Human output is exactly its URL.
|
|
91
|
-
REPO_URL=$(farthershore business create weather-api
|
|
91
|
+
REPO_URL=$(farthershore business create weather-api \
|
|
92
|
+
--idempotency-key <persisted-business-create-attempt-key>)
|
|
92
93
|
|
|
93
94
|
# 2. Clone it and author business/ from scratch.
|
|
94
95
|
git clone "$REPO_URL"
|
|
@@ -219,12 +220,14 @@ farthershore build --format json
|
|
|
219
220
|
Run the same verdict the GitHub `farthershore/validate` PR check produces, before
|
|
220
221
|
you push. It builds the manifest twice and compares the IR hash (the determinism
|
|
221
222
|
check the build runner enforces), then — when you pass `--business` — submits the
|
|
222
|
-
IR for a server
|
|
223
|
-
an economic-change verdict.
|
|
223
|
+
IR for a server verdict that returns compile diagnostics, the semantic diff, and
|
|
224
|
+
an economic-change verdict. The server may retain a diagnostic compilation
|
|
225
|
+
record, but validation never accepts or publishes business state, so it is safe
|
|
226
|
+
to repeat and does not take an idempotency key.
|
|
224
227
|
|
|
225
228
|
```bash
|
|
226
229
|
farthershore validate # local build + determinism only
|
|
227
|
-
farthershore validate --business weather-api
|
|
230
|
+
farthershore validate --business weather-api
|
|
228
231
|
farthershore validate --local-only --format json
|
|
229
232
|
```
|
|
230
233
|
|
|
@@ -245,10 +248,11 @@ farthershore business subdomain-check weather-api --format json
|
|
|
245
248
|
|
|
246
249
|
farthershore business create weather-api \
|
|
247
250
|
--display-name "Weather API" \
|
|
251
|
+
--idempotency-key <persisted-business-create-attempt-key> \
|
|
248
252
|
--format json
|
|
249
253
|
|
|
250
|
-
farthershore business publish weather-api --format json
|
|
251
|
-
farthershore business rollback weather-api wfe_previous --reason "bad release" --format json
|
|
254
|
+
farthershore business publish weather-api --format json --idempotency-key <persisted-business-publish-attempt-key>
|
|
255
|
+
farthershore business rollback weather-api wfe_previous --reason "bad release" --format json --idempotency-key <persisted-business-rollback-attempt-key>
|
|
252
256
|
farthershore business delete weather-api --yes --format json
|
|
253
257
|
```
|
|
254
258
|
|
|
@@ -338,7 +342,7 @@ farthershore organization role list <organizationId> --filter builtIn=true --sor
|
|
|
338
342
|
farthershore organization members <organizationId> --filter roleKey=auditor --sort email:asc --search person --format json
|
|
339
343
|
|
|
340
344
|
# Primary owner only; hands ultimate authority to another existing member.
|
|
341
|
-
farthershore organization ownership-transfer <organizationId> <newOwnerUserId> --yes --format json
|
|
345
|
+
farthershore organization ownership-transfer <organizationId> <newOwnerUserId> --yes --format json --idempotency-key <persisted-organization-ownership-transfer-attempt-key>
|
|
342
346
|
```
|
|
343
347
|
|
|
344
348
|
Selecting the default organization is a local credential concern, not an API
|
|
@@ -365,14 +369,15 @@ farthershore token create deploy-bot --org \
|
|
|
365
369
|
|
|
366
370
|
farthershore token list --org --format json
|
|
367
371
|
farthershore token approvals --org --format json
|
|
368
|
-
farthershore token approve <approvalId> --org --format json
|
|
372
|
+
farthershore token approve <approvalId> --org --format json --idempotency-key <persisted-token-approve-attempt-key>
|
|
369
373
|
farthershore token approve <approvalId> --org \
|
|
374
|
+
--idempotency-key <persisted-token-approve-attempt-key> \
|
|
370
375
|
--permissions '["business:read"]' --format json # trim on approval
|
|
371
376
|
farthershore token deny <approvalId> --org --format json
|
|
372
377
|
farthershore token update <tokenId> --org \
|
|
373
378
|
--permissions '["business:read"]' \
|
|
374
379
|
--idempotency-key org-token-update-2026-08-11 --format json
|
|
375
|
-
farthershore token rotate <tokenId> --org --format json
|
|
380
|
+
farthershore token rotate <tokenId> --org --format json --idempotency-key <persisted-token-rotate-attempt-key>
|
|
376
381
|
farthershore token revoke <tokenId> --org --yes --format json
|
|
377
382
|
```
|
|
378
383
|
|
|
@@ -383,9 +388,10 @@ exactly once; store it immediately. Human output follows the same rule: it
|
|
|
383
388
|
prints plaintext only for an ACTIVE one-time-secret response and says explicitly
|
|
384
389
|
when a PENDING request minted nothing.
|
|
385
390
|
|
|
386
|
-
Create and update
|
|
387
|
-
|
|
388
|
-
|
|
391
|
+
Create and update require `--idempotency-key`. Persist the key before the first
|
|
392
|
+
dispatch and reuse it only when repeating that exact logical request after an
|
|
393
|
+
interrupted invocation. The CLI never generates a key: a process-local key
|
|
394
|
+
would be lost across the restart where retry safety matters most.
|
|
389
395
|
|
|
390
396
|
### `farthershore stripe`
|
|
391
397
|
|
|
@@ -430,15 +436,17 @@ farthershore service-account approvals <businessId> --format json
|
|
|
430
436
|
farthershore service-account approve <businessId> <approvalId> \
|
|
431
437
|
--permissions '["route:read"]' --format json # optional trim
|
|
432
438
|
farthershore service-account deny <businessId> <approvalId> --format json
|
|
433
|
-
farthershore service-account rotate <businessId> <serviceAccountId> --format json
|
|
439
|
+
farthershore service-account rotate <businessId> <serviceAccountId> --format json --idempotency-key <persisted-service-account-rotate-attempt-key>
|
|
434
440
|
farthershore service-account revoke <businessId> <serviceAccountId> --yes --format json
|
|
435
441
|
```
|
|
436
442
|
|
|
437
443
|
Pass `--environment-id` and `--subscriber-organization` to override the two
|
|
438
444
|
context environment variables for one command. PENDING create/update responses
|
|
439
445
|
never print `plaintext`. ACTIVE creates
|
|
440
|
-
and rotations print the one-time key once. Create
|
|
441
|
-
|
|
446
|
+
and rotations print the one-time key once. Create, update, and rotate require a
|
|
447
|
+
caller-persisted key, just like one-time-secret org-token operations. A replayed
|
|
448
|
+
success includes `meta.idempotency.replayed: true`; follow it with a list read
|
|
449
|
+
before reporting current state.
|
|
442
450
|
|
|
443
451
|
This group is direct CLI-only and deliberately has no MCP projection: the MCP
|
|
444
452
|
operation registry carries builder principals, not portal consumer sessions.
|
|
@@ -484,8 +492,9 @@ farthershore plan list weather-api --format json
|
|
|
484
492
|
|
|
485
493
|
### `farthershore frontend`
|
|
486
494
|
|
|
487
|
-
Managed Frontend Hosting
|
|
488
|
-
|
|
495
|
+
Managed Frontend Hosting status, rollback, and a local preview. Builds are
|
|
496
|
+
Git-triggered: production builds on a GitHub Release and preview environments
|
|
497
|
+
build on pushes to their environment branch. `preview` runs the generated
|
|
489
498
|
`frontend/`'s `vite dev` with an injected `window.__FS_CONFIG__` shim so the
|
|
490
499
|
portal renders locally exactly as it serves in production. Pass `--mock` to
|
|
491
500
|
inject `{ mock: true }` instead of Core/Clerk config for local page inspection
|
|
@@ -493,7 +502,6 @@ with placeholder data and auth bypassed.
|
|
|
493
502
|
|
|
494
503
|
```bash
|
|
495
504
|
farthershore frontend status weather-api --format json
|
|
496
|
-
farthershore frontend deploy weather-api --format json
|
|
497
505
|
farthershore frontend rollback weather-api --release-id <hash> --format json
|
|
498
506
|
|
|
499
507
|
# Local preview (shells out to vite; needs a frontend/ project)
|
|
@@ -501,18 +509,63 @@ farthershore frontend dev # hot-reloading dev server,
|
|
|
501
509
|
farthershore frontend preview # production build served as-is, mock mode by default
|
|
502
510
|
farthershore frontend dev --live # against the real platform
|
|
503
511
|
farthershore frontend preview --core-url http://localhost:8787
|
|
504
|
-
|
|
512
|
+
|
|
513
|
+
# Local preview signed in as a test persona (hot reload against the real platform)
|
|
514
|
+
farthershore frontend dev --live --business acme --env preview --persona alice
|
|
515
|
+
farthershore frontend dev --live --business acme --env preview --persona persona_123 --port 4321
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
`--live --business --env --persona` (all three required, not combinable with
|
|
519
|
+
`--mock` or `--core-url`) opens `http://localhost:<port>` (default 5173)
|
|
520
|
+
already signed in as that test persona, exactly as the hosted portal would
|
|
521
|
+
be. The CLI issues a short-lived, origin-bound preview lease from Core and
|
|
522
|
+
holds it only in its own process memory; Vite runs on a private random
|
|
523
|
+
loopback port behind a CLI-owned proxy that attaches the lease to portal
|
|
524
|
+
requests and serves the secret-free sign-in bridge. Nothing secret ever
|
|
525
|
+
reaches the browser URL, DOM, storage, or logs — the browser only ever holds
|
|
526
|
+
the same HttpOnly session cookie the hosted portal uses. The lease renews
|
|
527
|
+
automatically while the command runs and is revoked when it exits (Ctrl-C
|
|
528
|
+
included); a lease that cannot be revoked expires within five minutes. Core
|
|
529
|
+
is always the one selected for the authenticated CLI (`--api-url` /
|
|
530
|
+
`FARTHERSHORE_API_URL`).
|
|
505
531
|
|
|
506
532
|
### `farthershore persona`
|
|
507
533
|
|
|
508
|
-
|
|
509
|
-
exercise the gateway
|
|
534
|
+
Create temporary subscriber users in a test-strategy environment so an agent
|
|
535
|
+
can exercise the same customer RBAC, browser session, and gateway paths as a
|
|
536
|
+
human. The Business SDK contributes raw permissions; the subscribing
|
|
537
|
+
organization composes those permissions into its own product roles.
|
|
510
538
|
|
|
511
539
|
```bash
|
|
512
|
-
|
|
540
|
+
# First persona creates and owns a temporary subscriber workspace.
|
|
541
|
+
farthershore persona bootstrap weather-api --env preview --plan pro --format json --idempotency-key <persisted-persona-bootstrap-attempt-key>
|
|
513
542
|
farthershore persona list weather-api --env preview --format json
|
|
514
|
-
farthershore persona
|
|
515
|
-
|
|
543
|
+
farthershore persona login weather-api <ownerPersonaId> --env preview --format json
|
|
544
|
+
|
|
545
|
+
# Join the same subscriber after its owner has enabled subscriber RBAC and
|
|
546
|
+
# created roles/defaults through the normal customer RBAC surface.
|
|
547
|
+
farthershore persona bootstrap weather-api --env preview --plan pro \
|
|
548
|
+
--subscriber-id <subscriberId> --account-role member --role viewer \
|
|
549
|
+
--format json --idempotency-key <persisted-member-bootstrap-attempt-key>
|
|
550
|
+
|
|
551
|
+
farthershore persona rotate weather-api <personaId> --env preview --format json --idempotency-key <persisted-persona-rotate-attempt-key>
|
|
552
|
+
farthershore persona delete weather-api <personaId> --env preview --format json
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
Bootstrap and rotation return a key once. `login` sends the 60-second,
|
|
556
|
+
single-use handoff only in the browser URL fragment to the platform-owned
|
|
557
|
+
`/persona-sign-in` bridge. The bridge establishes an HttpOnly browser session
|
|
558
|
+
and returns to the exact original portal path, query, and fragment. CLI output
|
|
559
|
+
contains portal metadata but never the handoff or a session bearer. Product
|
|
560
|
+
role keys must already exist in that subscriber's role catalog; omit `--role` to use its
|
|
561
|
+
configured default. Deletion tears down the temporary user and credential, and
|
|
562
|
+
deleting the environment also removes the remaining persona-owned workspace.
|
|
563
|
+
After an environment-branch apply, existing personas remain available but are
|
|
564
|
+
detached from the superseded subscription. Use `persona login` with the same
|
|
565
|
+
persona id and select a plan from the new branch contract; the CLI does not
|
|
566
|
+
fall back to a production plan. The old raw test key stays invalid. After the
|
|
567
|
+
persona is reattached, run `persona rotate` to mint a replacement key for
|
|
568
|
+
gateway testing; its product roles and explicit scope ceiling are preserved.
|
|
516
569
|
|
|
517
570
|
### `farthershore usage`
|
|
518
571
|
|
|
@@ -548,11 +601,11 @@ compiled integration that references it.
|
|
|
548
601
|
```bash
|
|
549
602
|
farthershore variables list weather-api --format json
|
|
550
603
|
printf '%s' "$SENTRY_AUTH_TOKEN" | farthershore variables set weather-api \
|
|
551
|
-
SENTRY_AUTH_TOKEN --format json
|
|
604
|
+
SENTRY_AUTH_TOKEN --format json --idempotency-key <persisted-sentry-variable-attempt-key>
|
|
552
605
|
printf '%s' "$POSTHOG_PROJECT_KEY" | farthershore variables set weather-api \
|
|
553
|
-
FS_PUBLIC_POSTHOG_KEY --format json
|
|
554
|
-
farthershore variables revoke weather-api POSTHOG_SECRET --yes --format json
|
|
555
|
-
farthershore variables rm weather-api POSTHOG_SECRET --yes --format json
|
|
606
|
+
FS_PUBLIC_POSTHOG_KEY --format json --idempotency-key <persisted-posthog-variable-attempt-key>
|
|
607
|
+
farthershore variables revoke weather-api POSTHOG_SECRET --yes --format json --idempotency-key <persisted-variables-revoke-attempt-key>
|
|
608
|
+
farthershore variables rm weather-api POSTHOG_SECRET --yes --format json --idempotency-key <persisted-variables-rm-attempt-key>
|
|
556
609
|
```
|
|
557
610
|
|
|
558
611
|
There is no builder-managed public-variable surface and values are never
|
|
@@ -570,13 +623,14 @@ farthershore backend list weather-api --format json
|
|
|
570
623
|
farthershore backend create weather-api \
|
|
571
624
|
--name "Production API" \
|
|
572
625
|
--origin-url https://api.example.com \
|
|
626
|
+
--idempotency-key <persisted-backend-create-attempt-key> \
|
|
573
627
|
--format json
|
|
574
628
|
farthershore backend bind weather-api api \
|
|
575
629
|
--env preview-42 \
|
|
576
630
|
--origin-url https://api-pr-42.example.com \
|
|
577
631
|
--format json
|
|
578
|
-
farthershore backend tokens create weather-api --backend <backendId> --format json
|
|
579
|
-
farthershore backend tokens rotate weather-api <tokenId> --format json
|
|
632
|
+
farthershore backend tokens create weather-api --backend <backendId> --format json --idempotency-key <persisted-backend-tokens-create-attempt-key>
|
|
633
|
+
farthershore backend tokens rotate weather-api <tokenId> --format json --idempotency-key <persisted-backend-tokens-rotate-attempt-key>
|
|
580
634
|
farthershore backend tokens revoke weather-api <tokenId> --yes --format json
|
|
581
635
|
```
|
|
582
636
|
|
|
@@ -621,12 +675,13 @@ farthershore webhook list weather-api --format json
|
|
|
621
675
|
farthershore webhook create weather-api \
|
|
622
676
|
--url https://hooks.example.com/farthershore \
|
|
623
677
|
--events subscription.created,payment.failed \
|
|
678
|
+
--idempotency-key <persisted-webhook-create-attempt-key> \
|
|
624
679
|
--format json
|
|
625
680
|
farthershore webhook update weather-api <webhookId> --disable --format json
|
|
626
|
-
farthershore webhook test weather-api <webhookId> --format json
|
|
627
|
-
farthershore webhook trigger weather-api <webhookId> --type payment.failed --format json
|
|
681
|
+
farthershore webhook test weather-api <webhookId> --idempotency-key <persisted-test-attempt-key> --format json
|
|
682
|
+
farthershore webhook trigger weather-api <webhookId> --type payment.failed --idempotency-key <persisted-trigger-attempt-key> --format json
|
|
628
683
|
farthershore webhook deliveries weather-api <webhookId> --limit 20 --format json
|
|
629
|
-
farthershore webhook rotate weather-api <webhookId> --format json
|
|
684
|
+
farthershore webhook rotate weather-api <webhookId> --format json --idempotency-key <persisted-webhook-rotate-attempt-key>
|
|
630
685
|
farthershore webhook delete weather-api <webhookId> --yes --format json
|
|
631
686
|
```
|
|
632
687
|
|
|
@@ -665,8 +720,10 @@ Manage checkout promo codes (operational state, not part of the manifest).
|
|
|
665
720
|
farthershore promo-code list weather-api --format json
|
|
666
721
|
farthershore promo-code create weather-api \
|
|
667
722
|
--code LAUNCH25 --kind percent_off --percent 25 --duration-months 3 \
|
|
723
|
+
--idempotency-key <persisted-promo-code-create-attempt-key> \
|
|
668
724
|
--plan <planId> --format json
|
|
669
725
|
farthershore promo-code create weather-api \
|
|
726
|
+
--idempotency-key <persisted-promo-code-create-attempt-key> \
|
|
670
727
|
--code SAVE500 --kind amount_off --amount-cents 500 --duration-months 1 --format json
|
|
671
728
|
farthershore promo-code archive weather-api <promoCodeId> --format json
|
|
672
729
|
farthershore promo-code reactivate weather-api <promoCodeId> --format json
|
|
@@ -682,18 +739,18 @@ Use `--all-plans` to clear plan scoping.
|
|
|
682
739
|
Install or refresh the platform-verified skills bundle together. The platform
|
|
683
740
|
pins this immutable release, and CI plus a daily repository check compare it to
|
|
684
741
|
GitHub's latest stable release so the guidance cannot silently drift.
|
|
685
|
-
This command requires `@farthershore/cli` 0.33.
|
|
742
|
+
This command requires `@farthershore/cli` 0.33.4 or newer.
|
|
686
743
|
|
|
687
744
|
```bash
|
|
688
745
|
set -euo pipefail
|
|
689
746
|
CLI_VERSION=$(farthershore --version)
|
|
690
|
-
printf '%s' "$CLI_VERSION" | node -e 'let v=""; process.stdin.on("data", c => v += c).on("end", () => { const m = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(?:\+[0-9A-Za-z.-]+)?$/.exec(v.trim()); if (!m || !(+m[1] > 0 || +m[2] > 33 || (+m[2] === 33 && +m[3] >=
|
|
747
|
+
printf '%s' "$CLI_VERSION" | node -e 'let v=""; process.stdin.on("data", c => v += c).on("end", () => { const m = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(?:\+[0-9A-Za-z.-]+)?$/.exec(v.trim()); if (!m || !(+m[1] > 0 || +m[2] > 33 || (+m[2] === 33 && +m[3] >= 4))) { console.error("Stop: CLI 0.33.4 or newer is required; ask the human to upgrade."); process.exitCode = 1; } })'
|
|
691
748
|
farthershore skills install --help
|
|
692
749
|
farthershore skills install
|
|
693
750
|
```
|
|
694
751
|
|
|
695
752
|
If either prerequisite fails, stop and ask the human to run
|
|
696
|
-
`npm install -g @farthershore/cli@0.33.
|
|
753
|
+
`npm install -g @farthershore/cli@0.33.4`, then repeat the checks.
|
|
697
754
|
Do not install or upgrade global tooling autonomously.
|
|
698
755
|
|
|
699
756
|
The Farther Shore CLI downloads the exact installer archive and verifies this
|
|
@@ -721,14 +778,14 @@ bracketed code is stable across releases — quote it in support threads.
|
|
|
721
778
|
Exit codes are a branchable taxonomy so a script can tell failure classes apart
|
|
722
779
|
without parsing text:
|
|
723
780
|
|
|
724
|
-
| Exit | Meaning
|
|
725
|
-
| ---- |
|
|
726
|
-
| `0` | Success
|
|
727
|
-
| `2` | Validation error (HTTP 400/422) — fix your input
|
|
728
|
-
| `3` | Auth / permission error (401/403) — re-authenticate
|
|
729
|
-
| `4` | Conflict / managed-by-code (409) — change it in the repo
|
|
730
|
-
| `5` | Server error (5xx) — retry
|
|
731
|
-
| `1` | Any other failure (local error, 402/404, argument errors, …)
|
|
781
|
+
| Exit | Meaning |
|
|
782
|
+
| ---- | -------------------------------------------------------------- |
|
|
783
|
+
| `0` | Success |
|
|
784
|
+
| `2` | Validation error (HTTP 400/422) — fix your input |
|
|
785
|
+
| `3` | Auth / permission error (401/403) — re-authenticate |
|
|
786
|
+
| `4` | Conflict / managed-by-code (409) — change it in the repo |
|
|
787
|
+
| `5` | Server error (5xx) — retry only when `error.retryable` is true |
|
|
788
|
+
| `1` | Any other failure (local error, 402/404, argument errors, …) |
|
|
732
789
|
|
|
733
790
|
## CI and agent usage
|
|
734
791
|
|