@farthershore/cli 0.33.6 → 0.35.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/CHANGELOG.md +103 -0
- package/README.md +207 -65
- package/dist/index.js +2076 -114
- package/dist/mcp.js +81 -81
- package/package.json +8 -5
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Changelog — @farthershore/cli
|
|
2
|
+
|
|
3
|
+
All notable changes to the `farthershore` CLI and its MCP server
|
|
4
|
+
(`farthershore-mcp`) are documented here. The CLI versions independently from
|
|
5
|
+
the SDKs. Pre-1.0: minor versions may include breaking changes. Releases
|
|
6
|
+
before 0.35.0 are recorded only in the git history.
|
|
7
|
+
|
|
8
|
+
## [0.35.0] - 2026-10-12
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- `farthershore api <endpoint>`: an authenticated request to any platform API
|
|
13
|
+
path, like `gh api`. `-X` sets the method; `-f` / `-F` add string or typed
|
|
14
|
+
fields (query parameters for GET, a JSON body otherwise); `--input` sends a
|
|
15
|
+
JSON file; `-H` adds headers (the auth, surface and organization headers are
|
|
16
|
+
refused); `--paginate` / `--max-pages` follow offset or cursor pages; `-i`
|
|
17
|
+
prints the status and headers; `--dry-run` appends `dry_run=true`. The
|
|
18
|
+
`{business}`, `{org}` / `{organization}` and `{env}` placeholders are filled
|
|
19
|
+
from the current context. Absolute URLs and other hosts are refused.
|
|
20
|
+
- `farthershore code search|describe|types|run`: code mode over the typed
|
|
21
|
+
operation surface.
|
|
22
|
+
- `code search` and `code describe` find operations and print their
|
|
23
|
+
metadata; `code types` prints `.d.ts` declarations for `fs` or one
|
|
24
|
+
namespace.
|
|
25
|
+
- `code run` runs a JavaScript/TypeScript script (a file, `-` for stdin, or
|
|
26
|
+
`-e`) with `fs`, `args`, `paginate` and `FartherShoreError` in scope. The
|
|
27
|
+
script runs in a worker with no credential and an empty environment, and
|
|
28
|
+
every call is checked by the CLI process.
|
|
29
|
+
- Read-only by default. `--allow-writes` permits non-destructive writes;
|
|
30
|
+
destructive and one-time-secret operations also need `--yes`.
|
|
31
|
+
`{ dryRun: true }` on a preview-capable write runs as a read.
|
|
32
|
+
Contract-class (managed-by-code) writes are always refused.
|
|
33
|
+
- Budgets: `--max-calls` (200), `--max-writes` (20), `--timeout` (60s), and
|
|
34
|
+
at most 4 calls in flight. A breach stops the script
|
|
35
|
+
(`CODE_MODE_BUDGET_EXCEEDED`), terminates the worker and cancels in-flight
|
|
36
|
+
requests.
|
|
37
|
+
- One-time secrets come back as `{ redacted: true, last4 }` unless
|
|
38
|
+
`--reveal-secrets` is passed; every result also goes through the secret
|
|
39
|
+
redaction backstop.
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
|
|
43
|
+
- The CLI and the MCP server now run on `@farthershore/client`: the shared
|
|
44
|
+
transport, credential sources, typed errors and namespaced operation
|
|
45
|
+
surface. `--yes`, `--dry-run` and the MCP `destructiveHint` are derived from
|
|
46
|
+
each operation's spec. Requests carry
|
|
47
|
+
`x-fs-client: @farthershore/client/<version> farthershore-cli/<version>`.
|
|
48
|
+
Errors carry `param` when the server names a field.
|
|
49
|
+
|
|
50
|
+
### Breaking
|
|
51
|
+
|
|
52
|
+
- These commands now require `--yes`: `business rollback`,
|
|
53
|
+
`frontend rollback`, `backend tokens rotate`, `webhook rotate`,
|
|
54
|
+
`token rotate` (maker token), `persona rotate`, `persona delete`,
|
|
55
|
+
`business rbac disable`, `consumer migrate-latest`, `consumer rbac disable`
|
|
56
|
+
and `consumer rbac roles delete`. A `--dry-run` of a preview-capable
|
|
57
|
+
operation never needs `--yes`. Their MCP tools now set
|
|
58
|
+
`destructiveHint: true`.
|
|
59
|
+
- Consumer RBAC writes have one operation key per verb instead of sharing
|
|
60
|
+
`consumer.roles.assign`: `consumer.roles.assign`, `consumer.rbac.enable`,
|
|
61
|
+
`consumer.rbac.disable`, `consumer.role.create`, `consumer.role.update` and
|
|
62
|
+
`consumer.role.delete`. Only `consumer.rbac.disable` and
|
|
63
|
+
`consumer.role.delete` are destructive, so `consumer rbac assign`,
|
|
64
|
+
`enable`, `roles create` and `roles update` run without `--yes`.
|
|
65
|
+
`consumer rbac roles create` is no longer retried automatically.
|
|
66
|
+
- `promo-code archive` no longer requires `--yes`, and its MCP tool's
|
|
67
|
+
`destructiveHint` is now `false`.
|
|
68
|
+
- `--dry-run` on an operation without a preview is refused locally with
|
|
69
|
+
`DRY_RUN_NOT_SUPPORTED`; nothing is sent.
|
|
70
|
+
- The retired request-key vocabulary is gone. `operations list` no longer
|
|
71
|
+
reports an `intrinsic_replay` retry kind (`service-account approve` is a
|
|
72
|
+
`convergent_write`), and the retry contract no longer carries
|
|
73
|
+
`same_key_replay`, `keyRequired` or `liveWhenFieldPresent`. CLI and MCP
|
|
74
|
+
help describe the retry rule plainly: reads retry; writes retry only on a
|
|
75
|
+
429 or a server-marked `retryable` + `safe_to_repeat` answer; anything else
|
|
76
|
+
is `OUTCOME_UNKNOWN` (exit 5) and names the read to reconcile with.
|
|
77
|
+
|
|
78
|
+
### Fixed
|
|
79
|
+
|
|
80
|
+
- `workflow-control replay` and `rollback-to-config` call Core at
|
|
81
|
+
`/agent/v1/replay` and `/agent/v1/rollback-to-config`. They always returned
|
|
82
|
+
404 before.
|
|
83
|
+
- A 401 on a cached exchanged token drops it, re-exchanges once and resends
|
|
84
|
+
once, so a long-lived MCP server recovers after a grant change or session
|
|
85
|
+
invalidation instead of failing for up to an hour. The refresh deadline
|
|
86
|
+
follows the token's lifetime rather than a possibly skewed local clock, and
|
|
87
|
+
concurrent first requests share one token exchange, which retries like a
|
|
88
|
+
read.
|
|
89
|
+
- The MCP server uses the CLI's organization (`--organization`, the linked
|
|
90
|
+
directory, or `auth organization use`) and API URL, and sends
|
|
91
|
+
`x-fs-surface: mcp`. It could act in a different organization before.
|
|
92
|
+
- POST endpoints that only read (analytics query, manifest compile, previews,
|
|
93
|
+
the builder bootstrap) and dry runs retry like reads instead of reporting
|
|
94
|
+
`OUTCOME_UNKNOWN`.
|
|
95
|
+
- Transport failures have stable codes instead of `INTERNAL_ERROR`:
|
|
96
|
+
`NETWORK_ERROR` and `TIMEOUT` (retryable for reads, exit 5),
|
|
97
|
+
`REQUEST_ABORTED`, `OUTCOME_UNKNOWN` for a write with no response, and
|
|
98
|
+
`RESPONSE_UNREADABLE` for a 2xx whose body could not be read. The original
|
|
99
|
+
failure is kept as `cause`. The attempt timeout now also covers the body
|
|
100
|
+
read.
|
|
101
|
+
- `farthershore api` never follows a redirect: a 3xx is reported as
|
|
102
|
+
`REDIRECT_NOT_FOLLOWED` with `details.location`, so headers never reach
|
|
103
|
+
another host.
|
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.
|
|
6
|
+
**Status: `0.35.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.
|
|
24
|
+
npm install -g @farthershore/cli@0.35.0
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
Or run it directly with npx:
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
|
-
npx -p @farthershore/cli@0.
|
|
30
|
+
npx -p @farthershore/cli@0.35.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.
|
|
36
|
+
npx -p @farthershore/cli@0.35.0 farthershore-mcp
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
## Authentication
|
|
@@ -87,12 +87,11 @@ credentials into the managed repository.
|
|
|
87
87
|
Create a managed business repo, author the business, validate it, and push:
|
|
88
88
|
|
|
89
89
|
```bash
|
|
90
|
-
# 1. Create the managed repo.
|
|
91
|
-
|
|
92
|
-
--idempotency-key <persisted-business-create-attempt-key>)
|
|
90
|
+
# 1. Create the managed repo. The command prints its URL.
|
|
91
|
+
farthershore business create weather-api
|
|
93
92
|
|
|
94
93
|
# 2. Clone it and author business/ from scratch.
|
|
95
|
-
git clone
|
|
94
|
+
git clone <printed-repository-url>
|
|
96
95
|
cd weather-api
|
|
97
96
|
# ...author business/ with @farthershore/business...
|
|
98
97
|
|
|
@@ -246,9 +245,8 @@ Run the same verdict the GitHub `farthershore/validate` PR check produces, befor
|
|
|
246
245
|
you push. It builds the manifest twice and compares the IR hash (the determinism
|
|
247
246
|
check the build runner enforces), then — when you pass `--business` — submits the
|
|
248
247
|
IR for a server verdict that returns compile diagnostics, the semantic diff, and
|
|
249
|
-
an economic-change verdict.
|
|
250
|
-
|
|
251
|
-
to repeat and does not take an idempotency key.
|
|
248
|
+
an economic-change verdict. Validation never accepts or publishes business
|
|
249
|
+
state, so it is safe to repeat.
|
|
252
250
|
|
|
253
251
|
```bash
|
|
254
252
|
farthershore validate # local build + determinism only
|
|
@@ -273,11 +271,10 @@ farthershore business subdomain-check weather-api --format json
|
|
|
273
271
|
|
|
274
272
|
farthershore business create weather-api \
|
|
275
273
|
--display-name "Weather API" \
|
|
276
|
-
--idempotency-key <persisted-business-create-attempt-key> \
|
|
277
274
|
--format json
|
|
278
275
|
|
|
279
|
-
farthershore business publish weather-api --format json
|
|
280
|
-
farthershore business rollback weather-api wfe_previous --reason "bad release" --format json
|
|
276
|
+
farthershore business publish weather-api --format json
|
|
277
|
+
farthershore business rollback weather-api wfe_previous --reason "bad release" --yes --format json
|
|
281
278
|
```
|
|
282
279
|
|
|
283
280
|
Deleting a business is **stage only** — the command is not registered in the
|
|
@@ -324,13 +321,13 @@ and requires the exact `business:rollback` permission.
|
|
|
324
321
|
`rbacEnabled` flag. `business rbac enable` / `disable` toggle that flag (like
|
|
325
322
|
`docsEnabled`, it is platform-owned and never repo-authored); once enabled,
|
|
326
323
|
subscriber organizations manage roles in their portal. Both toggles are
|
|
327
|
-
|
|
324
|
+
safe to repeat. Subscriber role and assignment state is kept server-side on
|
|
328
325
|
disable, so re-enabling is a pure flag flip.
|
|
329
326
|
|
|
330
327
|
```bash
|
|
331
328
|
farthershore business rbac weather-api --format json
|
|
332
329
|
farthershore business rbac enable weather-api --format json
|
|
333
|
-
farthershore business rbac disable weather-api --format json
|
|
330
|
+
farthershore business rbac disable weather-api --yes --format json
|
|
334
331
|
```
|
|
335
332
|
|
|
336
333
|
`business rbac subjects list` lists the custom permission vocabulary: subjects
|
|
@@ -377,7 +374,7 @@ farthershore organization role list <organizationId> --filter builtIn=true --sor
|
|
|
377
374
|
farthershore organization members <organizationId> --filter roleKey=auditor --sort email:asc --search person --format json
|
|
378
375
|
|
|
379
376
|
# Primary owner only; hands ultimate authority to another existing member.
|
|
380
|
-
farthershore organization ownership-transfer <organizationId> <newOwnerUserId> --yes --format json
|
|
377
|
+
farthershore organization ownership-transfer <organizationId> <newOwnerUserId> --yes --format json
|
|
381
378
|
```
|
|
382
379
|
|
|
383
380
|
Selecting the default organization is a local credential concern, not an API
|
|
@@ -399,20 +396,17 @@ farthershore token permission-catalog --org --format json
|
|
|
399
396
|
farthershore token create deploy-bot --org \
|
|
400
397
|
--permissions '["business:read","business:publish"]' \
|
|
401
398
|
--businesses business_1,business_2 \
|
|
402
|
-
--idempotency-key org-token-create-2026-08-11 \
|
|
403
399
|
--format json
|
|
404
400
|
|
|
405
401
|
farthershore token list --org --format json
|
|
406
402
|
farthershore token approvals --org --format json
|
|
407
|
-
farthershore token approve <approvalId> --org --format json
|
|
403
|
+
farthershore token approve <approvalId> --org --format json
|
|
408
404
|
farthershore token approve <approvalId> --org \
|
|
409
|
-
--idempotency-key <persisted-token-approve-attempt-key> \
|
|
410
405
|
--permissions '["business:read"]' --format json # trim on approval
|
|
411
406
|
farthershore token deny <approvalId> --org --format json
|
|
412
407
|
farthershore token update <tokenId> --org \
|
|
413
|
-
--permissions '["business:read"]'
|
|
414
|
-
|
|
415
|
-
farthershore token rotate <tokenId> --org --format json --idempotency-key <persisted-token-rotate-attempt-key>
|
|
408
|
+
--permissions '["business:read"]' --format json
|
|
409
|
+
farthershore token rotate <tokenId> --org --yes --format json
|
|
416
410
|
farthershore token revoke <tokenId> --org --yes --format json
|
|
417
411
|
```
|
|
418
412
|
|
|
@@ -423,10 +417,7 @@ exactly once; store it immediately. Human output follows the same rule: it
|
|
|
423
417
|
prints plaintext only for an ACTIVE one-time-secret response and says explicitly
|
|
424
418
|
when a PENDING request minted nothing.
|
|
425
419
|
|
|
426
|
-
|
|
427
|
-
dispatch and reuse it only when repeating that exact logical request after an
|
|
428
|
-
interrupted invocation. The CLI never generates a key: a process-local key
|
|
429
|
-
would be lost across the restart where retry safety matters most.
|
|
420
|
+
If a create or update times out, run `token list --org` before trying again.
|
|
430
421
|
|
|
431
422
|
### `farthershore stripe`
|
|
432
423
|
|
|
@@ -462,26 +453,22 @@ export FARTHERSHORE_SUBSCRIBER_ORGANIZATION_ID='<subscriber organization UUID>'
|
|
|
462
453
|
farthershore service-account list <businessId> --format json
|
|
463
454
|
farthershore service-account create <businessId> deploy-bot \
|
|
464
455
|
--permissions '["route:read","route:write"]' \
|
|
465
|
-
--scopes '["production"]'
|
|
466
|
-
--idempotency-key sa-create-2026-08-11 --format json
|
|
456
|
+
--scopes '["production"]' --format json
|
|
467
457
|
farthershore service-account update <businessId> <serviceAccountId> \
|
|
468
|
-
--permissions '["route:read"]'
|
|
469
|
-
--idempotency-key sa-update-2026-08-11 --format json
|
|
458
|
+
--permissions '["route:read"]' --format json
|
|
470
459
|
farthershore service-account approvals <businessId> --format json
|
|
471
460
|
farthershore service-account approve <businessId> <approvalId> \
|
|
472
461
|
--permissions '["route:read"]' --format json # optional trim
|
|
473
462
|
farthershore service-account deny <businessId> <approvalId> --format json
|
|
474
|
-
farthershore service-account rotate <businessId> <serviceAccountId> --format json
|
|
463
|
+
farthershore service-account rotate <businessId> <serviceAccountId> --format json
|
|
475
464
|
farthershore service-account revoke <businessId> <serviceAccountId> --yes --format json
|
|
476
465
|
```
|
|
477
466
|
|
|
478
467
|
Pass `--environment-id` and `--subscriber-organization` to override the two
|
|
479
468
|
context environment variables for one command. PENDING create/update responses
|
|
480
469
|
never print `plaintext`. ACTIVE creates
|
|
481
|
-
and rotations print the one-time key once.
|
|
482
|
-
|
|
483
|
-
success includes `meta.idempotency.replayed: true`; follow it with a list read
|
|
484
|
-
before reporting current state.
|
|
470
|
+
and rotations print the one-time key once. If one of these commands times out,
|
|
471
|
+
run `service-account list` before trying again.
|
|
485
472
|
|
|
486
473
|
This group is direct CLI-only and deliberately has no MCP projection: the MCP
|
|
487
474
|
operation registry carries builder principals, not portal consumer sessions.
|
|
@@ -537,7 +524,7 @@ with placeholder data and auth bypassed.
|
|
|
537
524
|
|
|
538
525
|
```bash
|
|
539
526
|
farthershore frontend status weather-api --format json
|
|
540
|
-
farthershore frontend rollback weather-api --release-id <hash> --format json
|
|
527
|
+
farthershore frontend rollback weather-api --release-id <hash> --yes --format json
|
|
541
528
|
|
|
542
529
|
# Local preview (shells out to vite; needs a frontend/ project)
|
|
543
530
|
farthershore frontend dev # hot-reloading dev server, mock mode by default
|
|
@@ -573,7 +560,7 @@ organization composes those permissions into its own product roles.
|
|
|
573
560
|
|
|
574
561
|
```bash
|
|
575
562
|
# First persona creates and owns a temporary subscriber workspace.
|
|
576
|
-
farthershore persona bootstrap weather-api --env preview --plan pro --format json
|
|
563
|
+
farthershore persona bootstrap weather-api --env preview --plan pro --format json
|
|
577
564
|
farthershore persona list weather-api --env preview --format json
|
|
578
565
|
farthershore persona login weather-api <ownerPersonaId> --env preview --format json
|
|
579
566
|
|
|
@@ -581,10 +568,10 @@ farthershore persona login weather-api <ownerPersonaId> --env preview --format j
|
|
|
581
568
|
# created roles/defaults through the normal customer RBAC surface.
|
|
582
569
|
farthershore persona bootstrap weather-api --env preview --plan pro \
|
|
583
570
|
--subscriber-id <subscriberId> --account-role member --role viewer \
|
|
584
|
-
--format json
|
|
571
|
+
--format json
|
|
585
572
|
|
|
586
|
-
farthershore persona rotate weather-api <personaId> --env preview --format json
|
|
587
|
-
farthershore persona delete weather-api <personaId> --env preview --format json
|
|
573
|
+
farthershore persona rotate weather-api <personaId> --env preview --yes --format json
|
|
574
|
+
farthershore persona delete weather-api <personaId> --env preview --yes --format json
|
|
588
575
|
```
|
|
589
576
|
|
|
590
577
|
Bootstrap and rotation return a key once. `login` sends the 60-second,
|
|
@@ -642,11 +629,11 @@ compiled integration that references it.
|
|
|
642
629
|
```bash
|
|
643
630
|
farthershore variables list weather-api --format json
|
|
644
631
|
printf '%s' "$SENTRY_AUTH_TOKEN" | farthershore variables set weather-api \
|
|
645
|
-
SENTRY_AUTH_TOKEN --format json
|
|
632
|
+
SENTRY_AUTH_TOKEN --format json
|
|
646
633
|
printf '%s' "$POSTHOG_PROJECT_KEY" | farthershore variables set weather-api \
|
|
647
|
-
FS_PUBLIC_POSTHOG_KEY --format json
|
|
648
|
-
farthershore variables revoke weather-api POSTHOG_SECRET --yes --format json
|
|
649
|
-
farthershore variables rm weather-api POSTHOG_SECRET --yes --format json
|
|
634
|
+
FS_PUBLIC_POSTHOG_KEY --format json
|
|
635
|
+
farthershore variables revoke weather-api POSTHOG_SECRET --yes --format json
|
|
636
|
+
farthershore variables rm weather-api POSTHOG_SECRET --yes --format json
|
|
650
637
|
```
|
|
651
638
|
|
|
652
639
|
There is no builder-managed public-variable surface and values are never
|
|
@@ -664,14 +651,13 @@ farthershore backend list weather-api --format json
|
|
|
664
651
|
farthershore backend create weather-api \
|
|
665
652
|
--name "Production API" \
|
|
666
653
|
--origin-url https://api.example.com \
|
|
667
|
-
--idempotency-key <persisted-backend-create-attempt-key> \
|
|
668
654
|
--format json
|
|
669
655
|
farthershore backend bind weather-api api \
|
|
670
656
|
--env preview-42 \
|
|
671
657
|
--origin-url https://api-pr-42.example.com \
|
|
672
658
|
--format json
|
|
673
|
-
farthershore backend tokens create weather-api --backend <backendId> --format json
|
|
674
|
-
farthershore backend tokens rotate weather-api <tokenId> --format json
|
|
659
|
+
farthershore backend tokens create weather-api --backend <backendId> --format json
|
|
660
|
+
farthershore backend tokens rotate weather-api <tokenId> --yes --format json
|
|
675
661
|
farthershore backend tokens revoke weather-api <tokenId> --yes --format json
|
|
676
662
|
```
|
|
677
663
|
|
|
@@ -716,13 +702,12 @@ farthershore webhook list weather-api --format json
|
|
|
716
702
|
farthershore webhook create weather-api \
|
|
717
703
|
--url https://hooks.example.com/farthershore \
|
|
718
704
|
--events subscription.created,payment.failed \
|
|
719
|
-
--idempotency-key <persisted-webhook-create-attempt-key> \
|
|
720
705
|
--format json
|
|
721
706
|
farthershore webhook update weather-api <webhookId> --disable --format json
|
|
722
|
-
farthershore webhook test weather-api <webhookId> --
|
|
723
|
-
farthershore webhook trigger weather-api <webhookId> --type payment.failed --
|
|
707
|
+
farthershore webhook test weather-api <webhookId> --format json
|
|
708
|
+
farthershore webhook trigger weather-api <webhookId> --type payment.failed --format json
|
|
724
709
|
farthershore webhook deliveries weather-api <webhookId> --limit 20 --format json
|
|
725
|
-
farthershore webhook rotate weather-api <webhookId> --format json
|
|
710
|
+
farthershore webhook rotate weather-api <webhookId> --yes --format json
|
|
726
711
|
farthershore webhook delete weather-api <webhookId> --yes --format json
|
|
727
712
|
```
|
|
728
713
|
|
|
@@ -761,10 +746,8 @@ Manage checkout promo codes (operational state, not part of the manifest).
|
|
|
761
746
|
farthershore promo-code list weather-api --format json
|
|
762
747
|
farthershore promo-code create weather-api \
|
|
763
748
|
--code LAUNCH25 --kind percent_off --percent 25 --duration-months 3 \
|
|
764
|
-
--idempotency-key <persisted-promo-code-create-attempt-key> \
|
|
765
749
|
--plan <planId> --format json
|
|
766
750
|
farthershore promo-code create weather-api \
|
|
767
|
-
--idempotency-key <persisted-promo-code-create-attempt-key> \
|
|
768
751
|
--code SAVE500 --kind amount_off --amount-cents 500 --duration-months 1 --format json
|
|
769
752
|
farthershore promo-code archive weather-api <promoCodeId> --format json
|
|
770
753
|
farthershore promo-code reactivate weather-api <promoCodeId> --format json
|
|
@@ -780,18 +763,18 @@ Use `--all-plans` to clear plan scoping.
|
|
|
780
763
|
Install or refresh the platform-verified skills bundle together. The platform
|
|
781
764
|
pins this immutable release, and CI plus a daily repository check compare it to
|
|
782
765
|
GitHub's latest stable release so the guidance cannot silently drift.
|
|
783
|
-
This command requires `@farthershore/cli` 0.
|
|
766
|
+
This command requires `@farthershore/cli` 0.35.0 or newer.
|
|
784
767
|
|
|
785
768
|
```bash
|
|
786
769
|
set -euo pipefail
|
|
787
770
|
CLI_VERSION=$(farthershore --version)
|
|
788
|
-
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] >
|
|
771
|
+
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] > 35 || (+m[2] === 35 && +m[3] >= 0))) { console.error("Stop: CLI 0.35.0 or newer is required; ask the human to upgrade."); process.exitCode = 1; } })'
|
|
789
772
|
farthershore skills install --help
|
|
790
773
|
farthershore skills install
|
|
791
774
|
```
|
|
792
775
|
|
|
793
776
|
If either prerequisite fails, stop and ask the human to run
|
|
794
|
-
`npm install -g @farthershore/cli@0.
|
|
777
|
+
`npm install -g @farthershore/cli@0.35.0`, then repeat the checks.
|
|
795
778
|
Do not install or upgrade global tooling autonomously.
|
|
796
779
|
|
|
797
780
|
The Farther Shore CLI downloads the exact installer archive and verifies this
|
|
@@ -806,6 +789,143 @@ Print the machine-readable action boundary: which operations are repo-authored
|
|
|
806
789
|
farthershore operations list --format json
|
|
807
790
|
```
|
|
808
791
|
|
|
792
|
+
### `farthershore api`
|
|
793
|
+
|
|
794
|
+
Send a raw authenticated request to any platform API endpoint and print the
|
|
795
|
+
response, like `gh api`. Use it for endpoints a typed command does not cover
|
|
796
|
+
yet. Every endpoint is described in the platform's OpenAPI document
|
|
797
|
+
(`farthershore api /openapi.json`).
|
|
798
|
+
|
|
799
|
+
```bash
|
|
800
|
+
farthershore api /businesses
|
|
801
|
+
farthershore api 'businesses/{business}/environments' --paginate
|
|
802
|
+
farthershore api -X PATCH 'businesses/{business}' -f displayName='Weather API'
|
|
803
|
+
farthershore api 'management/businesses/{business}/backends' -f name=api -f originUrl=https://api.example.com -F isDefault=true --dry-run
|
|
804
|
+
farthershore api -X POST 'businesses/{business}/promo-codes' --input promo.json
|
|
805
|
+
farthershore api 'builder/organizations/{org}/members' --include
|
|
806
|
+
farthershore api /businesses --format json | jq '.[].id'
|
|
807
|
+
```
|
|
808
|
+
|
|
809
|
+
- **Endpoint.** A path on the configured API (`--api-url` /
|
|
810
|
+
`FARTHERSHORE_API_URL`). Absolute URLs and other hosts are refused, so the
|
|
811
|
+
credential never leaves the platform, and redirects are never followed: a
|
|
812
|
+
3xx answer is an error (`REDIRECT_NOT_FOLLOWED`), so the credential and `-H`
|
|
813
|
+
headers never reach another location. Placeholders in the path and its
|
|
814
|
+
query are filled from the current context: `{business}` from
|
|
815
|
+
`--business`, `FARTHERSHORE_BUSINESS` or the linked directory; `{org}` /
|
|
816
|
+
`{organization}` from the selected organization; `{env}` from `--env`,
|
|
817
|
+
`FARTHERSHORE_ENV` or the linked environment.
|
|
818
|
+
- **Method.** `-X, --method`; default `GET`, or `POST` when fields or `--input`
|
|
819
|
+
are given.
|
|
820
|
+
- **Fields.** `-f key=value` sends a string; `-F key=value` converts `true`,
|
|
821
|
+
`false`, `null` and numbers, and reads `@file` (or `@-` for stdin). Nest with
|
|
822
|
+
`key[sub]=value`, append to an array with `key[]=value`. `GET` fields become
|
|
823
|
+
query parameters; otherwise they form the JSON body.
|
|
824
|
+
- **`--input <file|->`** sends a JSON body as-is (not combinable with fields).
|
|
825
|
+
- **`-H 'Name: value'`** adds a header. `Authorization`, `x-fs-surface`,
|
|
826
|
+
`x-fs-client` and the organization headers belong to the CLI and are refused.
|
|
827
|
+
- **`--paginate`** follows offset (`pagination.hasMore`) and cursor
|
|
828
|
+
(`nextCursor`) pages and prints one object with the lists concatenated;
|
|
829
|
+
`--max-pages <n>` (default 100) bounds it.
|
|
830
|
+
- **`-i, --include`** prints the HTTP status and response headers first.
|
|
831
|
+
- **`--dry-run`** appends `dry_run=true`.
|
|
832
|
+
|
|
833
|
+
The body is printed as-is (pretty in a terminal, compact with `--format json`),
|
|
834
|
+
never wrapped in the CLI envelope; there is no `--jq`, so pipe to `jq`. Errors
|
|
835
|
+
print the error envelope and use the exit codes below. Reads retry on transient
|
|
836
|
+
failures; a write is never repeated: a 5xx or lost answer exits `5` and its
|
|
837
|
+
error has `outcomeUnknown: true` (the `code` may be the server's own, e.g.
|
|
838
|
+
`TEARDOWN_FAILED`; key on `outcomeUnknown`), so read current state before
|
|
839
|
+
sending it again. `-i` also prints the status line and headers of a failed
|
|
840
|
+
answer, before the error envelope.
|
|
841
|
+
|
|
842
|
+
### `farthershore code` (code mode)
|
|
843
|
+
|
|
844
|
+
Code mode lets you (or an agent) find platform operations and run a script
|
|
845
|
+
against a typed `fs` client, instead of chaining one command per call. A
|
|
846
|
+
script can loop, filter and join results, and only its return value comes
|
|
847
|
+
back — the intermediate data never has to pass through a transcript.
|
|
848
|
+
|
|
849
|
+
**Agent quickstart: search → describe → types → run.**
|
|
850
|
+
|
|
851
|
+
```bash
|
|
852
|
+
# 1. Find operations (ranked by name, path, summary and description).
|
|
853
|
+
farthershore code search runtime token --format json
|
|
854
|
+
|
|
855
|
+
# 2. Read one: description, TypeScript signature, safety flags, reconcile
|
|
856
|
+
# read, required permission and a runnable example.
|
|
857
|
+
farthershore code describe runtimeTokens.revoke
|
|
858
|
+
|
|
859
|
+
# 3. Load the types you need (or the whole API) before writing the script.
|
|
860
|
+
farthershore code types runtimeTokens > fs.d.ts
|
|
861
|
+
|
|
862
|
+
# 4. Run it. Reads only, unless you opt in.
|
|
863
|
+
farthershore code run -e '
|
|
864
|
+
const businesses = await fs.businesses.list();
|
|
865
|
+
return businesses.filter((b) => b.status === args.status).map((b) => b.name);
|
|
866
|
+
' --arg status=DRAFT
|
|
867
|
+
```
|
|
868
|
+
|
|
869
|
+
- **`code search <query...>`** — `--limit <n>` (default 20),
|
|
870
|
+
`--side-effect read|write`, `--namespace <ns>`. Each hit shows the path
|
|
871
|
+
(`fs.runtimeTokens.revoke`), a one-line summary and its flags (read/write,
|
|
872
|
+
destructive, one-time secret, preview, paginated).
|
|
873
|
+
- **`code describe <path|opKey>`** — accepts `runtimeTokens.revoke`,
|
|
874
|
+
`fs.runtimeTokens.revoke` or the opKey `runtime_token.revoke`.
|
|
875
|
+
- **`code types [namespace]`** — a self-contained `.d.ts` for `fs`, generated
|
|
876
|
+
from the same tables `code run` enforces, with JSDoc from the operation
|
|
877
|
+
specs.
|
|
878
|
+
- **`code run [file|-]` / `-e '<code>'`** — the script is the body of an async
|
|
879
|
+
function: `await` freely and `return` the result (or `export default` a value
|
|
880
|
+
or an async function of `{ fs, args }`). `.ts` files (or `--ts`) have their
|
|
881
|
+
types stripped by Node; only erasable syntax is supported. `--arg key=value`
|
|
882
|
+
(repeatable) and `--args-json '{…}'` fill `args`. The return value is
|
|
883
|
+
printed as JSON on stdout; `console.*` goes to stderr, or into
|
|
884
|
+
`{ result, logs }` with `--format json`. `code run` needs Node.js 22.8 or
|
|
885
|
+
newer (`CODE_MODE_UNSUPPORTED_NODE` otherwise); TypeScript needs 22.13.
|
|
886
|
+
|
|
887
|
+
In scope inside a script: `fs` (every method, plus `fs.call(opKey, input,
|
|
888
|
+
options)`), `args`, `paginate(method, input)` / `collect(method, input)`,
|
|
889
|
+
`refs.business(ref)` / `refs.environment(businessId, ref)`, `poll({ check,
|
|
890
|
+
until, deadlineMs })`, `console`, `setTimeout` / `clearTimeout` and
|
|
891
|
+
`FartherShoreError`. Nothing else: no `require`, `import()`, `process`,
|
|
892
|
+
`fetch`, filesystem or network.
|
|
893
|
+
|
|
894
|
+
**Policy** (checked in the CLI process for every call, not in the script):
|
|
895
|
+
|
|
896
|
+
| Call | Needs |
|
|
897
|
+
| ------------------------------------------------------- | ----------------------------------------------------------- |
|
|
898
|
+
| read | nothing |
|
|
899
|
+
| write | `--allow-writes` (else `CODE_MODE_WRITE_NOT_ALLOWED`) |
|
|
900
|
+
| destructive or one-time-secret write | `--allow-writes --yes` (else `CODE_MODE_APPROVAL_REQUIRED`) |
|
|
901
|
+
| preview (`{ dryRun: true }` on a method marked preview) | nothing — it changes nothing |
|
|
902
|
+
| managed-as-code (contract) write | always refused |
|
|
903
|
+
|
|
904
|
+
One-time secrets (minted or rotated credentials) come back to the script as
|
|
905
|
+
`{ redacted: true, last4 }` unless you pass `--reveal-secrets`; a redacted
|
|
906
|
+
secret cannot be shown again, so rotate with `--reveal-secrets` when you need
|
|
907
|
+
the value. Other results pass the same credential masking as the MCP server.
|
|
908
|
+
|
|
909
|
+
**Budgets:** `--max-calls` (200), `--max-writes` (20), `--timeout` (60s; `60`,
|
|
910
|
+
`60s`, `500ms`, `2m`) and at most 4 calls in flight. Exceeding one stops the
|
|
911
|
+
script with `CODE_MODE_BUDGET_EXCEEDED` / `CODE_MODE_TIMEOUT`; Ctrl-C stops it
|
|
912
|
+
too. Stopping terminates the script and cancels its in-flight requests.
|
|
913
|
+
|
|
914
|
+
**Exit codes:** `0` success; `1` script error, refusal, budget or timeout; an
|
|
915
|
+
uncaught operation error keeps the CLI codes below (`2` input, `3` auth, `5`
|
|
916
|
+
server or `OUTCOME_UNKNOWN` — the error names the read that reconciles it).
|
|
917
|
+
|
|
918
|
+
**Isolation and threat model.** The script runs in a worker thread that never
|
|
919
|
+
receives the credential, the CLI config or the environment (it starts with an
|
|
920
|
+
empty one); its only capability is a message channel to the CLI process,
|
|
921
|
+
which applies the policy above and makes the authenticated request. Requests
|
|
922
|
+
are marked `code-mode` in the client header for audit. The script itself runs
|
|
923
|
+
in a fresh JavaScript context with only the language built-ins. This keeps
|
|
924
|
+
credentials out of script memory and gates every side effect. It is **not** a
|
|
925
|
+
sandbox for hostile code — Node's `vm` is not a security boundary — so run
|
|
926
|
+
scripts you would run yourself. The hosted MCP will run scripts in an
|
|
927
|
+
isolated hosted runtime instead.
|
|
928
|
+
|
|
809
929
|
## Errors and exit codes
|
|
810
930
|
|
|
811
931
|
In `--format json` mode, every command prints a single canonical envelope to
|
|
@@ -819,14 +939,31 @@ bracketed code is stable across releases — quote it in support threads.
|
|
|
819
939
|
Exit codes are a branchable taxonomy so a script can tell failure classes apart
|
|
820
940
|
without parsing text:
|
|
821
941
|
|
|
822
|
-
| Exit | Meaning
|
|
823
|
-
| ---- |
|
|
824
|
-
| `0` | Success
|
|
825
|
-
| `2` | Validation error (HTTP 400/422) — fix your input
|
|
826
|
-
| `3` | Auth / permission error (401/403) — re-authenticate
|
|
827
|
-
| `4` |
|
|
828
|
-
| `5` | Server error (5xx) —
|
|
829
|
-
| `1` | Any other failure
|
|
942
|
+
| Exit | Meaning |
|
|
943
|
+
| ---- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
944
|
+
| `0` | Success |
|
|
945
|
+
| `2` | Validation error (HTTP 400/422) — fix your input |
|
|
946
|
+
| `3` | Auth / permission error (401/403) — re-authenticate |
|
|
947
|
+
| `4` | `MANAGED_BY_CODE` (409 with that code only) — the contract is managed as code; change it in the repo and push |
|
|
948
|
+
| `5` | Server error (5xx), or `OUTCOME_UNKNOWN` — a write whose outcome is unknown; never repeat it blindly (see below) |
|
|
949
|
+
| `1` | Any other failure: local errors, 402/404, argument errors, and every other 409 (`CONFLICT`, `RELEASE_PENDING_ACCEPTANCE`, `ROLLBACK_IN_FLIGHT`, …) |
|
|
950
|
+
|
|
951
|
+
A 409 other than `MANAGED_BY_CODE` means the server refused a repeat or a
|
|
952
|
+
conflicting change (an existing name, a release still being applied, a rollback
|
|
953
|
+
already running). Wait or reconcile; do not edit `business/` for it.
|
|
954
|
+
|
|
955
|
+
Exit `5` covers two different cases. Branch on `error.retryDisposition`:
|
|
956
|
+
|
|
957
|
+
- **`reconcile_before_repeat`.** The write may or may not have run. Run the
|
|
958
|
+
read named in `error.details.reconcile` (also listed per command by
|
|
959
|
+
`farthershore operations list`) and repeat only if that read shows it did
|
|
960
|
+
not happen. The error can retain a server code such as `UPSTREAM_TIMEOUT`;
|
|
961
|
+
a lost response uses `OUTCOME_UNKNOWN`. Neither code alone decides whether
|
|
962
|
+
repeating the write is safe.
|
|
963
|
+
- **`safe_to_repeat`.** Retry only when `error.retryable` is also true.
|
|
964
|
+
|
|
965
|
+
The CLI retries reads automatically. It retries a write only on 429, or when
|
|
966
|
+
the server marks the failure `retryable` with a `safe_to_repeat` verdict.
|
|
830
967
|
|
|
831
968
|
## CI and agent usage
|
|
832
969
|
|
|
@@ -846,6 +983,11 @@ Organization, role, member, invitation, and org MakerToken administration
|
|
|
846
983
|
requires a live-user CLI session and is not projected into MCP; audit logs,
|
|
847
984
|
notifications, and apply timelines are also CLI-only.
|
|
848
985
|
|
|
986
|
+
The server resolves its target exactly as the CLI does: the stored login,
|
|
987
|
+
`FARTHERSHORE_API_URL` (else the configured API URL), and the organization
|
|
988
|
+
linked to its working directory, else the one chosen with
|
|
989
|
+
`farthershore auth organization use`.
|
|
990
|
+
|
|
849
991
|
```bash
|
|
850
992
|
farthershore-mcp
|
|
851
993
|
```
|