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 +180 -114
- package/dist/chunk-OBK2KTLC.js +16333 -0
- package/dist/cli.js +226 -1153
- package/dist/mcp-bridge-VEJ33LYD.js +191 -0
- package/package.json +17 -13
- package/AGENT_GUIDE.md +0 -200
- package/guides/planning.md +0 -57
package/README.md
CHANGED
|
@@ -1,150 +1,216 @@
|
|
|
1
|
-
# fortrip
|
|
1
|
+
# fortrip
|
|
2
2
|
|
|
3
|
-
Search,
|
|
4
|
-
The npm package and the command
|
|
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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
|
-
|
|
12
|
-
npx fortrip search --query Bangkok --check-in 2026-11-10 --check-out 2026-11-12
|
|
36
|
+
fortrip login
|
|
13
37
|
```
|
|
14
38
|
|
|
15
|
-
|
|
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
|
-
| `
|
|
22
|
-
| `
|
|
23
|
-
| `
|
|
24
|
-
| `
|
|
25
|
-
| `
|
|
26
|
-
| `
|
|
27
|
-
| `
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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`
|
|
35
|
-
|
|
98
|
+
occupancy: 2 rooms for 4 adults is `--rooms 2 --adults 2`. `rates` and `book`
|
|
99
|
+
both require `--rooms` and `--adults`.
|
|
36
100
|
|
|
37
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
-
|
|
117
|
+
For agents that can run shell commands, the same guide is also a skill:
|
|
106
118
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
119
|
+
```bash
|
|
120
|
+
npx skills add FortripEngineering/fortrip --skill fortrip-cli
|
|
121
|
+
```
|
|
110
122
|
|
|
111
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
161
|
+
Codex, with `codex mcp add fortrip -- npx -y fortrip mcp` or in
|
|
162
|
+
`~/.codex/config.toml`:
|
|
122
163
|
|
|
123
|
-
|
|
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
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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
|
-
|
|
132
|
-
|
|
133
|
-
|
|
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
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
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).
|
|
150
|
-
Fortrip service, hotel
|
|
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.
|