@farthershore/cli 0.34.0 → 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 +183 -24
- package/dist/index.js +2076 -114
- package/dist/mcp.js +81 -81
- package/package.json +7 -4
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
|
|
@@ -274,7 +274,7 @@ farthershore business create weather-api \
|
|
|
274
274
|
--format json
|
|
275
275
|
|
|
276
276
|
farthershore business publish weather-api --format json
|
|
277
|
-
farthershore business rollback weather-api wfe_previous --reason "bad release" --format json
|
|
277
|
+
farthershore business rollback weather-api wfe_previous --reason "bad release" --yes --format json
|
|
278
278
|
```
|
|
279
279
|
|
|
280
280
|
Deleting a business is **stage only** — the command is not registered in the
|
|
@@ -321,13 +321,13 @@ and requires the exact `business:rollback` permission.
|
|
|
321
321
|
`rbacEnabled` flag. `business rbac enable` / `disable` toggle that flag (like
|
|
322
322
|
`docsEnabled`, it is platform-owned and never repo-authored); once enabled,
|
|
323
323
|
subscriber organizations manage roles in their portal. Both toggles are
|
|
324
|
-
|
|
324
|
+
safe to repeat. Subscriber role and assignment state is kept server-side on
|
|
325
325
|
disable, so re-enabling is a pure flag flip.
|
|
326
326
|
|
|
327
327
|
```bash
|
|
328
328
|
farthershore business rbac weather-api --format json
|
|
329
329
|
farthershore business rbac enable weather-api --format json
|
|
330
|
-
farthershore business rbac disable weather-api --format json
|
|
330
|
+
farthershore business rbac disable weather-api --yes --format json
|
|
331
331
|
```
|
|
332
332
|
|
|
333
333
|
`business rbac subjects list` lists the custom permission vocabulary: subjects
|
|
@@ -406,7 +406,7 @@ farthershore token approve <approvalId> --org \
|
|
|
406
406
|
farthershore token deny <approvalId> --org --format json
|
|
407
407
|
farthershore token update <tokenId> --org \
|
|
408
408
|
--permissions '["business:read"]' --format json
|
|
409
|
-
farthershore token rotate <tokenId> --org --format json
|
|
409
|
+
farthershore token rotate <tokenId> --org --yes --format json
|
|
410
410
|
farthershore token revoke <tokenId> --org --yes --format json
|
|
411
411
|
```
|
|
412
412
|
|
|
@@ -524,7 +524,7 @@ with placeholder data and auth bypassed.
|
|
|
524
524
|
|
|
525
525
|
```bash
|
|
526
526
|
farthershore frontend status weather-api --format json
|
|
527
|
-
farthershore frontend rollback weather-api --release-id <hash> --format json
|
|
527
|
+
farthershore frontend rollback weather-api --release-id <hash> --yes --format json
|
|
528
528
|
|
|
529
529
|
# Local preview (shells out to vite; needs a frontend/ project)
|
|
530
530
|
farthershore frontend dev # hot-reloading dev server, mock mode by default
|
|
@@ -570,8 +570,8 @@ farthershore persona bootstrap weather-api --env preview --plan pro \
|
|
|
570
570
|
--subscriber-id <subscriberId> --account-role member --role viewer \
|
|
571
571
|
--format json
|
|
572
572
|
|
|
573
|
-
farthershore persona rotate weather-api <personaId> --env preview --format json
|
|
574
|
-
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
|
|
575
575
|
```
|
|
576
576
|
|
|
577
577
|
Bootstrap and rotation return a key once. `login` sends the 60-second,
|
|
@@ -657,7 +657,7 @@ farthershore backend bind weather-api api \
|
|
|
657
657
|
--origin-url https://api-pr-42.example.com \
|
|
658
658
|
--format json
|
|
659
659
|
farthershore backend tokens create weather-api --backend <backendId> --format json
|
|
660
|
-
farthershore backend tokens rotate weather-api <tokenId> --format json
|
|
660
|
+
farthershore backend tokens rotate weather-api <tokenId> --yes --format json
|
|
661
661
|
farthershore backend tokens revoke weather-api <tokenId> --yes --format json
|
|
662
662
|
```
|
|
663
663
|
|
|
@@ -707,7 +707,7 @@ farthershore webhook update weather-api <webhookId> --disable --format json
|
|
|
707
707
|
farthershore webhook test weather-api <webhookId> --format json
|
|
708
708
|
farthershore webhook trigger weather-api <webhookId> --type payment.failed --format json
|
|
709
709
|
farthershore webhook deliveries weather-api <webhookId> --limit 20 --format json
|
|
710
|
-
farthershore webhook rotate weather-api <webhookId> --format json
|
|
710
|
+
farthershore webhook rotate weather-api <webhookId> --yes --format json
|
|
711
711
|
farthershore webhook delete weather-api <webhookId> --yes --format json
|
|
712
712
|
```
|
|
713
713
|
|
|
@@ -763,18 +763,18 @@ Use `--all-plans` to clear plan scoping.
|
|
|
763
763
|
Install or refresh the platform-verified skills bundle together. The platform
|
|
764
764
|
pins this immutable release, and CI plus a daily repository check compare it to
|
|
765
765
|
GitHub's latest stable release so the guidance cannot silently drift.
|
|
766
|
-
This command requires `@farthershore/cli` 0.
|
|
766
|
+
This command requires `@farthershore/cli` 0.35.0 or newer.
|
|
767
767
|
|
|
768
768
|
```bash
|
|
769
769
|
set -euo pipefail
|
|
770
770
|
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] >
|
|
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; } })'
|
|
772
772
|
farthershore skills install --help
|
|
773
773
|
farthershore skills install
|
|
774
774
|
```
|
|
775
775
|
|
|
776
776
|
If either prerequisite fails, stop and ask the human to run
|
|
777
|
-
`npm install -g @farthershore/cli@0.
|
|
777
|
+
`npm install -g @farthershore/cli@0.35.0`, then repeat the checks.
|
|
778
778
|
Do not install or upgrade global tooling autonomously.
|
|
779
779
|
|
|
780
780
|
The Farther Shore CLI downloads the exact installer archive and verifies this
|
|
@@ -789,6 +789,143 @@ Print the machine-readable action boundary: which operations are repo-authored
|
|
|
789
789
|
farthershore operations list --format json
|
|
790
790
|
```
|
|
791
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
|
+
|
|
792
929
|
## Errors and exit codes
|
|
793
930
|
|
|
794
931
|
In `--format json` mode, every command prints a single canonical envelope to
|
|
@@ -802,14 +939,31 @@ bracketed code is stable across releases — quote it in support threads.
|
|
|
802
939
|
Exit codes are a branchable taxonomy so a script can tell failure classes apart
|
|
803
940
|
without parsing text:
|
|
804
941
|
|
|
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
|
|
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.
|
|
813
967
|
|
|
814
968
|
## CI and agent usage
|
|
815
969
|
|
|
@@ -829,6 +983,11 @@ Organization, role, member, invitation, and org MakerToken administration
|
|
|
829
983
|
requires a live-user CLI session and is not projected into MCP; audit logs,
|
|
830
984
|
notifications, and apply timelines are also CLI-only.
|
|
831
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
|
+
|
|
832
991
|
```bash
|
|
833
992
|
farthershore-mcp
|
|
834
993
|
```
|