fortrip 0.3.1 → 1.0.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/README.md CHANGED
@@ -1,150 +1,216 @@
1
- # fortrip-cli
1
+ # fortrip
2
2
 
3
- Search, price and book Fortrip hotels from the terminal or an AI agent.
4
- The npm package and the command are both `fortrip`.
3
+ Search hotels, check live room rates and book with a payment link, from the
4
+ terminal or an AI agent. Hotels only for now. The npm package and the command
5
+ are both `fortrip`.
5
6
 
6
- For MCP clients, see the separately maintained
7
- [Fortrip MCP](https://github.com/FortripEngineering/fortrip-mcp)
8
- repository for local and hosted connection instructions.
7
+ ```bash
8
+ npx -y fortrip login
9
+ npx -y fortrip search --query Bangkok --check-in 2026-11-10 --check-out 2026-11-12
10
+ ```
11
+
12
+ ## Install and run
13
+
14
+ Node.js 22 or newer. Run it with `npx`, which needs no install:
15
+
16
+ ```bash
17
+ npx -y fortrip <command>
18
+ ```
19
+
20
+ or install it once and run `fortrip <command>`:
21
+
22
+ ```bash
23
+ npm install --global fortrip
24
+ ```
25
+
26
+ `fortrip --help` lists the commands, `fortrip <command> --help` one command's
27
+ flags, and `fortrip --version` prints the version.
28
+
29
+ Upgrading from 0.3: 1.0 signs in with OAuth, so a 0.3 sign-in is not reused;
30
+ run `fortrip login` once. A `FORTRIP_TOKEN` from 0.3 is no longer accepted.
31
+ `fortrip mcp` replaces the separate `fortrip-mcp` package.
32
+
33
+ ## Sign in
9
34
 
10
35
  ```bash
11
- npx fortrip login # sign in through the browser
12
- npx fortrip search --query Bangkok --check-in 2026-11-10 --check-out 2026-11-12
36
+ fortrip login
13
37
  ```
14
38
 
15
- Requires Node.js 22 or newer. No runtime dependencies.
39
+ `login` prints a code and a link on stderr, opens the link in your browser
40
+ (not with `--no-browser`), and waits until you sign in to Fortrip and approve.
41
+ It then prints your account.
42
+
43
+ An AI agent can't sit in `login`, so any other command that needs a sign-in
44
+ doesn't wait: it exits with code 3 and prints `loginUrl`, `userCode` and
45
+ `expiresInSeconds` as JSON on stderr. The agent shows the link to the user;
46
+ once the user has approved it in the browser, the agent reruns the same
47
+ command, which finishes signing in and carries on. Commands that run in
48
+ parallel share one link. When Fortrip stops accepting the saved sign-in (it
49
+ was revoked, or it expired and couldn't be renewed), the command does the same
50
+ and keeps the old sign-in until the new link is approved.
51
+
52
+ You stay signed in. Access tokens last 24 hours and the CLI renews them
53
+ itself, before they run out; refresh tokens don't expire, so the sign-in lasts
54
+ until you run `fortrip logout`, which revokes this machine's sign-in and
55
+ deletes it (other machines stay signed in). `fortrip whoami` prints the
56
+ signed-in account.
57
+
58
+ The sign-in is saved in `~/.config/fortrip/credentials.json` (`$XDG_CONFIG_HOME`
59
+ is honoured), mode `0600`, per API URL, so a token is only sent to the server
60
+ that issued it.
61
+
62
+ If a new or renewed sign-in can't be saved (the file stays busy or turns out to
63
+ be damaged), `search`, `hotel`, `rates`, `book` and `whoami` still work for that
64
+ run, with the new token. The sign-in is kept in a `credentials.recovered-*.json`
65
+ file next to the credentials file, and the command's JSON output carries a
66
+ `warning` and, when the sign-in could be kept, that file in `recoveryFile`.
67
+ Later commands use it, and the next successful save merges it back. `login`
68
+ doesn't carry on in that case: it exits 1, with `recoveryFile` in the error, and
69
+ the sign-in is kept in that file all the same.
70
+
71
+ If the directory itself can't be written (a read-only home, as in some agent
72
+ sandboxes), `login` exits 1 before it asks you to approve anything, and any
73
+ other command that needs to save a sign-in exits 1 too. The error says to set
74
+ `XDG_CONFIG_HOME` to a directory that can be written, or to set `FORTRIP_TOKEN`.
16
75
 
17
76
  ## Commands
18
77
 
19
78
  | Command | What it does |
20
79
  |---|---|
