@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/dist/cli.js
CHANGED
|
@@ -1,22 +1,67 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
3
3
|
import { ApiClient } from './api-client.js';
|
|
4
|
+
import { AuthResolutionError, resolveAuth, } from './auth/resolve-auth.js';
|
|
5
|
+
import { flushLoggerSync, initLogger, log, serviceVersion, } from './logger.js';
|
|
4
6
|
import { createServer } from './server.js';
|
|
5
7
|
const ROCKHOPPER_API_URL = process.env.ROCKHOPPER_API_URL || 'https://api.rockhopper.co';
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
// KI-225: start the local rotating diagnostic logfile before anything else,
|
|
9
|
+
// so startup-path failures (auth, preflight, crashes) are captured. Never
|
|
10
|
+
// throws and never writes to stdout — falls back to a no-op logger.
|
|
11
|
+
await initLogger();
|
|
12
|
+
// Capture client-side crashes that would otherwise vanish (the backend can't
|
|
13
|
+
// see them). Registering these handlers suppresses Node's default crash, so
|
|
14
|
+
// uncaughtException re-exits 1 to PRESERVE the existing exit behavior; the
|
|
15
|
+
// fatal line is flushed to disk synchronously first.
|
|
16
|
+
process.on('uncaughtException', (err) => {
|
|
17
|
+
log.fatal({ event: 'uncaught_exception', err }, 'uncaught_exception');
|
|
18
|
+
flushLoggerSync();
|
|
19
|
+
process.exit(1);
|
|
20
|
+
});
|
|
21
|
+
process.on('unhandledRejection', (reason) => {
|
|
22
|
+
log.error({ event: 'unhandled_rejection', err: reason }, 'unhandled_rejection');
|
|
23
|
+
});
|
|
24
|
+
// ENG-1444: auth resolution order is
|
|
25
|
+
// 1. ROCKHOPPER_TOKEN env var (Personal Access Token — headless / CI)
|
|
26
|
+
// 2. Stored OAuth bundle in the OS keychain (prior device-grant flow)
|
|
27
|
+
// 3. Device-grant flow (prints code to stderr, polls for approval)
|
|
28
|
+
let resolved;
|
|
29
|
+
try {
|
|
30
|
+
resolved = await resolveAuth({
|
|
31
|
+
baseUrl: ROCKHOPPER_API_URL,
|
|
32
|
+
patFromEnv: process.env.ROCKHOPPER_TOKEN,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
catch (err) {
|
|
36
|
+
if (err instanceof AuthResolutionError) {
|
|
37
|
+
// KI-225: local auth failure before any API call (bad token / sign-in).
|
|
38
|
+
log.warn({ event: 'auth_failed', reason: err.code }, 'auth_failed');
|
|
39
|
+
if (err.code === 'pat_malformed') {
|
|
40
|
+
console.error(`Error: ${err.message}`);
|
|
41
|
+
console.error('Tokens start with "rh_pat_". Check that the full token was copied correctly.');
|
|
42
|
+
}
|
|
43
|
+
else if (err.code === 'device_grant_failed') {
|
|
44
|
+
console.error(`Error: Could not complete sign-in.\n${err.message}`);
|
|
45
|
+
console.error('You can also set ROCKHOPPER_TOKEN to a Personal Access Token (Settings → Personal Access Tokens) and re-launch.');
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
console.error(`Error: ${err.message}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
53
|
+
}
|
|
10
54
|
process.exit(1);
|
|
11
55
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
56
|
+
// Every catch branch above ends in `process.exit(1)`, so `resolved` is always
|
|
57
|
+
// assigned past this point. TS 6.0's stricter control-flow analysis can't prove
|
|
58
|
+
// that across the implicit-typed `let`, so narrow it explicitly here.
|
|
59
|
+
if (!resolved) {
|
|
15
60
|
process.exit(1);
|
|
16
61
|
}
|
|
17
62
|
const apiClient = new ApiClient({
|
|
18
63
|
baseUrl: ROCKHOPPER_API_URL,
|
|
19
|
-
token:
|
|
64
|
+
token: resolved.accessToken,
|
|
20
65
|
});
|
|
21
66
|
try {
|
|
22
67
|
await apiClient.getMe();
|
|
@@ -24,8 +69,19 @@ try {
|
|
|
24
69
|
catch (err) {
|
|
25
70
|
const msg = err instanceof Error ? err.message : String(err);
|
|
26
71
|
if (msg.includes('401') || msg.includes('403')) {
|
|
27
|
-
|
|
28
|
-
|
|
72
|
+
// KI-225: preflight token rejection — the local auth-fail signal.
|
|
73
|
+
log.warn({
|
|
74
|
+
event: 'auth_failed',
|
|
75
|
+
reason: resolved.source === 'pat' ? 'pat_invalid' : 'oauth_invalid',
|
|
76
|
+
}, 'auth_failed');
|
|
77
|
+
if (resolved.source === 'pat') {
|
|
78
|
+
console.error('Error: ROCKHOPPER_TOKEN is invalid or expired.\n' +
|
|
79
|
+
'Create a new Personal Access Token in Rockhopper Settings and set it as ROCKHOPPER_TOKEN.');
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
console.error(`Error: Stored OAuth token is invalid (source: ${resolved.source}).\n` +
|
|
83
|
+
'Re-launch the MCP server — it will run the device-grant flow again.');
|
|
84
|
+
}
|
|
29
85
|
}
|
|
30
86
|
else {
|
|
31
87
|
console.error(`Error: Could not reach Rockhopper API at ${ROCKHOPPER_API_URL}.\n` +
|
|
@@ -34,6 +90,8 @@ catch (err) {
|
|
|
34
90
|
process.exit(1);
|
|
35
91
|
}
|
|
36
92
|
const server = createServer(apiClient);
|
|
93
|
+
// KI-225: one line per launch — anchors a session in the file.
|
|
94
|
+
log.info({ event: 'mcp_server_start', version: serviceVersion }, 'mcp_server_start');
|
|
37
95
|
const transport = new StdioServerTransport();
|
|
38
96
|
await server.connect(transport);
|
|
39
97
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,kBAAkB,GACtB,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runs `fn` inside an AsyncLocalStorage scope carrying `id`. Reads via
|
|
3
|
+
* {@link getCorrelationId} anywhere in the (sync or async) continuation
|
|
4
|
+
* return the same id. Mints a fresh UUID v4 when `id` is omitted.
|
|
5
|
+
*/
|
|
6
|
+
export declare const runWithCorrelationId: <T>(fn: () => T, id?: string) => T;
|
|
7
|
+
/** Current correlation id, or `undefined` when called outside a scope. */
|
|
8
|
+
export declare const getCorrelationId: () => string | undefined;
|
|
9
|
+
//# sourceMappingURL=correlation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"correlation.d.ts","sourceRoot":"","sources":["../src/correlation.ts"],"names":[],"mappings":"AAmBA;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAAI,CAAC,EACpC,IAAI,MAAM,CAAC,EACX,KAAI,MAAqB,KACxB,CAAoB,CAAC;AAExB,0EAA0E;AAC1E,eAAO,MAAM,gBAAgB,QAAO,MAAM,GAAG,SAA2B,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
/**
|
|
4
|
+
* Phase 1.1 / KI-226 — correlation id propagation.
|
|
5
|
+
*
|
|
6
|
+
* Per-tool-call scope: a single correlation id covers every outbound
|
|
7
|
+
* Rockhopper API call a tool invocation makes (including multi-call
|
|
8
|
+
* fan-outs like search). The id rides the `X-Correlation-Id` header out of
|
|
9
|
+
* {@link ApiClient.request}, so an mcp-server-originated request is
|
|
10
|
+
* traceable as a group in backend logs.
|
|
11
|
+
*
|
|
12
|
+
* The id is a non-sensitive UUID v4 — never co-log the bearer token with it.
|
|
13
|
+
* `randomUUID` comes from `node:crypto` (NOT the global `crypto`) because the
|
|
14
|
+
* package supports Node 18, where global `crypto.randomUUID` is not
|
|
15
|
+
* guaranteed.
|
|
16
|
+
*/
|
|
17
|
+
const als = new AsyncLocalStorage();
|
|
18
|
+
/**
|
|
19
|
+
* Runs `fn` inside an AsyncLocalStorage scope carrying `id`. Reads via
|
|
20
|
+
* {@link getCorrelationId} anywhere in the (sync or async) continuation
|
|
21
|
+
* return the same id. Mints a fresh UUID v4 when `id` is omitted.
|
|
22
|
+
*/
|
|
23
|
+
export const runWithCorrelationId = (fn, id = randomUUID()) => als.run(id, fn);
|
|
24
|
+
/** Current correlation id, or `undefined` when called outside a scope. */
|
|
25
|
+
export const getCorrelationId = () => als.getStore();
|
|
26
|
+
//# sourceMappingURL=correlation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"correlation.js","sourceRoot":"","sources":["../src/correlation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC;;;;;;;;;;;;;GAaG;AACH,MAAM,GAAG,GAAG,IAAI,iBAAiB,EAAU,CAAC;AAE5C;;;;GAIG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAClC,EAAW,EACX,KAAa,UAAU,EAAE,EACtB,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;AAExB,0EAA0E;AAC1E,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAuB,EAAE,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import pino from 'pino';
|
|
2
|
+
import pinoRoll from 'pino-roll';
|
|
3
|
+
/** The 5 log methods we expose. A real `pino.Logger` satisfies this. */
|
|
4
|
+
export interface DiagnosticLogger {
|
|
5
|
+
debug: pino.LogFn;
|
|
6
|
+
info: pino.LogFn;
|
|
7
|
+
warn: pino.LogFn;
|
|
8
|
+
error: pino.LogFn;
|
|
9
|
+
fatal: pino.LogFn;
|
|
10
|
+
}
|
|
11
|
+
export declare const serviceVersion: string;
|
|
12
|
+
/**
|
|
13
|
+
* Builds a file-only diagnostic logger. NEVER throws and NEVER writes to
|
|
14
|
+
* stdout — on opt-out or any failure it returns a no-op logger. Exposed
|
|
15
|
+
* (vs. only the {@link log} singleton) so tests can drive an isolated
|
|
16
|
+
* instance pointed at a tmpdir.
|
|
17
|
+
*/
|
|
18
|
+
export declare function createDiagnosticLogger(opts?: {
|
|
19
|
+
dir?: string;
|
|
20
|
+
disable?: boolean;
|
|
21
|
+
level?: string;
|
|
22
|
+
}): Promise<{
|
|
23
|
+
logger: DiagnosticLogger;
|
|
24
|
+
flush: () => Promise<void>;
|
|
25
|
+
destination?: Awaited<ReturnType<typeof pinoRoll>>;
|
|
26
|
+
}>;
|
|
27
|
+
/**
|
|
28
|
+
* Process-wide singleton. Starts as a no-op (so importing this module —
|
|
29
|
+
* including from the library entry / mcp-gateway — has no side effect and
|
|
30
|
+
* opens no file) and is swapped to the real file logger by
|
|
31
|
+
* {@link initLogger}, which the stdio CLI calls at startup.
|
|
32
|
+
*/
|
|
33
|
+
export declare let log: DiagnosticLogger;
|
|
34
|
+
/** Idempotently constructs the singleton from env config. Never rejects. */
|
|
35
|
+
export declare function initLogger(): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Best-effort synchronous flush — for the crash path, where the last
|
|
38
|
+
* `fatal` line must hit disk before {@link process.exit}. No-op when the
|
|
39
|
+
* logger is disabled / not yet ready.
|
|
40
|
+
*/
|
|
41
|
+
export declare function flushLoggerSync(): void;
|
|
42
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AA2BA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,QAAQ,MAAM,WAAW,CAAC;AAGjC,wEAAwE;AACxE,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC;IAClB,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC;IACjB,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC;IACjB,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC;IAClB,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC;CACnB;AA0BD,eAAO,MAAM,cAAc,QAAkB,CAAC;AAuB9C;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAC7D,OAAO,CAAC;IACT,MAAM,EAAE,gBAAgB,CAAC;IACzB,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,WAAW,CAAC,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC,CAAC;CACpD,CAAC,CAmDD;AAED;;;;;GAKG;AACH,eAAO,IAAI,GAAG,EAAE,gBAA6B,CAAC;AAK9C,4EAA4E;AAC5E,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAQhD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAMtC"}
|
package/dist/logger.js
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 1.5 / KI-225 — local, rotating diagnostic logfile.
|
|
3
|
+
*
|
|
4
|
+
* Why this exists: the backend already logs everything that *reaches* the
|
|
5
|
+
* API. The unique value of a client-side log is the failures that NEVER
|
|
6
|
+
* reach the backend (network-unreachable, local auth rejection, schema
|
|
7
|
+
* drift, uncaught crashes) plus a local request-latency view. The file is
|
|
8
|
+
* the customer's to keep and hand to support — there is NO remote
|
|
9
|
+
* transmission.
|
|
10
|
+
*
|
|
11
|
+
* 🚨 HARD CONSTRAINT — stdout is the MCP stdio transport. Logs MUST go to
|
|
12
|
+
* the FILE ONLY, never stdout. We therefore:
|
|
13
|
+
* - build pino against a {@link pino-roll} Sonic-boom file destination
|
|
14
|
+
* (NOT pino's default stdout destination, NOT a worker transport), and
|
|
15
|
+
* - fall back to a NO-OP logger on ANY construction failure — never
|
|
16
|
+
* crash the server, never write to stdout.
|
|
17
|
+
*
|
|
18
|
+
* Redaction (SOC2-adjacent, runs on customer machines): callers must only
|
|
19
|
+
* ever pass safe fields — event, method, URL pathname (no query/token),
|
|
20
|
+
* status, durationMs, tool name, correlationId, version, error
|
|
21
|
+
* type/message. Never tokens, Authorization headers, request/response
|
|
22
|
+
* bodies, tool arguments, file contents, or cell data.
|
|
23
|
+
*/
|
|
24
|
+
import fs from 'node:fs';
|
|
25
|
+
import { createRequire } from 'node:module';
|
|
26
|
+
import os from 'node:os';
|
|
27
|
+
import path from 'node:path';
|
|
28
|
+
import pino from 'pino';
|
|
29
|
+
import pinoRoll from 'pino-roll';
|
|
30
|
+
import { getCorrelationId } from './correlation.js';
|
|
31
|
+
const SERVICE_NAME = 'mcp-server';
|
|
32
|
+
const LOG_FILE_BASENAME = 'mcp-server.log';
|
|
33
|
+
const LOG_MAX_SIZE = '5m';
|
|
34
|
+
const LOG_FILE_COUNT = 5;
|
|
35
|
+
const DEFAULT_LOG_DIR = path.join(os.homedir(), '.rockhopper', 'mcp-server');
|
|
36
|
+
const VALID_LEVELS = new Set([
|
|
37
|
+
'fatal',
|
|
38
|
+
'error',
|
|
39
|
+
'warn',
|
|
40
|
+
'info',
|
|
41
|
+
'debug',
|
|
42
|
+
'trace',
|
|
43
|
+
'silent',
|
|
44
|
+
]);
|
|
45
|
+
/** Package version stamped into every line's `base`. Best-effort read. */
|
|
46
|
+
const requireJson = createRequire(import.meta.url);
|
|
47
|
+
let resolvedVersion = '0.0.0';
|
|
48
|
+
try {
|
|
49
|
+
const pkg = requireJson('../package.json');
|
|
50
|
+
if (pkg.version)
|
|
51
|
+
resolvedVersion = pkg.version;
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// package.json unreadable — keep the sentinel; never crash over a version.
|
|
55
|
+
}
|
|
56
|
+
export const serviceVersion = resolvedVersion;
|
|
57
|
+
/** Shared no-op so disabled/failed logging is a single cheap call site. */
|
|
58
|
+
const noopFn = () => { };
|
|
59
|
+
const noopLogger = {
|
|
60
|
+
debug: noopFn,
|
|
61
|
+
info: noopFn,
|
|
62
|
+
warn: noopFn,
|
|
63
|
+
error: noopFn,
|
|
64
|
+
fatal: noopFn,
|
|
65
|
+
};
|
|
66
|
+
function isTruthyEnv(value) {
|
|
67
|
+
if (!value)
|
|
68
|
+
return false;
|
|
69
|
+
const v = value.trim().toLowerCase();
|
|
70
|
+
return v !== '' && v !== '0' && v !== 'false' && v !== 'no';
|
|
71
|
+
}
|
|
72
|
+
function normalizeLevel(level) {
|
|
73
|
+
const v = level?.trim().toLowerCase();
|
|
74
|
+
return v && VALID_LEVELS.has(v) ? v : 'info';
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Builds a file-only diagnostic logger. NEVER throws and NEVER writes to
|
|
78
|
+
* stdout — on opt-out or any failure it returns a no-op logger. Exposed
|
|
79
|
+
* (vs. only the {@link log} singleton) so tests can drive an isolated
|
|
80
|
+
* instance pointed at a tmpdir.
|
|
81
|
+
*/
|
|
82
|
+
export async function createDiagnosticLogger(opts = {}) {
|
|
83
|
+
const disable = opts.disable ?? isTruthyEnv(process.env.ROCKHOPPER_MCP_LOG_DISABLE);
|
|
84
|
+
if (disable) {
|
|
85
|
+
return { logger: noopLogger, flush: async () => { } };
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
const envDir = process.env.ROCKHOPPER_MCP_LOG_DIR?.trim();
|
|
89
|
+
const dir = opts.dir ?? (envDir && envDir.length ? envDir : DEFAULT_LOG_DIR);
|
|
90
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
91
|
+
const destination = await pinoRoll({
|
|
92
|
+
file: path.join(dir, LOG_FILE_BASENAME),
|
|
93
|
+
size: LOG_MAX_SIZE,
|
|
94
|
+
limit: { count: LOG_FILE_COUNT },
|
|
95
|
+
mkdir: true,
|
|
96
|
+
});
|
|
97
|
+
// A logging IO error must never crash the server (or escape as an
|
|
98
|
+
// unhandled 'error' event). Swallow it — diagnostics are best-effort.
|
|
99
|
+
destination.on('error', () => { });
|
|
100
|
+
const logger = pino({
|
|
101
|
+
level: normalizeLevel(opts.level ?? process.env.ROCKHOPPER_MCP_LOG_LEVEL),
|
|
102
|
+
base: { service: SERVICE_NAME, version: serviceVersion },
|
|
103
|
+
serializers: { err: pino.stdSerializers.err },
|
|
104
|
+
// Every line auto-carries the per-tool-call correlationId (Phase 1.1
|
|
105
|
+
// ALS scope) when one is active — no call site has to thread it.
|
|
106
|
+
mixin() {
|
|
107
|
+
const id = getCorrelationId();
|
|
108
|
+
return id ? { correlationId: id } : {};
|
|
109
|
+
},
|
|
110
|
+
}, destination);
|
|
111
|
+
const flush = () => new Promise((resolve) => {
|
|
112
|
+
try {
|
|
113
|
+
destination.flush(() => resolve());
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
resolve();
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
return { logger, flush, destination };
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
// fs / pino-roll / pino failure — degrade to no-op, never to stdout.
|
|
123
|
+
return { logger: noopLogger, flush: async () => { } };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Process-wide singleton. Starts as a no-op (so importing this module —
|
|
128
|
+
* including from the library entry / mcp-gateway — has no side effect and
|
|
129
|
+
* opens no file) and is swapped to the real file logger by
|
|
130
|
+
* {@link initLogger}, which the stdio CLI calls at startup.
|
|
131
|
+
*/
|
|
132
|
+
export let log = noopLogger;
|
|
133
|
+
let activeDestination;
|
|
134
|
+
let initPromise;
|
|
135
|
+
/** Idempotently constructs the singleton from env config. Never rejects. */
|
|
136
|
+
export async function initLogger() {
|
|
137
|
+
if (initPromise)
|
|
138
|
+
return initPromise;
|
|
139
|
+
initPromise = (async () => {
|
|
140
|
+
const built = await createDiagnosticLogger();
|
|
141
|
+
log = built.logger;
|
|
142
|
+
activeDestination = built.destination;
|
|
143
|
+
})();
|
|
144
|
+
return initPromise;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Best-effort synchronous flush — for the crash path, where the last
|
|
148
|
+
* `fatal` line must hit disk before {@link process.exit}. No-op when the
|
|
149
|
+
* logger is disabled / not yet ready.
|
|
150
|
+
*/
|
|
151
|
+
export function flushLoggerSync() {
|
|
152
|
+
try {
|
|
153
|
+
activeDestination?.flushSync();
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
// Stream not ready or already closed — nothing more we can do pre-exit.
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAElD,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAElD,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,GAAG,IAAI,CAuNvE"}
|
package/dist/prompts/index.js
CHANGED
|
@@ -7,17 +7,20 @@ export function registerPrompts(server, api) {
|
|
|
7
7
|
fileMsId: z.string().describe('Platform ID of the enrolled file'),
|
|
8
8
|
},
|
|
9
9
|
}, async ({ fileMsId }) => {
|
|
10
|
-
const [file, versions,
|
|
10
|
+
const [file, versions, changesPage] = await Promise.all([
|
|
11
11
|
api.getEnrolledFile(fileMsId),
|
|
12
12
|
api.getFileVersions(fileMsId),
|
|
13
|
-
|
|
13
|
+
// KI-097: switched to cursor-paginated route. Top-of-prompt summary
|
|
14
|
+
// uses `totalCount` for the full file count; the per-cell preview
|
|
15
|
+
// uses up to 20 rows from this first page (sufficient for a recap).
|
|
16
|
+
api.getUnattributedChangesPaginated(fileMsId),
|
|
14
17
|
]);
|
|
15
18
|
const recentVersions = versions.slice(0, 5);
|
|
16
19
|
const versionSummary = recentVersions
|
|
17
20
|
.map((v) => `- v${v.majorVersion}.${v.minorVersion}.${v.patchVersion}: ${v.description || 'No description'} (${v.createdAt})`)
|
|
18
21
|
.join('\n');
|
|
19
|
-
const changeSummary = changes.length
|
|
20
|
-
? changes
|
|
22
|
+
const changeSummary = changesPage.changes.length
|
|
23
|
+
? changesPage.changes
|
|
21
24
|
.slice(0, 20)
|
|
22
25
|
.map((c) => `- ${c.sheetName}!${c.cellAddress}: ${JSON.stringify(c.oldValue)} → ${JSON.stringify(c.newValue)}`)
|
|
23
26
|
.join('\n')
|
|
@@ -30,7 +33,7 @@ export function registerPrompts(server, api) {
|
|
|
30
33
|
type: 'text',
|
|
31
34
|
text: `Summarize the recent activity on the file "${file.name}".\n\n` +
|
|
32
35
|
`## Recent Versions (last ${recentVersions.length} of ${versions.length})\n${versionSummary}\n\n` +
|
|
33
|
-
`## Unattributed Changes (${
|
|
36
|
+
`## Unattributed Changes (${changesPage.totalCount} total)\n${changeSummary}\n\n` +
|
|
34
37
|
`Provide a concise summary of what has changed recently, who made changes, and any notable patterns.`,
|
|
35
38
|
},
|
|
36
39
|
},
|
|
@@ -115,11 +118,14 @@ export function registerPrompts(server, api) {
|
|
|
115
118
|
fileMsId: z.string().describe('Platform ID of the enrolled file'),
|
|
116
119
|
},
|
|
117
120
|
}, async ({ fileMsId }) => {
|
|
118
|
-
const [file, versions, comments,
|
|
121
|
+
const [file, versions, comments, changesPage] = await Promise.all([
|
|
119
122
|
api.getEnrolledFile(fileMsId),
|
|
120
123
|
api.getFileVersions(fileMsId),
|
|
121
124
|
api.getFileComments(fileMsId),
|
|
122
|
-
|
|
125
|
+
// KI-097: switched to cursor-paginated route. The file-overview
|
|
126
|
+
// prompt only displays a total count, so we use `totalCount` from
|
|
127
|
+
// the first page — no need to fetch every row.
|
|
128
|
+
api.getUnattributedChangesPaginated(fileMsId),
|
|
123
129
|
]);
|
|
124
130
|
const latestVersion = versions[0];
|
|
125
131
|
let reviews = [];
|
|
@@ -127,7 +133,12 @@ export function registerPrompts(server, api) {
|
|
|
127
133
|
reviews = await api.getReviewsForVersion(latestVersion.internalId);
|
|
128
134
|
}
|
|
129
135
|
const unresolvedComments = comments.filter((c) => !c.resolved);
|
|
130
|
-
|
|
136
|
+
// Backend's ReviewRequestStatus enum is uppercase (PENDING/APPROVED/CANCELLED).
|
|
137
|
+
// Prior code compared against lowercase 'approved' and a nonexistent 'rejected',
|
|
138
|
+
// so APPROVED + CANCELLED reviews were silently classified as pending (sibling
|
|
139
|
+
// of KI-099). Match positive intent — "pending = PENDING" — with defensive
|
|
140
|
+
// .toUpperCase() so the check survives future backend casing flips.
|
|
141
|
+
const pendingReviews = reviews.filter((r) => r.status?.toUpperCase() === 'PENDING');
|
|
131
142
|
return {
|
|
132
143
|
messages: [
|
|
133
144
|
{
|
|
@@ -145,7 +156,7 @@ export function registerPrompts(server, api) {
|
|
|
145
156
|
: 'No versions yet.\n') +
|
|
146
157
|
`\n## Comments: ${comments.length} total, ${unresolvedComments.length} unresolved\n` +
|
|
147
158
|
`## Reviews: ${reviews.length} total, ${pendingReviews.length} pending\n` +
|
|
148
|
-
`## Unattributed Changes: ${
|
|
159
|
+
`## Unattributed Changes: ${changesPage.totalCount}\n\n` +
|
|
149
160
|
`Provide a status report highlighting anything that needs attention.`,
|
|
150
161
|
},
|
|
151
162
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,MAAM,UAAU,eAAe,CAAC,MAAiB,EAAE,GAAc;IAC/D,MAAM,CAAC,cAAc,CACnB,wBAAwB,EACxB;QACE,KAAK,EAAE,0BAA0B;QACjC,WAAW,EACT,+EAA+E;QACjF,UAAU,EAAE;YACV,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;SAClE;KACF,EACD,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QACrB,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"changes.d.ts","sourceRoot":"","sources":["../../src/resources/changes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAElD,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,SAAS,GACb,IAAI,
|
|
1
|
+
{"version":3,"file":"changes.d.ts","sourceRoot":"","sources":["../../src/resources/changes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAElD,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,SAAS,GACb,IAAI,CAoCN"}
|
|
@@ -10,13 +10,19 @@ export function registerChangeResources(server, api) {
|
|
|
10
10
|
description: 'Pending cell-level changes not yet attributed to a version for a file',
|
|
11
11
|
mimeType: 'application/json',
|
|
12
12
|
}, async (uri, { fileMsId }) => {
|
|
13
|
-
|
|
13
|
+
// KI-097: switched to cursor-paginated route. Resource returns the
|
|
14
|
+
// full envelope (`{changes, nextCursor, totalCount, snapshotId, ...}`)
|
|
15
|
+
// so consumers can paginate by re-reading the resource with a
|
|
16
|
+
// different cursor — though most clients will treat this as a
|
|
17
|
+
// single read. Resource shape is now the paginated envelope, not
|
|
18
|
+
// a bare array.
|
|
19
|
+
const page = await api.getUnattributedChangesPaginated(fileMsId);
|
|
14
20
|
return {
|
|
15
21
|
contents: [
|
|
16
22
|
{
|
|
17
23
|
uri: uri.href,
|
|
18
24
|
mimeType: 'application/json',
|
|
19
|
-
text: JSON.stringify(
|
|
25
|
+
text: JSON.stringify(page, null, 2),
|
|
20
26
|
},
|
|
21
27
|
],
|
|
22
28
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"changes.js","sourceRoot":"","sources":["../../src/resources/changes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAI3E,MAAM,UAAU,uBAAuB,CACrC,MAAiB,EACjB,GAAc;IAEd,+EAA+E;IAC/E,gFAAgF;IAChF,+DAA+D;IAC/D,MAAM,CAAC,gBAAgB,CACrB,sBAAsB,EACtB,IAAI,gBAAgB,CAAC,uCAAuC,EAAE;QAC5D,IAAI,EAAE,SAAS;KAChB,CAAC,EACF;QACE,KAAK,EAAE,sBAAsB;QAC7B,WAAW,EACT,uEAAuE;QACzE,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,EAAE,GAAG,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC1B,MAAM,
|
|
1
|
+
{"version":3,"file":"changes.js","sourceRoot":"","sources":["../../src/resources/changes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AAI3E,MAAM,UAAU,uBAAuB,CACrC,MAAiB,EACjB,GAAc;IAEd,+EAA+E;IAC/E,gFAAgF;IAChF,+DAA+D;IAC/D,MAAM,CAAC,gBAAgB,CACrB,sBAAsB,EACtB,IAAI,gBAAgB,CAAC,uCAAuC,EAAE;QAC5D,IAAI,EAAE,SAAS;KAChB,CAAC,EACF;QACE,KAAK,EAAE,sBAAsB;QAC7B,WAAW,EACT,uEAAuE;QACzE,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,EAAE,GAAG,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC1B,mEAAmE;QACnE,uEAAuE;QACvE,8DAA8D;QAC9D,8DAA8D;QAC9D,iEAAiE;QACjE,gBAAgB;QAChB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,+BAA+B,CACpD,QAAkB,CACnB,CAAC;QACF,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,GAAG,EAAE,GAAG,CAAC,IAAI;oBACb,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;iBACpC;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -8,7 +8,7 @@ Rockhopper uses three distinct identifiers. Mixing them is the most common cause
|
|
|
8
8
|
|
|
9
9
|
| ID | Type | Where it comes from | Where it goes |
|
|
10
10
|
|----|------|---------------------|---------------|
|
|
11
|
-
| `fileMsId` | string | `list_files` response, `rockhopper://files` resource | Tools that act on a file: `get_file_versions`, `get_file_comments`, `add_comment`, `create_version`, `discard_changes`, `get_cell_history`, `get_unattributed_changes`, `
|
|
11
|
+
| `fileMsId` | string | `list_files` response, `rockhopper://files` resource | Tools that act on a file: `get_file_versions`, `get_file_comments`, `add_comment`, `create_version`, `discard_changes`, `get_cell_history`, `get_unattributed_changes`, `rename_file` |
|
|
12
12
|
| `versionId` | number | `get_file_versions` response (`internalId` field), `create_version` response | Tools that act on a specific version snapshot: `get_reviews`, `create_review_request`, `approve_review`, `cancel_review` |
|
|
13
13
|
| `versionInternalId` | number | `get_file_comments` response (comments scope to a version) | Comment-thread tools: `add_comment`, `reply_to_comment`, `resolve_comment` |
|
|
14
14
|
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAK5C,OAAO,EAAiB,KAAK,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAqD5E,wBAAgB,YAAY,CAC1B,SAAS,EAAE,SAAS,EACpB,OAAO,CAAC,EAAE,oBAAoB,GAC7B,SAAS,CA+BX"}
|
package/dist/server.js
CHANGED
|
@@ -1,7 +1,43 @@
|
|
|
1
1
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import { runWithCorrelationId } from './correlation.js';
|
|
3
|
+
import { log } from './logger.js';
|
|
2
4
|
import { registerPrompts } from './prompts/index.js';
|
|
3
5
|
import { registerResources } from './resources/index.js';
|
|
4
6
|
import { registerTools } from './tools/index.js';
|
|
7
|
+
/**
|
|
8
|
+
* Phase 1.1 / KI-226 + Phase 1.5 / KI-225 — wrap every tool handler once.
|
|
9
|
+
* Intercepting `registerTool` here (vs. wrapping each of the ~16 handlers)
|
|
10
|
+
* means all current and future tools are covered automatically. The wrapper:
|
|
11
|
+
* - runs the handler inside {@link runWithCorrelationId}, so every outbound
|
|
12
|
+
* `ApiClient` call it makes — including multi-call fan-outs like search —
|
|
13
|
+
* shares one `X-Correlation-Id` (1.1), and
|
|
14
|
+
* - times the handler and logs a `tool_call` / `tool_call_failed` line to
|
|
15
|
+
* the local diagnostic file (1.5). Only the tool NAME is logged — never
|
|
16
|
+
* the tool arguments, which may carry file refs / PII.
|
|
17
|
+
* The handler callback is always the last positional argument to
|
|
18
|
+
* `registerTool`; the loose casts insulate this seam from the SDK's generic
|
|
19
|
+
* `ToolCallback` union. On a handler throw we log then re-throw — behavior
|
|
20
|
+
* (the error surfacing to the SDK) is preserved.
|
|
21
|
+
*/
|
|
22
|
+
function installCorrelationScope(server) {
|
|
23
|
+
const baseRegisterTool = server.registerTool.bind(server);
|
|
24
|
+
server.registerTool = ((name, config, cb) => {
|
|
25
|
+
const handler = cb;
|
|
26
|
+
const wrapped = (...args) => runWithCorrelationId(async () => {
|
|
27
|
+
const start = Date.now();
|
|
28
|
+
try {
|
|
29
|
+
const result = await handler(...args);
|
|
30
|
+
log.info({ event: 'tool_call', tool: name, durationMs: Date.now() - start, outcome: 'ok' }, 'tool_call');
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
log.error({ event: 'tool_call_failed', tool: name, durationMs: Date.now() - start, err }, 'tool_call_failed');
|
|
35
|
+
throw err;
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
return baseRegisterTool(name, config, wrapped);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
5
41
|
export function createServer(apiClient, options) {
|
|
6
42
|
const readOnly = options?.scope === 'read-only';
|
|
7
43
|
const server = new McpServer({
|
|
@@ -19,9 +55,10 @@ export function createServer(apiClient, options) {
|
|
|
19
55
|
'versions, comments, reviews, or cell history. Write operations ' +
|
|
20
56
|
'(add_comment, reply_to_comment, resolve_comment, create_review_request, ' +
|
|
21
57
|
'approve_review, cancel_review, create_version, discard_changes, ' +
|
|
22
|
-
'
|
|
58
|
+
'rename_file) require a read-write scoped token. ' +
|
|
23
59
|
'File IDs use the platformId field (e.g. from list_files output).',
|
|
24
60
|
});
|
|
61
|
+
installCorrelationScope(server);
|
|
25
62
|
registerResources(server, apiClient);
|
|
26
63
|
registerTools(server, apiClient, options);
|
|
27
64
|
registerPrompts(server, apiClient);
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,aAAa,EAA6B,MAAM,kBAAkB,CAAC;AAE5E,MAAM,UAAU,YAAY,CAC1B,SAAoB,EACpB,OAA8B;IAE9B,MAAM,QAAQ,GAAG,OAAO,EAAE,KAAK,KAAK,WAAW,CAAC;IAEhD,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B;QACE,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,OAAO;KACjB,EACD;QACE,YAAY,EAAE,QAAQ;YACpB,CAAC,CAAC,yDAAyD;gBACzD,oEAAoE;gBACpE,gDAAgD;gBAChD,gEAAgE;gBAChE,kEAAkE;YACpE,CAAC,CAAC,0DAA0D;gBAC1D,oEAAoE;gBACpE,iEAAiE;gBACjE,0EAA0E;gBAC1E,kEAAkE;gBAClE,
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,aAAa,EAA6B,MAAM,kBAAkB,CAAC;AAE5E;;;;;;;;;;;;;;GAcG;AACH,SAAS,uBAAuB,CAAC,MAAiB;IAChD,MAAM,gBAAgB,GAAG,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1D,MAAM,CAAC,YAAY,GAAG,CAAC,CACrB,IAAY,EACZ,MAAe,EACf,EAAW,EAC0B,EAAE;QACvC,MAAM,OAAO,GAAG,EAAqC,CAAC;QACtD,MAAM,OAAO,GAAG,CAAC,GAAG,IAAe,EAAW,EAAE,CAC9C,oBAAoB,CAAC,KAAK,IAAI,EAAE;YAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACzB,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;gBACtC,GAAG,CAAC,IAAI,CACN,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,EACjF,WAAW,CACZ,CAAC;gBACF,OAAO,MAAM,CAAC;YAChB,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,GAAG,CAAC,KAAK,CACP,EAAE,KAAK,EAAE,kBAAkB,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,GAAG,EAAE,EAC9E,kBAAkB,CACnB,CAAC;gBACF,MAAM,GAAG,CAAC;YACZ,CAAC;QACH,CAAC,CAAC,CAAC;QACL,OACE,gBAKD,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3B,CAAC,CAA+B,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,SAAoB,EACpB,OAA8B;IAE9B,MAAM,QAAQ,GAAG,OAAO,EAAE,KAAK,KAAK,WAAW,CAAC;IAEhD,MAAM,MAAM,GAAG,IAAI,SAAS,CAC1B;QACE,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,OAAO;KACjB,EACD;QACE,YAAY,EAAE,QAAQ;YACpB,CAAC,CAAC,yDAAyD;gBACzD,oEAAoE;gBACpE,gDAAgD;gBAChD,gEAAgE;gBAChE,kEAAkE;YACpE,CAAC,CAAC,0DAA0D;gBAC1D,oEAAoE;gBACpE,iEAAiE;gBACjE,0EAA0E;gBAC1E,kEAAkE;gBAClE,kDAAkD;gBAClD,kEAAkE;KACvE,CACF,CAAC;IAEF,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAChC,iBAAiB,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACrC,aAAa,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IAC1C,eAAe,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAEnC,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAElD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,SAAS,GACb,IAAI,
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAElD,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,EACjB,GAAG,EAAE,SAAS,GACb,IAAI,CA4MN"}
|