@rockhopper-co/mcp-server 0.6.0 → 0.8.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 +156 -1
- package/README.md +57 -10
- package/dist/api-client.d.ts +67 -5
- package/dist/api-client.d.ts.map +1 -1
- package/dist/api-client.js +143 -19
- package/dist/api-client.js.map +1 -1
- package/dist/auth/device-grant-client.d.ts +80 -0
- package/dist/auth/device-grant-client.d.ts.map +1 -0
- package/dist/auth/device-grant-client.js +140 -0
- package/dist/auth/device-grant-client.js.map +1 -0
- package/dist/auth/resolve-auth.d.ts +52 -0
- package/dist/auth/resolve-auth.d.ts.map +1 -0
- package/dist/auth/resolve-auth.js +100 -0
- package/dist/auth/resolve-auth.js.map +1 -0
- package/dist/auth/token-store.d.ts +51 -0
- package/dist/auth/token-store.d.ts.map +1 -0
- package/dist/auth/token-store.js +98 -0
- package/dist/auth/token-store.js.map +1 -0
- package/dist/cli.js +68 -10
- package/dist/cli.js.map +1 -1
- package/dist/correlation.d.ts +9 -0
- package/dist/correlation.d.ts.map +1 -0
- package/dist/correlation.js +26 -0
- package/dist/correlation.js.map +1 -0
- package/dist/logger.d.ts +42 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +159 -0
- package/dist/logger.js.map +1 -0
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js +20 -9
- package/dist/prompts/index.js.map +1 -1
- package/dist/resources/changes.d.ts.map +1 -1
- package/dist/resources/changes.js +8 -2
- package/dist/resources/changes.js.map +1 -1
- package/dist/resources/orchestration-guide.md +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +38 -1
- package/dist/server.js.map +1 -1
- package/dist/tools/search.d.ts.map +1 -1
- package/dist/tools/search.js +113 -20
- package/dist/tools/search.js.map +1 -1
- package/dist/tools/write-files.js +4 -4
- package/dist/tools/write-files.js.map +1 -1
- package/dist/tools/write-reviews.d.ts.map +1 -1
- package/dist/tools/write-reviews.js +3 -1
- package/dist/tools/write-reviews.js.map +1 -1
- package/dist/types.d.ts +23 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/zod-schemas.d.ts +63 -0
- package/dist/zod-schemas.d.ts.map +1 -0
- package/dist/zod-schemas.js +62 -0
- package/dist/zod-schemas.js.map +1 -0
- package/package.json +13 -6
package/CHANGELOG.md
CHANGED
|
@@ -4,7 +4,162 @@ All notable changes to this project are documented here. Follows
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
|
|
5
5
|
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
-
## [
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **Local rotating diagnostic logfile (KI-225).** The server now writes a
|
|
11
|
+
local diagnostic log to `~/.rockhopper/mcp-server/` (rotated via
|
|
12
|
+
`pino-roll`, ~5 MB × 5 files). It captures request latency plus the
|
|
13
|
+
client-side failures the backend never sees — network-unreachable
|
|
14
|
+
(`api_unreachable`), local auth rejection (`auth_failed`), response schema
|
|
15
|
+
drift (`schema_validation_failed`), per-tool-call timing (`tool_call` /
|
|
16
|
+
`tool_call_failed`), and uncaught crashes (`uncaught_exception` /
|
|
17
|
+
`unhandled_rejection`). Every line auto-carries the Phase 1.1
|
|
18
|
+
`correlationId`.
|
|
19
|
+
- **File only — never stdout** (stdout is the MCP stdio transport). On any
|
|
20
|
+
failure to open the file, logging degrades to a no-op; the server never
|
|
21
|
+
crashes and never writes to stdout.
|
|
22
|
+
- **No remote transmission.** The file stays on the customer's machine and
|
|
23
|
+
can be handed to support.
|
|
24
|
+
- **Redacted.** Tokens, `Authorization` headers, request/response bodies,
|
|
25
|
+
tool arguments, and cell data are never logged — only event, method, URL
|
|
26
|
+
pathname (no query), status, durationMs, tool name, correlationId,
|
|
27
|
+
version, and error type/message.
|
|
28
|
+
- Configurable via `ROCKHOPPER_MCP_LOG_DIR` / `ROCKHOPPER_MCP_LOG_LEVEL`;
|
|
29
|
+
disable with `ROCKHOPPER_MCP_LOG_DISABLE`.
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
- **`get_cell_history`, `resolve_comment`, and `rename_file` no longer
|
|
33
|
+
render `undefined` for every field (KI-096).** Diagnosis revealed the
|
|
34
|
+
formatters were correct — the backend was returning the wrong shape
|
|
35
|
+
on all three endpoints. Backend PR
|
|
36
|
+
[#478](https://github.com/Rockhopper-Co/backend/pull/478) fixed the
|
|
37
|
+
shapes; this PR adopts them:
|
|
38
|
+
- `getCellHistory` passes `?format=mcp` to opt into the backend's
|
|
39
|
+
normalized projection (`{versionId, value, changedBy, changedAt}`).
|
|
40
|
+
Default `format` preserves the raw-CTE shape the frontend cell-
|
|
41
|
+
history popover consumes — we never call that path.
|
|
42
|
+
- `resolveComment` + `updateEnrolledFile` continue to call the same
|
|
43
|
+
URLs but now receive the updated `FileChat` / `EnrolledFile` entity
|
|
44
|
+
(was TypeORM `UpdateResult`).
|
|
45
|
+
- `CellHistoryEntry.versionId` retyped `number` → `string` (was a
|
|
46
|
+
contributing root cause of the `Version undefined` symptom — the
|
|
47
|
+
backend's semver string never coerced to the declared numeric type).
|
|
48
|
+
- **`api-client.ts`: zod-parse opt-in for response validation
|
|
49
|
+
(KI-096).** `request<T>(path, init?, responseSchema?)` now accepts an
|
|
50
|
+
optional zod schema; when supplied, the response is parsed with
|
|
51
|
+
`safeParse` and any drift throws a useful diagnostic
|
|
52
|
+
(`Rockhopper API response failed schema check at <path>: <field> —
|
|
53
|
+
<message>`) instead of silently rendering `undefined` in formatters.
|
|
54
|
+
Three call sites opt in: `getCellHistory`, `resolveComment`,
|
|
55
|
+
`updateEnrolledFile`. Other methods stay unchanged; a sweep ticket
|
|
56
|
+
can migrate them later. New `src/zod-schemas.ts` module holds the
|
|
57
|
+
per-entity schemas.
|
|
58
|
+
|
|
59
|
+
### Added
|
|
60
|
+
- **`search_files` `matchIn` parameter.** Optional enum (`name` |
|
|
61
|
+
`comments` | `versions` | `all`); defaults to `name` for back-compat.
|
|
62
|
+
Broadens search past file-name substring into comment text
|
|
63
|
+
(`FileChat.message`) and version descriptions (`FileVersion.description`).
|
|
64
|
+
Backed by [backend PR #472](https://github.com/Rockhopper-Co/backend/pull/472)
|
|
65
|
+
/ ENG-1383; behavior available once that merges. Closes KI-080.
|
|
66
|
+
- **OAuth device-grant flow (RFC 8628) as default auth.** First launch
|
|
67
|
+
with no `ROCKHOPPER_TOKEN` env var now prints a verification code +
|
|
68
|
+
URL to stderr, polls the backend's `/auth/device/{code,token}`
|
|
69
|
+
endpoints, and persists the resulting bearer token in the OS keychain
|
|
70
|
+
(Keychain on macOS, Credential Manager on Windows, libsecret on
|
|
71
|
+
Linux). Subsequent launches reuse the stored token silently. Tokens
|
|
72
|
+
default to a 60-minute lifetime; on expiry the next launch silently
|
|
73
|
+
re-runs the flow. `ROCKHOPPER_TOKEN` still takes precedence when set
|
|
74
|
+
— PAT path preserved for headless / CI scenarios. Backed by
|
|
75
|
+
[backend PR #473](https://github.com/Rockhopper-Co/backend/pull/473)
|
|
76
|
+
/ ENG-1384. Closes KI-081 / ENG-1444.
|
|
77
|
+
- **`get_unattributed_changes` cursor pagination + cap/summary (KI-097).**
|
|
78
|
+
File-wide mode now uses the dedicated paginated backend route
|
|
79
|
+
(`GET /unattributed-changes/paginated/:fileMsId`, added by
|
|
80
|
+
[backend PR #475](https://github.com/Rockhopper-Co/backend/pull/475) /
|
|
81
|
+
KI-102) instead of the legacy unpaginated route. The MCP tool gains an
|
|
82
|
+
optional `cursor` input for round-tripping the backend's cursor.
|
|
83
|
+
Responses are now capped at 200 displayed rows with a summary line
|
|
84
|
+
("Showing X of Y change(s) on this page (Z total across the file)" +
|
|
85
|
+
top-sheets breakdown) and a pagination hint when more pages or hidden
|
|
86
|
+
rows are available. Audit measured one file at 12.5 MB / 28k rows on
|
|
87
|
+
the old route — context-blowing for AI clients; now bounded under
|
|
88
|
+
the 25k-token MCP limit. Sheet-filter mode (`sheetName` set) is
|
|
89
|
+
unchanged — it stays unpaginated since sheet size inherently bounds
|
|
90
|
+
it. Closes KI-097.
|
|
91
|
+
|
|
92
|
+
### Changed
|
|
93
|
+
- `ROCKHOPPER_TOKEN` is now **optional** (was required). Unset → OAuth.
|
|
94
|
+
Set → PAT auth path.
|
|
95
|
+
- **`ApiClient.getUnattributedChanges` refactored into two methods**
|
|
96
|
+
(KI-097): `getUnattributedChangesBySheet(fileMsId, sheetName)` for
|
|
97
|
+
the sheet-filtered legacy route, and
|
|
98
|
+
`getUnattributedChangesPaginated(fileMsId, cursor?)` for the new
|
|
99
|
+
cursor-paginated route. The old combined method is removed. External
|
|
100
|
+
consumers of `ApiClient` (e.g. `mcp-gateway`) only use `createServer`
|
|
101
|
+
+ `ApiClient` as types, not these methods directly, so the rename has
|
|
102
|
+
zero blast radius outside this repo.
|
|
103
|
+
|
|
104
|
+
### Dependencies
|
|
105
|
+
- **`keytar`** (new runtime dep) — OS-native keychain wrapper. Linux
|
|
106
|
+
requires `libsecret` installed; otherwise the OAuth path errors with
|
|
107
|
+
a clear remediation message and you must fall back to PAT.
|
|
108
|
+
|
|
109
|
+
### Changed (breaking)
|
|
110
|
+
- **`update_file_description` renamed to `rename_file`.** The tool always
|
|
111
|
+
performed a rename (its `name` input wires to backend
|
|
112
|
+
`PATCH /enrolled-files/:fileMsId`); the old name described non-existent
|
|
113
|
+
"description" semantics. Customers using the npm-installed local server
|
|
114
|
+
should update any tool-name allowlists or prompts referencing
|
|
115
|
+
`update_file_description`. Closes KI-100 / ENG-1439.
|
|
116
|
+
|
|
117
|
+
### Fixed
|
|
118
|
+
- **`cancel_review` now actually cancels PENDING reviews.** The
|
|
119
|
+
pre-flight status check at `tools/write-reviews.ts` compared against
|
|
120
|
+
the lowercase string `'pending'`, but the backend's
|
|
121
|
+
`ReviewRequestStatus` enum is uppercase (`PENDING`/`APPROVED`/
|
|
122
|
+
`CANCELLED`). The check always failed → `api.cancelReview()` was never
|
|
123
|
+
invoked → every cancel returned "cannot be cancelled — status is
|
|
124
|
+
'PENDING'". Now uses a defensive `.toUpperCase()` comparison so the
|
|
125
|
+
fix survives future backend casing flips. Closes KI-099 / ENG-1438.
|
|
126
|
+
|
|
127
|
+
### Internal
|
|
128
|
+
- Test fixtures in `src/__tests__/unit/test-helpers.ts` and
|
|
129
|
+
`src/__tests__/e2e/fixtures/rockhopper-api-fixtures.ts` updated to use
|
|
130
|
+
the real backend's uppercase `ReviewRequestStatus` enum values. Prior
|
|
131
|
+
fixtures used lowercase, which masked KI-099 by being bug-symmetric
|
|
132
|
+
with the broken code.
|
|
133
|
+
|
|
134
|
+
### Fixed (bundled — same casing-bug class as KI-099)
|
|
135
|
+
- **`file-overview` prompt no longer mis-classifies APPROVED + CANCELLED
|
|
136
|
+
reviews as pending.** `prompts/index.ts:180` filtered with lowercase
|
|
137
|
+
`r.status !== 'approved' && r.status !== 'rejected'`, but
|
|
138
|
+
`ReviewRequestStatus` is uppercase and contains no `'rejected'` value
|
|
139
|
+
(`PENDING`/`APPROVED`/`CANCELLED` only). Result: all non-pending
|
|
140
|
+
reviews were silently counted as pending in the prompt output. Now
|
|
141
|
+
filters with positive intent — `r.status?.toUpperCase() === 'PENDING'`.
|
|
142
|
+
Sibling fix to KI-099; same casing-bug class but in a different
|
|
143
|
+
surface (prompt vs. tool).
|
|
144
|
+
|
|
145
|
+
### Tooling
|
|
146
|
+
- **`npm run lint` now works.** The `lint` script referenced
|
|
147
|
+
`eslint src/` but `eslint` was missing from `devDependencies`, so any
|
|
148
|
+
fresh install silently produced `sh: eslint: command not found`. Added
|
|
149
|
+
`@eslint/js`, `eslint`, `globals`, and `typescript-eslint` as devDeps
|
|
150
|
+
and shipped a flat-config `eslint.config.js` that mirrors the
|
|
151
|
+
`mcp-gateway` repo's setup. Test files relax
|
|
152
|
+
`@typescript-eslint/no-explicit-any` (mock-stub casts) while production
|
|
153
|
+
code keeps the rule on. Lint is clean across `src/`.
|
|
154
|
+
|
|
155
|
+
## [0.6.0] — 2026-05-13
|
|
156
|
+
|
|
157
|
+
> Released to npm as `0.6.0`. The release branch was prepared with
|
|
158
|
+
> `package.json` at `0.5.0` (set in [PR #37](https://github.com/Rockhopper-Co/mcp-server/pull/37)),
|
|
159
|
+
> but the `release:minor` script ran on top of that and produced `0.6.0`
|
|
160
|
+
> via `npm version minor`. No code differs between the `0.5.0` manifest
|
|
161
|
+
> and the `0.6.0` published artifact — the bump is purely a version-string
|
|
162
|
+
> change. Content below is what shipped.
|
|
8
163
|
|
|
9
164
|
### Changed
|
|
10
165
|
- **`resources/list` no longer enumerates per-file instances.** The 4
|
package/README.md
CHANGED
|
@@ -6,17 +6,41 @@ MCP (Model Context Protocol) server for Rockhopper. Lets AI tools like Claude, C
|
|
|
6
6
|
|
|
7
7
|
- Node.js 18+
|
|
8
8
|
- A Rockhopper account with at least one enrolled file
|
|
9
|
-
- A Personal Access Token
|
|
9
|
+
- (Optional) A Personal Access Token — only required for headless / CI / scripted setups
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## Authentication
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
The server supports two auth modes. **OAuth (recommended)** is the default — no token to copy and paste. **PAT** stays available for headless scenarios.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
### OAuth (recommended)
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
On first launch, the server prints a short verification code to stderr and a URL to visit. Sign in once in your browser — the resulting bearer token is stored in your OS keychain (Keychain on macOS, Credential Manager on Windows, libsecret on Linux). Subsequent launches pick the token up silently.
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
Nothing to configure — just launch the server with no `ROCKHOPPER_TOKEN` set:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx @rockhopper-co/mcp-server
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
You'll see (on stderr):
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
Rockhopper — sign in to authorize this MCP client.
|
|
29
|
+
Open: https://app.rockhopper.co/device?user_code=ABCD2345
|
|
30
|
+
(or visit https://app.rockhopper.co/device and enter code: ABCD2345)
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Tokens default to a 60-minute lifetime. When yours expires, the next launch silently re-runs the device flow.
|
|
34
|
+
|
|
35
|
+
> **Linux**: requires `libsecret` to be installed (`apt-get install libsecret-1-dev` on Debian/Ubuntu, `dnf install libsecret` on Fedora). If unavailable, fall back to the PAT path below.
|
|
36
|
+
|
|
37
|
+
### Personal Access Token (headless / CI)
|
|
38
|
+
|
|
39
|
+
For non-interactive setups, generate a PAT in the Rockhopper web app under **Settings > Personal Access Tokens** (`read-only` or `read-write` scope) and set it as `ROCKHOPPER_TOKEN`. PATs take precedence over OAuth — if `ROCKHOPPER_TOKEN` is set, the device-grant flow is skipped.
|
|
40
|
+
|
|
41
|
+
## Setup
|
|
42
|
+
|
|
43
|
+
### 1. Install
|
|
20
44
|
|
|
21
45
|
```bash
|
|
22
46
|
npm install -g @rockhopper-co/mcp-server
|
|
@@ -28,7 +52,7 @@ Or run directly with npx:
|
|
|
28
52
|
npx @rockhopper-co/mcp-server
|
|
29
53
|
```
|
|
30
54
|
|
|
31
|
-
###
|
|
55
|
+
### 2. Configure your AI tool
|
|
32
56
|
|
|
33
57
|
#### Claude Desktop / Claude Code
|
|
34
58
|
|
|
@@ -41,7 +65,6 @@ Add to your MCP config (`~/.claude/mcp.json` or Claude Desktop settings):
|
|
|
41
65
|
"command": "npx",
|
|
42
66
|
"args": ["-y", "@rockhopper-co/mcp-server"],
|
|
43
67
|
"env": {
|
|
44
|
-
"ROCKHOPPER_TOKEN": "rh_pat_your_token_here",
|
|
45
68
|
"ROCKHOPPER_API_URL": "https://api.rockhopper.co"
|
|
46
69
|
}
|
|
47
70
|
}
|
|
@@ -49,6 +72,8 @@ Add to your MCP config (`~/.claude/mcp.json` or Claude Desktop settings):
|
|
|
49
72
|
}
|
|
50
73
|
```
|
|
51
74
|
|
|
75
|
+
Leave `ROCKHOPPER_TOKEN` out to use OAuth (recommended). Set it if you want PAT auth instead.
|
|
76
|
+
|
|
52
77
|
#### Cursor
|
|
53
78
|
|
|
54
79
|
Add to `.cursor/mcp.json` in your project:
|
|
@@ -60,7 +85,6 @@ Add to `.cursor/mcp.json` in your project:
|
|
|
60
85
|
"command": "npx",
|
|
61
86
|
"args": ["-y", "@rockhopper-co/mcp-server"],
|
|
62
87
|
"env": {
|
|
63
|
-
"ROCKHOPPER_TOKEN": "rh_pat_your_token_here",
|
|
64
88
|
"ROCKHOPPER_API_URL": "https://api.rockhopper.co"
|
|
65
89
|
}
|
|
66
90
|
}
|
|
@@ -72,8 +96,31 @@ Add to `.cursor/mcp.json` in your project:
|
|
|
72
96
|
|
|
73
97
|
| Variable | Required | Default | Description |
|
|
74
98
|
|----------|----------|---------|-------------|
|
|
75
|
-
| `ROCKHOPPER_TOKEN` |
|
|
99
|
+
| `ROCKHOPPER_TOKEN` | No | — | Personal Access Token (starts with `rh_pat_`). When unset, OAuth device-grant flow runs on first launch. |
|
|
76
100
|
| `ROCKHOPPER_API_URL` | No | `https://api.rockhopper.co` | Rockhopper API base URL |
|
|
101
|
+
| `ROCKHOPPER_MCP_LOG_DIR` | No | `~/.rockhopper/mcp-server/` | Directory for the local diagnostic logfile (see below). |
|
|
102
|
+
| `ROCKHOPPER_MCP_LOG_DISABLE` | No | — | Set truthy (`1` / `true`) to disable local diagnostic logging entirely. |
|
|
103
|
+
| `ROCKHOPPER_MCP_LOG_LEVEL` | No | `info` | Diagnostic log level (`fatal` / `error` / `warn` / `info` / `debug` / `trace` / `silent`). |
|
|
104
|
+
|
|
105
|
+
## Diagnostic Logging
|
|
106
|
+
|
|
107
|
+
The server writes a **local diagnostic logfile** to `~/.rockhopper/mcp-server/`
|
|
108
|
+
(rotated, size-capped at ~5 MB × 5 files, named `mcp-server.<n>.log`). It
|
|
109
|
+
records request latency and the client-side failures the API never sees —
|
|
110
|
+
network-unreachable errors, local auth rejections, response schema drift, and
|
|
111
|
+
uncaught crashes — so you can hand the file to Rockhopper support when
|
|
112
|
+
something misbehaves.
|
|
113
|
+
|
|
114
|
+
- **Local only.** Nothing is transmitted anywhere — the file stays on your
|
|
115
|
+
machine. There is no remote telemetry.
|
|
116
|
+
- **Redacted.** Tokens, the `Authorization` header, request/response bodies,
|
|
117
|
+
tool arguments, and cell data are **never** written. Lines carry only
|
|
118
|
+
event name, HTTP method, URL pathname (no query string), status code,
|
|
119
|
+
duration, tool name, a correlation id, and error type/message.
|
|
120
|
+
- **Configurable.** Point it elsewhere with `ROCKHOPPER_MCP_LOG_DIR`, change
|
|
121
|
+
verbosity with `ROCKHOPPER_MCP_LOG_LEVEL`, or turn it off with
|
|
122
|
+
`ROCKHOPPER_MCP_LOG_DISABLE=1`. If the file can't be opened, logging
|
|
123
|
+
silently disables — it never interferes with the server.
|
|
77
124
|
|
|
78
125
|
## Postman
|
|
79
126
|
|
package/dist/api-client.d.ts
CHANGED
|
@@ -1,21 +1,49 @@
|
|
|
1
|
-
import type { CellHistoryEntry, EnrolledFile, FileChat, FileVersion, ReviewActivity, ReviewRequest, Team, UnattributedChange, UserSummary } from './types.js';
|
|
1
|
+
import type { CellHistoryEntry, EnrolledFile, FileChat, FileVersion, PaginatedUnattributedResponse, ReviewActivity, ReviewRequest, Team, UnattributedChange, UserSummary } from './types.js';
|
|
2
2
|
export interface ApiClientConfig {
|
|
3
3
|
baseUrl: string;
|
|
4
4
|
token: string;
|
|
5
|
+
/**
|
|
6
|
+
* Phase 1.1 / KI-226 — optional fixed correlation id stamped on every
|
|
7
|
+
* outbound request's `X-Correlation-Id` header. The mcp-gateway sets this
|
|
8
|
+
* to forward its own per-request id onto tool-call traffic (it constructs a
|
|
9
|
+
* fresh `ApiClient` per request). Precedence for the header value:
|
|
10
|
+
* an explicit per-call `init.headers['X-Correlation-Id']` >
|
|
11
|
+
* this config value > the per-tool-call ALS id (`getCorrelationId()`) >
|
|
12
|
+
* a freshly minted UUID v4.
|
|
13
|
+
*/
|
|
14
|
+
correlationId?: string;
|
|
5
15
|
}
|
|
6
16
|
export declare class ApiClient {
|
|
7
17
|
private readonly baseUrl;
|
|
8
18
|
private readonly token;
|
|
19
|
+
private readonly correlationId?;
|
|
9
20
|
constructor(config: ApiClientConfig);
|
|
21
|
+
/**
|
|
22
|
+
* KI-096: optional `responseSchema` validates the response shape with
|
|
23
|
+
* zod. When supplied, drift between backend's actual response and the
|
|
24
|
+
* mcp-server's declared type fails LOUDLY with a `ZodError` (wrapped
|
|
25
|
+
* here in an Error with the path that drifted) instead of silently
|
|
26
|
+
* rendering `undefined` in tool formatters. Opt-in per call site so
|
|
27
|
+
* existing methods stay untouched until a sweep migrates them.
|
|
28
|
+
*/
|
|
10
29
|
private request;
|
|
11
30
|
getMe(): Promise<UserSummary>;
|
|
12
31
|
getTeam(teamId: number): Promise<Team>;
|
|
13
32
|
listEnrolledFiles(params?: {
|
|
14
33
|
search?: string;
|
|
34
|
+
matchIn?: 'name' | 'comments' | 'versions' | 'all';
|
|
15
35
|
}): Promise<EnrolledFile[]>;
|
|
16
36
|
getEnrolledFile(fileMsId: string): Promise<EnrolledFile>;
|
|
17
37
|
getFileVersions(fileMsId: string): Promise<FileVersion[]>;
|
|
18
38
|
getFileVersion(versionInternalId: number): Promise<FileVersion>;
|
|
39
|
+
/**
|
|
40
|
+
* KI-096: passes `?format=mcp` to opt into the backend's normalized
|
|
41
|
+
* projection `{versionId, value, changedBy, changedAt}` (added by
|
|
42
|
+
* backend PR #478). Default `format` (omitted) returns the raw CTE
|
|
43
|
+
* row shape the frontend cell-history popover consumes — we never
|
|
44
|
+
* call that path. Zod-parses the response so future drift between
|
|
45
|
+
* backend and mcp-server contracts fails loudly.
|
|
46
|
+
*/
|
|
19
47
|
getCellHistory(fileMsId: string, sheetName: string, cellAddress: string): Promise<CellHistoryEntry[]>;
|
|
20
48
|
getFileComments(fileMsId: string): Promise<FileChat[]>;
|
|
21
49
|
getComment(chatId: number): Promise<FileChat>;
|
|
@@ -29,6 +57,14 @@ export declare class ApiClient {
|
|
|
29
57
|
message: string;
|
|
30
58
|
versionInternalId: number;
|
|
31
59
|
}): Promise<FileChat>;
|
|
60
|
+
/**
|
|
61
|
+
* KI-096: zod-parses the response. Backend PR #478 fixed
|
|
62
|
+
* `PATCH /file-chat/:chatId` to return the updated entity (was
|
|
63
|
+
* UpdateResult) AND to persist `resolved` (was silently dropped).
|
|
64
|
+
* The schema check pins both fixes — if either regresses, the parse
|
|
65
|
+
* fails with a clear message instead of the formatter rendering
|
|
66
|
+
* `Comment undefined marked as resolved.`
|
|
67
|
+
*/
|
|
32
68
|
resolveComment(chatId: number): Promise<FileChat>;
|
|
33
69
|
getReviewsForVersion(versionId: number): Promise<ReviewRequest[]>;
|
|
34
70
|
getReviewsForLatestVersion(fileMsId: string): Promise<ReviewRequest[]>;
|
|
@@ -43,10 +79,28 @@ export declare class ApiClient {
|
|
|
43
79
|
approveReview(reviewId: number, body: {
|
|
44
80
|
notes?: string;
|
|
45
81
|
}): Promise<ReviewRequest>;
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
82
|
+
/**
|
|
83
|
+
* Sheet-filtered unattributed changes. Returns ALL rows for the given
|
|
84
|
+
* sheet on the file (no pagination — sheet filter inherently bounds
|
|
85
|
+
* result size). Use this when the caller already knows which sheet to
|
|
86
|
+
* inspect; use {@link getUnattributedChangesPaginated} for the file-wide
|
|
87
|
+
* view.
|
|
88
|
+
*/
|
|
89
|
+
getUnattributedChangesBySheet(fileMsId: string, sheetName: string): Promise<UnattributedChange[]>;
|
|
90
|
+
/**
|
|
91
|
+
* Cursor-paginated file-wide unattributed changes (KI-097).
|
|
92
|
+
*
|
|
93
|
+
* Hits the non-shadowable `GET /unattributed-changes/paginated/:fileMsId`
|
|
94
|
+
* route added by backend PR #475 (KI-102). The legacy `:fileMsId/v2`
|
|
95
|
+
* route is shadowed by `:fileMsId/:sheetName` route ordering and returns
|
|
96
|
+
* an empty array; do not call it from here.
|
|
97
|
+
*
|
|
98
|
+
* Pass `cursor` returned by a previous call to fetch the next page.
|
|
99
|
+
* Snapshot TTL is 30 minutes — older cursors cause the backend to return
|
|
100
|
+
* HTTP 410 GONE with `{ resyncRequired: { code: 'SNAPSHOT_EXPIRED' } }`,
|
|
101
|
+
* which surfaces here as a thrown RockhopperApiError.
|
|
102
|
+
*/
|
|
103
|
+
getUnattributedChangesPaginated(fileMsId: string, cursor?: string): Promise<PaginatedUnattributedResponse>;
|
|
50
104
|
createVersion(body: {
|
|
51
105
|
enrolledFileMsId: string;
|
|
52
106
|
version: {
|
|
@@ -60,6 +114,14 @@ export declare class ApiClient {
|
|
|
60
114
|
description: string;
|
|
61
115
|
}): Promise<FileVersion>;
|
|
62
116
|
cancelReview(reviewId: number): Promise<ReviewRequest>;
|
|
117
|
+
/**
|
|
118
|
+
* KI-096: zod-parses the response. Backend PR #478 fixed
|
|
119
|
+
* `PATCH /enrolled-files/:fileMsId` to return the updated entity
|
|
120
|
+
* (was UpdateResult typed as Promise<any>). The schema check pins
|
|
121
|
+
* the entity contract — if it regresses, the parse fails with a
|
|
122
|
+
* clear message instead of `rename_file` rendering
|
|
123
|
+
* `File renamed to 'undefined' (id: undefined).`
|
|
124
|
+
*/
|
|
63
125
|
updateEnrolledFile(fileMsId: string, body: {
|
|
64
126
|
name?: string;
|
|
65
127
|
}): Promise<EnrolledFile>;
|
package/dist/api-client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"api-client.d.ts","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"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"}
|
package/dist/api-client.js
CHANGED
|
@@ -1,25 +1,97 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { getCorrelationId } from './correlation.js';
|
|
3
|
+
import { log } from './logger.js';
|
|
4
|
+
import { CellHistoryEntryArraySchema, EnrolledFileSchema, FileChatSchema, } from './zod-schemas.js';
|
|
1
5
|
export class ApiClient {
|
|
2
6
|
baseUrl;
|
|
3
7
|
token;
|
|
8
|
+
correlationId;
|
|
4
9
|
constructor(config) {
|
|
5
10
|
this.baseUrl = config.baseUrl.replace(/\/+$/, '');
|
|
6
11
|
this.token = config.token;
|
|
12
|
+
this.correlationId = config.correlationId;
|
|
7
13
|
}
|
|
8
|
-
|
|
14
|
+
/**
|
|
15
|
+
* KI-096: optional `responseSchema` validates the response shape with
|
|
16
|
+
* zod. When supplied, drift between backend's actual response and the
|
|
17
|
+
* mcp-server's declared type fails LOUDLY with a `ZodError` (wrapped
|
|
18
|
+
* here in an Error with the path that drifted) instead of silently
|
|
19
|
+
* rendering `undefined` in tool formatters. Opt-in per call site so
|
|
20
|
+
* existing methods stay untouched until a sweep migrates them.
|
|
21
|
+
*/
|
|
22
|
+
async request(path, init, responseSchema) {
|
|
9
23
|
const url = `${this.baseUrl}${path}`;
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
24
|
+
// KI-225: log only the URL pathname (drop the query string) — query may
|
|
25
|
+
// carry search terms / cell refs; it never carries the token (header
|
|
26
|
+
// only), but it's not a safe field to persist.
|
|
27
|
+
const pathname = path.split('?')[0];
|
|
28
|
+
const method = (init?.method ?? 'GET').toUpperCase();
|
|
29
|
+
const start = Date.now();
|
|
30
|
+
let response;
|
|
31
|
+
try {
|
|
32
|
+
response = await fetch(url, {
|
|
33
|
+
...init,
|
|
34
|
+
headers: {
|
|
35
|
+
Authorization: `Bearer ${this.token}`,
|
|
36
|
+
'Content-Type': 'application/json',
|
|
37
|
+
// KI-226: trace this request in backend logs. Placed BEFORE the
|
|
38
|
+
// `...init?.headers` spread so a per-call header still wins but the
|
|
39
|
+
// id can't be dropped. Precedence: per-call > config > ALS > mint.
|
|
40
|
+
// Non-sensitive UUID — never co-logged with the bearer token above.
|
|
41
|
+
'X-Correlation-Id': this.correlationId ?? getCorrelationId() ?? randomUUID(),
|
|
42
|
+
...init?.headers,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
// KI-225: the can't-reach-the-API case — a thrown fetch is a network
|
|
48
|
+
// failure, the class of error that NEVER reaches the backend log.
|
|
49
|
+
log.error({ event: 'api_unreachable', method, path: pathname, durationMs: Date.now() - start, err }, 'api_unreachable');
|
|
50
|
+
throw err;
|
|
51
|
+
}
|
|
52
|
+
const durationMs = Date.now() - start;
|
|
18
53
|
if (!response.ok) {
|
|
54
|
+
// KI-225: classify auth rejections (401/403) so they're greppable
|
|
55
|
+
// separately from generic HTTP errors.
|
|
56
|
+
const classification = response.status === 401 || response.status === 403
|
|
57
|
+
? 'auth_failed'
|
|
58
|
+
: 'http_error';
|
|
59
|
+
log.warn({
|
|
60
|
+
event: 'api_request_failed',
|
|
61
|
+
method,
|
|
62
|
+
path: pathname,
|
|
63
|
+
status: response.status,
|
|
64
|
+
durationMs,
|
|
65
|
+
classification,
|
|
66
|
+
}, 'api_request_failed');
|
|
19
67
|
const body = await response.text().catch(() => '');
|
|
20
68
|
throw new Error(`Rockhopper API ${response.status}: ${response.statusText} — ${body}`);
|
|
21
69
|
}
|
|
22
|
-
|
|
70
|
+
log.info({ event: 'api_request', method, path: pathname, status: response.status, durationMs }, 'api_request');
|
|
71
|
+
const json = await response.json();
|
|
72
|
+
if (responseSchema) {
|
|
73
|
+
const parsed = responseSchema.safeParse(json);
|
|
74
|
+
if (!parsed.success) {
|
|
75
|
+
// Surface a useful diagnostic — the formatter would otherwise show
|
|
76
|
+
// `undefined`, hiding the contract break. Include the path of the
|
|
77
|
+
// first issue so the cause is obvious from the error message.
|
|
78
|
+
const first = parsed.error.issues[0];
|
|
79
|
+
// KI-225: schema drift is a client-side detection the backend can't
|
|
80
|
+
// see. Log the issue path + message ONLY — never the raw payload
|
|
81
|
+
// (`json`), which may contain file/cell data.
|
|
82
|
+
log.warn({
|
|
83
|
+
event: 'schema_validation_failed',
|
|
84
|
+
endpoint: pathname,
|
|
85
|
+
issue: first?.path.join('.') || '<root>',
|
|
86
|
+
err: first?.message,
|
|
87
|
+
}, 'schema_validation_failed');
|
|
88
|
+
throw new Error(`Rockhopper API response failed schema check at ${path}: ` +
|
|
89
|
+
`${first?.path.join('.') || '<root>'} — ${first?.message} ` +
|
|
90
|
+
`(${parsed.error.issues.length} issue(s) total)`);
|
|
91
|
+
}
|
|
92
|
+
return parsed.data;
|
|
93
|
+
}
|
|
94
|
+
return json;
|
|
23
95
|
}
|
|
24
96
|
// --- Users ---
|
|
25
97
|
async getMe() {
|
|
@@ -34,6 +106,8 @@ export class ApiClient {
|
|
|
34
106
|
const query = new URLSearchParams();
|
|
35
107
|
if (params?.search)
|
|
36
108
|
query.set('search', params.search);
|
|
109
|
+
if (params?.matchIn)
|
|
110
|
+
query.set('matchIn', params.matchIn);
|
|
37
111
|
const qs = query.toString();
|
|
38
112
|
return this.request(`/enrolled-files${qs ? `?${qs}` : ''}`);
|
|
39
113
|
}
|
|
@@ -47,9 +121,21 @@ export class ApiClient {
|
|
|
47
121
|
async getFileVersion(versionInternalId) {
|
|
48
122
|
return this.request(`/file-versions/file/version/${versionInternalId}`);
|
|
49
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* KI-096: passes `?format=mcp` to opt into the backend's normalized
|
|
126
|
+
* projection `{versionId, value, changedBy, changedAt}` (added by
|
|
127
|
+
* backend PR #478). Default `format` (omitted) returns the raw CTE
|
|
128
|
+
* row shape the frontend cell-history popover consumes — we never
|
|
129
|
+
* call that path. Zod-parses the response so future drift between
|
|
130
|
+
* backend and mcp-server contracts fails loudly.
|
|
131
|
+
*/
|
|
50
132
|
async getCellHistory(fileMsId, sheetName, cellAddress) {
|
|
51
|
-
const query = new URLSearchParams({
|
|
52
|
-
|
|
133
|
+
const query = new URLSearchParams({
|
|
134
|
+
cell: cellAddress,
|
|
135
|
+
sheetName,
|
|
136
|
+
format: 'mcp',
|
|
137
|
+
});
|
|
138
|
+
return this.request(`/file-versions/file/${fileMsId}/cell-history?${query}`, undefined, CellHistoryEntryArraySchema);
|
|
53
139
|
}
|
|
54
140
|
// --- File Chat (Comments) ---
|
|
55
141
|
async getFileComments(fileMsId) {
|
|
@@ -70,11 +156,19 @@ export class ApiClient {
|
|
|
70
156
|
body: JSON.stringify(body),
|
|
71
157
|
});
|
|
72
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* KI-096: zod-parses the response. Backend PR #478 fixed
|
|
161
|
+
* `PATCH /file-chat/:chatId` to return the updated entity (was
|
|
162
|
+
* UpdateResult) AND to persist `resolved` (was silently dropped).
|
|
163
|
+
* The schema check pins both fixes — if either regresses, the parse
|
|
164
|
+
* fails with a clear message instead of the formatter rendering
|
|
165
|
+
* `Comment undefined marked as resolved.`
|
|
166
|
+
*/
|
|
73
167
|
async resolveComment(chatId) {
|
|
74
168
|
return this.request(`/file-chat/${chatId}`, {
|
|
75
169
|
method: 'PATCH',
|
|
76
170
|
body: JSON.stringify({ resolved: true }),
|
|
77
|
-
});
|
|
171
|
+
}, FileChatSchema);
|
|
78
172
|
}
|
|
79
173
|
// --- Reviews ---
|
|
80
174
|
async getReviewsForVersion(versionId) {
|
|
@@ -102,11 +196,33 @@ export class ApiClient {
|
|
|
102
196
|
});
|
|
103
197
|
}
|
|
104
198
|
// --- Unattributed Changes ---
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
199
|
+
/**
|
|
200
|
+
* Sheet-filtered unattributed changes. Returns ALL rows for the given
|
|
201
|
+
* sheet on the file (no pagination — sheet filter inherently bounds
|
|
202
|
+
* result size). Use this when the caller already knows which sheet to
|
|
203
|
+
* inspect; use {@link getUnattributedChangesPaginated} for the file-wide
|
|
204
|
+
* view.
|
|
205
|
+
*/
|
|
206
|
+
async getUnattributedChangesBySheet(fileMsId, sheetName) {
|
|
207
|
+
const path = `/unattributed-changes/${fileMsId}/${encodeURIComponent(sheetName)}`;
|
|
208
|
+
return this.request(path);
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Cursor-paginated file-wide unattributed changes (KI-097).
|
|
212
|
+
*
|
|
213
|
+
* Hits the non-shadowable `GET /unattributed-changes/paginated/:fileMsId`
|
|
214
|
+
* route added by backend PR #475 (KI-102). The legacy `:fileMsId/v2`
|
|
215
|
+
* route is shadowed by `:fileMsId/:sheetName` route ordering and returns
|
|
216
|
+
* an empty array; do not call it from here.
|
|
217
|
+
*
|
|
218
|
+
* Pass `cursor` returned by a previous call to fetch the next page.
|
|
219
|
+
* Snapshot TTL is 30 minutes — older cursors cause the backend to return
|
|
220
|
+
* HTTP 410 GONE with `{ resyncRequired: { code: 'SNAPSHOT_EXPIRED' } }`,
|
|
221
|
+
* which surfaces here as a thrown RockhopperApiError.
|
|
222
|
+
*/
|
|
223
|
+
async getUnattributedChangesPaginated(fileMsId, cursor) {
|
|
224
|
+
const qs = cursor ? `?cursor=${encodeURIComponent(cursor)}` : '';
|
|
225
|
+
const path = `/unattributed-changes/paginated/${fileMsId}${qs}`;
|
|
110
226
|
return this.request(path);
|
|
111
227
|
}
|
|
112
228
|
// --- Version lifecycle ---
|
|
@@ -130,11 +246,19 @@ export class ApiClient {
|
|
|
130
246
|
});
|
|
131
247
|
}
|
|
132
248
|
// --- File metadata update ---
|
|
249
|
+
/**
|
|
250
|
+
* KI-096: zod-parses the response. Backend PR #478 fixed
|
|
251
|
+
* `PATCH /enrolled-files/:fileMsId` to return the updated entity
|
|
252
|
+
* (was UpdateResult typed as Promise<any>). The schema check pins
|
|
253
|
+
* the entity contract — if it regresses, the parse fails with a
|
|
254
|
+
* clear message instead of `rename_file` rendering
|
|
255
|
+
* `File renamed to 'undefined' (id: undefined).`
|
|
256
|
+
*/
|
|
133
257
|
async updateEnrolledFile(fileMsId, body) {
|
|
134
258
|
return this.request(`/enrolled-files/${fileMsId}`, {
|
|
135
259
|
method: 'PATCH',
|
|
136
260
|
body: JSON.stringify(body),
|
|
137
|
-
});
|
|
261
|
+
}, EnrolledFileSchema);
|
|
138
262
|
}
|
|
139
263
|
}
|
|
140
264
|
//# sourceMappingURL=api-client.js.map
|
package/dist/api-client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"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"}
|