21
- | `login [--no-browser]` | Device-code login: prints a code, opens `/cli/authorize`, waits for you to approve |
22
- | `logout` | Revokes the saved token on the server and deletes it locally |
23
- | `whoami` | The signed-in account |
24
- | `search` | Hotels with indicative prices |
25
- | `hotel <hotelId> [--with-rooms]` | Static hotel detail |
26
- | `rates` | Live rooms and rates |
27
- | `book` | Order + payment link (a Fortrip page that continues to Stripe) |
28
-
29
- Run `fortrip --help` for every flag, or `fortrip <command> --help` for one
30
- command's. `search`, `rates` and `book` also accept `--body '<json>'` or
80
+ | `search` | Find hotels with indicative prices |
81
+ | `hotel <hotelId>` | Static hotel detail: description, policies, facilities and photos |
82
+ | `rates` | Live rooms and rates for up to 15 hotels |
83
+ | `book` | Create an order and get a payment link |
84
+ | `login` | Sign in through the browser (device code) |
85
+ | `logout` | Revoke and forget the saved token |
86
+ | `whoami` | Show the signed-in account |
87
+ | `guide [topic]` | Print the guide for AI agents (Markdown) |
88
+ | `mcp` | Run an MCP server over stdio for local clients, bridged to Fortrip's hosted server |
89
+
90
+ ```bash
91
+ fortrip rates --hotel <hotelId> --check-in 2026-11-10 --check-out 2026-11-12 --rooms 1 --adults 2
92
+ ```
93
+
94
+ `search`, `rates` and `book` also accept `--body '<json>'` or
31
95
  `--body @file.json` with the raw request body; flags override its fields.
32
96
 
33
97
  `--adults` and `--child-age` are per room, and every room has the same
34
- occupancy: 2 rooms for 4 adults is `--rooms 2 --adults 2`. `rates` defaults
35
- to 1 room for 2 adults; `book` requires `--rooms` and `--adults`.
98
+ occupancy: 2 rooms for 4 adults is `--rooms 2 --adults 2`. `rates` and `book`
99
+ both require `--rooms` and `--adults`.
36
100
 
37
- Output is JSON on stdout. Errors are JSON on stderr, with fixed exit codes:
101
+ `book` creates an unpaid order and prints a payment link for it. Nothing is
102
+ charged until the person pays on the page the link opens.
38
103
 
39
- | Code | Meaning |
40
- |---|---|
41
- | 0 | Success |
42
- | 1 | Other error (`retryable: true` on stderr: worth one retry) |
43
- | 2 | Invalid arguments (local or HTTP 400) |
44
- | 3 | Not logged in, or the sign-in wasn't accepted (HTTP 401) |
45
- | 4 | Rate limited (HTTP 429; `retryAfterSeconds` on stderr) |
46
-
47
- ## Credentials
48
-
49
- - `login` saves the token to `~/.config/fortrip/credentials.json`
50
- (`$XDG_CONFIG_HOME` is honoured), mode `0600`. Saved tokens are stored per
51
- API URL, so a saved token is only sent to the server that issued it.
52
- - Without a token, any other command starts a device login and exits 3 with
53
- `loginUrl` on stderr instead of waiting. Once that link is approved in the
54
- browser, rerunning the command saves the token and carries on. This is how
55
- AI agents sign in, since they can't sit in `login`. Commands run in
56
- parallel share one login link. If the server doesn't accept the saved
57
- token, the command keeps it and starts a new login the same way; once that
58
- link is approved, the new token replaces the saved one.
59
- - `FORTRIP_TOKEN` overrides the saved login (CI, remote sandboxes). It is not
60
- tied to a server: it is sent to whatever `FORTRIP_API_URL` points at. If the
61
- server doesn't accept it, commands exit 3 with `tokenSource: "FORTRIP_TOKEN"`
62
- and no `loginUrl`.
63
- - `FORTRIP_API_URL` overrides the base URL (default `https://fortrip.ai`).
64
- Plain `http` is only accepted for `localhost`.
65
- - `FORTRIP_CURRENCY` sets the default `--currency` for `search` and `rates`
66
- (`CNY` or `USD`; the API defaults to `CNY`). Display only: `book`
67
- charges the currency it returns.
68
-
69
- `logout` revokes the saved token. With the Fortrip server update released
70
- alongside CLI 0.3.1, sign-ins that go unused for 90 days stop working, and
71
- signed-in users can list and revoke their CLI sign-ins in their Fortrip
72
- account (account menu → **Fortrip CLI**).
73
-
74
- If a new sign-in can't be saved (the file is busy or damaged), it is kept
75
- in a `credentials.recovered-*.json` file next to `credentials.json` (mode
76
- `0600`), and the command's JSON output names it in `warning` and
77
- `recoveryFile`. The next successful save merges it back and removes the
78
- file; `logout` revokes and removes these too.
79
-
80
- Sharing `credentials.json` with 0.3.0 works on a best-effort basis: 0.3.0
81
- finds the newest pending login where it expects it, but it writes the file
82
- without a lock, so don't sign in with 0.3.0 and 0.3.1 at the same moment.
83
-
84
- ## Agent skill
104
+ ## For AI agents
85
105
 
