@farthershore/cli 0.34.0 → 0.36.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 +121 -0
- package/README.md +201 -59
- package/dist/index.js +2082 -120
- package/package.json +8 -8
- package/dist/mcp.js +0 -160
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# Changelog — @farthershore/cli
|
|
2
|
+
|
|
3
|
+
All notable changes to the `farthershore` CLI are documented here. The CLI
|
|
4
|
+
versions independently from the SDKs. Pre-1.0: minor versions may include
|
|
5
|
+
breaking changes. Releases before 0.35.0 are recorded only in the git history.
|
|
6
|
+
|
|
7
|
+
## [0.36.0] - 2026-10-13
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- **Breaking:** `farthershore create api` is now `farthershore backend scaffold`
|
|
12
|
+
(same flags), so it no longer reads like `farthershore api`. The top-level
|
|
13
|
+
`create` group is gone, and its error codes are renamed from `CREATE_API_*`
|
|
14
|
+
to `BACKEND_SCAFFOLD_*` (for example `BACKEND_SCAFFOLD_EXISTS`).
|
|
15
|
+
- Every command calls the `@farthershore/client` operation surface directly;
|
|
16
|
+
command output and flags are unchanged.
|
|
17
|
+
|
|
18
|
+
### Removed
|
|
19
|
+
|
|
20
|
+
- **Breaking:** the local stdio MCP server and its `farthershore-mcp` binary
|
|
21
|
+
are gone. MCP launch configurations that run `farthershore-mcp` (or
|
|
22
|
+
`npx -p @farthershore/cli farthershore-mcp`) stop working on upgrade. Use
|
|
23
|
+
`farthershore code run` or `farthershore api` from an agent until the hosted
|
|
24
|
+
MCP server ships.
|
|
25
|
+
|
|
26
|
+
## [0.35.0] - 2026-10-12
|
|
27
|
+
|
|
28
|
+
### Added
|
|
29
|
+
|
|
30
|
+
- `farthershore api <endpoint>`: an authenticated request to any platform API
|
|
31
|
+
path, like `gh api`. `-X` sets the method; `-f` / `-F` add string or typed
|
|
32
|
+
fields (query parameters for GET, a JSON body otherwise); `--input` sends a
|
|
33
|
+
JSON file; `-H` adds headers (the auth, surface and organization headers are
|
|
34
|
+
refused); `--paginate` / `--max-pages` follow offset or cursor pages; `-i`
|
|
35
|
+
prints the status and headers; `--dry-run` appends `dry_run=true`. The
|
|
36
|
+
`{business}`, `{org}` / `{organization}` and `{env}` placeholders are filled
|
|
37
|
+
from the current context. Absolute URLs and other hosts are refused.
|
|
38
|
+
- `farthershore code search|describe|types|run`: code mode over the typed
|
|
39
|
+
operation surface.
|
|
40
|
+
- `code search` and `code describe` find operations and print their
|
|
41
|
+
metadata; `code types` prints `.d.ts` declarations for `fs` or one
|
|
42
|
+
namespace.
|
|
43
|
+
- `code run` runs a JavaScript/TypeScript script (a file, `-` for stdin, or
|
|
44
|
+
`-e`) with `fs`, `args`, `paginate` and `FartherShoreError` in scope. The
|
|
45
|
+
script runs in a worker with no credential and an empty environment, and
|
|
46
|
+
every call is checked by the CLI process.
|
|
47
|
+
- Read-only by default. `--allow-writes` permits non-destructive writes;
|
|
48
|
+
destructive and one-time-secret operations also need `--yes`.
|
|
49
|
+
`{ dryRun: true }` on a preview-capable write runs as a read.
|
|
50
|
+
Contract-class (managed-by-code) writes are always refused.
|
|
51
|
+
- Budgets: `--max-calls` (200), `--max-writes` (20), `--timeout` (60s), and
|
|
52
|
+
at most 4 calls in flight. A breach stops the script
|
|
53
|
+
(`CODE_MODE_BUDGET_EXCEEDED`), terminates the worker and cancels in-flight
|
|
54
|
+
requests.
|
|
55
|
+
- One-time secrets come back as `{ redacted: true, last4 }` unless
|
|
56
|
+
`--reveal-secrets` is passed; every result also goes through the secret
|
|
57
|
+
redaction backstop.
|
|
58
|
+
|
|
59
|
+
### Changed
|
|
60
|
+
|
|
61
|
+
- The CLI and the MCP server now run on `@farthershore/client`: the shared
|
|
62
|
+
transport, credential sources, typed errors and namespaced operation
|
|
63
|
+
surface. `--yes`, `--dry-run` and the MCP `destructiveHint` are derived from
|
|
64
|
+
each operation's spec. Requests carry
|
|
65
|
+
`x-fs-client: @farthershore/client/<version> farthershore-cli/<version>`.
|
|
66
|
+
Errors carry `param` when the server names a field.
|
|
67
|
+
|
|
68
|
+
### Breaking
|
|
69
|
+
|
|
70
|
+
- These commands now require `--yes`: `business rollback`,
|
|
71
|
+
`frontend rollback`, `backend tokens rotate`, `webhook rotate`,
|
|
72
|
+
`token rotate` (maker token), `persona rotate`, `persona delete`,
|
|
73
|
+
`business rbac disable`, `consumer migrate-latest`, `consumer rbac disable`
|
|
74
|
+
and `consumer rbac roles delete`. A `--dry-run` of a preview-capable
|
|
75
|
+
operation never needs `--yes`. Their MCP tools now set
|
|
76
|
+
`destructiveHint: true`.
|
|
77
|
+
- Consumer RBAC writes have one operation key per verb instead of sharing
|
|
78
|
+
`consumer.roles.assign`: `consumer.roles.assign`, `consumer.rbac.enable`,
|
|
79
|
+
`consumer.rbac.disable`, `consumer.role.create`, `consumer.role.update` and
|
|
80
|
+
`consumer.role.delete`. Only `consumer.rbac.disable` and
|
|
81
|
+
`consumer.role.delete` are destructive, so `consumer rbac assign`,
|
|
82
|
+
`enable`, `roles create` and `roles update` run without `--yes`.
|
|
83
|
+
`consumer rbac roles create` is no longer retried automatically.
|
|
84
|
+
- `promo-code archive` no longer requires `--yes`, and its MCP tool's
|
|
85
|
+
`destructiveHint` is now `false`.
|
|
86
|
+
- `--dry-run` on an operation without a preview is refused locally with
|
|
87
|
+
`DRY_RUN_NOT_SUPPORTED`; nothing is sent.
|
|
88
|
+
- The retired request-key vocabulary is gone. `operations list` no longer
|
|
89
|
+
reports an `intrinsic_replay` retry kind (`service-account approve` is a
|
|
90
|
+
`convergent_write`), and the retry contract no longer carries
|
|
91
|
+
`same_key_replay`, `keyRequired` or `liveWhenFieldPresent`. CLI and MCP
|
|
92
|
+
help describe the retry rule plainly: reads retry; writes retry only on a
|
|
93
|
+
429 or a server-marked `retryable` + `safe_to_repeat` answer; anything else
|
|
94
|
+
is `OUTCOME_UNKNOWN` (exit 5) and names the read to reconcile with.
|
|
95
|
+
|
|
96
|
+
### Fixed
|
|
97
|
+
|
|
98
|
+
- `workflow-control replay` and `rollback-to-config` call Core at
|
|
99
|
+
`/agent/v1/replay` and `/agent/v1/rollback-to-config`. They always returned
|
|
100
|
+
404 before.
|
|
101
|
+
- A 401 on a cached exchanged token drops it, re-exchanges once and resends
|
|
102
|
+
once, so a long-lived MCP server recovers after a grant change or session
|
|
103
|
+
invalidation instead of failing for up to an hour. The refresh deadline
|
|
104
|
+
follows the token's lifetime rather than a possibly skewed local clock, and
|
|
105
|
+
concurrent first requests share one token exchange, which retries like a
|
|
106
|
+
read.
|
|
107
|
+
- The MCP server uses the CLI's organization (`--organization`, the linked
|
|
108
|
+
directory, or `auth organization use`) and API URL, and sends
|
|
109
|
+
`x-fs-surface: mcp`. It could act in a different organization before.
|
|
110
|
+
- POST endpoints that only read (analytics query, manifest compile, previews,
|
|
111
|
+
the builder bootstrap) and dry runs retry like reads instead of reporting
|
|
112
|
+
`OUTCOME_UNKNOWN`.
|
|
113
|
+
- Transport failures have stable codes instead of `INTERNAL_ERROR`:
|
|
114
|
+
`NETWORK_ERROR` and `TIMEOUT` (retryable for reads, exit 5),
|
|
115
|
+
`REQUEST_ABORTED`, `OUTCOME_UNKNOWN` for a write with no response, and
|
|
116
|
+
`RESPONSE_UNREADABLE` for a 2xx whose body could not be read. The original
|
|
117
|
+
failure is kept as `cause`. The attempt timeout now also covers the body
|
|
118
|
+
read.
|
|
119
|
+
- `farthershore api` never follows a redirect: a 3xx is reported as
|
|
120
|
+
`REDIRECT_NOT_FOLLOWED` with `details.location`, so headers never reach
|
|
121
|
+
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.36.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,
|
|
@@ -15,25 +15,18 @@ This CLI is the tool layer around that repo: provision a managed business repo,
|
|
|
15
15
|
validate it locally before you push, inspect publication state, and run
|
|
16
16
|
day-to-day operations (consumers, secrets, backends, webhooks, promo codes,
|
|
17
17
|
usage). It is designed to be safe for both humans and agents — every command
|
|
18
|
-
takes `--format json` for non-interactive scripting
|
|
19
|
-
the explicitly agent-operable subset of the CLI surface.
|
|
18
|
+
takes `--format json` for non-interactive scripting.
|
|
20
19
|
|
|
21
20
|
## Install
|
|
22
21
|
|
|
23
22
|
```bash
|
|
24
|
-
npm install -g @farthershore/cli@0.
|
|
23
|
+
npm install -g @farthershore/cli@0.36.0
|
|
25
24
|
```
|
|
26
25
|
|
|
27
26
|
Or run it directly with npx:
|
|
28
27
|
|
|
29
28
|
```bash
|
|
30
|
-
npx -p @farthershore/cli@0.
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
The package also ships an MCP stdio server for agents:
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
npx -p @farthershore/cli@0.34.0 farthershore-mcp
|
|
29
|
+
npx -p @farthershore/cli@0.36.0 farthershore --help
|
|
37
30
|
```
|
|
38
31
|
|
|
39
32
|
## Authentication
|
|
@@ -209,17 +202,17 @@ before pagination; the CLI does not sort or filter a partial page locally.
|
|
|
209
202
|
Each command rejects fields outside its endpoint-specific allowlist shown by
|
|
210
203
|
`--help`.
|
|
211
204
|
|
|
212
|
-
### `farthershore
|
|
205
|
+
### `farthershore backend scaffold`
|
|
213
206
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
207
|
+
Scaffold a starter backend into `api/` inside a managed builder repo, by
|
|
208
|
+
downloading the public Node template tarball, then patch the repo root
|
|
209
|
+
`.gitignore`. It runs locally and needs no login.
|
|
217
210
|
|
|
218
211
|
```bash
|
|
219
|
-
farthershore
|
|
220
|
-
farthershore
|
|
221
|
-
farthershore
|
|
222
|
-
farthershore
|
|
212
|
+
farthershore backend scaffold
|
|
213
|
+
farthershore backend scaffold --path ../weather-api
|
|
214
|
+
farthershore backend scaffold --force
|
|
215
|
+
farthershore backend scaffold --node --ref v0.1.0 --format json
|
|
223
216
|
```
|
|
224
217
|
|
|
225
218
|
`--node` is the default language today: Node (TypeScript + Express). `--ref`
|
|
@@ -274,7 +267,7 @@ farthershore business create weather-api \
|
|
|
274
267
|
--format json
|
|
275
268
|
|
|
276
269
|
farthershore business publish weather-api --format json
|
|
277
|
-
farthershore business rollback weather-api wfe_previous --reason "bad release" --format json
|
|
270
|
+
farthershore business rollback weather-api wfe_previous --reason "bad release" --yes --format json
|
|
278
271
|
```
|
|
279
272
|
|
|
280
273
|
Deleting a business is **stage only** — the command is not registered in the
|
|
@@ -321,13 +314,13 @@ and requires the exact `business:rollback` permission.
|
|
|
321
314
|
`rbacEnabled` flag. `business rbac enable` / `disable` toggle that flag (like
|
|
322
315
|
`docsEnabled`, it is platform-owned and never repo-authored); once enabled,
|
|
323
316
|
subscriber organizations manage roles in their portal. Both toggles are
|
|
324
|
-
|
|
317
|
+
safe to repeat. Subscriber role and assignment state is kept server-side on
|
|
325
318
|
disable, so re-enabling is a pure flag flip.
|
|
326
319
|
|
|
327
320
|
```bash
|
|
328
321
|
farthershore business rbac weather-api --format json
|
|
329
322
|
farthershore business rbac enable weather-api --format json
|
|
330
|
-
farthershore business rbac disable weather-api --format json
|
|
323
|
+
farthershore business rbac disable weather-api --yes --format json
|
|
331
324
|
```
|
|
332
325
|
|
|
333
326
|
`business rbac subjects list` lists the custom permission vocabulary: subjects
|
|
@@ -385,8 +378,7 @@ default, and `--org <id>` overrides it for one command.
|
|
|
385
378
|
|
|
386
379
|
Create and administer organization-owned MakerTokens. These commands require a
|
|
387
380
|
signed-in user CLI session (`farthershore login`); an existing MakerToken cannot
|
|
388
|
-
list, mint, approve, rotate, revoke, or otherwise administer credentials.
|
|
389
|
-
entire group is CLI-only and is deliberately absent from `farthershore-mcp`.
|
|
381
|
+
list, mint, approve, rotate, revoke, or otherwise administer credentials.
|
|
390
382
|
|
|
391
383
|
```bash
|
|
392
384
|
# Exact permissions a human may delegate — read this before choosing --permissions.
|
|
@@ -406,7 +398,7 @@ farthershore token approve <approvalId> --org \
|
|
|
406
398
|
farthershore token deny <approvalId> --org --format json
|
|
407
399
|
farthershore token update <tokenId> --org \
|
|
408
400
|
--permissions '["business:read"]' --format json
|
|
409
|
-
farthershore token rotate <tokenId> --org --format json
|
|
401
|
+
farthershore token rotate <tokenId> --org --yes --format json
|
|
410
402
|
farthershore token revoke <tokenId> --org --yes --format json
|
|
411
403
|
```
|
|
412
404
|
|
|
@@ -470,8 +462,8 @@ never print `plaintext`. ACTIVE creates
|
|
|
470
462
|
and rotations print the one-time key once. If one of these commands times out,
|
|
471
463
|
run `service-account list` before trying again.
|
|
472
464
|
|
|
473
|
-
This group is
|
|
474
|
-
|
|
465
|
+
This group is registered directly rather than through the operation registry:
|
|
466
|
+
that registry carries builder principals, not portal consumer sessions.
|
|
475
467
|
|
|
476
468
|
### `farthershore limit`
|
|
477
469
|
|
|
@@ -522,9 +514,18 @@ portal renders locally exactly as it serves in production. Pass `--mock` to
|
|
|
522
514
|
inject `{ mock: true }` instead of Core/Clerk config for local page inspection
|
|
523
515
|
with placeholder data and auth bypassed.
|
|
524
516
|
|
|
517
|
+
A build is published only when its output ships the SDK's managed sign-in.
|
|
518
|
+
A refused build never replaces what is live; `frontend status` shows the
|
|
519
|
+
reason, and `builds[].diagnostics[].code` is `FRONTEND_SIGN_IN_MISSING` (mount
|
|
520
|
+
`<FartherShoreRoot>` and render `<FsSignIn />`) or `FRONTEND_SDK_TOO_OLD`
|
|
521
|
+
(upgrade `@farthershore/farthershore-js`). `--wait` exits `BUILD_FAILED` with
|
|
522
|
+
that code in `details.reasonCode`. Mock mode is for this local preview only: a
|
|
523
|
+
hosted portal ignores it, and always uses the platform's sign-in.
|
|
524
|
+
|
|
525
525
|
```bash
|
|
526
526
|
farthershore frontend status weather-api --format json
|
|
527
|
-
farthershore frontend
|
|
527
|
+
farthershore frontend status weather-api --wait --ref <commitSha> --format json
|
|
528
|
+
farthershore frontend rollback weather-api --release-id <hash> --yes --format json
|
|
528
529
|
|
|
529
530
|
# Local preview (shells out to vite; needs a frontend/ project)
|
|
530
531
|
farthershore frontend dev # hot-reloading dev server, mock mode by default
|
|
@@ -570,8 +571,8 @@ farthershore persona bootstrap weather-api --env preview --plan pro \
|
|
|
570
571
|
--subscriber-id <subscriberId> --account-role member --role viewer \
|
|
571
572
|
--format json
|
|
572
573
|
|
|
573
|
-
farthershore persona rotate weather-api <personaId> --env preview --format json
|
|
574
|
-
farthershore persona delete weather-api <personaId> --env preview --format json
|
|
574
|
+
farthershore persona rotate weather-api <personaId> --env preview --yes --format json
|
|
575
|
+
farthershore persona delete weather-api <personaId> --env preview --yes --format json
|
|
575
576
|
```
|
|
576
577
|
|
|
577
578
|
Bootstrap and rotation return a key once. `login` sends the 60-second,
|
|
@@ -657,7 +658,7 @@ farthershore backend bind weather-api api \
|
|
|
657
658
|
--origin-url https://api-pr-42.example.com \
|
|
658
659
|
--format json
|
|
659
660
|
farthershore backend tokens create weather-api --backend <backendId> --format json
|
|
660
|
-
farthershore backend tokens rotate weather-api <tokenId> --format json
|
|
661
|
+
farthershore backend tokens rotate weather-api <tokenId> --yes --format json
|
|
661
662
|
farthershore backend tokens revoke weather-api <tokenId> --yes --format json
|
|
662
663
|
```
|
|
663
664
|
|
|
@@ -707,7 +708,7 @@ farthershore webhook update weather-api <webhookId> --disable --format json
|
|
|
707
708
|
farthershore webhook test weather-api <webhookId> --format json
|
|
708
709
|
farthershore webhook trigger weather-api <webhookId> --type payment.failed --format json
|
|
709
710
|
farthershore webhook deliveries weather-api <webhookId> --limit 20 --format json
|
|
710
|
-
farthershore webhook rotate weather-api <webhookId> --format json
|
|
711
|
+
farthershore webhook rotate weather-api <webhookId> --yes --format json
|
|
711
712
|
farthershore webhook delete weather-api <webhookId> --yes --format json
|
|
712
713
|
```
|
|
713
714
|
|
|
@@ -734,8 +735,8 @@ farthershore webhook listen weather-api --forward-to localhost:3000/webhooks \
|
|
|
734
735
|
```
|
|
735
736
|
|
|
736
737
|
`listen` needs `cloudflared` — bundled as an optional
|
|
737
|
-
`@farthershore/cloudflared-<platform>` dependency, or on your PATH.
|
|
738
|
-
|
|
738
|
+
`@farthershore/cloudflared-<platform>` dependency, or on your PATH. A listener
|
|
739
|
+
killed hard leaves an
|
|
739
740
|
endpoint with a `*.trycloudflare.com` URL; `webhook delete --yes` removes it.
|
|
740
741
|
|
|
741
742
|
### `farthershore promo-code`
|
|
@@ -763,18 +764,18 @@ Use `--all-plans` to clear plan scoping.
|
|
|
763
764
|
Install or refresh the platform-verified skills bundle together. The platform
|
|
764
765
|
pins this immutable release, and CI plus a daily repository check compare it to
|
|
765
766
|
GitHub's latest stable release so the guidance cannot silently drift.
|
|
766
|
-
This command requires `@farthershore/cli` 0.
|
|
767
|
+
This command requires `@farthershore/cli` 0.36.0 or newer.
|
|
767
768
|
|
|
768
769
|
```bash
|
|
769
770
|
set -euo pipefail
|
|
770
771
|
CLI_VERSION=$(farthershore --version)
|
|
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] >
|
|
772
|
+
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] > 36 || (+m[2] === 36 && +m[3] >= 0))) { console.error("Stop: CLI 0.36.0 or newer is required; ask the human to upgrade."); process.exitCode = 1; } })'
|
|
772
773
|
farthershore skills install --help
|
|
773
774
|
farthershore skills install
|
|
774
775
|
```
|
|
775
776
|
|
|
776
777
|
If either prerequisite fails, stop and ask the human to run
|
|
777
|
-
`npm install -g @farthershore/cli@0.
|
|
778
|
+
`npm install -g @farthershore/cli@0.36.0`, then repeat the checks.
|
|
778
779
|
Do not install or upgrade global tooling autonomously.
|
|
779
780
|
|
|
780
781
|
The Farther Shore CLI downloads the exact installer archive and verifies this
|
|
@@ -789,6 +790,144 @@ Print the machine-readable action boundary: which operations are repo-authored
|
|
|
789
790
|
farthershore operations list --format json
|
|
790
791
|
```
|
|
791
792
|
|
|
793
|
+
### `farthershore api`
|
|
794
|
+
|
|
795
|
+
Send a raw authenticated request to any platform API endpoint and print the
|
|
796
|
+
response, like `gh api`. Use it for endpoints a typed command does not cover
|
|
797
|
+
yet. Every endpoint is described in the platform's OpenAPI document
|
|
798
|
+
(`farthershore api /openapi.json`).
|
|
799
|
+
|
|
800
|
+
```bash
|
|
801
|
+
farthershore api /businesses
|
|
802
|
+
farthershore api 'businesses/{business}/environments' --paginate
|
|
803
|
+
farthershore api -X PATCH 'businesses/{business}' -f displayName='Weather API'
|
|
804
|
+
farthershore api 'management/businesses/{business}/backends' -f name=api -f originUrl=https://api.example.com -F isDefault=true --dry-run
|
|
805
|
+
farthershore api -X POST 'businesses/{business}/promo-codes' --input promo.json
|
|
806
|
+
farthershore api 'builder/organizations/{org}/members' --include
|
|
807
|
+
farthershore api /businesses --format json | jq '.[].id'
|
|
808
|
+
```
|
|
809
|
+
|
|
810
|
+
- **Endpoint.** A path on the configured API (`--api-url` /
|
|
811
|
+
`FARTHERSHORE_API_URL`). Absolute URLs and other hosts are refused, so the
|
|
812
|
+
credential never leaves the platform, and redirects are never followed: a
|
|
813
|
+
3xx answer is an error (`REDIRECT_NOT_FOLLOWED`), so the credential and `-H`
|
|
814
|
+
headers never reach another location. Placeholders in the path and its
|
|
815
|
+
query are filled from the current context: `{business}` from
|
|
816
|
+
`--business`, `FARTHERSHORE_BUSINESS` or the linked directory; `{org}` /
|
|
817
|
+
`{organization}` from the selected organization; `{env}` from `--env`,
|
|
818
|
+
`FARTHERSHORE_ENV` or the linked environment.
|
|
819
|
+
- **Method.** `-X, --method`; default `GET`, or `POST` when fields or `--input`
|
|
820
|
+
are given.
|
|
821
|
+
- **Fields.** `-f key=value` sends a string; `-F key=value` converts `true`,
|
|
822
|
+
`false`, `null` and numbers, and reads `@file` (or `@-` for stdin). Nest with
|
|
823
|
+
`key[sub]=value`, append to an array with `key[]=value`. `GET` fields become
|
|
824
|
+
query parameters; otherwise they form the JSON body.
|
|
825
|
+
- **`--input <file|->`** sends a JSON body as-is (not combinable with fields).
|
|
826
|
+
- **`-H 'Name: value'`** adds a header. `Authorization`, `x-fs-surface`,
|
|
827
|
+
`x-fs-client` and the organization headers belong to the CLI and are refused.
|
|
828
|
+
- **`--paginate`** follows offset (`pagination.hasMore`) and cursor
|
|
829
|
+
(`nextCursor`) pages and prints one object with the lists concatenated;
|
|
830
|
+
`--max-pages <n>` (default 100) bounds it.
|
|
831
|
+
- **`-i, --include`** prints the HTTP status and response headers first.
|
|
832
|
+
- **`--dry-run`** appends `dry_run=true`.
|
|
833
|
+
|
|
834
|
+
The body is printed as-is (pretty in a terminal, compact with `--format json`),
|
|
835
|
+
never wrapped in the CLI envelope; there is no `--jq`, so pipe to `jq`. Errors
|
|
836
|
+
print the error envelope and use the exit codes below. Reads retry on transient
|
|
837
|
+
failures; a write is never repeated: a 5xx or lost answer exits `5` and its
|
|
838
|
+
error has `outcomeUnknown: true` (the `code` may be the server's own, e.g.
|
|
839
|
+
`TEARDOWN_FAILED`; key on `outcomeUnknown`), so read current state before
|
|
840
|
+
sending it again. `-i` also prints the status line and headers of a failed
|
|
841
|
+
answer, before the error envelope.
|
|
842
|
+
|
|
843
|
+
### `farthershore code` (code mode)
|
|
844
|
+
|
|
845
|
+
Code mode lets you (or an agent) find platform operations and run a script
|
|
846
|
+
against a typed `fs` client, instead of chaining one command per call. A
|
|
847
|
+
script can loop, filter and join results, and only its return value comes
|
|
848
|
+
back — the intermediate data never has to pass through a transcript.
|
|
849
|
+
|
|
850
|
+
**Agent quickstart: search → describe → types → run.**
|
|
851
|
+
|
|
852
|
+
```bash
|
|
853
|
+
# 1. Find operations (ranked by name, path, summary and description).
|
|
854
|
+
farthershore code search runtime token --format json
|
|
855
|
+
|
|
856
|
+
# 2. Read one: description, TypeScript signature, safety flags, reconcile
|
|
857
|
+
# read, required permission and a runnable example.
|
|
858
|
+
farthershore code describe runtimeTokens.revoke
|
|
859
|
+
|
|
860
|
+
# 3. Load the types you need (or the whole API) before writing the script.
|
|
861
|
+
farthershore code types runtimeTokens > fs.d.ts
|
|
862
|
+
|
|
863
|
+
# 4. Run it. Reads only, unless you opt in.
|
|
864
|
+
farthershore code run -e '
|
|
865
|
+
const businesses = await fs.businesses.list();
|
|
866
|
+
return businesses.filter((b) => b.status === args.status).map((b) => b.name);
|
|
867
|
+
' --arg status=DRAFT
|
|
868
|
+
```
|
|
869
|
+
|
|
870
|
+
- **`code search <query...>`** — `--limit <n>` (default 20),
|
|
871
|
+
`--side-effect read|write`, `--namespace <ns>`. Each hit shows the path
|
|
872
|
+
(`fs.runtimeTokens.revoke`), a one-line summary and its flags (read/write,
|
|
873
|
+
destructive, one-time secret, preview, paginated).
|
|
874
|
+
- **`code describe <path|opKey>`** — accepts `runtimeTokens.revoke`,
|
|
875
|
+
`fs.runtimeTokens.revoke` or the opKey `runtime_token.revoke`.
|
|
876
|
+
- **`code types [namespace]`** — a self-contained `.d.ts` for `fs`, generated
|
|
877
|
+
from the same tables `code run` enforces, with JSDoc from the operation
|
|
878
|
+
specs.
|
|
879
|
+
- **`code run [file|-]` / `-e '<code>'`** — the script is the body of an async
|
|
880
|
+
function: `await` freely and `return` the result (or `export default` a value
|
|
881
|
+
or an async function of `{ fs, args }`). `.ts` files (or `--ts`) have their
|
|
882
|
+
types stripped by Node; only erasable syntax is supported. `--arg key=value`
|
|
883
|
+
(repeatable) and `--args-json '{…}'` fill `args`. The return value is
|
|
884
|
+
printed as JSON on stdout; `console.*` goes to stderr, or into
|
|
885
|
+
`{ result, logs }` with `--format json`. `code run` needs Node.js 22.8 or
|
|
886
|
+
newer (`CODE_MODE_UNSUPPORTED_NODE` otherwise); TypeScript needs 22.13.
|
|
887
|
+
|
|
888
|
+
In scope inside a script: `fs` (every method, plus `fs.call(opKey, input,
|
|
889
|
+
options)`), `args`, `paginate(method, input)` / `collect(method, input)`,
|
|
890
|
+
`refs.business(ref)` / `refs.environment(businessId, ref)`, `poll({ check,
|
|
891
|
+
until, deadlineMs })`, `console`, `setTimeout` / `clearTimeout` and
|
|
892
|
+
`FartherShoreError`. Nothing else: no `require`, `import()`, `process`,
|
|
893
|
+
`fetch`, filesystem or network.
|
|
894
|
+
|
|
895
|
+
**Policy** (checked in the CLI process for every call, not in the script):
|
|
896
|
+
|
|
897
|
+
| Call | Needs |
|
|
898
|
+
| ------------------------------------------------------- | ----------------------------------------------------------- |
|
|
899
|
+
| read | nothing |
|
|
900
|
+
| write | `--allow-writes` (else `CODE_MODE_WRITE_NOT_ALLOWED`) |
|
|
901
|
+
| destructive or one-time-secret write | `--allow-writes --yes` (else `CODE_MODE_APPROVAL_REQUIRED`) |
|
|
902
|
+
| preview (`{ dryRun: true }` on a method marked preview) | nothing — it changes nothing |
|
|
903
|
+
| managed-as-code (contract) write | always refused |
|
|
904
|
+
|
|
905
|
+
One-time secrets (minted or rotated credentials) come back to the script as
|
|
906
|
+
`{ redacted: true, last4 }` unless you pass `--reveal-secrets`; a redacted
|
|
907
|
+
secret cannot be shown again, so rotate with `--reveal-secrets` when you need
|
|
908
|
+
the value. In every other result, credential-shaped strings (tokens, API keys,
|
|
909
|
+
JWTs) and known secret fields are masked before the script sees them.
|
|
910
|
+
|
|
911
|
+
**Budgets:** `--max-calls` (200), `--max-writes` (20), `--timeout` (60s; `60`,
|
|
912
|
+
`60s`, `500ms`, `2m`) and at most 4 calls in flight. Exceeding one stops the
|
|
913
|
+
script with `CODE_MODE_BUDGET_EXCEEDED` / `CODE_MODE_TIMEOUT`; Ctrl-C stops it
|
|
914
|
+
too. Stopping terminates the script and cancels its in-flight requests.
|
|
915
|
+
|
|
916
|
+
**Exit codes:** `0` success; `1` script error, refusal, budget or timeout; an
|
|
917
|
+
uncaught operation error keeps the CLI codes below (`2` input, `3` auth, `5`
|
|
918
|
+
server or `OUTCOME_UNKNOWN` — the error names the read that reconciles it).
|
|
919
|
+
|
|
920
|
+
**Isolation and threat model.** The script runs in a worker thread that never
|
|
921
|
+
receives the credential, the CLI config or the environment (it starts with an
|
|
922
|
+
empty one); its only capability is a message channel to the CLI process,
|
|
923
|
+
which applies the policy above and makes the authenticated request. Requests
|
|
924
|
+
are marked `code-mode` in the client header for audit. The script itself runs
|
|
925
|
+
in a fresh JavaScript context with only the language built-ins. This keeps
|
|
926
|
+
credentials out of script memory and gates every side effect. It is **not** a
|
|
927
|
+
sandbox for hostile code — Node's `vm` is not a security boundary — so run
|
|
928
|
+
scripts you would run yourself. The hosted MCP will run scripts in an
|
|
929
|
+
isolated hosted runtime instead.
|
|
930
|
+
|
|
792
931
|
## Errors and exit codes
|
|
793
932
|
|
|
794
933
|
In `--format json` mode, every command prints a single canonical envelope to
|
|
@@ -802,14 +941,31 @@ bracketed code is stable across releases — quote it in support threads.
|
|
|
802
941
|
Exit codes are a branchable taxonomy so a script can tell failure classes apart
|
|
803
942
|
without parsing text:
|
|
804
943
|
|
|
805
|
-
| Exit | Meaning
|
|
806
|
-
| ---- |
|
|
807
|
-
| `0` | Success
|
|
808
|
-
| `2` | Validation error (HTTP 400/422) — fix your input
|
|
809
|
-
| `3` | Auth / permission error (401/403) — re-authenticate
|
|
810
|
-
| `4` |
|
|
811
|
-
| `5` | Server error (5xx) —
|
|
812
|
-
| `1` | Any other failure
|
|
944
|
+
| Exit | Meaning |
|
|
945
|
+
| ---- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
946
|
+
| `0` | Success |
|
|
947
|
+
| `2` | Validation error (HTTP 400/422) — fix your input |
|
|
948
|
+
| `3` | Auth / permission error (401/403) — re-authenticate |
|
|
949
|
+
| `4` | `MANAGED_BY_CODE` (409 with that code only) — the contract is managed as code; change it in the repo and push |
|
|
950
|
+
| `5` | Server error (5xx), or `OUTCOME_UNKNOWN` — a write whose outcome is unknown; never repeat it blindly (see below) |
|
|
951
|
+
| `1` | Any other failure: local errors, 402/404, argument errors, and every other 409 (`CONFLICT`, `RELEASE_PENDING_ACCEPTANCE`, `ROLLBACK_IN_FLIGHT`, …) |
|
|
952
|
+
|
|
953
|
+
A 409 other than `MANAGED_BY_CODE` means the server refused a repeat or a
|
|
954
|
+
conflicting change (an existing name, a release still being applied, a rollback
|
|
955
|
+
already running). Wait or reconcile; do not edit `business/` for it.
|
|
956
|
+
|
|
957
|
+
Exit `5` covers two different cases. Branch on `error.retryDisposition`:
|
|
958
|
+
|
|
959
|
+
- **`reconcile_before_repeat`.** The write may or may not have run. Run the
|
|
960
|
+
read named in `error.details.reconcile` (also listed per command by
|
|
961
|
+
`farthershore operations list`) and repeat only if that read shows it did
|
|
962
|
+
not happen. The error can retain a server code such as `UPSTREAM_TIMEOUT`;
|
|
963
|
+
a lost response uses `OUTCOME_UNKNOWN`. Neither code alone decides whether
|
|
964
|
+
repeating the write is safe.
|
|
965
|
+
- **`safe_to_repeat`.** Retry only when `error.retryable` is also true.
|
|
966
|
+
|
|
967
|
+
The CLI retries reads automatically. It retries a write only on 429, or when
|
|
968
|
+
the server marks the failure `retryable` with a `safe_to_repeat` verdict.
|
|
813
969
|
|
|
814
970
|
## CI and agent usage
|
|
815
971
|
|
|
@@ -819,20 +975,6 @@ MakerToken through `FARTHERSHORE_TOKEN`. Device login waits for human approval;
|
|
|
819
975
|
`farthershore validate --local-only` need no network or auth and are safe to
|
|
820
976
|
run in CI.
|
|
821
977
|
|
|
822
|
-
## MCP server
|
|
823
|
-
|
|
824
|
-
The MCP server (`farthershore-mcp`) projects its tools from the same operation
|
|
825
|
-
registry that defines the CLI commands. Every MCP tool has a CLI sibling, but
|
|
826
|
-
not every CLI command is exposed through MCP. Tool names use the `fs_*` prefix
|
|
827
|
-
and cover only operations explicitly marked agent-operable in that registry.
|
|
828
|
-
Organization, role, member, invitation, and org MakerToken administration
|
|
829
|
-
requires a live-user CLI session and is not projected into MCP; audit logs,
|
|
830
|
-
notifications, and apply timelines are also CLI-only.
|
|
831
|
-
|
|
832
|
-
```bash
|
|
833
|
-
farthershore-mcp
|
|
834
|
-
```
|
|
835
|
-
|
|
836
978
|
## Learn more
|
|
837
979
|
|
|
838
980
|
- Platform documentation: [farthershore.com](https://farthershore.com)
|