@arabold/docs-mcp-server 2.1.0 → 2.2.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.
@@ -0,0 +1,7 @@
1
+ -- Migration: Create metadata table for tracking global configuration state.
2
+ -- Used to persist the active embedding model and vector dimension so the system
3
+ -- can detect configuration changes between startups and prevent silent data corruption.
4
+ CREATE TABLE IF NOT EXISTS metadata (
5
+ key TEXT PRIMARY KEY,
6
+ value TEXT NOT NULL
7
+ );
package/dist/index.js CHANGED
@@ -4,8 +4,8 @@ import { s as sanitizeEnvironment, l as logger } from "./logger-CLtABTNb.js";
4
4
  process.setSourceMapsEnabled(true);
5
5
  sanitizeEnvironment();
6
6
  const [{ runCli }, { ensurePlaywrightBrowsersInstalled }] = await Promise.all([
7
- import("./main-CmXZnHFM.js"),
8
- import("./utils-XwXdQlZ_.js").then((n) => n.u)
7
+ import("./main-B6iwx1JH.js"),
8
+ import("./utils-ntayxPjd.js").then((n) => n.u)
9
9
  ]);
10
10
  ensurePlaywrightBrowsersInstalled();
11
11
  runCli().catch((error) => {
@@ -9,7 +9,7 @@ import path from "node:path";
9
9
  import { URL as URL$1 } from "node:url";
10
10
  import envPaths from "env-paths";
11
11
  import { l as logger, n as normalizeEnvValue, g as getLogLevelFromEnv, a as setLogLevel, L as LogLevel } from "./logger-CLtABTNb.js";
12
- import { t as telemetry, T as TelemetryEvent, P as PipelineJobStatus, g as getProjectRoot, E as EmbeddingConfig, a as EventType, S as ServerEventName, s as shouldEnableTelemetry, r as resolveProtocol, p as parseAuthConfig, v as validateAuthConfig, w as warnHttpUsage, e as ensurePlaywrightBrowsersInstalled, b as getEventBus, c as createAppServerConfig, d as parseHeaders, f as validatePort, h as validateHost, i as resolveStorePath, j as initTelemetry, k as EventBusService, l as TelemetryService } from "./utils-XwXdQlZ_.js";
12
+ import { t as telemetry, T as TelemetryEvent, P as PipelineJobStatus, g as getProjectRoot, E as EmbeddingConfig, a as EventType, S as ServerEventName, s as shouldEnableTelemetry, r as resolveProtocol, p as parseAuthConfig, v as validateAuthConfig, w as warnHttpUsage, e as ensurePlaywrightBrowsersInstalled, b as getEventBus, h as handleEmbeddingModelChange, c as createAppServerConfig, d as parseHeaders, f as validatePort, i as validateHost, j as resolveStorePath, k as initTelemetry, l as EventBusService, m as TelemetryService } from "./utils-ntayxPjd.js";
13
13
  import yargs from "yargs";
14
14
  import { hideBin } from "yargs/helpers";
15
15
  import yaml from "yaml";
@@ -117,6 +117,23 @@ class DimensionError extends StoreError {
117
117
  }
118
118
  class ConnectionError extends StoreError {
119
119
  }
120
+ class EmbeddingModelChangedError extends StoreError {
121
+ constructor(previousModel, previousDimension, currentModel, currentDimension) {
122
+ super(
123
+ `Embedding model change detected:
124
+ Previous: ${previousModel} (${previousDimension} dimensions)
125
+ Current: ${currentModel} (${currentDimension} dimensions)
126
+
127
+ All existing vectors are incompatible and must be invalidated.
128
+ To confirm this change, start the server interactively (with a TTY connected)
129
+ and follow the prompts.`
130
+ );
131
+ this.previousModel = previousModel;
132
+ this.previousDimension = previousDimension;
133
+ this.currentModel = currentModel;
134
+ this.currentDimension = currentDimension;
135
+ }
136
+ }
120
137
  class MissingCredentialsError extends StoreError {
121
138
  constructor(provider, missingCredentials) {
122
139
  super(
@@ -456,7 +473,7 @@ const AppConfigSchema = z.object({
456
473
  batchChars: z.coerce.number().int().default(DEFAULT_CONFIG.embeddings.batchChars),
457
474
  requestTimeoutMs: z.coerce.number().int().default(DEFAULT_CONFIG.embeddings.requestTimeoutMs),
458
475
  initTimeoutMs: z.coerce.number().int().default(DEFAULT_CONFIG.embeddings.initTimeoutMs),
459
- vectorDimension: z.coerce.number().int().default(DEFAULT_CONFIG.embeddings.vectorDimension)
476
+ vectorDimension: z.coerce.number().int().min(1, "embedding dimension must be at least 1").default(DEFAULT_CONFIG.embeddings.vectorDimension)
460
477
  }).default(DEFAULT_CONFIG.embeddings),
461
478
  db: z.object({
462
479
  migrationMaxRetries: z.coerce.number().int().default(DEFAULT_CONFIG.db.migrationMaxRetries),
@@ -1963,6 +1980,17 @@ class ChallengeError extends ScraperError {
1963
1980
  this.challengeType = challengeType;
1964
1981
  }
1965
1982
  }
1983
+ class TlsCertificateError extends ScraperError {
1984
+ constructor(url, code, cause) {
1985
+ super(
1986
+ `TLS certificate validation failed for ${url}${code ? ` (${code})` : ""}. The remote site may have an incomplete or untrusted certificate chain.`,
1987
+ false,
1988
+ cause
1989
+ );
1990
+ this.url = url;
1991
+ this.code = code;
1992
+ }
1993
+ }
1966
1994
  class MimeTypeUtils {
1967
1995
  /**
1968
1996
  * Parses a Content-Type header string into its MIME type and charset.
@@ -2420,6 +2448,9 @@ class MimeTypeUtils {
2420
2448
  "text/x-xml": "xml",
2421
2449
  "text/xml": "xml",
2422
2450
  "application/xml": "xml",
2451
+ "application/xslt+xml": "xml",
2452
+ "application/xml-dtd": "xml",
2453
+ "application/wsdl+xml": "xml",
2423
2454
  "text/x-sql": "sql",
2424
2455
  "text/x-graphql": "graphql",
2425
2456
  // Schema/API definitions
@@ -2688,6 +2719,15 @@ class HttpFetcher {
2688
2719
  "EPERM"
2689
2720
  // Operation not permitted
2690
2721
  ];
2722
+ tlsCertificateErrorCodes = [
2723
+ "CERT_HAS_EXPIRED",
2724
+ "DEPTH_ZERO_SELF_SIGNED_CERT",
2725
+ "ERR_TLS_CERT_ALTNAME_INVALID",
2726
+ "SELF_SIGNED_CERT_IN_CHAIN",
2727
+ "UNABLE_TO_GET_ISSUER_CERT",
2728
+ "UNABLE_TO_GET_ISSUER_CERT_LOCALLY",
2729
+ "UNABLE_TO_VERIFY_LEAF_SIGNATURE"
2730
+ ];
2691
2731
  fingerprintGenerator;
2692
2732
  constructor(scraperConfig) {
2693
2733
  this.maxRetriesDefault = scraperConfig.fetcher.maxRetries;
@@ -2700,6 +2740,9 @@ class HttpFetcher {
2700
2740
  async delay(ms) {
2701
2741
  return new Promise((resolve) => setTimeout(resolve, ms));
2702
2742
  }
2743
+ isTlsCertificateError(code) {
2744
+ return code ? this.tlsCertificateErrorCodes.includes(code) : false;
2745
+ }
2703
2746
  async fetch(source, options) {
2704
2747
  const maxRetries = options?.maxRetries ?? this.maxRetriesDefault;
2705
2748
  const baseDelay = options?.retryDelay ?? this.baseDelayDefaultMs;
@@ -2796,6 +2839,7 @@ class HttpFetcher {
2796
2839
  const axiosError = error;
2797
2840
  const status = axiosError.response?.status;
2798
2841
  const code = axiosError.code;
2842
+ const errorCause = error instanceof Error ? error : void 0;
2799
2843
  if (options?.signal?.aborted || code === "ERR_CANCELED") {
2800
2844
  throw new CancellationError("HTTP fetch cancelled");
2801
2845
  }
@@ -2835,6 +2879,9 @@ class HttpFetcher {
2835
2879
  throw new ChallengeError(source, status, "cloudflare");
2836
2880
  }
2837
2881
  }
2882
+ if (this.isTlsCertificateError(code)) {
2883
+ throw new TlsCertificateError(source, code, errorCause);
2884
+ }
2838
2885
  if (attempt < maxRetries && (status === void 0 || this.retryableStatusCodes.includes(status)) && !this.nonRetryableErrorCodes.includes(code ?? "")) {
2839
2886
  const delay = baseDelay * 2 ** attempt;
2840
2887
  logger.warn(
@@ -2846,7 +2893,7 @@ class HttpFetcher {
2846
2893
  throw new ScraperError(
2847
2894
  `Failed to fetch ${source} after ${attempt + 1} attempts: ${axiosError.message ?? "Unknown error"}`,
2848
2895
  true,
2849
- error instanceof Error ? error : void 0
2896
+ errorCause
2850
2897
  );
2851
2898
  }
2852
2899
  }
@@ -2891,6 +2938,12 @@ class AutoDetectFetcher {
2891
2938
  );
2892
2939
  return this.browserFetcher.fetch(source, options);
2893
2940
  }
2941
+ if (error instanceof TlsCertificateError) {
2942
+ logger.info(
2943
+ `🔄 TLS certificate validation failed for ${source}, falling back to browser fetcher...`
2944
+ );
2945
+ return this.browserFetcher.fetch(source, options);
2946
+ }
2894
2947
  throw error;
2895
2948
  }
2896
2949
  }
@@ -9180,6 +9233,91 @@ class DocumentStore {
9180
9233
  }
9181
9234
  return [...vector, ...new Array(this.dbDimension - vector.length).fill(0)];
9182
9235
  }
9236
+ /**
9237
+ * Reads the stored embedding model and dimension from the metadata table.
9238
+ * Returns null for each value that doesn't exist (e.g., first run or pre-metadata database).
9239
+ */
9240
+ getEmbeddingMetadata() {
9241
+ const modelRow = this.db.prepare("SELECT value FROM metadata WHERE key = ?").get("embedding_model");
9242
+ const dimensionRow = this.db.prepare("SELECT value FROM metadata WHERE key = ?").get("embedding_dimension");
9243
+ return {
9244
+ model: modelRow?.value ?? null,
9245
+ dimension: dimensionRow?.value ?? null
9246
+ };
9247
+ }
9248
+ /**
9249
+ * Persists the active embedding model and dimension to the metadata table.
9250
+ * Uses upsert (INSERT ON CONFLICT UPDATE) so it works for both first-run and subsequent updates.
9251
+ * Uses inline db.prepare() so this method works before prepareStatements() is called.
9252
+ */
9253
+ setEmbeddingMetadata(model, dimension) {
9254
+ const stmt = this.db.prepare(
9255
+ "INSERT INTO metadata (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value"
9256
+ );
9257
+ stmt.run("embedding_model", model);
9258
+ stmt.run("embedding_dimension", String(dimension));
9259
+ }
9260
+ /**
9261
+ * Compares the configured embedding model and dimension against stored metadata.
9262
+ * Throws EmbeddingModelChangedError if either has changed since the last run.
9263
+ *
9264
+ * Skipped when:
9265
+ * - No metadata exists (first run / upgrade from pre-metadata DB → silent initialization)
9266
+ * - No embedding model is configured (FTS-only mode)
9267
+ * - Credentials are unavailable for the configured provider (will fall back to FTS-only)
9268
+ */
9269
+ checkEmbeddingModelChange() {
9270
+ if (!this.embeddingConfig) {
9271
+ return;
9272
+ }
9273
+ if (!areCredentialsAvailable(this.embeddingConfig.provider)) {
9274
+ return;
9275
+ }
9276
+ const stored = this.getEmbeddingMetadata();
9277
+ if (stored.model === null) {
9278
+ return;
9279
+ }
9280
+ const currentModel = this.config.app.embeddingModel;
9281
+ const currentDimension = String(this.config.embeddings.vectorDimension);
9282
+ const modelChanged = stored.model !== currentModel;
9283
+ const dimensionChanged = stored.dimension !== null && stored.dimension !== currentDimension;
9284
+ if (modelChanged || dimensionChanged) {
9285
+ throw new EmbeddingModelChangedError(
9286
+ stored.model,
9287
+ stored.dimension ?? "unknown",
9288
+ currentModel,
9289
+ currentDimension
9290
+ );
9291
+ }
9292
+ }
9293
+ /**
9294
+ * Invalidates all existing embedding vectors after a confirmed model/dimension change.
9295
+ * Sets all document embeddings to NULL, drops and recreates the vec table as empty,
9296
+ * and updates the metadata with the new model and dimension.
9297
+ *
9298
+ * After invalidation, FTS search continues working; vector search returns no results
9299
+ * until libraries are re-scraped.
9300
+ */
9301
+ invalidateAllVectors(newModel, newDimension) {
9302
+ logger.warn(
9303
+ `⚠️ Invalidating all embedding vectors due to model/dimension change.
9304
+ All libraries must be re-scraped to restore vector search.
9305
+ Full-text search remains available for all existing documents.`
9306
+ );
9307
+ this.db.exec("UPDATE documents SET embedding = NULL");
9308
+ this.db.exec("DROP TABLE IF EXISTS documents_vec");
9309
+ this.db.exec(`
9310
+ CREATE VIRTUAL TABLE documents_vec USING vec0(
9311
+ library_id INTEGER NOT NULL,
9312
+ version_id INTEGER NOT NULL,
9313
+ embedding FLOAT[${newDimension}]
9314
+ );
9315
+ `);
9316
+ this.setEmbeddingMetadata(newModel, newDimension);
9317
+ logger.info(
9318
+ `✅ Embedding vectors invalidated. Metadata updated to: ${newModel} (${newDimension}d)`
9319
+ );
9320
+ }
9183
9321
  /**
9184
9322
  * Initialize the embeddings client using the provided config.
9185
9323
  * If no embedding config is provided (null or undefined), embeddings will not be initialized.
@@ -9238,6 +9376,9 @@ class DocumentStore {
9238
9376
  }
9239
9377
  EmbeddingConfig.setKnownModelDimensions(config.model, this.modelDimension);
9240
9378
  }
9379
+ if (this.embeddings instanceof FixedDimensionEmbeddings && this.embeddings.allowTruncate) {
9380
+ this.modelDimension = Math.min(this.modelDimension, this.dbDimension);
9381
+ }
9241
9382
  if (this.modelDimension > this.dbDimension) {
9242
9383
  throw new DimensionError(config.modelSpec, this.modelDimension, this.dbDimension);
9243
9384
  }
@@ -9245,6 +9386,7 @@ class DocumentStore {
9245
9386
  logger.debug(
9246
9387
  `Embeddings initialized: ${config.provider}:${config.model} (${this.modelDimension}d)`
9247
9388
  );
9389
+ this.setEmbeddingMetadata(config.modelSpec, this.dbDimension);
9248
9390
  } catch (error) {
9249
9391
  if (error instanceof Error) {
9250
9392
  if (error.message.includes("does not exist") || error.message.includes("MODEL_NOT_FOUND")) {
@@ -9285,14 +9427,14 @@ class DocumentStore {
9285
9427
  * This prevents FTS5 syntax errors while supporting intuitive phrase searches.
9286
9428
  *
9287
9429
  * Query construction:
9288
- * - Exact match of full input: `("escaped full query")`
9289
- * - Individual terms: `("term1" AND "term2" AND "phrase")`
9290
- * - Combined: `("full query") OR ("term1" AND "term2")`
9430
+ * - Exact match of full input: `"escaped full query"`
9431
+ * - Individual terms: `"term1" OR "term2" OR "phrase"`
9432
+ * - Combined: `"full query" OR "term1" OR "term2"`
9291
9433
  *
9292
9434
  * Examples:
9293
- * - `foo bar` -> `("foo bar") OR ("foo" AND "bar")`
9294
- * - `"hello world"` -> `("hello world")`
9295
- * - `test "exact phrase" word` -> `("test exact phrase word") OR ("test" AND "exact phrase" AND "word")`
9435
+ * - `foo bar` -> `"foo bar" OR "foo" OR "bar"`
9436
+ * - `"hello world"` -> `"hello world"`
9437
+ * - `test "exact phrase" word` -> `"test exact phrase word" OR "test" OR "exact phrase" OR "word"`
9296
9438
  */
9297
9439
  escapeFtsQuery(query) {
9298
9440
  const tokens = [];
@@ -9350,6 +9492,8 @@ class DocumentStore {
9350
9492
  maxRetries: this.config.db.migrationMaxRetries,
9351
9493
  retryDelayMs: this.config.db.migrationRetryDelayMs
9352
9494
  });
9495
+ this.checkEmbeddingModelChange();
9496
+ this.ensureVectorTable();
9353
9497
  this.prepareStatements();
9354
9498
  await this.initializeEmbeddings();
9355
9499
  } catch (error) {
@@ -9359,12 +9503,66 @@ class DocumentStore {
9359
9503
  throw new ConnectionError("Failed to initialize database connection", error);
9360
9504
  }
9361
9505
  }
9506
+ /**
9507
+ * Resolves a model change by invalidating all vectors and completing initialization.
9508
+ * Called by the CLI layer after the user confirms a model/dimension change.
9509
+ * Assumes initialize() was previously called and threw EmbeddingModelChangedError,
9510
+ * meaning steps 1-2 (load extensions, apply migrations) completed successfully.
9511
+ * Steps 3+ (ensureVectorTable, prepareStatements, initializeEmbeddings) are
9512
+ * completed here after invalidation.
9513
+ */
9514
+ async resolveModelChange() {
9515
+ const currentModel = this.config.app.embeddingModel;
9516
+ const currentDimension = this.config.embeddings.vectorDimension;
9517
+ this.invalidateAllVectors(currentModel, currentDimension);
9518
+ this.ensureVectorTable();
9519
+ this.prepareStatements();
9520
+ await this.initializeEmbeddings();
9521
+ }
9362
9522
  /**
9363
9523
  * Gracefully closes database connections
9364
9524
  */
9365
9525
  async shutdown() {
9366
9526
  this.db.close();
9367
9527
  }
9528
+ /**
9529
+ * Creates or reconciles the documents_vec virtual table with configurable dimension.
9530
+ * Called after migrations and model change detection. The table is initially created
9531
+ * by migration 003 with a fixed 1536 dimension; this method reconciles it at runtime
9532
+ * if the configured dimension differs.
9533
+ * Idempotent: if the table already exists with the same dimension, no-op; if dimension
9534
+ * changed in config, drops and recreates so any embedding provider (e.g. 1536 or 3584) works.
9535
+ *
9536
+ * Note: No backfill of existing embeddings is performed. Vectors are populated during
9537
+ * scraping, not at startup. Old vectors from a different dimension or model are incompatible
9538
+ * and are handled by the model change detection system (checkEmbeddingModelChange).
9539
+ */
9540
+ ensureVectorTable() {
9541
+ const dim = this.config.embeddings.vectorDimension;
9542
+ if (typeof dim !== "number" || !Number.isInteger(dim) || dim < 1) {
9543
+ throw new StoreError(
9544
+ `Invalid embeddings.vectorDimension: ${dim}. Must be a positive integer.`
9545
+ );
9546
+ }
9547
+ const existingSql = this.db.prepare(
9548
+ "SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'documents_vec';"
9549
+ ).get();
9550
+ if (existingSql) {
9551
+ const match = existingSql.sql.match(/embedding\s+FLOAT\s*\[\s*(\d+)\s*]/i);
9552
+ const existingDim = match ? Number(match[1]) : null;
9553
+ if (existingDim === dim) {
9554
+ return;
9555
+ }
9556
+ this.db.exec("DROP TABLE documents_vec;");
9557
+ }
9558
+ this.db.exec(`
9559
+ CREATE VIRTUAL TABLE documents_vec USING vec0(
9560
+ library_id INTEGER NOT NULL,
9561
+ version_id INTEGER NOT NULL,
9562
+ embedding FLOAT[${dim}]
9563
+ );
9564
+ `);
9565
+ }
9368
9566
  /**
9369
9567
  * Resolves a library name and version string to version_id.
9370
9568
  * Creates library and version records if they don't exist.
@@ -10281,6 +10479,13 @@ class DocumentManagementService {
10281
10479
  async initialize() {
10282
10480
  await this.store.initialize();
10283
10481
  }
10482
+ /**
10483
+ * Resolves a confirmed embedding model change by invalidating all vectors
10484
+ * and completing the initialization that was interrupted by EmbeddingModelChangedError.
10485
+ */
10486
+ async resolveModelChange() {
10487
+ await this.store.resolveModelChange();
10488
+ }
10284
10489
  /**
10285
10490
  * Shuts down the underlying document store and cleans up pipeline resources.
10286
10491
  */
@@ -11455,7 +11660,7 @@ const Layout = ({
11455
11660
  children,
11456
11661
  eventClientConfig
11457
11662
  }) => {
11458
- const versionString = version || "2.1.0";
11663
+ const versionString = version || "2.2.0";
11459
11664
  const versionInitializer = `versionUpdate({ currentVersion: ${`'${versionString}'`} })`;
11460
11665
  return /* @__PURE__ */ jsxs("html", { lang: "en", children: [
11461
11666
  /* @__PURE__ */ jsxs("head", { children: [
@@ -13807,7 +14012,7 @@ class AppServer {
13807
14012
  try {
13808
14013
  if (telemetry.isEnabled()) {
13809
14014
  telemetry.setGlobalContext({
13810
- appVersion: "2.1.0",
14015
+ appVersion: "2.2.0",
13811
14016
  appPlatform: process.platform,
13812
14017
  appNodeVersion: process.version,
13813
14018
  appServicesEnabled: this.getActiveServicesList(),
@@ -14926,6 +15131,11 @@ const TEXT_EXTENSIONS = /* @__PURE__ */ new Set([
14926
15131
  ".html",
14927
15132
  ".htm",
14928
15133
  ".xml",
15134
+ ".xsl",
15135
+ ".xslt",
15136
+ ".xsd",
15137
+ ".dtd",
15138
+ ".wsdl",
14929
15139
  ".xhtml",
14930
15140
  // Stylesheets
14931
15141
  ".css",
@@ -16996,7 +17206,16 @@ function createDefaultAction(cli) {
16996
17206
  }
16997
17207
  ensurePlaywrightBrowsersInstalled();
16998
17208
  const eventBus = getEventBus(argv);
16999
- const docService = await createLocalDocumentManagement(eventBus, appConfig);
17209
+ const docService = new DocumentManagementService(eventBus, appConfig);
17210
+ try {
17211
+ await docService.initialize();
17212
+ } catch (error) {
17213
+ if (error instanceof EmbeddingModelChangedError) {
17214
+ await handleEmbeddingModelChange(error, docService);
17215
+ } else {
17216
+ throw error;
17217
+ }
17218
+ }
17000
17219
  const pipelineOptions = {
17001
17220
  recoverJobs: argv.resume || false,
17002
17221
  appConfig
@@ -17279,11 +17498,24 @@ function createMcpCommand(cli) {
17279
17498
  try {
17280
17499
  const serverUrl = argv.serverUrl;
17281
17500
  const eventBus = getEventBus(argv);
17282
- const docService = await createDocumentManagement({
17283
- serverUrl,
17284
- eventBus,
17285
- appConfig
17286
- });
17501
+ let docService;
17502
+ if (serverUrl) {
17503
+ const client = new DocumentManagementClient(serverUrl);
17504
+ await client.initialize();
17505
+ docService = client;
17506
+ } else {
17507
+ const service = new DocumentManagementService(eventBus, appConfig);
17508
+ try {
17509
+ await service.initialize();
17510
+ } catch (error) {
17511
+ if (error instanceof EmbeddingModelChangedError) {
17512
+ await handleEmbeddingModelChange(error, service);
17513
+ } else {
17514
+ throw error;
17515
+ }
17516
+ }
17517
+ docService = service;
17518
+ }
17287
17519
  const pipelineOptions = {
17288
17520
  recoverJobs: false,
17289
17521
  // MCP command doesn't support job recovery
@@ -17961,7 +18193,7 @@ function createCli(argv) {
17961
18193
  let globalEventBus = null;
17962
18194
  let globalTelemetryService = null;
17963
18195
  const commandStartTimes = /* @__PURE__ */ new Map();
17964
- const cli = registerGlobalOutputOptions(yargs(hideBin(argv))).scriptName("docs-mcp-server").strict().usage("Usage: $0 <command> [options]").version("2.1.0").option("verbose", {
18196
+ const cli = registerGlobalOutputOptions(yargs(hideBin(argv))).scriptName("docs-mcp-server").strict().usage("Usage: $0 <command> [options]").version("2.2.0").option("verbose", {
17965
18197
  type: "boolean",
17966
18198
  description: "Enable verbose (debug) logging",
17967
18199
  default: false
@@ -18022,7 +18254,7 @@ function createCli(argv) {
18022
18254
  if (shouldEnableTelemetry() && telemetry.isEnabled()) {
18023
18255
  const commandName = argv2._[0]?.toString() || "default";
18024
18256
  telemetry.setGlobalContext({
18025
- appVersion: "2.1.0",
18257
+ appVersion: "2.2.0",
18026
18258
  appPlatform: process.platform,
18027
18259
  appNodeVersion: process.version,
18028
18260
  appInterface: "cli",
@@ -18168,4 +18400,4 @@ export {
18168
18400
  cleanupCliCommand,
18169
18401
  runCli
18170
18402
  };
18171
- //# sourceMappingURL=main-CmXZnHFM.js.map
18403
+ //# sourceMappingURL=main-B6iwx1JH.js.map