86
106
  ```bash
87
- npx skills add FortripEngineering/fortrip-plugins --skill fortrip-cli
107
+ npx -y fortrip guide # when to use the CLI, call order, sign-in, what to show before a payment link
108
+ npx -y fortrip guide planning # flexible dates, budgets, split stays, several destinations
88
109
  ```
89
110
 
90
- The skill lives in
91
- [fortrip-plugins](https://github.com/FortripEngineering/fortrip-plugins); the
92
- Claude directory plugin there uses the hosted MCP instead of the CLI. The
93
- skill only tells the agent to run `npx -y fortrip@latest skill`, which prints
94
- [`AGENT_GUIDE.md`](AGENT_GUIDE.md): when to use the CLI, the call order, login,
95
- and what to show the user before handing over a payment link. The guide ships
96
- with the package, so a CLI release updates every installed skill. Edit
97
- `AGENT_GUIDE.md`, not the skill.
98
-
99
- `fortrip skill planning` prints [`guides/planning.md`](guides/planning.md):
100
- what to ask, how to rank and how to present options for flexible dates,
101
- budgets, split stays and several destinations. Both guides are printed with
102
- `fortrip@latest` replaced by the running version, so an agent keeps using the
103
- same CLI for the whole conversation.
111
+ Both print Markdown, with `fortrip@latest` replaced by the running version, so
112
+ an agent keeps using the same CLI for the whole conversation. The guide is
113
+ written once in
114
+ [`@fortrip/agent-contract`](https://github.com/FortripEngineering/fortrip/tree/main/packages/contract/guide)
115
+ and compiled into the CLI.
104
116
 
105
- ## Support
117
+ For agents that can run shell commands, the same guide is also a skill:
106
118
 
107
- For changes, cancellations, refunds or other help with a booking, email
108
- [info@fortrip.ai](mailto:info@fortrip.ai) with the booking's order link
109
- (`orderUrl`).
119
+ ```bash
120
+ npx skills add FortripEngineering/fortrip --skill fortrip-cli
121
+ ```
110
122
 
111
- ## Development
123
+ ## MCP server
124
+
125
+ `fortrip mcp` runs an MCP server on stdio for clients that start local
126
+ servers. It forwards to Fortrip's hosted MCP server, `https://fortrip.ai/api/mcp`,
127
+ with your saved sign-in. Sign in once with `npx -y fortrip login` before you
128
+ add the server to a client.
129
+
130
+ If the client starts the server before you have, the server fails to connect:
131
+ its first request, `initialize`, is answered with a JSON-RPC error (`-32001`)
132
+ whose message says to run `npx -y fortrip login` in a terminal, or to open the
133
+ sign-in link it names and approve it. Clients typically close the connection
134
+ after a failed `initialize`, so sign in (or approve that link), then restart the
135
+ server or reconnect it (`/mcp` in Claude Code). If a sign-in stops working
136
+ later, only the request that hit it fails with the same kind of error, and the
137
+ server keeps running.
138
+
139
+ Claude Desktop (Settings, Developer, Edit Config; on macOS
140
+ `~/Library/Application Support/Claude/claude_desktop_config.json`, on Windows
141
+ `%APPDATA%\Claude\claude_desktop_config.json`) and Cursor (`~/.cursor/mcp.json`,
142
+ or `.cursor/mcp.json` in a project):
143
+
144
+ ```json
145
+ {
146
+ "mcpServers": {
147
+ "fortrip": {
148
+ "command": "npx",
149
+ "args": ["-y", "fortrip", "mcp"]
150
+ }
151
+ }
152
+ }
153
+ ```
154
+
155
+ Claude Code:
112
156
 
113
157
  ```bash
114
- pnpm install
115
- pnpm dev search --query Bangkok ... # run from source
116
- pnpm test
117
- pnpm typecheck
118
- pnpm build # dist/cli.js
158
+ claude mcp add fortrip -- npx -y fortrip mcp
119
159
  ```
120
160
 
121
- Point at a local Fortrip app with `FORTRIP_API_URL=http://localhost:3000`.
161
+ Codex, with `codex mcp add fortrip -- npx -y fortrip mcp` or in
162
+ `~/.codex/config.toml`:
122
163
 
123
- ## Releasing
164
+ ```toml
165
+ [mcp_servers.fortrip]
166
+ command = "npx"
167
+ args = ["-y", "fortrip", "mcp"]
168
+ ```
169
+
170
+ Clients that support remote MCP servers with OAuth don't need the CLI: add
171
+ `https://fortrip.ai/api/mcp` as a remote server and sign in to Fortrip in the
172
+ browser when the client asks. In Claude Code, that is
173
+ `claude mcp add --transport http fortrip https://fortrip.ai/api/mcp`.
174
+
175
+ ## Environment variables
176
+
177
+ | Variable | Meaning |
178
+ |---|---|
179
+ | `FORTRIP_TOKEN` | An access token, used instead of the saved sign-in. It lasts at most 24 hours, so it suits one sandbox session or one CI run, not standing CI. It isn't tied to a server: it is sent to whatever `FORTRIP_API_URL` points at. If Fortrip doesn't accept it, or it contains a line break or another character that can't be sent in a header, commands exit 3 with `tokenSource: "FORTRIP_TOKEN"` and no `loginUrl`; the error never repeats the token. |
180
+ | `FORTRIP_API_URL` | The base URL (default `https://fortrip.ai`). Plain `http` is only accepted for `localhost`. |
181
+ | `FORTRIP_CURRENCY` | The default `--currency` for `search` and `rates` (`CNY` or `USD`; the API uses `CNY` when nothing sets one). It only changes how prices are shown: `book` charges the currency it returns. |
182
+
183
+ ## Output and exit codes
124
184
 
125
- Pushing a `v*` tag publishes to npm through
126
- [`.github/workflows/publish.yml`](.github/workflows/publish.yml), which signs
127
- in with npm trusted publishing (no npm token in GitHub). Pull requests and
128
- pushes to `main` run typecheck, tests and the build through
129
- [`.github/workflows/ci.yml`](.github/workflows/ci.yml).
185
+ Data commands (`search`, `hotel`, `rates`, `book`, `login`, `logout`,
186
+ `whoami`) print JSON on stdout. `guide` prints Markdown, and `fortrip mcp`
187
+ speaks MCP over stdio. Errors are JSON on stderr, with an `error` message, the
188
+ `exitCode` and any details.
130
189
 
131
- 1. Bump the version in a PR and merge it into `main`:
132
- `npm version minor --no-git-tag-version` (or `patch`).
133
- 2. Tag the merged commit on `main` and push the tag:
190
+ | Code | Meaning |
191
+ |---|---|
192
+ | 0 | Success |
193
+ | 1 | Other error (`retryable: true` on stderr: worth one retry) |
194
+ | 2 | Invalid arguments (local or HTTP 400) |
195
+ | 3 | Not signed in, or the sign-in wasn't accepted (HTTP 401); `loginUrl` on stderr |
196
+ | 4 | Rate limited (HTTP 429; `retryAfterSeconds` on stderr) |
134
197
 
135
- ```bash
136
- git checkout main && git pull
137
- git tag v0.2.0 && git push origin v0.2.0
138
- ```
198
+ ## Support
199
+
200
+ For changes, cancellations, refunds or other help with a booking, email
201
+ [info@fortrip.ai](mailto:info@fortrip.ai) with the booking's order link
202
+ (`orderUrl`).
203
+
204
+ ## Releasing
139
205
 
140
- The workflow refuses a tag that doesn't match `package.json` or isn't on
141
- `main`. A `build` job runs typecheck, tests and the build and packs the
142
- tarball; a `publish` job in the `npm-publish` environment publishes that
143
- tarball, with no install or build of its own. Every installed skill picks up
144
- the new guide on its next `npx fortrip@latest skill`.
206
+ Both packages in this repository, `fortrip` and `@fortrip/agent-contract`,
207
+ are released together from a `vX.Y.Z` tag. See
208
+ [Releasing](https://github.com/FortripEngineering/fortrip#releasing) in the
209
+ repository's README.
145
210
 
146
211
  ## License
147
212
 
148
213
  The code and documentation in this repository are licensed under the
149
- [MIT License](LICENSE). This license does not grant access to the hosted
150
- Fortrip service, hotel inventory, or third-party data.
214
+ [MIT License](https://github.com/FortripEngineering/fortrip/blob/main/LICENSE).
215
+ This license does not grant access to the hosted Fortrip service, hotel
216
+ inventory, or third-party data.