threadnote 0.7.12 → 1.1.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.
@@ -3645,49 +3645,49 @@ var require_fast_uri = __commonJS({
3645
3645
  schemelessOptions.skipEscape = true;
3646
3646
  return serialize(resolved, schemelessOptions);
3647
3647
  }
3648
- function resolveComponent(base, relative2, options, skipNormalization) {
3648
+ function resolveComponent(base, relative3, options, skipNormalization) {
3649
3649
  const target = {};
3650
3650
  if (!skipNormalization) {
3651
3651
  base = parse3(serialize(base, options), options);
3652
- relative2 = parse3(serialize(relative2, options), options);
3652
+ relative3 = parse3(serialize(relative3, options), options);
3653
3653
  }
3654
3654
  options = options || {};
3655
- if (!options.tolerant && relative2.scheme) {
3656
- target.scheme = relative2.scheme;
3657
- target.userinfo = relative2.userinfo;
3658
- target.host = relative2.host;
3659
- target.port = relative2.port;
3660
- target.path = removeDotSegments(relative2.path || "");
3661
- target.query = relative2.query;
3655
+ if (!options.tolerant && relative3.scheme) {
3656
+ target.scheme = relative3.scheme;
3657
+ target.userinfo = relative3.userinfo;
3658
+ target.host = relative3.host;
3659
+ target.port = relative3.port;
3660
+ target.path = removeDotSegments(relative3.path || "");
3661
+ target.query = relative3.query;
3662
3662
  } else {
3663
- if (relative2.userinfo !== void 0 || relative2.host !== void 0 || relative2.port !== void 0) {
3664
- target.userinfo = relative2.userinfo;
3665
- target.host = relative2.host;
3666
- target.port = relative2.port;
3667
- target.path = removeDotSegments(relative2.path || "");
3668
- target.query = relative2.query;
3663
+ if (relative3.userinfo !== void 0 || relative3.host !== void 0 || relative3.port !== void 0) {
3664
+ target.userinfo = relative3.userinfo;
3665
+ target.host = relative3.host;
3666
+ target.port = relative3.port;
3667
+ target.path = removeDotSegments(relative3.path || "");
3668
+ target.query = relative3.query;
3669
3669
  } else {
3670
- if (!relative2.path) {
3670
+ if (!relative3.path) {
3671
3671
  target.path = base.path;
3672
- if (relative2.query !== void 0) {
3673
- target.query = relative2.query;
3672
+ if (relative3.query !== void 0) {
3673
+ target.query = relative3.query;
3674
3674
  } else {
3675
3675
  target.query = base.query;
3676
3676
  }
3677
3677
  } else {
3678
- if (relative2.path[0] === "/") {
3679
- target.path = removeDotSegments(relative2.path);
3678
+ if (relative3.path[0] === "/") {
3679
+ target.path = removeDotSegments(relative3.path);
3680
3680
  } else {
3681
3681
  if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) {
3682
- target.path = "/" + relative2.path;
3682
+ target.path = "/" + relative3.path;
3683
3683
  } else if (!base.path) {
3684
- target.path = relative2.path;
3684
+ target.path = relative3.path;
3685
3685
  } else {
3686
- target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative2.path;
3686
+ target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative3.path;
3687
3687
  }
3688
3688
  target.path = removeDotSegments(target.path);
3689
3689
  }
3690
- target.query = relative2.query;
3690
+ target.query = relative3.query;
3691
3691
  }
3692
3692
  target.userinfo = base.userinfo;
3693
3693
  target.host = base.host;
@@ -3695,7 +3695,7 @@ var require_fast_uri = __commonJS({
3695
3695
  }
3696
3696
  target.scheme = base.scheme;
3697
3697
  }
3698
- target.fragment = relative2.fragment;
3698
+ target.fragment = relative3.fragment;
3699
3699
  return target;
3700
3700
  }
3701
3701
  function equal(uriA, uriB, options) {
@@ -25867,6 +25867,7 @@ var InitializedNotificationSchema = NotificationSchema.extend({
25867
25867
  method: literal("notifications/initialized"),
25868
25868
  params: NotificationsParamsSchema.optional()
25869
25869
  });
25870
+ var isInitializedNotification = (value) => InitializedNotificationSchema.safeParse(value).success;
25870
25871
  var PingRequestSchema = RequestSchema.extend({
25871
25872
  method: literal("ping"),
25872
25873
  params: BaseRequestParamsSchema.optional()
@@ -29350,6 +29351,715 @@ var AjvJsonSchemaValidator = class {
29350
29351
  }
29351
29352
  };
29352
29353
 
29354
+ // node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/client.js
29355
+ var ExperimentalClientTasks = class {
29356
+ constructor(_client) {
29357
+ this._client = _client;
29358
+ }
29359
+ /**
29360
+ * Calls a tool and returns an AsyncGenerator that yields response messages.
29361
+ * The generator is guaranteed to end with either a 'result' or 'error' message.
29362
+ *
29363
+ * This method provides streaming access to tool execution, allowing you to
29364
+ * observe intermediate task status updates for long-running tool calls.
29365
+ * Automatically validates structured output if the tool has an outputSchema.
29366
+ *
29367
+ * @example
29368
+ * ```typescript
29369
+ * const stream = client.experimental.tasks.callToolStream({ name: 'myTool', arguments: {} });
29370
+ * for await (const message of stream) {
29371
+ * switch (message.type) {
29372
+ * case 'taskCreated':
29373
+ * console.log('Tool execution started:', message.task.taskId);
29374
+ * break;
29375
+ * case 'taskStatus':
29376
+ * console.log('Tool status:', message.task.status);
29377
+ * break;
29378
+ * case 'result':
29379
+ * console.log('Tool result:', message.result);
29380
+ * break;
29381
+ * case 'error':
29382
+ * console.error('Tool error:', message.error);
29383
+ * break;
29384
+ * }
29385
+ * }
29386
+ * ```
29387
+ *
29388
+ * @param params - Tool call parameters (name and arguments)
29389
+ * @param resultSchema - Zod schema for validating the result (defaults to CallToolResultSchema)
29390
+ * @param options - Optional request options (timeout, signal, task creation params, etc.)
29391
+ * @returns AsyncGenerator that yields ResponseMessage objects
29392
+ *
29393
+ * @experimental
29394
+ */
29395
+ async *callToolStream(params, resultSchema = CallToolResultSchema, options) {
29396
+ const clientInternal = this._client;
29397
+ const optionsWithTask = {
29398
+ ...options,
29399
+ // We check if the tool is known to be a task during auto-configuration, but assume
29400
+ // the caller knows what they're doing if they pass this explicitly
29401
+ task: options?.task ?? (clientInternal.isToolTask(params.name) ? {} : void 0)
29402
+ };
29403
+ const stream = clientInternal.requestStream({ method: "tools/call", params }, resultSchema, optionsWithTask);
29404
+ const validator = clientInternal.getToolOutputValidator(params.name);
29405
+ for await (const message of stream) {
29406
+ if (message.type === "result" && validator) {
29407
+ const result = message.result;
29408
+ if (!result.structuredContent && !result.isError) {
29409
+ yield {
29410
+ type: "error",
29411
+ error: new McpError(ErrorCode.InvalidRequest, `Tool ${params.name} has an output schema but did not return structured content`)
29412
+ };
29413
+ return;
29414
+ }
29415
+ if (result.structuredContent) {
29416
+ try {
29417
+ const validationResult = validator(result.structuredContent);
29418
+ if (!validationResult.valid) {
29419
+ yield {
29420
+ type: "error",
29421
+ error: new McpError(ErrorCode.InvalidParams, `Structured content does not match the tool's output schema: ${validationResult.errorMessage}`)
29422
+ };
29423
+ return;
29424
+ }
29425
+ } catch (error51) {
29426
+ if (error51 instanceof McpError) {
29427
+ yield { type: "error", error: error51 };
29428
+ return;
29429
+ }
29430
+ yield {
29431
+ type: "error",
29432
+ error: new McpError(ErrorCode.InvalidParams, `Failed to validate structured content: ${error51 instanceof Error ? error51.message : String(error51)}`)
29433
+ };
29434
+ return;
29435
+ }
29436
+ }
29437
+ }
29438
+ yield message;
29439
+ }
29440
+ }
29441
+ /**
29442
+ * Gets the current status of a task.
29443
+ *
29444
+ * @param taskId - The task identifier
29445
+ * @param options - Optional request options
29446
+ * @returns The task status
29447
+ *
29448
+ * @experimental
29449
+ */
29450
+ async getTask(taskId, options) {
29451
+ return this._client.getTask({ taskId }, options);
29452
+ }
29453
+ /**
29454
+ * Retrieves the result of a completed task.
29455
+ *
29456
+ * @param taskId - The task identifier
29457
+ * @param resultSchema - Zod schema for validating the result
29458
+ * @param options - Optional request options
29459
+ * @returns The task result
29460
+ *
29461
+ * @experimental
29462
+ */
29463
+ async getTaskResult(taskId, resultSchema, options) {
29464
+ return this._client.getTaskResult({ taskId }, resultSchema, options);
29465
+ }
29466
+ /**
29467
+ * Lists tasks with optional pagination.
29468
+ *
29469
+ * @param cursor - Optional pagination cursor
29470
+ * @param options - Optional request options
29471
+ * @returns List of tasks with optional next cursor
29472
+ *
29473
+ * @experimental
29474
+ */
29475
+ async listTasks(cursor, options) {
29476
+ return this._client.listTasks(cursor ? { cursor } : void 0, options);
29477
+ }
29478
+ /**
29479
+ * Cancels a running task.
29480
+ *
29481
+ * @param taskId - The task identifier
29482
+ * @param options - Optional request options
29483
+ *
29484
+ * @experimental
29485
+ */
29486
+ async cancelTask(taskId, options) {
29487
+ return this._client.cancelTask({ taskId }, options);
29488
+ }
29489
+ /**
29490
+ * Sends a request and returns an AsyncGenerator that yields response messages.
29491
+ * The generator is guaranteed to end with either a 'result' or 'error' message.
29492
+ *
29493
+ * This method provides streaming access to request processing, allowing you to
29494
+ * observe intermediate task status updates for task-augmented requests.
29495
+ *
29496
+ * @param request - The request to send
29497
+ * @param resultSchema - Zod schema for validating the result
29498
+ * @param options - Optional request options (timeout, signal, task creation params, etc.)
29499
+ * @returns AsyncGenerator that yields ResponseMessage objects
29500
+ *
29501
+ * @experimental
29502
+ */
29503
+ requestStream(request, resultSchema, options) {
29504
+ return this._client.requestStream(request, resultSchema, options);
29505
+ }
29506
+ };
29507
+
29508
+ // node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/helpers.js
29509
+ function assertToolsCallTaskCapability(requests, method, entityName) {
29510
+ if (!requests) {
29511
+ throw new Error(`${entityName} does not support task creation (required for ${method})`);
29512
+ }
29513
+ switch (method) {
29514
+ case "tools/call":
29515
+ if (!requests.tools?.call) {
29516
+ throw new Error(`${entityName} does not support task creation for tools/call (required for ${method})`);
29517
+ }
29518
+ break;
29519
+ default:
29520
+ break;
29521
+ }
29522
+ }
29523
+ function assertClientRequestTaskCapability(requests, method, entityName) {
29524
+ if (!requests) {
29525
+ throw new Error(`${entityName} does not support task creation (required for ${method})`);
29526
+ }
29527
+ switch (method) {
29528
+ case "sampling/createMessage":
29529
+ if (!requests.sampling?.createMessage) {
29530
+ throw new Error(`${entityName} does not support task creation for sampling/createMessage (required for ${method})`);
29531
+ }
29532
+ break;
29533
+ case "elicitation/create":
29534
+ if (!requests.elicitation?.create) {
29535
+ throw new Error(`${entityName} does not support task creation for elicitation/create (required for ${method})`);
29536
+ }
29537
+ break;
29538
+ default:
29539
+ break;
29540
+ }
29541
+ }
29542
+
29543
+ // node_modules/@modelcontextprotocol/sdk/dist/esm/client/index.js
29544
+ function applyElicitationDefaults(schema2, data) {
29545
+ if (!schema2 || data === null || typeof data !== "object")
29546
+ return;
29547
+ if (schema2.type === "object" && schema2.properties && typeof schema2.properties === "object") {
29548
+ const obj = data;
29549
+ const props = schema2.properties;
29550
+ for (const key of Object.keys(props)) {
29551
+ const propSchema = props[key];
29552
+ if (obj[key] === void 0 && Object.prototype.hasOwnProperty.call(propSchema, "default")) {
29553
+ obj[key] = propSchema.default;
29554
+ }
29555
+ if (obj[key] !== void 0) {
29556
+ applyElicitationDefaults(propSchema, obj[key]);
29557
+ }
29558
+ }
29559
+ }
29560
+ if (Array.isArray(schema2.anyOf)) {
29561
+ for (const sub of schema2.anyOf) {
29562
+ if (typeof sub !== "boolean") {
29563
+ applyElicitationDefaults(sub, data);
29564
+ }
29565
+ }
29566
+ }
29567
+ if (Array.isArray(schema2.oneOf)) {
29568
+ for (const sub of schema2.oneOf) {
29569
+ if (typeof sub !== "boolean") {
29570
+ applyElicitationDefaults(sub, data);
29571
+ }
29572
+ }
29573
+ }
29574
+ }
29575
+ function getSupportedElicitationModes(capabilities) {
29576
+ if (!capabilities) {
29577
+ return { supportsFormMode: false, supportsUrlMode: false };
29578
+ }
29579
+ const hasFormCapability = capabilities.form !== void 0;
29580
+ const hasUrlCapability = capabilities.url !== void 0;
29581
+ const supportsFormMode = hasFormCapability || !hasFormCapability && !hasUrlCapability;
29582
+ const supportsUrlMode = hasUrlCapability;
29583
+ return { supportsFormMode, supportsUrlMode };
29584
+ }
29585
+ var Client = class extends Protocol {
29586
+ /**
29587
+ * Initializes this client with the given name and version information.
29588
+ */
29589
+ constructor(_clientInfo, options) {
29590
+ super(options);
29591
+ this._clientInfo = _clientInfo;
29592
+ this._cachedToolOutputValidators = /* @__PURE__ */ new Map();
29593
+ this._cachedKnownTaskTools = /* @__PURE__ */ new Set();
29594
+ this._cachedRequiredTaskTools = /* @__PURE__ */ new Set();
29595
+ this._listChangedDebounceTimers = /* @__PURE__ */ new Map();
29596
+ this._capabilities = options?.capabilities ?? {};
29597
+ this._jsonSchemaValidator = options?.jsonSchemaValidator ?? new AjvJsonSchemaValidator();
29598
+ if (options?.listChanged) {
29599
+ this._pendingListChangedConfig = options.listChanged;
29600
+ }
29601
+ }
29602
+ /**
29603
+ * Set up handlers for list changed notifications based on config and server capabilities.
29604
+ * This should only be called after initialization when server capabilities are known.
29605
+ * Handlers are silently skipped if the server doesn't advertise the corresponding listChanged capability.
29606
+ * @internal
29607
+ */
29608
+ _setupListChangedHandlers(config2) {
29609
+ if (config2.tools && this._serverCapabilities?.tools?.listChanged) {
29610
+ this._setupListChangedHandler("tools", ToolListChangedNotificationSchema, config2.tools, async () => {
29611
+ const result = await this.listTools();
29612
+ return result.tools;
29613
+ });
29614
+ }
29615
+ if (config2.prompts && this._serverCapabilities?.prompts?.listChanged) {
29616
+ this._setupListChangedHandler("prompts", PromptListChangedNotificationSchema, config2.prompts, async () => {
29617
+ const result = await this.listPrompts();
29618
+ return result.prompts;
29619
+ });
29620
+ }
29621
+ if (config2.resources && this._serverCapabilities?.resources?.listChanged) {
29622
+ this._setupListChangedHandler("resources", ResourceListChangedNotificationSchema, config2.resources, async () => {
29623
+ const result = await this.listResources();
29624
+ return result.resources;
29625
+ });
29626
+ }
29627
+ }
29628
+ /**
29629
+ * Access experimental features.
29630
+ *
29631
+ * WARNING: These APIs are experimental and may change without notice.
29632
+ *
29633
+ * @experimental
29634
+ */
29635
+ get experimental() {
29636
+ if (!this._experimental) {
29637
+ this._experimental = {
29638
+ tasks: new ExperimentalClientTasks(this)
29639
+ };
29640
+ }
29641
+ return this._experimental;
29642
+ }
29643
+ /**
29644
+ * Registers new capabilities. This can only be called before connecting to a transport.
29645
+ *
29646
+ * The new capabilities will be merged with any existing capabilities previously given (e.g., at initialization).
29647
+ */
29648
+ registerCapabilities(capabilities) {
29649
+ if (this.transport) {
29650
+ throw new Error("Cannot register capabilities after connecting to transport");
29651
+ }
29652
+ this._capabilities = mergeCapabilities(this._capabilities, capabilities);
29653
+ }
29654
+ /**
29655
+ * Override request handler registration to enforce client-side validation for elicitation.
29656
+ */
29657
+ setRequestHandler(requestSchema, handler) {
29658
+ const shape = getObjectShape(requestSchema);
29659
+ const methodSchema = shape?.method;
29660
+ if (!methodSchema) {
29661
+ throw new Error("Schema is missing a method literal");
29662
+ }
29663
+ let methodValue;
29664
+ if (isZ4Schema(methodSchema)) {
29665
+ const v4Schema = methodSchema;
29666
+ const v4Def = v4Schema._zod?.def;
29667
+ methodValue = v4Def?.value ?? v4Schema.value;
29668
+ } else {
29669
+ const v3Schema = methodSchema;
29670
+ const legacyDef = v3Schema._def;
29671
+ methodValue = legacyDef?.value ?? v3Schema.value;
29672
+ }
29673
+ if (typeof methodValue !== "string") {
29674
+ throw new Error("Schema method literal must be a string");
29675
+ }
29676
+ const method = methodValue;
29677
+ if (method === "elicitation/create") {
29678
+ const wrappedHandler = async (request, extra) => {
29679
+ const validatedRequest = safeParse2(ElicitRequestSchema, request);
29680
+ if (!validatedRequest.success) {
29681
+ const errorMessage2 = validatedRequest.error instanceof Error ? validatedRequest.error.message : String(validatedRequest.error);
29682
+ throw new McpError(ErrorCode.InvalidParams, `Invalid elicitation request: ${errorMessage2}`);
29683
+ }
29684
+ const { params } = validatedRequest.data;
29685
+ params.mode = params.mode ?? "form";
29686
+ const { supportsFormMode, supportsUrlMode } = getSupportedElicitationModes(this._capabilities.elicitation);
29687
+ if (params.mode === "form" && !supportsFormMode) {
29688
+ throw new McpError(ErrorCode.InvalidParams, "Client does not support form-mode elicitation requests");
29689
+ }
29690
+ if (params.mode === "url" && !supportsUrlMode) {
29691
+ throw new McpError(ErrorCode.InvalidParams, "Client does not support URL-mode elicitation requests");
29692
+ }
29693
+ const result = await Promise.resolve(handler(request, extra));
29694
+ if (params.task) {
29695
+ const taskValidationResult = safeParse2(CreateTaskResultSchema, result);
29696
+ if (!taskValidationResult.success) {
29697
+ const errorMessage2 = taskValidationResult.error instanceof Error ? taskValidationResult.error.message : String(taskValidationResult.error);
29698
+ throw new McpError(ErrorCode.InvalidParams, `Invalid task creation result: ${errorMessage2}`);
29699
+ }
29700
+ return taskValidationResult.data;
29701
+ }
29702
+ const validationResult = safeParse2(ElicitResultSchema, result);
29703
+ if (!validationResult.success) {
29704
+ const errorMessage2 = validationResult.error instanceof Error ? validationResult.error.message : String(validationResult.error);
29705
+ throw new McpError(ErrorCode.InvalidParams, `Invalid elicitation result: ${errorMessage2}`);
29706
+ }
29707
+ const validatedResult = validationResult.data;
29708
+ const requestedSchema = params.mode === "form" ? params.requestedSchema : void 0;
29709
+ if (params.mode === "form" && validatedResult.action === "accept" && validatedResult.content && requestedSchema) {
29710
+ if (this._capabilities.elicitation?.form?.applyDefaults) {
29711
+ try {
29712
+ applyElicitationDefaults(requestedSchema, validatedResult.content);
29713
+ } catch {
29714
+ }
29715
+ }
29716
+ }
29717
+ return validatedResult;
29718
+ };
29719
+ return super.setRequestHandler(requestSchema, wrappedHandler);
29720
+ }
29721
+ if (method === "sampling/createMessage") {
29722
+ const wrappedHandler = async (request, extra) => {
29723
+ const validatedRequest = safeParse2(CreateMessageRequestSchema, request);
29724
+ if (!validatedRequest.success) {
29725
+ const errorMessage2 = validatedRequest.error instanceof Error ? validatedRequest.error.message : String(validatedRequest.error);
29726
+ throw new McpError(ErrorCode.InvalidParams, `Invalid sampling request: ${errorMessage2}`);
29727
+ }
29728
+ const { params } = validatedRequest.data;
29729
+ const result = await Promise.resolve(handler(request, extra));
29730
+ if (params.task) {
29731
+ const taskValidationResult = safeParse2(CreateTaskResultSchema, result);
29732
+ if (!taskValidationResult.success) {
29733
+ const errorMessage2 = taskValidationResult.error instanceof Error ? taskValidationResult.error.message : String(taskValidationResult.error);
29734
+ throw new McpError(ErrorCode.InvalidParams, `Invalid task creation result: ${errorMessage2}`);
29735
+ }
29736
+ return taskValidationResult.data;
29737
+ }
29738
+ const hasTools = params.tools || params.toolChoice;
29739
+ const resultSchema = hasTools ? CreateMessageResultWithToolsSchema : CreateMessageResultSchema;
29740
+ const validationResult = safeParse2(resultSchema, result);
29741
+ if (!validationResult.success) {
29742
+ const errorMessage2 = validationResult.error instanceof Error ? validationResult.error.message : String(validationResult.error);
29743
+ throw new McpError(ErrorCode.InvalidParams, `Invalid sampling result: ${errorMessage2}`);
29744
+ }
29745
+ return validationResult.data;
29746
+ };
29747
+ return super.setRequestHandler(requestSchema, wrappedHandler);
29748
+ }
29749
+ return super.setRequestHandler(requestSchema, handler);
29750
+ }
29751
+ assertCapability(capability, method) {
29752
+ if (!this._serverCapabilities?.[capability]) {
29753
+ throw new Error(`Server does not support ${capability} (required for ${method})`);
29754
+ }
29755
+ }
29756
+ async connect(transport, options) {
29757
+ await super.connect(transport);
29758
+ if (transport.sessionId !== void 0) {
29759
+ return;
29760
+ }
29761
+ try {
29762
+ const result = await this.request({
29763
+ method: "initialize",
29764
+ params: {
29765
+ protocolVersion: LATEST_PROTOCOL_VERSION,
29766
+ capabilities: this._capabilities,
29767
+ clientInfo: this._clientInfo
29768
+ }
29769
+ }, InitializeResultSchema, options);
29770
+ if (result === void 0) {
29771
+ throw new Error(`Server sent invalid initialize result: ${result}`);
29772
+ }
29773
+ if (!SUPPORTED_PROTOCOL_VERSIONS.includes(result.protocolVersion)) {
29774
+ throw new Error(`Server's protocol version is not supported: ${result.protocolVersion}`);
29775
+ }
29776
+ this._serverCapabilities = result.capabilities;
29777
+ this._serverVersion = result.serverInfo;
29778
+ if (transport.setProtocolVersion) {
29779
+ transport.setProtocolVersion(result.protocolVersion);
29780
+ }
29781
+ this._instructions = result.instructions;
29782
+ await this.notification({
29783
+ method: "notifications/initialized"
29784
+ });
29785
+ if (this._pendingListChangedConfig) {
29786
+ this._setupListChangedHandlers(this._pendingListChangedConfig);
29787
+ this._pendingListChangedConfig = void 0;
29788
+ }
29789
+ } catch (error51) {
29790
+ void this.close();
29791
+ throw error51;
29792
+ }
29793
+ }
29794
+ /**
29795
+ * After initialization has completed, this will be populated with the server's reported capabilities.
29796
+ */
29797
+ getServerCapabilities() {
29798
+ return this._serverCapabilities;
29799
+ }
29800
+ /**
29801
+ * After initialization has completed, this will be populated with information about the server's name and version.
29802
+ */
29803
+ getServerVersion() {
29804
+ return this._serverVersion;
29805
+ }
29806
+ /**
29807
+ * After initialization has completed, this may be populated with information about the server's instructions.
29808
+ */
29809
+ getInstructions() {
29810
+ return this._instructions;
29811
+ }
29812
+ assertCapabilityForMethod(method) {
29813
+ switch (method) {
29814
+ case "logging/setLevel":
29815
+ if (!this._serverCapabilities?.logging) {
29816
+ throw new Error(`Server does not support logging (required for ${method})`);
29817
+ }
29818
+ break;
29819
+ case "prompts/get":
29820
+ case "prompts/list":
29821
+ if (!this._serverCapabilities?.prompts) {
29822
+ throw new Error(`Server does not support prompts (required for ${method})`);
29823
+ }
29824
+ break;
29825
+ case "resources/list":
29826
+ case "resources/templates/list":
29827
+ case "resources/read":
29828
+ case "resources/subscribe":
29829
+ case "resources/unsubscribe":
29830
+ if (!this._serverCapabilities?.resources) {
29831
+ throw new Error(`Server does not support resources (required for ${method})`);
29832
+ }
29833
+ if (method === "resources/subscribe" && !this._serverCapabilities.resources.subscribe) {
29834
+ throw new Error(`Server does not support resource subscriptions (required for ${method})`);
29835
+ }
29836
+ break;
29837
+ case "tools/call":
29838
+ case "tools/list":
29839
+ if (!this._serverCapabilities?.tools) {
29840
+ throw new Error(`Server does not support tools (required for ${method})`);
29841
+ }
29842
+ break;
29843
+ case "completion/complete":
29844
+ if (!this._serverCapabilities?.completions) {
29845
+ throw new Error(`Server does not support completions (required for ${method})`);
29846
+ }
29847
+ break;
29848
+ case "initialize":
29849
+ break;
29850
+ case "ping":
29851
+ break;
29852
+ }
29853
+ }
29854
+ assertNotificationCapability(method) {
29855
+ switch (method) {
29856
+ case "notifications/roots/list_changed":
29857
+ if (!this._capabilities.roots?.listChanged) {
29858
+ throw new Error(`Client does not support roots list changed notifications (required for ${method})`);
29859
+ }
29860
+ break;
29861
+ case "notifications/initialized":
29862
+ break;
29863
+ case "notifications/cancelled":
29864
+ break;
29865
+ case "notifications/progress":
29866
+ break;
29867
+ }
29868
+ }
29869
+ assertRequestHandlerCapability(method) {
29870
+ if (!this._capabilities) {
29871
+ return;
29872
+ }
29873
+ switch (method) {
29874
+ case "sampling/createMessage":
29875
+ if (!this._capabilities.sampling) {
29876
+ throw new Error(`Client does not support sampling capability (required for ${method})`);
29877
+ }
29878
+ break;
29879
+ case "elicitation/create":
29880
+ if (!this._capabilities.elicitation) {
29881
+ throw new Error(`Client does not support elicitation capability (required for ${method})`);
29882
+ }
29883
+ break;
29884
+ case "roots/list":
29885
+ if (!this._capabilities.roots) {
29886
+ throw new Error(`Client does not support roots capability (required for ${method})`);
29887
+ }
29888
+ break;
29889
+ case "tasks/get":
29890
+ case "tasks/list":
29891
+ case "tasks/result":
29892
+ case "tasks/cancel":
29893
+ if (!this._capabilities.tasks) {
29894
+ throw new Error(`Client does not support tasks capability (required for ${method})`);
29895
+ }
29896
+ break;
29897
+ case "ping":
29898
+ break;
29899
+ }
29900
+ }
29901
+ assertTaskCapability(method) {
29902
+ assertToolsCallTaskCapability(this._serverCapabilities?.tasks?.requests, method, "Server");
29903
+ }
29904
+ assertTaskHandlerCapability(method) {
29905
+ if (!this._capabilities) {
29906
+ return;
29907
+ }
29908
+ assertClientRequestTaskCapability(this._capabilities.tasks?.requests, method, "Client");
29909
+ }
29910
+ async ping(options) {
29911
+ return this.request({ method: "ping" }, EmptyResultSchema, options);
29912
+ }
29913
+ async complete(params, options) {
29914
+ return this.request({ method: "completion/complete", params }, CompleteResultSchema, options);
29915
+ }
29916
+ async setLoggingLevel(level, options) {
29917
+ return this.request({ method: "logging/setLevel", params: { level } }, EmptyResultSchema, options);
29918
+ }
29919
+ async getPrompt(params, options) {
29920
+ return this.request({ method: "prompts/get", params }, GetPromptResultSchema, options);
29921
+ }
29922
+ async listPrompts(params, options) {
29923
+ return this.request({ method: "prompts/list", params }, ListPromptsResultSchema, options);
29924
+ }
29925
+ async listResources(params, options) {
29926
+ return this.request({ method: "resources/list", params }, ListResourcesResultSchema, options);
29927
+ }
29928
+ async listResourceTemplates(params, options) {
29929
+ return this.request({ method: "resources/templates/list", params }, ListResourceTemplatesResultSchema, options);
29930
+ }
29931
+ async readResource(params, options) {
29932
+ return this.request({ method: "resources/read", params }, ReadResourceResultSchema, options);
29933
+ }
29934
+ async subscribeResource(params, options) {
29935
+ return this.request({ method: "resources/subscribe", params }, EmptyResultSchema, options);
29936
+ }
29937
+ async unsubscribeResource(params, options) {
29938
+ return this.request({ method: "resources/unsubscribe", params }, EmptyResultSchema, options);
29939
+ }
29940
+ /**
29941
+ * Calls a tool and waits for the result. Automatically validates structured output if the tool has an outputSchema.
29942
+ *
29943
+ * For task-based execution with streaming behavior, use client.experimental.tasks.callToolStream() instead.
29944
+ */
29945
+ async callTool(params, resultSchema = CallToolResultSchema, options) {
29946
+ if (this.isToolTaskRequired(params.name)) {
29947
+ throw new McpError(ErrorCode.InvalidRequest, `Tool "${params.name}" requires task-based execution. Use client.experimental.tasks.callToolStream() instead.`);
29948
+ }
29949
+ const result = await this.request({ method: "tools/call", params }, resultSchema, options);
29950
+ const validator = this.getToolOutputValidator(params.name);
29951
+ if (validator) {
29952
+ if (!result.structuredContent && !result.isError) {
29953
+ throw new McpError(ErrorCode.InvalidRequest, `Tool ${params.name} has an output schema but did not return structured content`);
29954
+ }
29955
+ if (result.structuredContent) {
29956
+ try {
29957
+ const validationResult = validator(result.structuredContent);
29958
+ if (!validationResult.valid) {
29959
+ throw new McpError(ErrorCode.InvalidParams, `Structured content does not match the tool's output schema: ${validationResult.errorMessage}`);
29960
+ }
29961
+ } catch (error51) {
29962
+ if (error51 instanceof McpError) {
29963
+ throw error51;
29964
+ }
29965
+ throw new McpError(ErrorCode.InvalidParams, `Failed to validate structured content: ${error51 instanceof Error ? error51.message : String(error51)}`);
29966
+ }
29967
+ }
29968
+ }
29969
+ return result;
29970
+ }
29971
+ isToolTask(toolName) {
29972
+ if (!this._serverCapabilities?.tasks?.requests?.tools?.call) {
29973
+ return false;
29974
+ }
29975
+ return this._cachedKnownTaskTools.has(toolName);
29976
+ }
29977
+ /**
29978
+ * Check if a tool requires task-based execution.
29979
+ * Unlike isToolTask which includes 'optional' tools, this only checks for 'required'.
29980
+ */
29981
+ isToolTaskRequired(toolName) {
29982
+ return this._cachedRequiredTaskTools.has(toolName);
29983
+ }
29984
+ /**
29985
+ * Cache validators for tool output schemas.
29986
+ * Called after listTools() to pre-compile validators for better performance.
29987
+ */
29988
+ cacheToolMetadata(tools) {
29989
+ this._cachedToolOutputValidators.clear();
29990
+ this._cachedKnownTaskTools.clear();
29991
+ this._cachedRequiredTaskTools.clear();
29992
+ for (const tool of tools) {
29993
+ if (tool.outputSchema) {
29994
+ const toolValidator = this._jsonSchemaValidator.getValidator(tool.outputSchema);
29995
+ this._cachedToolOutputValidators.set(tool.name, toolValidator);
29996
+ }
29997
+ const taskSupport = tool.execution?.taskSupport;
29998
+ if (taskSupport === "required" || taskSupport === "optional") {
29999
+ this._cachedKnownTaskTools.add(tool.name);
30000
+ }
30001
+ if (taskSupport === "required") {
30002
+ this._cachedRequiredTaskTools.add(tool.name);
30003
+ }
30004
+ }
30005
+ }
30006
+ /**
30007
+ * Get cached validator for a tool
30008
+ */
30009
+ getToolOutputValidator(toolName) {
30010
+ return this._cachedToolOutputValidators.get(toolName);
30011
+ }
30012
+ async listTools(params, options) {
30013
+ const result = await this.request({ method: "tools/list", params }, ListToolsResultSchema, options);
30014
+ this.cacheToolMetadata(result.tools);
30015
+ return result;
30016
+ }
30017
+ /**
30018
+ * Set up a single list changed handler.
30019
+ * @internal
30020
+ */
30021
+ _setupListChangedHandler(listType, notificationSchema, options, fetcher) {
30022
+ const parseResult = ListChangedOptionsBaseSchema.safeParse(options);
30023
+ if (!parseResult.success) {
30024
+ throw new Error(`Invalid ${listType} listChanged options: ${parseResult.error.message}`);
30025
+ }
30026
+ if (typeof options.onChanged !== "function") {
30027
+ throw new Error(`Invalid ${listType} listChanged options: onChanged must be a function`);
30028
+ }
30029
+ const { autoRefresh, debounceMs } = parseResult.data;
30030
+ const { onChanged } = options;
30031
+ const refresh = async () => {
30032
+ if (!autoRefresh) {
30033
+ onChanged(null, null);
30034
+ return;
30035
+ }
30036
+ try {
30037
+ const items = await fetcher();
30038
+ onChanged(null, items);
30039
+ } catch (e) {
30040
+ const error51 = e instanceof Error ? e : new Error(String(e));
30041
+ onChanged(error51, null);
30042
+ }
30043
+ };
30044
+ const handler = () => {
30045
+ if (debounceMs) {
30046
+ const existingTimer = this._listChangedDebounceTimers.get(listType);
30047
+ if (existingTimer) {
30048
+ clearTimeout(existingTimer);
30049
+ }
30050
+ const timer = setTimeout(refresh, debounceMs);
30051
+ this._listChangedDebounceTimers.set(listType, timer);
30052
+ } else {
30053
+ refresh();
30054
+ }
30055
+ };
30056
+ this.setNotificationHandler(notificationSchema, handler);
30057
+ }
30058
+ async sendRootsListChanged() {
30059
+ return this.notification({ method: "notifications/roots/list_changed" });
30060
+ }
30061
+ };
30062
+
29353
30063
  // node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/server.js
29354
30064
  var ExperimentalServerTasks = class {
29355
30065
  constructor(_server) {
@@ -29563,41 +30273,6 @@ var ExperimentalServerTasks = class {
29563
30273
  }
29564
30274
  };
29565
30275
 
29566
- // node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/helpers.js
29567
- function assertToolsCallTaskCapability(requests, method, entityName) {
29568
- if (!requests) {
29569
- throw new Error(`${entityName} does not support task creation (required for ${method})`);
29570
- }
29571
- switch (method) {
29572
- case "tools/call":
29573
- if (!requests.tools?.call) {
29574
- throw new Error(`${entityName} does not support task creation for tools/call (required for ${method})`);
29575
- }
29576
- break;
29577
- default:
29578
- break;
29579
- }
29580
- }
29581
- function assertClientRequestTaskCapability(requests, method, entityName) {
29582
- if (!requests) {
29583
- throw new Error(`${entityName} does not support task creation (required for ${method})`);
29584
- }
29585
- switch (method) {
29586
- case "sampling/createMessage":
29587
- if (!requests.sampling?.createMessage) {
29588
- throw new Error(`${entityName} does not support task creation for sampling/createMessage (required for ${method})`);
29589
- }
29590
- break;
29591
- case "elicitation/create":
29592
- if (!requests.elicitation?.create) {
29593
- throw new Error(`${entityName} does not support task creation for elicitation/create (required for ${method})`);
29594
- }
29595
- break;
29596
- default:
29597
- break;
29598
- }
29599
- }
29600
-
29601
30276
  // node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js
29602
30277
  var Server = class extends Protocol {
29603
30278
  /**
@@ -30949,15 +31624,1476 @@ var StdioServerTransport = class {
30949
31624
  }
30950
31625
  };
30951
31626
 
31627
+ // node_modules/@modelcontextprotocol/sdk/dist/esm/shared/transport.js
31628
+ function normalizeHeaders(headers) {
31629
+ if (!headers)
31630
+ return {};
31631
+ if (headers instanceof Headers) {
31632
+ return Object.fromEntries(headers.entries());
31633
+ }
31634
+ if (Array.isArray(headers)) {
31635
+ return Object.fromEntries(headers);
31636
+ }
31637
+ return { ...headers };
31638
+ }
31639
+ function createFetchWithInit(baseFetch = fetch, baseInit) {
31640
+ if (!baseInit) {
31641
+ return baseFetch;
31642
+ }
31643
+ return async (url2, init) => {
31644
+ const mergedInit = {
31645
+ ...baseInit,
31646
+ ...init,
31647
+ // Headers need special handling - merge instead of replace
31648
+ headers: init?.headers ? { ...normalizeHeaders(baseInit.headers), ...normalizeHeaders(init.headers) } : baseInit.headers
31649
+ };
31650
+ return baseFetch(url2, mergedInit);
31651
+ };
31652
+ }
31653
+
31654
+ // node_modules/pkce-challenge/dist/index.node.js
31655
+ var crypto;
31656
+ crypto = globalThis.crypto?.webcrypto ?? // Node.js [18-16] REPL
31657
+ globalThis.crypto ?? // Node.js >18
31658
+ import("node:crypto").then((m) => m.webcrypto);
31659
+ async function getRandomValues(size) {
31660
+ return (await crypto).getRandomValues(new Uint8Array(size));
31661
+ }
31662
+ async function random(size) {
31663
+ const mask = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~";
31664
+ const evenDistCutoff = Math.pow(2, 8) - Math.pow(2, 8) % mask.length;
31665
+ let result = "";
31666
+ while (result.length < size) {
31667
+ const randomBytes = await getRandomValues(size - result.length);
31668
+ for (const randomByte of randomBytes) {
31669
+ if (randomByte < evenDistCutoff) {
31670
+ result += mask[randomByte % mask.length];
31671
+ }
31672
+ }
31673
+ }
31674
+ return result;
31675
+ }
31676
+ async function generateVerifier(length) {
31677
+ return await random(length);
31678
+ }
31679
+ async function generateChallenge(code_verifier) {
31680
+ const buffer = await (await crypto).subtle.digest("SHA-256", new TextEncoder().encode(code_verifier));
31681
+ return btoa(String.fromCharCode(...new Uint8Array(buffer))).replace(/\//g, "_").replace(/\+/g, "-").replace(/=/g, "");
31682
+ }
31683
+ async function pkceChallenge(length) {
31684
+ if (!length)
31685
+ length = 43;
31686
+ if (length < 43 || length > 128) {
31687
+ throw `Expected a length between 43 and 128. Received ${length}.`;
31688
+ }
31689
+ const verifier = await generateVerifier(length);
31690
+ const challenge = await generateChallenge(verifier);
31691
+ return {
31692
+ code_verifier: verifier,
31693
+ code_challenge: challenge
31694
+ };
31695
+ }
31696
+
31697
+ // node_modules/@modelcontextprotocol/sdk/dist/esm/shared/auth.js
31698
+ var SafeUrlSchema = url().superRefine((val, ctx) => {
31699
+ if (!URL.canParse(val)) {
31700
+ ctx.addIssue({
31701
+ code: ZodIssueCode2.custom,
31702
+ message: "URL must be parseable",
31703
+ fatal: true
31704
+ });
31705
+ return NEVER;
31706
+ }
31707
+ }).refine((url2) => {
31708
+ const u = new URL(url2);
31709
+ return u.protocol !== "javascript:" && u.protocol !== "data:" && u.protocol !== "vbscript:";
31710
+ }, { message: "URL cannot use javascript:, data:, or vbscript: scheme" });
31711
+ var OAuthProtectedResourceMetadataSchema = looseObject({
31712
+ resource: string2().url(),
31713
+ authorization_servers: array(SafeUrlSchema).optional(),
31714
+ jwks_uri: string2().url().optional(),
31715
+ scopes_supported: array(string2()).optional(),
31716
+ bearer_methods_supported: array(string2()).optional(),
31717
+ resource_signing_alg_values_supported: array(string2()).optional(),
31718
+ resource_name: string2().optional(),
31719
+ resource_documentation: string2().optional(),
31720
+ resource_policy_uri: string2().url().optional(),
31721
+ resource_tos_uri: string2().url().optional(),
31722
+ tls_client_certificate_bound_access_tokens: boolean2().optional(),
31723
+ authorization_details_types_supported: array(string2()).optional(),
31724
+ dpop_signing_alg_values_supported: array(string2()).optional(),
31725
+ dpop_bound_access_tokens_required: boolean2().optional()
31726
+ });
31727
+ var OAuthMetadataSchema = looseObject({
31728
+ issuer: string2(),
31729
+ authorization_endpoint: SafeUrlSchema,
31730
+ token_endpoint: SafeUrlSchema,
31731
+ registration_endpoint: SafeUrlSchema.optional(),
31732
+ scopes_supported: array(string2()).optional(),
31733
+ response_types_supported: array(string2()),
31734
+ response_modes_supported: array(string2()).optional(),
31735
+ grant_types_supported: array(string2()).optional(),
31736
+ token_endpoint_auth_methods_supported: array(string2()).optional(),
31737
+ token_endpoint_auth_signing_alg_values_supported: array(string2()).optional(),
31738
+ service_documentation: SafeUrlSchema.optional(),
31739
+ revocation_endpoint: SafeUrlSchema.optional(),
31740
+ revocation_endpoint_auth_methods_supported: array(string2()).optional(),
31741
+ revocation_endpoint_auth_signing_alg_values_supported: array(string2()).optional(),
31742
+ introspection_endpoint: string2().optional(),
31743
+ introspection_endpoint_auth_methods_supported: array(string2()).optional(),
31744
+ introspection_endpoint_auth_signing_alg_values_supported: array(string2()).optional(),
31745
+ code_challenge_methods_supported: array(string2()).optional(),
31746
+ client_id_metadata_document_supported: boolean2().optional()
31747
+ });
31748
+ var OpenIdProviderMetadataSchema = looseObject({
31749
+ issuer: string2(),
31750
+ authorization_endpoint: SafeUrlSchema,
31751
+ token_endpoint: SafeUrlSchema,
31752
+ userinfo_endpoint: SafeUrlSchema.optional(),
31753
+ jwks_uri: SafeUrlSchema,
31754
+ registration_endpoint: SafeUrlSchema.optional(),
31755
+ scopes_supported: array(string2()).optional(),
31756
+ response_types_supported: array(string2()),
31757
+ response_modes_supported: array(string2()).optional(),
31758
+ grant_types_supported: array(string2()).optional(),
31759
+ acr_values_supported: array(string2()).optional(),
31760
+ subject_types_supported: array(string2()),
31761
+ id_token_signing_alg_values_supported: array(string2()),
31762
+ id_token_encryption_alg_values_supported: array(string2()).optional(),
31763
+ id_token_encryption_enc_values_supported: array(string2()).optional(),
31764
+ userinfo_signing_alg_values_supported: array(string2()).optional(),
31765
+ userinfo_encryption_alg_values_supported: array(string2()).optional(),
31766
+ userinfo_encryption_enc_values_supported: array(string2()).optional(),
31767
+ request_object_signing_alg_values_supported: array(string2()).optional(),
31768
+ request_object_encryption_alg_values_supported: array(string2()).optional(),
31769
+ request_object_encryption_enc_values_supported: array(string2()).optional(),
31770
+ token_endpoint_auth_methods_supported: array(string2()).optional(),
31771
+ token_endpoint_auth_signing_alg_values_supported: array(string2()).optional(),
31772
+ display_values_supported: array(string2()).optional(),
31773
+ claim_types_supported: array(string2()).optional(),
31774
+ claims_supported: array(string2()).optional(),
31775
+ service_documentation: string2().optional(),
31776
+ claims_locales_supported: array(string2()).optional(),
31777
+ ui_locales_supported: array(string2()).optional(),
31778
+ claims_parameter_supported: boolean2().optional(),
31779
+ request_parameter_supported: boolean2().optional(),
31780
+ request_uri_parameter_supported: boolean2().optional(),
31781
+ require_request_uri_registration: boolean2().optional(),
31782
+ op_policy_uri: SafeUrlSchema.optional(),
31783
+ op_tos_uri: SafeUrlSchema.optional(),
31784
+ client_id_metadata_document_supported: boolean2().optional()
31785
+ });
31786
+ var OpenIdProviderDiscoveryMetadataSchema = object2({
31787
+ ...OpenIdProviderMetadataSchema.shape,
31788
+ ...OAuthMetadataSchema.pick({
31789
+ code_challenge_methods_supported: true
31790
+ }).shape
31791
+ });
31792
+ var OAuthTokensSchema = object2({
31793
+ access_token: string2(),
31794
+ id_token: string2().optional(),
31795
+ // Optional for OAuth 2.1, but necessary in OpenID Connect
31796
+ token_type: string2(),
31797
+ expires_in: coerce_exports2.number().optional(),
31798
+ scope: string2().optional(),
31799
+ refresh_token: string2().optional()
31800
+ }).strip();
31801
+ var OAuthErrorResponseSchema = object2({
31802
+ error: string2(),
31803
+ error_description: string2().optional(),
31804
+ error_uri: string2().optional()
31805
+ });
31806
+ var OptionalSafeUrlSchema = SafeUrlSchema.optional().or(literal("").transform(() => void 0));
31807
+ var OAuthClientMetadataSchema = object2({
31808
+ redirect_uris: array(SafeUrlSchema),
31809
+ token_endpoint_auth_method: string2().optional(),
31810
+ grant_types: array(string2()).optional(),
31811
+ response_types: array(string2()).optional(),
31812
+ client_name: string2().optional(),
31813
+ client_uri: SafeUrlSchema.optional(),
31814
+ logo_uri: OptionalSafeUrlSchema,
31815
+ scope: string2().optional(),
31816
+ contacts: array(string2()).optional(),
31817
+ tos_uri: OptionalSafeUrlSchema,
31818
+ policy_uri: string2().optional(),
31819
+ jwks_uri: SafeUrlSchema.optional(),
31820
+ jwks: any().optional(),
31821
+ software_id: string2().optional(),
31822
+ software_version: string2().optional(),
31823
+ software_statement: string2().optional()
31824
+ }).strip();
31825
+ var OAuthClientInformationSchema = object2({
31826
+ client_id: string2(),
31827
+ client_secret: string2().optional(),
31828
+ client_id_issued_at: number2().optional(),
31829
+ client_secret_expires_at: number2().optional()
31830
+ }).strip();
31831
+ var OAuthClientInformationFullSchema = OAuthClientMetadataSchema.merge(OAuthClientInformationSchema);
31832
+ var OAuthClientRegistrationErrorSchema = object2({
31833
+ error: string2(),
31834
+ error_description: string2().optional()
31835
+ }).strip();
31836
+ var OAuthTokenRevocationRequestSchema = object2({
31837
+ token: string2(),
31838
+ token_type_hint: string2().optional()
31839
+ }).strip();
31840
+
31841
+ // node_modules/@modelcontextprotocol/sdk/dist/esm/shared/auth-utils.js
31842
+ function resourceUrlFromServerUrl(url2) {
31843
+ const resourceURL = typeof url2 === "string" ? new URL(url2) : new URL(url2.href);
31844
+ resourceURL.hash = "";
31845
+ return resourceURL;
31846
+ }
31847
+ function checkResourceAllowed({ requestedResource, configuredResource }) {
31848
+ const requested = typeof requestedResource === "string" ? new URL(requestedResource) : new URL(requestedResource.href);
31849
+ const configured = typeof configuredResource === "string" ? new URL(configuredResource) : new URL(configuredResource.href);
31850
+ if (requested.origin !== configured.origin) {
31851
+ return false;
31852
+ }
31853
+ if (requested.pathname.length < configured.pathname.length) {
31854
+ return false;
31855
+ }
31856
+ const requestedPath = requested.pathname.endsWith("/") ? requested.pathname : requested.pathname + "/";
31857
+ const configuredPath = configured.pathname.endsWith("/") ? configured.pathname : configured.pathname + "/";
31858
+ return requestedPath.startsWith(configuredPath);
31859
+ }
31860
+
31861
+ // node_modules/@modelcontextprotocol/sdk/dist/esm/server/auth/errors.js
31862
+ var OAuthError = class extends Error {
31863
+ constructor(message, errorUri) {
31864
+ super(message);
31865
+ this.errorUri = errorUri;
31866
+ this.name = this.constructor.name;
31867
+ }
31868
+ /**
31869
+ * Converts the error to a standard OAuth error response object
31870
+ */
31871
+ toResponseObject() {
31872
+ const response = {
31873
+ error: this.errorCode,
31874
+ error_description: this.message
31875
+ };
31876
+ if (this.errorUri) {
31877
+ response.error_uri = this.errorUri;
31878
+ }
31879
+ return response;
31880
+ }
31881
+ get errorCode() {
31882
+ return this.constructor.errorCode;
31883
+ }
31884
+ };
31885
+ var InvalidRequestError = class extends OAuthError {
31886
+ };
31887
+ InvalidRequestError.errorCode = "invalid_request";
31888
+ var InvalidClientError = class extends OAuthError {
31889
+ };
31890
+ InvalidClientError.errorCode = "invalid_client";
31891
+ var InvalidGrantError = class extends OAuthError {
31892
+ };
31893
+ InvalidGrantError.errorCode = "invalid_grant";
31894
+ var UnauthorizedClientError = class extends OAuthError {
31895
+ };
31896
+ UnauthorizedClientError.errorCode = "unauthorized_client";
31897
+ var UnsupportedGrantTypeError = class extends OAuthError {
31898
+ };
31899
+ UnsupportedGrantTypeError.errorCode = "unsupported_grant_type";
31900
+ var InvalidScopeError = class extends OAuthError {
31901
+ };
31902
+ InvalidScopeError.errorCode = "invalid_scope";
31903
+ var AccessDeniedError = class extends OAuthError {
31904
+ };
31905
+ AccessDeniedError.errorCode = "access_denied";
31906
+ var ServerError = class extends OAuthError {
31907
+ };
31908
+ ServerError.errorCode = "server_error";
31909
+ var TemporarilyUnavailableError = class extends OAuthError {
31910
+ };
31911
+ TemporarilyUnavailableError.errorCode = "temporarily_unavailable";
31912
+ var UnsupportedResponseTypeError = class extends OAuthError {
31913
+ };
31914
+ UnsupportedResponseTypeError.errorCode = "unsupported_response_type";
31915
+ var UnsupportedTokenTypeError = class extends OAuthError {
31916
+ };
31917
+ UnsupportedTokenTypeError.errorCode = "unsupported_token_type";
31918
+ var InvalidTokenError = class extends OAuthError {
31919
+ };
31920
+ InvalidTokenError.errorCode = "invalid_token";
31921
+ var MethodNotAllowedError = class extends OAuthError {
31922
+ };
31923
+ MethodNotAllowedError.errorCode = "method_not_allowed";
31924
+ var TooManyRequestsError = class extends OAuthError {
31925
+ };
31926
+ TooManyRequestsError.errorCode = "too_many_requests";
31927
+ var InvalidClientMetadataError = class extends OAuthError {
31928
+ };
31929
+ InvalidClientMetadataError.errorCode = "invalid_client_metadata";
31930
+ var InsufficientScopeError = class extends OAuthError {
31931
+ };
31932
+ InsufficientScopeError.errorCode = "insufficient_scope";
31933
+ var InvalidTargetError = class extends OAuthError {
31934
+ };
31935
+ InvalidTargetError.errorCode = "invalid_target";
31936
+ var OAUTH_ERRORS = {
31937
+ [InvalidRequestError.errorCode]: InvalidRequestError,
31938
+ [InvalidClientError.errorCode]: InvalidClientError,
31939
+ [InvalidGrantError.errorCode]: InvalidGrantError,
31940
+ [UnauthorizedClientError.errorCode]: UnauthorizedClientError,
31941
+ [UnsupportedGrantTypeError.errorCode]: UnsupportedGrantTypeError,
31942
+ [InvalidScopeError.errorCode]: InvalidScopeError,
31943
+ [AccessDeniedError.errorCode]: AccessDeniedError,
31944
+ [ServerError.errorCode]: ServerError,
31945
+ [TemporarilyUnavailableError.errorCode]: TemporarilyUnavailableError,
31946
+ [UnsupportedResponseTypeError.errorCode]: UnsupportedResponseTypeError,
31947
+ [UnsupportedTokenTypeError.errorCode]: UnsupportedTokenTypeError,
31948
+ [InvalidTokenError.errorCode]: InvalidTokenError,
31949
+ [MethodNotAllowedError.errorCode]: MethodNotAllowedError,
31950
+ [TooManyRequestsError.errorCode]: TooManyRequestsError,
31951
+ [InvalidClientMetadataError.errorCode]: InvalidClientMetadataError,
31952
+ [InsufficientScopeError.errorCode]: InsufficientScopeError,
31953
+ [InvalidTargetError.errorCode]: InvalidTargetError
31954
+ };
31955
+
31956
+ // node_modules/@modelcontextprotocol/sdk/dist/esm/client/auth.js
31957
+ var UnauthorizedError = class extends Error {
31958
+ constructor(message) {
31959
+ super(message ?? "Unauthorized");
31960
+ }
31961
+ };
31962
+ function isClientAuthMethod(method) {
31963
+ return ["client_secret_basic", "client_secret_post", "none"].includes(method);
31964
+ }
31965
+ var AUTHORIZATION_CODE_RESPONSE_TYPE = "code";
31966
+ var AUTHORIZATION_CODE_CHALLENGE_METHOD = "S256";
31967
+ function selectClientAuthMethod(clientInformation, supportedMethods) {
31968
+ const hasClientSecret = clientInformation.client_secret !== void 0;
31969
+ if ("token_endpoint_auth_method" in clientInformation && clientInformation.token_endpoint_auth_method && isClientAuthMethod(clientInformation.token_endpoint_auth_method) && (supportedMethods.length === 0 || supportedMethods.includes(clientInformation.token_endpoint_auth_method))) {
31970
+ return clientInformation.token_endpoint_auth_method;
31971
+ }
31972
+ if (supportedMethods.length === 0) {
31973
+ return hasClientSecret ? "client_secret_basic" : "none";
31974
+ }
31975
+ if (hasClientSecret && supportedMethods.includes("client_secret_basic")) {
31976
+ return "client_secret_basic";
31977
+ }
31978
+ if (hasClientSecret && supportedMethods.includes("client_secret_post")) {
31979
+ return "client_secret_post";
31980
+ }
31981
+ if (supportedMethods.includes("none")) {
31982
+ return "none";
31983
+ }
31984
+ return hasClientSecret ? "client_secret_post" : "none";
31985
+ }
31986
+ function applyClientAuthentication(method, clientInformation, headers, params) {
31987
+ const { client_id, client_secret } = clientInformation;
31988
+ switch (method) {
31989
+ case "client_secret_basic":
31990
+ applyBasicAuth(client_id, client_secret, headers);
31991
+ return;
31992
+ case "client_secret_post":
31993
+ applyPostAuth(client_id, client_secret, params);
31994
+ return;
31995
+ case "none":
31996
+ applyPublicAuth(client_id, params);
31997
+ return;
31998
+ default:
31999
+ throw new Error(`Unsupported client authentication method: ${method}`);
32000
+ }
32001
+ }
32002
+ function applyBasicAuth(clientId, clientSecret, headers) {
32003
+ if (!clientSecret) {
32004
+ throw new Error("client_secret_basic authentication requires a client_secret");
32005
+ }
32006
+ const credentials = btoa(`${clientId}:${clientSecret}`);
32007
+ headers.set("Authorization", `Basic ${credentials}`);
32008
+ }
32009
+ function applyPostAuth(clientId, clientSecret, params) {
32010
+ params.set("client_id", clientId);
32011
+ if (clientSecret) {
32012
+ params.set("client_secret", clientSecret);
32013
+ }
32014
+ }
32015
+ function applyPublicAuth(clientId, params) {
32016
+ params.set("client_id", clientId);
32017
+ }
32018
+ async function parseErrorResponse(input) {
32019
+ const statusCode = input instanceof Response ? input.status : void 0;
32020
+ const body = input instanceof Response ? await input.text() : input;
32021
+ try {
32022
+ const result = OAuthErrorResponseSchema.parse(JSON.parse(body));
32023
+ const { error: error51, error_description, error_uri } = result;
32024
+ const errorClass = OAUTH_ERRORS[error51] || ServerError;
32025
+ return new errorClass(error_description || "", error_uri);
32026
+ } catch (error51) {
32027
+ const errorMessage2 = `${statusCode ? `HTTP ${statusCode}: ` : ""}Invalid OAuth error response: ${error51}. Raw body: ${body}`;
32028
+ return new ServerError(errorMessage2);
32029
+ }
32030
+ }
32031
+ async function auth(provider, options) {
32032
+ try {
32033
+ return await authInternal(provider, options);
32034
+ } catch (error51) {
32035
+ if (error51 instanceof InvalidClientError || error51 instanceof UnauthorizedClientError) {
32036
+ await provider.invalidateCredentials?.("all");
32037
+ return await authInternal(provider, options);
32038
+ } else if (error51 instanceof InvalidGrantError) {
32039
+ await provider.invalidateCredentials?.("tokens");
32040
+ return await authInternal(provider, options);
32041
+ }
32042
+ throw error51;
32043
+ }
32044
+ }
32045
+ async function authInternal(provider, { serverUrl, authorizationCode, scope, resourceMetadataUrl, fetchFn }) {
32046
+ const cachedState = await provider.discoveryState?.();
32047
+ let resourceMetadata;
32048
+ let authorizationServerUrl;
32049
+ let metadata;
32050
+ let effectiveResourceMetadataUrl = resourceMetadataUrl;
32051
+ if (!effectiveResourceMetadataUrl && cachedState?.resourceMetadataUrl) {
32052
+ effectiveResourceMetadataUrl = new URL(cachedState.resourceMetadataUrl);
32053
+ }
32054
+ if (cachedState?.authorizationServerUrl) {
32055
+ authorizationServerUrl = cachedState.authorizationServerUrl;
32056
+ resourceMetadata = cachedState.resourceMetadata;
32057
+ metadata = cachedState.authorizationServerMetadata ?? await discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn });
32058
+ if (!resourceMetadata) {
32059
+ try {
32060
+ resourceMetadata = await discoverOAuthProtectedResourceMetadata(serverUrl, { resourceMetadataUrl: effectiveResourceMetadataUrl }, fetchFn);
32061
+ } catch {
32062
+ }
32063
+ }
32064
+ if (metadata !== cachedState.authorizationServerMetadata || resourceMetadata !== cachedState.resourceMetadata) {
32065
+ await provider.saveDiscoveryState?.({
32066
+ authorizationServerUrl: String(authorizationServerUrl),
32067
+ resourceMetadataUrl: effectiveResourceMetadataUrl?.toString(),
32068
+ resourceMetadata,
32069
+ authorizationServerMetadata: metadata
32070
+ });
32071
+ }
32072
+ } else {
32073
+ const serverInfo = await discoverOAuthServerInfo(serverUrl, { resourceMetadataUrl: effectiveResourceMetadataUrl, fetchFn });
32074
+ authorizationServerUrl = serverInfo.authorizationServerUrl;
32075
+ metadata = serverInfo.authorizationServerMetadata;
32076
+ resourceMetadata = serverInfo.resourceMetadata;
32077
+ await provider.saveDiscoveryState?.({
32078
+ authorizationServerUrl: String(authorizationServerUrl),
32079
+ resourceMetadataUrl: effectiveResourceMetadataUrl?.toString(),
32080
+ resourceMetadata,
32081
+ authorizationServerMetadata: metadata
32082
+ });
32083
+ }
32084
+ const resource = await selectResourceURL(serverUrl, provider, resourceMetadata);
32085
+ const resolvedScope = scope || resourceMetadata?.scopes_supported?.join(" ") || provider.clientMetadata.scope;
32086
+ let clientInformation = await Promise.resolve(provider.clientInformation());
32087
+ if (!clientInformation) {
32088
+ if (authorizationCode !== void 0) {
32089
+ throw new Error("Existing OAuth client information is required when exchanging an authorization code");
32090
+ }
32091
+ const supportsUrlBasedClientId = metadata?.client_id_metadata_document_supported === true;
32092
+ const clientMetadataUrl = provider.clientMetadataUrl;
32093
+ if (clientMetadataUrl && !isHttpsUrl(clientMetadataUrl)) {
32094
+ throw new InvalidClientMetadataError(`clientMetadataUrl must be a valid HTTPS URL with a non-root pathname, got: ${clientMetadataUrl}`);
32095
+ }
32096
+ const shouldUseUrlBasedClientId = supportsUrlBasedClientId && clientMetadataUrl;
32097
+ if (shouldUseUrlBasedClientId) {
32098
+ clientInformation = {
32099
+ client_id: clientMetadataUrl
32100
+ };
32101
+ await provider.saveClientInformation?.(clientInformation);
32102
+ } else {
32103
+ if (!provider.saveClientInformation) {
32104
+ throw new Error("OAuth client information must be saveable for dynamic registration");
32105
+ }
32106
+ const fullInformation = await registerClient(authorizationServerUrl, {
32107
+ metadata,
32108
+ clientMetadata: provider.clientMetadata,
32109
+ scope: resolvedScope,
32110
+ fetchFn
32111
+ });
32112
+ await provider.saveClientInformation(fullInformation);
32113
+ clientInformation = fullInformation;
32114
+ }
32115
+ }
32116
+ const nonInteractiveFlow = !provider.redirectUrl;
32117
+ if (authorizationCode !== void 0 || nonInteractiveFlow) {
32118
+ const tokens2 = await fetchToken(provider, authorizationServerUrl, {
32119
+ metadata,
32120
+ resource,
32121
+ authorizationCode,
32122
+ fetchFn
32123
+ });
32124
+ await provider.saveTokens(tokens2);
32125
+ return "AUTHORIZED";
32126
+ }
32127
+ const tokens = await provider.tokens();
32128
+ if (tokens?.refresh_token) {
32129
+ try {
32130
+ const newTokens = await refreshAuthorization(authorizationServerUrl, {
32131
+ metadata,
32132
+ clientInformation,
32133
+ refreshToken: tokens.refresh_token,
32134
+ resource,
32135
+ addClientAuthentication: provider.addClientAuthentication,
32136
+ fetchFn
32137
+ });
32138
+ await provider.saveTokens(newTokens);
32139
+ return "AUTHORIZED";
32140
+ } catch (error51) {
32141
+ if (!(error51 instanceof OAuthError) || error51 instanceof ServerError) {
32142
+ } else {
32143
+ throw error51;
32144
+ }
32145
+ }
32146
+ }
32147
+ const state = provider.state ? await provider.state() : void 0;
32148
+ const { authorizationUrl, codeVerifier } = await startAuthorization(authorizationServerUrl, {
32149
+ metadata,
32150
+ clientInformation,
32151
+ state,
32152
+ redirectUrl: provider.redirectUrl,
32153
+ scope: resolvedScope,
32154
+ resource
32155
+ });
32156
+ await provider.saveCodeVerifier(codeVerifier);
32157
+ await provider.redirectToAuthorization(authorizationUrl);
32158
+ return "REDIRECT";
32159
+ }
32160
+ function isHttpsUrl(value) {
32161
+ if (!value)
32162
+ return false;
32163
+ try {
32164
+ const url2 = new URL(value);
32165
+ return url2.protocol === "https:" && url2.pathname !== "/";
32166
+ } catch {
32167
+ return false;
32168
+ }
32169
+ }
32170
+ async function selectResourceURL(serverUrl, provider, resourceMetadata) {
32171
+ const defaultResource = resourceUrlFromServerUrl(serverUrl);
32172
+ if (provider.validateResourceURL) {
32173
+ return await provider.validateResourceURL(defaultResource, resourceMetadata?.resource);
32174
+ }
32175
+ if (!resourceMetadata) {
32176
+ return void 0;
32177
+ }
32178
+ if (!checkResourceAllowed({ requestedResource: defaultResource, configuredResource: resourceMetadata.resource })) {
32179
+ throw new Error(`Protected resource ${resourceMetadata.resource} does not match expected ${defaultResource} (or origin)`);
32180
+ }
32181
+ return new URL(resourceMetadata.resource);
32182
+ }
32183
+ function extractWWWAuthenticateParams(res) {
32184
+ const authenticateHeader = res.headers.get("WWW-Authenticate");
32185
+ if (!authenticateHeader) {
32186
+ return {};
32187
+ }
32188
+ const [type2, scheme] = authenticateHeader.split(" ");
32189
+ if (type2.toLowerCase() !== "bearer" || !scheme) {
32190
+ return {};
32191
+ }
32192
+ const resourceMetadataMatch = extractFieldFromWwwAuth(res, "resource_metadata") || void 0;
32193
+ let resourceMetadataUrl;
32194
+ if (resourceMetadataMatch) {
32195
+ try {
32196
+ resourceMetadataUrl = new URL(resourceMetadataMatch);
32197
+ } catch {
32198
+ }
32199
+ }
32200
+ const scope = extractFieldFromWwwAuth(res, "scope") || void 0;
32201
+ const error51 = extractFieldFromWwwAuth(res, "error") || void 0;
32202
+ return {
32203
+ resourceMetadataUrl,
32204
+ scope,
32205
+ error: error51
32206
+ };
32207
+ }
32208
+ function extractFieldFromWwwAuth(response, fieldName) {
32209
+ const wwwAuthHeader = response.headers.get("WWW-Authenticate");
32210
+ if (!wwwAuthHeader) {
32211
+ return null;
32212
+ }
32213
+ const pattern = new RegExp(`${fieldName}=(?:"([^"]+)"|([^\\s,]+))`);
32214
+ const match = wwwAuthHeader.match(pattern);
32215
+ if (match) {
32216
+ return match[1] || match[2];
32217
+ }
32218
+ return null;
32219
+ }
32220
+ async function discoverOAuthProtectedResourceMetadata(serverUrl, opts, fetchFn = fetch) {
32221
+ const response = await discoverMetadataWithFallback(serverUrl, "oauth-protected-resource", fetchFn, {
32222
+ protocolVersion: opts?.protocolVersion,
32223
+ metadataUrl: opts?.resourceMetadataUrl
32224
+ });
32225
+ if (!response || response.status === 404) {
32226
+ await response?.body?.cancel();
32227
+ throw new Error(`Resource server does not implement OAuth 2.0 Protected Resource Metadata.`);
32228
+ }
32229
+ if (!response.ok) {
32230
+ await response.body?.cancel();
32231
+ throw new Error(`HTTP ${response.status} trying to load well-known OAuth protected resource metadata.`);
32232
+ }
32233
+ return OAuthProtectedResourceMetadataSchema.parse(await response.json());
32234
+ }
32235
+ async function fetchWithCorsRetry(url2, headers, fetchFn = fetch) {
32236
+ try {
32237
+ return await fetchFn(url2, { headers });
32238
+ } catch (error51) {
32239
+ if (error51 instanceof TypeError) {
32240
+ if (headers) {
32241
+ return fetchWithCorsRetry(url2, void 0, fetchFn);
32242
+ } else {
32243
+ return void 0;
32244
+ }
32245
+ }
32246
+ throw error51;
32247
+ }
32248
+ }
32249
+ function buildWellKnownPath(wellKnownPrefix, pathname = "", options = {}) {
32250
+ if (pathname.endsWith("/")) {
32251
+ pathname = pathname.slice(0, -1);
32252
+ }
32253
+ return options.prependPathname ? `${pathname}/.well-known/${wellKnownPrefix}` : `/.well-known/${wellKnownPrefix}${pathname}`;
32254
+ }
32255
+ async function tryMetadataDiscovery(url2, protocolVersion, fetchFn = fetch) {
32256
+ const headers = {
32257
+ "MCP-Protocol-Version": protocolVersion
32258
+ };
32259
+ return await fetchWithCorsRetry(url2, headers, fetchFn);
32260
+ }
32261
+ function shouldAttemptFallback(response, pathname) {
32262
+ return !response || response.status >= 400 && response.status < 500 && pathname !== "/";
32263
+ }
32264
+ async function discoverMetadataWithFallback(serverUrl, wellKnownType, fetchFn, opts) {
32265
+ const issuer = new URL(serverUrl);
32266
+ const protocolVersion = opts?.protocolVersion ?? LATEST_PROTOCOL_VERSION;
32267
+ let url2;
32268
+ if (opts?.metadataUrl) {
32269
+ url2 = new URL(opts.metadataUrl);
32270
+ } else {
32271
+ const wellKnownPath = buildWellKnownPath(wellKnownType, issuer.pathname);
32272
+ url2 = new URL(wellKnownPath, opts?.metadataServerUrl ?? issuer);
32273
+ url2.search = issuer.search;
32274
+ }
32275
+ let response = await tryMetadataDiscovery(url2, protocolVersion, fetchFn);
32276
+ if (!opts?.metadataUrl && shouldAttemptFallback(response, issuer.pathname)) {
32277
+ const rootUrl = new URL(`/.well-known/${wellKnownType}`, issuer);
32278
+ response = await tryMetadataDiscovery(rootUrl, protocolVersion, fetchFn);
32279
+ }
32280
+ return response;
32281
+ }
32282
+ function buildDiscoveryUrls(authorizationServerUrl) {
32283
+ const url2 = typeof authorizationServerUrl === "string" ? new URL(authorizationServerUrl) : authorizationServerUrl;
32284
+ const hasPath = url2.pathname !== "/";
32285
+ const urlsToTry = [];
32286
+ if (!hasPath) {
32287
+ urlsToTry.push({
32288
+ url: new URL("/.well-known/oauth-authorization-server", url2.origin),
32289
+ type: "oauth"
32290
+ });
32291
+ urlsToTry.push({
32292
+ url: new URL(`/.well-known/openid-configuration`, url2.origin),
32293
+ type: "oidc"
32294
+ });
32295
+ return urlsToTry;
32296
+ }
32297
+ let pathname = url2.pathname;
32298
+ if (pathname.endsWith("/")) {
32299
+ pathname = pathname.slice(0, -1);
32300
+ }
32301
+ urlsToTry.push({
32302
+ url: new URL(`/.well-known/oauth-authorization-server${pathname}`, url2.origin),
32303
+ type: "oauth"
32304
+ });
32305
+ urlsToTry.push({
32306
+ url: new URL(`/.well-known/openid-configuration${pathname}`, url2.origin),
32307
+ type: "oidc"
32308
+ });
32309
+ urlsToTry.push({
32310
+ url: new URL(`${pathname}/.well-known/openid-configuration`, url2.origin),
32311
+ type: "oidc"
32312
+ });
32313
+ return urlsToTry;
32314
+ }
32315
+ async function discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn = fetch, protocolVersion = LATEST_PROTOCOL_VERSION } = {}) {
32316
+ const headers = {
32317
+ "MCP-Protocol-Version": protocolVersion,
32318
+ Accept: "application/json"
32319
+ };
32320
+ const urlsToTry = buildDiscoveryUrls(authorizationServerUrl);
32321
+ for (const { url: endpointUrl, type: type2 } of urlsToTry) {
32322
+ const response = await fetchWithCorsRetry(endpointUrl, headers, fetchFn);
32323
+ if (!response) {
32324
+ continue;
32325
+ }
32326
+ if (!response.ok) {
32327
+ await response.body?.cancel();
32328
+ if (response.status >= 400 && response.status < 500) {
32329
+ continue;
32330
+ }
32331
+ throw new Error(`HTTP ${response.status} trying to load ${type2 === "oauth" ? "OAuth" : "OpenID provider"} metadata from ${endpointUrl}`);
32332
+ }
32333
+ if (type2 === "oauth") {
32334
+ return OAuthMetadataSchema.parse(await response.json());
32335
+ } else {
32336
+ return OpenIdProviderDiscoveryMetadataSchema.parse(await response.json());
32337
+ }
32338
+ }
32339
+ return void 0;
32340
+ }
32341
+ async function discoverOAuthServerInfo(serverUrl, opts) {
32342
+ let resourceMetadata;
32343
+ let authorizationServerUrl;
32344
+ try {
32345
+ resourceMetadata = await discoverOAuthProtectedResourceMetadata(serverUrl, { resourceMetadataUrl: opts?.resourceMetadataUrl }, opts?.fetchFn);
32346
+ if (resourceMetadata.authorization_servers && resourceMetadata.authorization_servers.length > 0) {
32347
+ authorizationServerUrl = resourceMetadata.authorization_servers[0];
32348
+ }
32349
+ } catch {
32350
+ }
32351
+ if (!authorizationServerUrl) {
32352
+ authorizationServerUrl = String(new URL("/", serverUrl));
32353
+ }
32354
+ const authorizationServerMetadata = await discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn: opts?.fetchFn });
32355
+ return {
32356
+ authorizationServerUrl,
32357
+ authorizationServerMetadata,
32358
+ resourceMetadata
32359
+ };
32360
+ }
32361
+ async function startAuthorization(authorizationServerUrl, { metadata, clientInformation, redirectUrl, scope, state, resource }) {
32362
+ let authorizationUrl;
32363
+ if (metadata) {
32364
+ authorizationUrl = new URL(metadata.authorization_endpoint);
32365
+ if (!metadata.response_types_supported.includes(AUTHORIZATION_CODE_RESPONSE_TYPE)) {
32366
+ throw new Error(`Incompatible auth server: does not support response type ${AUTHORIZATION_CODE_RESPONSE_TYPE}`);
32367
+ }
32368
+ if (metadata.code_challenge_methods_supported && !metadata.code_challenge_methods_supported.includes(AUTHORIZATION_CODE_CHALLENGE_METHOD)) {
32369
+ throw new Error(`Incompatible auth server: does not support code challenge method ${AUTHORIZATION_CODE_CHALLENGE_METHOD}`);
32370
+ }
32371
+ } else {
32372
+ authorizationUrl = new URL("/authorize", authorizationServerUrl);
32373
+ }
32374
+ const challenge = await pkceChallenge();
32375
+ const codeVerifier = challenge.code_verifier;
32376
+ const codeChallenge = challenge.code_challenge;
32377
+ authorizationUrl.searchParams.set("response_type", AUTHORIZATION_CODE_RESPONSE_TYPE);
32378
+ authorizationUrl.searchParams.set("client_id", clientInformation.client_id);
32379
+ authorizationUrl.searchParams.set("code_challenge", codeChallenge);
32380
+ authorizationUrl.searchParams.set("code_challenge_method", AUTHORIZATION_CODE_CHALLENGE_METHOD);
32381
+ authorizationUrl.searchParams.set("redirect_uri", String(redirectUrl));
32382
+ if (state) {
32383
+ authorizationUrl.searchParams.set("state", state);
32384
+ }
32385
+ if (scope) {
32386
+ authorizationUrl.searchParams.set("scope", scope);
32387
+ }
32388
+ if (scope?.includes("offline_access")) {
32389
+ authorizationUrl.searchParams.append("prompt", "consent");
32390
+ }
32391
+ if (resource) {
32392
+ authorizationUrl.searchParams.set("resource", resource.href);
32393
+ }
32394
+ return { authorizationUrl, codeVerifier };
32395
+ }
32396
+ function prepareAuthorizationCodeRequest(authorizationCode, codeVerifier, redirectUri) {
32397
+ return new URLSearchParams({
32398
+ grant_type: "authorization_code",
32399
+ code: authorizationCode,
32400
+ code_verifier: codeVerifier,
32401
+ redirect_uri: String(redirectUri)
32402
+ });
32403
+ }
32404
+ async function executeTokenRequest(authorizationServerUrl, { metadata, tokenRequestParams, clientInformation, addClientAuthentication, resource, fetchFn }) {
32405
+ const tokenUrl = metadata?.token_endpoint ? new URL(metadata.token_endpoint) : new URL("/token", authorizationServerUrl);
32406
+ const headers = new Headers({
32407
+ "Content-Type": "application/x-www-form-urlencoded",
32408
+ Accept: "application/json"
32409
+ });
32410
+ if (resource) {
32411
+ tokenRequestParams.set("resource", resource.href);
32412
+ }
32413
+ if (addClientAuthentication) {
32414
+ await addClientAuthentication(headers, tokenRequestParams, tokenUrl, metadata);
32415
+ } else if (clientInformation) {
32416
+ const supportedMethods = metadata?.token_endpoint_auth_methods_supported ?? [];
32417
+ const authMethod = selectClientAuthMethod(clientInformation, supportedMethods);
32418
+ applyClientAuthentication(authMethod, clientInformation, headers, tokenRequestParams);
32419
+ }
32420
+ const response = await (fetchFn ?? fetch)(tokenUrl, {
32421
+ method: "POST",
32422
+ headers,
32423
+ body: tokenRequestParams
32424
+ });
32425
+ if (!response.ok) {
32426
+ throw await parseErrorResponse(response);
32427
+ }
32428
+ return OAuthTokensSchema.parse(await response.json());
32429
+ }
32430
+ async function refreshAuthorization(authorizationServerUrl, { metadata, clientInformation, refreshToken, resource, addClientAuthentication, fetchFn }) {
32431
+ const tokenRequestParams = new URLSearchParams({
32432
+ grant_type: "refresh_token",
32433
+ refresh_token: refreshToken
32434
+ });
32435
+ const tokens = await executeTokenRequest(authorizationServerUrl, {
32436
+ metadata,
32437
+ tokenRequestParams,
32438
+ clientInformation,
32439
+ addClientAuthentication,
32440
+ resource,
32441
+ fetchFn
32442
+ });
32443
+ return { refresh_token: refreshToken, ...tokens };
32444
+ }
32445
+ async function fetchToken(provider, authorizationServerUrl, { metadata, resource, authorizationCode, fetchFn } = {}) {
32446
+ const scope = provider.clientMetadata.scope;
32447
+ let tokenRequestParams;
32448
+ if (provider.prepareTokenRequest) {
32449
+ tokenRequestParams = await provider.prepareTokenRequest(scope);
32450
+ }
32451
+ if (!tokenRequestParams) {
32452
+ if (!authorizationCode) {
32453
+ throw new Error("Either provider.prepareTokenRequest() or authorizationCode is required");
32454
+ }
32455
+ if (!provider.redirectUrl) {
32456
+ throw new Error("redirectUrl is required for authorization_code flow");
32457
+ }
32458
+ const codeVerifier = await provider.codeVerifier();
32459
+ tokenRequestParams = prepareAuthorizationCodeRequest(authorizationCode, codeVerifier, provider.redirectUrl);
32460
+ }
32461
+ const clientInformation = await provider.clientInformation();
32462
+ return executeTokenRequest(authorizationServerUrl, {
32463
+ metadata,
32464
+ tokenRequestParams,
32465
+ clientInformation: clientInformation ?? void 0,
32466
+ addClientAuthentication: provider.addClientAuthentication,
32467
+ resource,
32468
+ fetchFn
32469
+ });
32470
+ }
32471
+ async function registerClient(authorizationServerUrl, { metadata, clientMetadata, scope, fetchFn }) {
32472
+ let registrationUrl;
32473
+ if (metadata) {
32474
+ if (!metadata.registration_endpoint) {
32475
+ throw new Error("Incompatible auth server: does not support dynamic client registration");
32476
+ }
32477
+ registrationUrl = new URL(metadata.registration_endpoint);
32478
+ } else {
32479
+ registrationUrl = new URL("/register", authorizationServerUrl);
32480
+ }
32481
+ const response = await (fetchFn ?? fetch)(registrationUrl, {
32482
+ method: "POST",
32483
+ headers: {
32484
+ "Content-Type": "application/json"
32485
+ },
32486
+ body: JSON.stringify({
32487
+ ...clientMetadata,
32488
+ ...scope !== void 0 ? { scope } : {}
32489
+ })
32490
+ });
32491
+ if (!response.ok) {
32492
+ throw await parseErrorResponse(response);
32493
+ }
32494
+ return OAuthClientInformationFullSchema.parse(await response.json());
32495
+ }
32496
+
32497
+ // node_modules/eventsource-parser/dist/index.js
32498
+ var ParseError = class extends Error {
32499
+ constructor(message, options) {
32500
+ super(message), this.name = "ParseError", this.type = options.type, this.field = options.field, this.value = options.value, this.line = options.line;
32501
+ }
32502
+ };
32503
+ var LF = 10;
32504
+ var CR = 13;
32505
+ var SPACE = 32;
32506
+ function noop(_arg) {
32507
+ }
32508
+ function createParser(callbacks) {
32509
+ if (typeof callbacks == "function")
32510
+ throw new TypeError(
32511
+ "`callbacks` must be an object, got a function instead. Did you mean `{onEvent: fn}`?"
32512
+ );
32513
+ const { onEvent = noop, onError = noop, onRetry = noop, onComment } = callbacks, pendingFragments = [];
32514
+ let isFirstChunk = true, id, data = "", dataLines = 0, eventType;
32515
+ function feed(chunk) {
32516
+ if (isFirstChunk && (isFirstChunk = false, chunk.charCodeAt(0) === 239 && chunk.charCodeAt(1) === 187 && chunk.charCodeAt(2) === 191 && (chunk = chunk.slice(3))), pendingFragments.length === 0) {
32517
+ const trailing2 = processLines(chunk);
32518
+ trailing2 !== "" && pendingFragments.push(trailing2);
32519
+ return;
32520
+ }
32521
+ if (chunk.indexOf(`
32522
+ `) === -1 && chunk.indexOf("\r") === -1) {
32523
+ pendingFragments.push(chunk);
32524
+ return;
32525
+ }
32526
+ pendingFragments.push(chunk);
32527
+ const input = pendingFragments.join("");
32528
+ pendingFragments.length = 0;
32529
+ const trailing = processLines(input);
32530
+ trailing !== "" && pendingFragments.push(trailing);
32531
+ }
32532
+ function processLines(chunk) {
32533
+ let searchIndex = 0;
32534
+ if (chunk.indexOf("\r") === -1) {
32535
+ let lfIndex = chunk.indexOf(`
32536
+ `, searchIndex);
32537
+ for (; lfIndex !== -1; ) {
32538
+ if (searchIndex === lfIndex) {
32539
+ dataLines > 0 && onEvent({ id, event: eventType, data }), id = void 0, data = "", dataLines = 0, eventType = void 0, searchIndex = lfIndex + 1, lfIndex = chunk.indexOf(`
32540
+ `, searchIndex);
32541
+ continue;
32542
+ }
32543
+ const firstCharCode = chunk.charCodeAt(searchIndex);
32544
+ if (isDataPrefix(chunk, searchIndex, firstCharCode)) {
32545
+ const valueStart = chunk.charCodeAt(searchIndex + 5) === SPACE ? searchIndex + 6 : searchIndex + 5, value = chunk.slice(valueStart, lfIndex);
32546
+ if (dataLines === 0 && chunk.charCodeAt(lfIndex + 1) === LF) {
32547
+ onEvent({ id, event: eventType, data: value }), id = void 0, data = "", eventType = void 0, searchIndex = lfIndex + 2, lfIndex = chunk.indexOf(`
32548
+ `, searchIndex);
32549
+ continue;
32550
+ }
32551
+ data = dataLines === 0 ? value : `${data}
32552
+ ${value}`, dataLines++;
32553
+ } else isEventPrefix(chunk, searchIndex, firstCharCode) ? eventType = chunk.slice(
32554
+ chunk.charCodeAt(searchIndex + 6) === SPACE ? searchIndex + 7 : searchIndex + 6,
32555
+ lfIndex
32556
+ ) || void 0 : parseLine(chunk, searchIndex, lfIndex);
32557
+ searchIndex = lfIndex + 1, lfIndex = chunk.indexOf(`
32558
+ `, searchIndex);
32559
+ }
32560
+ return chunk.slice(searchIndex);
32561
+ }
32562
+ for (; searchIndex < chunk.length; ) {
32563
+ const crIndex = chunk.indexOf("\r", searchIndex), lfIndex = chunk.indexOf(`
32564
+ `, searchIndex);
32565
+ let lineEnd = -1;
32566
+ if (crIndex !== -1 && lfIndex !== -1 ? lineEnd = crIndex < lfIndex ? crIndex : lfIndex : crIndex !== -1 ? crIndex === chunk.length - 1 ? lineEnd = -1 : lineEnd = crIndex : lfIndex !== -1 && (lineEnd = lfIndex), lineEnd === -1)
32567
+ break;
32568
+ parseLine(chunk, searchIndex, lineEnd), searchIndex = lineEnd + 1, chunk.charCodeAt(searchIndex - 1) === CR && chunk.charCodeAt(searchIndex) === LF && searchIndex++;
32569
+ }
32570
+ return chunk.slice(searchIndex);
32571
+ }
32572
+ function parseLine(chunk, start, end) {
32573
+ if (start === end) {
32574
+ dispatchEvent();
32575
+ return;
32576
+ }
32577
+ const firstCharCode = chunk.charCodeAt(start);
32578
+ if (isDataPrefix(chunk, start, firstCharCode)) {
32579
+ const valueStart = chunk.charCodeAt(start + 5) === SPACE ? start + 6 : start + 5, value2 = chunk.slice(valueStart, end);
32580
+ data = dataLines === 0 ? value2 : `${data}
32581
+ ${value2}`, dataLines++;
32582
+ return;
32583
+ }
32584
+ if (isEventPrefix(chunk, start, firstCharCode)) {
32585
+ eventType = chunk.slice(chunk.charCodeAt(start + 6) === SPACE ? start + 7 : start + 6, end) || void 0;
32586
+ return;
32587
+ }
32588
+ if (firstCharCode === 105 && chunk.charCodeAt(start + 1) === 100 && chunk.charCodeAt(start + 2) === 58) {
32589
+ const value2 = chunk.slice(chunk.charCodeAt(start + 3) === SPACE ? start + 4 : start + 3, end);
32590
+ id = value2.includes("\0") ? void 0 : value2;
32591
+ return;
32592
+ }
32593
+ if (firstCharCode === 58) {
32594
+ if (onComment) {
32595
+ const line2 = chunk.slice(start, end);
32596
+ onComment(line2.slice(chunk.charCodeAt(start + 1) === SPACE ? 2 : 1));
32597
+ }
32598
+ return;
32599
+ }
32600
+ const line = chunk.slice(start, end), fieldSeparatorIndex = line.indexOf(":");
32601
+ if (fieldSeparatorIndex === -1) {
32602
+ processField(line, "", line);
32603
+ return;
32604
+ }
32605
+ const field = line.slice(0, fieldSeparatorIndex), offset = line.charCodeAt(fieldSeparatorIndex + 1) === SPACE ? 2 : 1, value = line.slice(fieldSeparatorIndex + offset);
32606
+ processField(field, value, line);
32607
+ }
32608
+ function processField(field, value, line) {
32609
+ switch (field) {
32610
+ case "event":
32611
+ eventType = value || void 0;
32612
+ break;
32613
+ case "data":
32614
+ data = dataLines === 0 ? value : `${data}
32615
+ ${value}`, dataLines++;
32616
+ break;
32617
+ case "id":
32618
+ id = value.includes("\0") ? void 0 : value;
32619
+ break;
32620
+ case "retry":
32621
+ /^\d+$/.test(value) ? onRetry(parseInt(value, 10)) : onError(
32622
+ new ParseError(`Invalid \`retry\` value: "${value}"`, {
32623
+ type: "invalid-retry",
32624
+ value,
32625
+ line
32626
+ })
32627
+ );
32628
+ break;
32629
+ default:
32630
+ onError(
32631
+ new ParseError(
32632
+ `Unknown field "${field.length > 20 ? `${field.slice(0, 20)}\u2026` : field}"`,
32633
+ { type: "unknown-field", field, value, line }
32634
+ )
32635
+ );
32636
+ break;
32637
+ }
32638
+ }
32639
+ function dispatchEvent() {
32640
+ dataLines > 0 && onEvent({
32641
+ id,
32642
+ event: eventType,
32643
+ data
32644
+ }), id = void 0, data = "", dataLines = 0, eventType = void 0;
32645
+ }
32646
+ function reset(options = {}) {
32647
+ if (options.consume && pendingFragments.length > 0) {
32648
+ const incompleteLine = pendingFragments.join("");
32649
+ parseLine(incompleteLine, 0, incompleteLine.length);
32650
+ }
32651
+ isFirstChunk = true, id = void 0, data = "", dataLines = 0, eventType = void 0, pendingFragments.length = 0;
32652
+ }
32653
+ return { feed, reset };
32654
+ }
32655
+ function isDataPrefix(chunk, i, firstCharCode) {
32656
+ return firstCharCode === 100 && chunk.charCodeAt(i + 1) === 97 && chunk.charCodeAt(i + 2) === 116 && chunk.charCodeAt(i + 3) === 97 && chunk.charCodeAt(i + 4) === 58;
32657
+ }
32658
+ function isEventPrefix(chunk, i, firstCharCode) {
32659
+ return firstCharCode === 101 && chunk.charCodeAt(i + 1) === 118 && chunk.charCodeAt(i + 2) === 101 && chunk.charCodeAt(i + 3) === 110 && chunk.charCodeAt(i + 4) === 116 && chunk.charCodeAt(i + 5) === 58;
32660
+ }
32661
+
32662
+ // node_modules/eventsource-parser/dist/stream.js
32663
+ var EventSourceParserStream = class extends TransformStream {
32664
+ constructor({ onError, onRetry, onComment } = {}) {
32665
+ let parser;
32666
+ super({
32667
+ start(controller) {
32668
+ parser = createParser({
32669
+ onEvent: (event) => {
32670
+ controller.enqueue(event);
32671
+ },
32672
+ onError(error51) {
32673
+ onError === "terminate" ? controller.error(error51) : typeof onError == "function" && onError(error51);
32674
+ },
32675
+ onRetry,
32676
+ onComment
32677
+ });
32678
+ },
32679
+ transform(chunk) {
32680
+ parser.feed(chunk);
32681
+ }
32682
+ });
32683
+ }
32684
+ };
32685
+
32686
+ // node_modules/@modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js
32687
+ var DEFAULT_STREAMABLE_HTTP_RECONNECTION_OPTIONS = {
32688
+ initialReconnectionDelay: 1e3,
32689
+ maxReconnectionDelay: 3e4,
32690
+ reconnectionDelayGrowFactor: 1.5,
32691
+ maxRetries: 2
32692
+ };
32693
+ var StreamableHTTPError = class extends Error {
32694
+ constructor(code, message) {
32695
+ super(`Streamable HTTP error: ${message}`);
32696
+ this.code = code;
32697
+ }
32698
+ };
32699
+ var StreamableHTTPClientTransport = class {
32700
+ constructor(url2, opts) {
32701
+ this._hasCompletedAuthFlow = false;
32702
+ this._url = url2;
32703
+ this._resourceMetadataUrl = void 0;
32704
+ this._scope = void 0;
32705
+ this._requestInit = opts?.requestInit;
32706
+ this._authProvider = opts?.authProvider;
32707
+ this._fetch = opts?.fetch;
32708
+ this._fetchWithInit = createFetchWithInit(opts?.fetch, opts?.requestInit);
32709
+ this._sessionId = opts?.sessionId;
32710
+ this._reconnectionOptions = opts?.reconnectionOptions ?? DEFAULT_STREAMABLE_HTTP_RECONNECTION_OPTIONS;
32711
+ }
32712
+ async _authThenStart() {
32713
+ if (!this._authProvider) {
32714
+ throw new UnauthorizedError("No auth provider");
32715
+ }
32716
+ let result;
32717
+ try {
32718
+ result = await auth(this._authProvider, {
32719
+ serverUrl: this._url,
32720
+ resourceMetadataUrl: this._resourceMetadataUrl,
32721
+ scope: this._scope,
32722
+ fetchFn: this._fetchWithInit
32723
+ });
32724
+ } catch (error51) {
32725
+ this.onerror?.(error51);
32726
+ throw error51;
32727
+ }
32728
+ if (result !== "AUTHORIZED") {
32729
+ throw new UnauthorizedError();
32730
+ }
32731
+ return await this._startOrAuthSse({ resumptionToken: void 0 });
32732
+ }
32733
+ async _commonHeaders() {
32734
+ const headers = {};
32735
+ if (this._authProvider) {
32736
+ const tokens = await this._authProvider.tokens();
32737
+ if (tokens) {
32738
+ headers["Authorization"] = `Bearer ${tokens.access_token}`;
32739
+ }
32740
+ }
32741
+ if (this._sessionId) {
32742
+ headers["mcp-session-id"] = this._sessionId;
32743
+ }
32744
+ if (this._protocolVersion) {
32745
+ headers["mcp-protocol-version"] = this._protocolVersion;
32746
+ }
32747
+ const extraHeaders = normalizeHeaders(this._requestInit?.headers);
32748
+ return new Headers({
32749
+ ...headers,
32750
+ ...extraHeaders
32751
+ });
32752
+ }
32753
+ async _startOrAuthSse(options) {
32754
+ const { resumptionToken } = options;
32755
+ try {
32756
+ const headers = await this._commonHeaders();
32757
+ headers.set("Accept", "text/event-stream");
32758
+ if (resumptionToken) {
32759
+ headers.set("last-event-id", resumptionToken);
32760
+ }
32761
+ const response = await (this._fetch ?? fetch)(this._url, {
32762
+ method: "GET",
32763
+ headers,
32764
+ signal: this._abortController?.signal
32765
+ });
32766
+ if (!response.ok) {
32767
+ await response.body?.cancel();
32768
+ if (response.status === 401 && this._authProvider) {
32769
+ return await this._authThenStart();
32770
+ }
32771
+ if (response.status === 405) {
32772
+ return;
32773
+ }
32774
+ throw new StreamableHTTPError(response.status, `Failed to open SSE stream: ${response.statusText}`);
32775
+ }
32776
+ this._handleSseStream(response.body, options, true);
32777
+ } catch (error51) {
32778
+ this.onerror?.(error51);
32779
+ throw error51;
32780
+ }
32781
+ }
32782
+ /**
32783
+ * Calculates the next reconnection delay using backoff algorithm
32784
+ *
32785
+ * @param attempt Current reconnection attempt count for the specific stream
32786
+ * @returns Time to wait in milliseconds before next reconnection attempt
32787
+ */
32788
+ _getNextReconnectionDelay(attempt) {
32789
+ if (this._serverRetryMs !== void 0) {
32790
+ return this._serverRetryMs;
32791
+ }
32792
+ const initialDelay = this._reconnectionOptions.initialReconnectionDelay;
32793
+ const growFactor = this._reconnectionOptions.reconnectionDelayGrowFactor;
32794
+ const maxDelay = this._reconnectionOptions.maxReconnectionDelay;
32795
+ return Math.min(initialDelay * Math.pow(growFactor, attempt), maxDelay);
32796
+ }
32797
+ /**
32798
+ * Schedule a reconnection attempt using server-provided retry interval or backoff
32799
+ *
32800
+ * @param lastEventId The ID of the last received event for resumability
32801
+ * @param attemptCount Current reconnection attempt count for this specific stream
32802
+ */
32803
+ _scheduleReconnection(options, attemptCount = 0) {
32804
+ const maxRetries = this._reconnectionOptions.maxRetries;
32805
+ if (attemptCount >= maxRetries) {
32806
+ this.onerror?.(new Error(`Maximum reconnection attempts (${maxRetries}) exceeded.`));
32807
+ return;
32808
+ }
32809
+ const delay = this._getNextReconnectionDelay(attemptCount);
32810
+ this._reconnectionTimeout = setTimeout(() => {
32811
+ this._startOrAuthSse(options).catch((error51) => {
32812
+ this.onerror?.(new Error(`Failed to reconnect SSE stream: ${error51 instanceof Error ? error51.message : String(error51)}`));
32813
+ this._scheduleReconnection(options, attemptCount + 1);
32814
+ });
32815
+ }, delay);
32816
+ }
32817
+ _handleSseStream(stream, options, isReconnectable) {
32818
+ if (!stream) {
32819
+ return;
32820
+ }
32821
+ const { onresumptiontoken, replayMessageId } = options;
32822
+ let lastEventId;
32823
+ let hasPrimingEvent = false;
32824
+ let receivedResponse = false;
32825
+ const processStream = async () => {
32826
+ try {
32827
+ const reader = stream.pipeThrough(new TextDecoderStream()).pipeThrough(new EventSourceParserStream({
32828
+ onRetry: (retryMs) => {
32829
+ this._serverRetryMs = retryMs;
32830
+ }
32831
+ })).getReader();
32832
+ while (true) {
32833
+ const { value: event, done } = await reader.read();
32834
+ if (done) {
32835
+ break;
32836
+ }
32837
+ if (event.id) {
32838
+ lastEventId = event.id;
32839
+ hasPrimingEvent = true;
32840
+ onresumptiontoken?.(event.id);
32841
+ }
32842
+ if (!event.data) {
32843
+ continue;
32844
+ }
32845
+ if (!event.event || event.event === "message") {
32846
+ try {
32847
+ const message = JSONRPCMessageSchema.parse(JSON.parse(event.data));
32848
+ if (isJSONRPCResultResponse(message)) {
32849
+ receivedResponse = true;
32850
+ if (replayMessageId !== void 0) {
32851
+ message.id = replayMessageId;
32852
+ }
32853
+ }
32854
+ this.onmessage?.(message);
32855
+ } catch (error51) {
32856
+ this.onerror?.(error51);
32857
+ }
32858
+ }
32859
+ }
32860
+ const canResume = isReconnectable || hasPrimingEvent;
32861
+ const needsReconnect = canResume && !receivedResponse;
32862
+ if (needsReconnect && this._abortController && !this._abortController.signal.aborted) {
32863
+ this._scheduleReconnection({
32864
+ resumptionToken: lastEventId,
32865
+ onresumptiontoken,
32866
+ replayMessageId
32867
+ }, 0);
32868
+ }
32869
+ } catch (error51) {
32870
+ this.onerror?.(new Error(`SSE stream disconnected: ${error51}`));
32871
+ const canResume = isReconnectable || hasPrimingEvent;
32872
+ const needsReconnect = canResume && !receivedResponse;
32873
+ if (needsReconnect && this._abortController && !this._abortController.signal.aborted) {
32874
+ try {
32875
+ this._scheduleReconnection({
32876
+ resumptionToken: lastEventId,
32877
+ onresumptiontoken,
32878
+ replayMessageId
32879
+ }, 0);
32880
+ } catch (error52) {
32881
+ this.onerror?.(new Error(`Failed to reconnect: ${error52 instanceof Error ? error52.message : String(error52)}`));
32882
+ }
32883
+ }
32884
+ }
32885
+ };
32886
+ processStream();
32887
+ }
32888
+ async start() {
32889
+ if (this._abortController) {
32890
+ throw new Error("StreamableHTTPClientTransport already started! If using Client class, note that connect() calls start() automatically.");
32891
+ }
32892
+ this._abortController = new AbortController();
32893
+ }
32894
+ /**
32895
+ * Call this method after the user has finished authorizing via their user agent and is redirected back to the MCP client application. This will exchange the authorization code for an access token, enabling the next connection attempt to successfully auth.
32896
+ */
32897
+ async finishAuth(authorizationCode) {
32898
+ if (!this._authProvider) {
32899
+ throw new UnauthorizedError("No auth provider");
32900
+ }
32901
+ const result = await auth(this._authProvider, {
32902
+ serverUrl: this._url,
32903
+ authorizationCode,
32904
+ resourceMetadataUrl: this._resourceMetadataUrl,
32905
+ scope: this._scope,
32906
+ fetchFn: this._fetchWithInit
32907
+ });
32908
+ if (result !== "AUTHORIZED") {
32909
+ throw new UnauthorizedError("Failed to authorize");
32910
+ }
32911
+ }
32912
+ async close() {
32913
+ if (this._reconnectionTimeout) {
32914
+ clearTimeout(this._reconnectionTimeout);
32915
+ this._reconnectionTimeout = void 0;
32916
+ }
32917
+ this._abortController?.abort();
32918
+ this.onclose?.();
32919
+ }
32920
+ async send(message, options) {
32921
+ try {
32922
+ const { resumptionToken, onresumptiontoken } = options || {};
32923
+ if (resumptionToken) {
32924
+ this._startOrAuthSse({ resumptionToken, replayMessageId: isJSONRPCRequest(message) ? message.id : void 0 }).catch((err) => this.onerror?.(err));
32925
+ return;
32926
+ }
32927
+ const headers = await this._commonHeaders();
32928
+ headers.set("content-type", "application/json");
32929
+ headers.set("accept", "application/json, text/event-stream");
32930
+ const init = {
32931
+ ...this._requestInit,
32932
+ method: "POST",
32933
+ headers,
32934
+ body: JSON.stringify(message),
32935
+ signal: this._abortController?.signal
32936
+ };
32937
+ const response = await (this._fetch ?? fetch)(this._url, init);
32938
+ const sessionId = response.headers.get("mcp-session-id");
32939
+ if (sessionId) {
32940
+ this._sessionId = sessionId;
32941
+ }
32942
+ if (!response.ok) {
32943
+ const text = await response.text().catch(() => null);
32944
+ if (response.status === 401 && this._authProvider) {
32945
+ if (this._hasCompletedAuthFlow) {
32946
+ throw new StreamableHTTPError(401, "Server returned 401 after successful authentication");
32947
+ }
32948
+ const { resourceMetadataUrl, scope } = extractWWWAuthenticateParams(response);
32949
+ this._resourceMetadataUrl = resourceMetadataUrl;
32950
+ this._scope = scope;
32951
+ const result = await auth(this._authProvider, {
32952
+ serverUrl: this._url,
32953
+ resourceMetadataUrl: this._resourceMetadataUrl,
32954
+ scope: this._scope,
32955
+ fetchFn: this._fetchWithInit
32956
+ });
32957
+ if (result !== "AUTHORIZED") {
32958
+ throw new UnauthorizedError();
32959
+ }
32960
+ this._hasCompletedAuthFlow = true;
32961
+ return this.send(message);
32962
+ }
32963
+ if (response.status === 403 && this._authProvider) {
32964
+ const { resourceMetadataUrl, scope, error: error51 } = extractWWWAuthenticateParams(response);
32965
+ if (error51 === "insufficient_scope") {
32966
+ const wwwAuthHeader = response.headers.get("WWW-Authenticate");
32967
+ if (this._lastUpscopingHeader === wwwAuthHeader) {
32968
+ throw new StreamableHTTPError(403, "Server returned 403 after trying upscoping");
32969
+ }
32970
+ if (scope) {
32971
+ this._scope = scope;
32972
+ }
32973
+ if (resourceMetadataUrl) {
32974
+ this._resourceMetadataUrl = resourceMetadataUrl;
32975
+ }
32976
+ this._lastUpscopingHeader = wwwAuthHeader ?? void 0;
32977
+ const result = await auth(this._authProvider, {
32978
+ serverUrl: this._url,
32979
+ resourceMetadataUrl: this._resourceMetadataUrl,
32980
+ scope: this._scope,
32981
+ fetchFn: this._fetch
32982
+ });
32983
+ if (result !== "AUTHORIZED") {
32984
+ throw new UnauthorizedError();
32985
+ }
32986
+ return this.send(message);
32987
+ }
32988
+ }
32989
+ throw new StreamableHTTPError(response.status, `Error POSTing to endpoint: ${text}`);
32990
+ }
32991
+ this._hasCompletedAuthFlow = false;
32992
+ this._lastUpscopingHeader = void 0;
32993
+ if (response.status === 202) {
32994
+ await response.body?.cancel();
32995
+ if (isInitializedNotification(message)) {
32996
+ this._startOrAuthSse({ resumptionToken: void 0 }).catch((err) => this.onerror?.(err));
32997
+ }
32998
+ return;
32999
+ }
33000
+ const messages = Array.isArray(message) ? message : [message];
33001
+ const hasRequests = messages.filter((msg) => "method" in msg && "id" in msg && msg.id !== void 0).length > 0;
33002
+ const contentType = response.headers.get("content-type");
33003
+ if (hasRequests) {
33004
+ if (contentType?.includes("text/event-stream")) {
33005
+ this._handleSseStream(response.body, { onresumptiontoken }, false);
33006
+ } else if (contentType?.includes("application/json")) {
33007
+ const data = await response.json();
33008
+ const responseMessages = Array.isArray(data) ? data.map((msg) => JSONRPCMessageSchema.parse(msg)) : [JSONRPCMessageSchema.parse(data)];
33009
+ for (const msg of responseMessages) {
33010
+ this.onmessage?.(msg);
33011
+ }
33012
+ } else {
33013
+ await response.body?.cancel();
33014
+ throw new StreamableHTTPError(-1, `Unexpected content type: ${contentType}`);
33015
+ }
33016
+ } else {
33017
+ await response.body?.cancel();
33018
+ }
33019
+ } catch (error51) {
33020
+ this.onerror?.(error51);
33021
+ throw error51;
33022
+ }
33023
+ }
33024
+ get sessionId() {
33025
+ return this._sessionId;
33026
+ }
33027
+ /**
33028
+ * Terminates the current session by sending a DELETE request to the server.
33029
+ *
33030
+ * Clients that no longer need a particular session
33031
+ * (e.g., because the user is leaving the client application) SHOULD send an
33032
+ * HTTP DELETE to the MCP endpoint with the Mcp-Session-Id header to explicitly
33033
+ * terminate the session.
33034
+ *
33035
+ * The server MAY respond with HTTP 405 Method Not Allowed, indicating that
33036
+ * the server does not allow clients to terminate sessions.
33037
+ */
33038
+ async terminateSession() {
33039
+ if (!this._sessionId) {
33040
+ return;
33041
+ }
33042
+ try {
33043
+ const headers = await this._commonHeaders();
33044
+ const init = {
33045
+ ...this._requestInit,
33046
+ method: "DELETE",
33047
+ headers,
33048
+ signal: this._abortController?.signal
33049
+ };
33050
+ const response = await (this._fetch ?? fetch)(this._url, init);
33051
+ await response.body?.cancel();
33052
+ if (!response.ok && response.status !== 405) {
33053
+ throw new StreamableHTTPError(response.status, `Failed to terminate session: ${response.statusText}`);
33054
+ }
33055
+ this._sessionId = void 0;
33056
+ } catch (error51) {
33057
+ this.onerror?.(error51);
33058
+ throw error51;
33059
+ }
33060
+ }
33061
+ setProtocolVersion(version2) {
33062
+ this._protocolVersion = version2;
33063
+ }
33064
+ get protocolVersion() {
33065
+ return this._protocolVersion;
33066
+ }
33067
+ /**
33068
+ * Resume an SSE stream from a previous event ID.
33069
+ * Opens a GET SSE connection with Last-Event-ID header to replay missed events.
33070
+ *
33071
+ * @param lastEventId The event ID to resume from
33072
+ * @param options Optional callback to receive new resumption tokens
33073
+ */
33074
+ async resumeStream(lastEventId, options) {
33075
+ await this._startOrAuthSse({
33076
+ resumptionToken: lastEventId,
33077
+ onresumptiontoken: options?.onresumptiontoken
33078
+ });
33079
+ }
33080
+ };
33081
+
30952
33082
  // src/mcp_server.ts
30953
- var import_promises4 = require("node:fs/promises");
33083
+ var import_promises5 = require("node:fs/promises");
30954
33084
  var import_node_os3 = require("node:os");
30955
- var import_node_path4 = require("node:path");
33085
+ var import_node_path5 = require("node:path");
30956
33086
 
30957
33087
  // src/constants.ts
33088
+ var DEFAULT_HOST = "127.0.0.1";
33089
+ var DEFAULT_PORT = 1933;
30958
33090
  var DEFAULT_ACCOUNT = "local";
30959
33091
  var DEFAULT_AGENT_ID = "threadnote";
30960
33092
 
33093
+ // src/index_repair.ts
33094
+ var import_promises3 = require("node:fs/promises");
33095
+ var import_node_path2 = require("node:path");
33096
+
30961
33097
  // src/manifest.ts
30962
33098
  var import_promises2 = require("node:fs/promises");
30963
33099
 
@@ -33688,15 +35824,11 @@ async function maybeRun(dryRun, executable, args, options = {}) {
33688
35824
  }
33689
35825
  async function runCommand(executable, args, options = {}) {
33690
35826
  return new Promise((resolvePromise, rejectPromise) => {
33691
- const child = (0, import_node_child_process.spawn)(executable, args, { cwd: options.cwd });
33692
- const stdoutChunks = [];
33693
- const stderrChunks = [];
33694
35827
  const maxOutputBytes = options.maxOutputBytes ?? defaultCommandMaxOutputBytes();
33695
- let stdoutBytes = 0;
33696
- let stderrBytes = 0;
33697
35828
  let finished = false;
33698
- let failureResult;
33699
35829
  let killTimer;
35830
+ let killEscalationTimer;
35831
+ let failureMessage;
33700
35832
  let sentTerminationSignal = false;
33701
35833
  const timeoutMs = options.timeoutMs ?? defaultCommandTimeoutMs();
33702
35834
  const finish = (result) => {
@@ -33707,22 +35839,47 @@ async function runCommand(executable, args, options = {}) {
33707
35839
  if (killTimer) {
33708
35840
  clearTimeout(killTimer);
33709
35841
  }
35842
+ if (killEscalationTimer) {
35843
+ clearTimeout(killEscalationTimer);
35844
+ }
33710
35845
  if (result.exitCode !== 0 && options.allowFailure !== true) {
33711
35846
  rejectPromise(new Error(`${formatShellCommand(executable, args)} failed: ${result.stderr || result.stdout}`));
33712
35847
  return;
33713
35848
  }
33714
35849
  resolvePromise(result);
33715
35850
  };
35851
+ const child = (0, import_node_child_process.execFile)(
35852
+ executable,
35853
+ [...args],
35854
+ {
35855
+ cwd: options.cwd,
35856
+ encoding: "utf8",
35857
+ maxBuffer: maxOutputBytes
35858
+ },
35859
+ (err, stdout2, stderr) => {
35860
+ finish(
35861
+ commandResultFromExecFileCallback({
35862
+ args,
35863
+ err,
35864
+ executable,
35865
+ failureMessage,
35866
+ maxOutputBytes,
35867
+ stderr,
35868
+ stdout: stdout2
35869
+ })
35870
+ );
35871
+ }
35872
+ );
33716
35873
  const failAndKill = (message) => {
33717
- if (failureResult) {
35874
+ if (failureMessage) {
33718
35875
  return;
33719
35876
  }
33720
- failureResult = { exitCode: 124, stderr: message, stdout: stdoutChunks.join("") };
35877
+ failureMessage = message;
33721
35878
  if (!sentTerminationSignal) {
33722
35879
  sentTerminationSignal = true;
33723
35880
  child.kill("SIGTERM");
33724
35881
  }
33725
- setTimeout(() => {
35882
+ killEscalationTimer = setTimeout(() => {
33726
35883
  if (!finished) {
33727
35884
  child.kill("SIGKILL");
33728
35885
  }
@@ -33734,54 +35891,20 @@ async function runCommand(executable, args, options = {}) {
33734
35891
  }, timeoutMs);
33735
35892
  killTimer.unref?.();
33736
35893
  }
33737
- child.stdout.on("data", (chunk) => {
33738
- if (failureResult) {
33739
- return;
33740
- }
33741
- const text = String(chunk);
33742
- stdoutBytes += Buffer.byteLength(text);
33743
- if (stdoutBytes + stderrBytes > maxOutputBytes) {
33744
- failAndKill(`${formatShellCommand(executable, args)} exceeded output limit of ${maxOutputBytes} bytes`);
33745
- return;
33746
- }
33747
- stdoutChunks.push(text);
33748
- });
33749
- child.stderr.on("data", (chunk) => {
33750
- if (failureResult) {
33751
- return;
33752
- }
33753
- const text = String(chunk);
33754
- stderrBytes += Buffer.byteLength(text);
33755
- if (stdoutBytes + stderrBytes > maxOutputBytes) {
33756
- failAndKill(`${formatShellCommand(executable, args)} exceeded output limit of ${maxOutputBytes} bytes`);
33757
- return;
33758
- }
33759
- stderrChunks.push(text);
33760
- });
33761
- child.on("error", (err) => {
33762
- if (finished) {
33763
- return;
33764
- }
33765
- if (killTimer) {
33766
- clearTimeout(killTimer);
33767
- }
33768
- if (options.allowFailure === true) {
33769
- finish({ exitCode: 127, stderr: errorMessage(err), stdout: "" });
33770
- } else {
33771
- finished = true;
33772
- rejectPromise(err);
33773
- }
33774
- });
33775
- child.on("close", (code) => {
33776
- const result = failureResult ?? {
33777
- exitCode: code ?? 1,
33778
- stderr: stderrChunks.join(""),
33779
- stdout: stdoutChunks.join("")
33780
- };
33781
- finish(result);
33782
- });
33783
35894
  });
33784
35895
  }
35896
+ function commandResultFromExecFileCallback(params) {
35897
+ if (params.failureMessage) {
35898
+ return { exitCode: 124, stderr: params.failureMessage, stdout: params.stdout };
35899
+ }
35900
+ if (!params.err) {
35901
+ return { exitCode: 0, stderr: params.stderr, stdout: params.stdout };
35902
+ }
35903
+ const error51 = params.err;
35904
+ const exitCode = typeof error51.code === "number" ? error51.code : error51.code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER" ? 124 : 127;
35905
+ const stderr = error51.code === "ERR_CHILD_PROCESS_STDIO_MAXBUFFER" ? `${formatShellCommand(params.executable, params.args)} exceeded output limit of ${params.maxOutputBytes} bytes` : params.stderr || errorMessage(error51);
35906
+ return { exitCode, stderr, stdout: params.stdout };
35907
+ }
33785
35908
  function defaultCommandTimeoutMs() {
33786
35909
  return positiveIntegerFromEnv("THREADNOTE_COMMAND_TIMEOUT_MS") ?? 10 * 60 * 1e3;
33787
35910
  }
@@ -33808,6 +35931,13 @@ async function sleep(ms) {
33808
35931
  setTimeout(resolvePromise, ms);
33809
35932
  });
33810
35933
  }
35934
+ async function ensureDirectory(path, dryRun) {
35935
+ if (dryRun) {
35936
+ console.log(`Would create directory: ${path}`);
35937
+ return;
35938
+ }
35939
+ await (0, import_promises.mkdir)(path, { recursive: true });
35940
+ }
33811
35941
  async function exists(path) {
33812
35942
  try {
33813
35943
  await (0, import_promises.access)(path);
@@ -33830,6 +35960,13 @@ async function readFileIfExists(path) {
33830
35960
  return void 0;
33831
35961
  }
33832
35962
  }
35963
+ function parsePort(value) {
35964
+ const parsed = Number(value);
35965
+ if (!Number.isInteger(parsed) || parsed <= 0 || parsed > 65535) {
35966
+ throw new Error(`Invalid port: ${value}`);
35967
+ }
35968
+ return parsed;
35969
+ }
33833
35970
  function expandPath(path) {
33834
35971
  if (path === "~") {
33835
35972
  return (0, import_node_os.homedir)();
@@ -33893,6 +36030,9 @@ function uniqueUsefulWorkspaceTerms(values) {
33893
36030
  }
33894
36031
  return terms;
33895
36032
  }
36033
+ function toPosixPath(path) {
36034
+ return path.split(import_node_path.sep).join("/");
36035
+ }
33896
36036
  function trimTrailingSlash(value) {
33897
36037
  return value.endsWith("/") ? value.slice(0, -1) : value;
33898
36038
  }
@@ -34043,8 +36183,262 @@ function readStringArray(object3, key) {
34043
36183
  return value;
34044
36184
  }
34045
36185
 
36186
+ // src/runtime.ts
36187
+ function withIdentity(config2, args) {
36188
+ return [...args, "--account", config2.account, "--user", config2.user, "--agent-id", config2.agentId];
36189
+ }
36190
+
36191
+ // src/index_repair.ts
36192
+ var AUTO_REPAIR_STATE_FILE = "index-auto-repair.json";
36193
+ var AUTO_REPAIR_TTL_MS = 6 * 60 * 60 * 1e3;
36194
+ var MAX_SCAN_DEPTH = 5;
36195
+ var MAX_REPAIR_TARGETS = 4;
36196
+ async function repairStaleRecallIndex(config2, ov, options = {}) {
36197
+ options.onProgress?.({ type: "scan-start" });
36198
+ const targets = await findStaleRecallIndexTargets(config2, options);
36199
+ const repairTargets = targets.slice(0, options.maxTargets ?? MAX_REPAIR_TARGETS);
36200
+ options.onProgress?.({
36201
+ repairTargetCount: repairTargets.length,
36202
+ totalTargets: targets.length,
36203
+ type: "scan-complete"
36204
+ });
36205
+ if (targets.length === 0) {
36206
+ return { repairedUris: [], skippedRecentUris: [], warnings: [] };
36207
+ }
36208
+ const state = options.dryRun === true ? { entries: {}, version: 1 } : await readAutoRepairState(config2);
36209
+ const now = Date.now();
36210
+ const repairedUris = [];
36211
+ const skippedRecentUris = [];
36212
+ const warnings = [];
36213
+ for (const [targetIndex, target] of repairTargets.entries()) {
36214
+ const progressBase = { index: targetIndex + 1, target, total: repairTargets.length };
36215
+ const previous = state.entries[target.uri];
36216
+ if (previous?.signature === target.signature && now - Date.parse(previous.repairedAt) < AUTO_REPAIR_TTL_MS && options.dryRun !== true && options.ignoreBackoff !== true) {
36217
+ options.onProgress?.({ ...progressBase, type: "repair-skip-recent" });
36218
+ skippedRecentUris.push(target.uri);
36219
+ continue;
36220
+ }
36221
+ if (options.dryRun === true) {
36222
+ options.onProgress?.({ ...progressBase, type: "repair-dry-run" });
36223
+ repairedUris.push(target.uri);
36224
+ continue;
36225
+ }
36226
+ options.onProgress?.({ ...progressBase, type: "repair-start" });
36227
+ const result = await runCommand(
36228
+ ov,
36229
+ withIdentity(config2, ["reindex", target.uri, "--mode", "semantic_and_vectors", "--wait", "true"]),
36230
+ { allowFailure: true }
36231
+ );
36232
+ if (result.exitCode === 0) {
36233
+ repairedUris.push(target.uri);
36234
+ state.entries[target.uri] = { repairedAt: new Date(now).toISOString(), signature: target.signature };
36235
+ } else {
36236
+ warnings.push(indexRepairWarning(target.uri, result));
36237
+ await options.onRepairFailure?.(target, result);
36238
+ }
36239
+ }
36240
+ if (options.dryRun !== true && repairedUris.length > 0) {
36241
+ await writeAutoRepairState(config2, state);
36242
+ }
36243
+ return { repairedUris, skippedRecentUris, warnings };
36244
+ }
36245
+ async function findStaleRecallIndexTargets(config2, options = {}) {
36246
+ const roots = await scanRoots(config2, options);
36247
+ const byUri = /* @__PURE__ */ new Map();
36248
+ for (const root of roots) {
36249
+ if (!await exists(root.path)) {
36250
+ continue;
36251
+ }
36252
+ const sidecars = await staleSidecars(root.path, root.uri);
36253
+ if (options.collapseToRoots === true) {
36254
+ for (const sidecar of sidecars) {
36255
+ const uri = collapseStaleSidecarUri(root.uri, sidecar.relativePath, options.collapseDepth);
36256
+ const current = byUri.get(uri) ?? { parts: [], staleCount: 0, uri };
36257
+ current.parts.push(`${sidecar.relativePath}
36258
+ ${sidecar.content}`);
36259
+ current.staleCount += 1;
36260
+ byUri.set(uri, current);
36261
+ }
36262
+ continue;
36263
+ }
36264
+ for (const sidecar of sidecars) {
36265
+ const current = byUri.get(sidecar.uri) ?? { parts: [], staleCount: 0, uri: sidecar.uri };
36266
+ current.parts.push(`${sidecar.relativePath}
36267
+ ${sidecar.content}`);
36268
+ current.staleCount += 1;
36269
+ byUri.set(sidecar.uri, current);
36270
+ }
36271
+ }
36272
+ return [...byUri.values()].map((target) => ({
36273
+ signature: sha256([target.uri, ...target.parts.sort()].join("\n---\n")),
36274
+ staleCount: target.staleCount,
36275
+ uri: target.uri
36276
+ }));
36277
+ }
36278
+ function collapseStaleSidecarUri(rootUri, relativePath, depth = 0) {
36279
+ const normalizedRootUri = trimLocalRootUri(rootUri);
36280
+ if (depth <= 0) {
36281
+ return normalizedRootUri;
36282
+ }
36283
+ const parentParts = relativePath.split("/").slice(0, -1);
36284
+ const collapsedParts = parentParts.slice(0, depth);
36285
+ return collapsedParts.length === 0 ? normalizedRootUri : `${normalizedRootUri}/${collapsedParts.join("/")}`;
36286
+ }
36287
+ function formatRecallIndexRepairMessages(result, options = {}) {
36288
+ const messages = [];
36289
+ const maxUris = options.maxUris ?? result.repairedUris.length;
36290
+ for (const uri of result.repairedUris.slice(0, maxUris)) {
36291
+ messages.push(
36292
+ `${options.dryRun === true ? "Would auto-reindex stale recall scope" : "Auto-reindexed stale recall scope"}: ${uri}`
36293
+ );
36294
+ }
36295
+ const hiddenUriCount = result.repairedUris.length - maxUris;
36296
+ if (hiddenUriCount > 0) {
36297
+ messages.push(
36298
+ options.dryRun === true ? `Would auto-reindex ${hiddenUriCount} more stale recall scope(s).` : `Auto-reindexed ${hiddenUriCount} more stale recall scope(s).`
36299
+ );
36300
+ }
36301
+ for (const warning2 of result.warnings) {
36302
+ messages.push(`Auto-index repair warning: ${warning2}`);
36303
+ }
36304
+ return messages;
36305
+ }
36306
+ function filterStaleRecallSummaryRows(output) {
36307
+ return output.split(/\r?\n/).filter((line) => !isStaleRecallSummaryRow(line)).join("\n").trim();
36308
+ }
36309
+ function isStaleRecallSummaryRow(line) {
36310
+ return /viking:\/\/\S+\/\.(?:abstract|overview)\.md\b/.test(line) && isStaleSummary(line);
36311
+ }
36312
+ async function scanRoots(config2, options) {
36313
+ const accountRoot = (0, import_node_path2.join)(config2.agentContextHome, "data", "viking", config2.account);
36314
+ const roots = [
36315
+ {
36316
+ path: (0, import_node_path2.join)(accountRoot, "user", uriSegment(config2.user), "memories"),
36317
+ uri: `viking://user/${uriSegment(config2.user)}/memories`
36318
+ }
36319
+ ];
36320
+ const query = options.query;
36321
+ if (query) {
36322
+ const project = await inferProjectFromQuery(config2.manifestPath, query);
36323
+ const projectPath = project?.uri.startsWith("viking://resources/") ? (0, import_node_path2.join)(accountRoot, "resources", ...project.uri.slice("viking://resources/".length).split("/")) : void 0;
36324
+ if (project && projectPath) {
36325
+ roots.push({ path: projectPath, uri: project.uri });
36326
+ }
36327
+ }
36328
+ if (options.includeManifestResources === true) {
36329
+ roots.push(...await manifestResourceRoots(config2, accountRoot));
36330
+ }
36331
+ const scanAgentSkills = options.includeAgentSkills === true || (query ? /\bskills?\b/.test(query.toLowerCase()) : false);
36332
+ if (scanAgentSkills) {
36333
+ roots.push({ path: (0, import_node_path2.join)(accountRoot, "resources", "agent-skills"), uri: "viking://resources/agent-skills" });
36334
+ }
36335
+ return dedupeRoots(roots);
36336
+ }
36337
+ async function manifestResourceRoots(config2, accountRoot) {
36338
+ try {
36339
+ const manifest = await readSeedManifest(config2.manifestPath);
36340
+ return manifest.projects.filter((project) => project.uri.startsWith("viking://resources/")).map((project) => ({
36341
+ path: (0, import_node_path2.join)(accountRoot, "resources", ...project.uri.slice("viking://resources/".length).split("/")),
36342
+ uri: project.uri
36343
+ }));
36344
+ } catch (_err) {
36345
+ return [];
36346
+ }
36347
+ }
36348
+ function dedupeRoots(roots) {
36349
+ const seen = /* @__PURE__ */ new Set();
36350
+ const deduped = [];
36351
+ for (const root of roots) {
36352
+ if (seen.has(root.uri)) {
36353
+ continue;
36354
+ }
36355
+ seen.add(root.uri);
36356
+ deduped.push(root);
36357
+ }
36358
+ return deduped;
36359
+ }
36360
+ async function staleSidecars(rootPath, rootUri) {
36361
+ const results = [];
36362
+ async function visit(path, depth) {
36363
+ let entries;
36364
+ try {
36365
+ entries = await (0, import_promises3.readdir)(path, { withFileTypes: true });
36366
+ } catch (_err) {
36367
+ return;
36368
+ }
36369
+ for (const entry of entries) {
36370
+ const childPath = (0, import_node_path2.join)(path, entry.name);
36371
+ if (entry.isFile() && isSummarySidecar(entry.name)) {
36372
+ let content;
36373
+ try {
36374
+ content = await (0, import_promises3.readFile)(childPath, "utf8");
36375
+ } catch (_err) {
36376
+ continue;
36377
+ }
36378
+ if (!isStaleSummary(content)) {
36379
+ continue;
36380
+ }
36381
+ const parentPath = (0, import_node_path2.dirname)(childPath);
36382
+ const parentRelative = toPosixPath((0, import_node_path2.relative)(rootPath, parentPath));
36383
+ const relativePath = toPosixPath((0, import_node_path2.relative)(rootPath, childPath));
36384
+ results.push({
36385
+ content: content.trim(),
36386
+ relativePath,
36387
+ uri: parentRelative ? `${trimLocalRootUri(rootUri)}/${parentRelative}` : trimLocalRootUri(rootUri)
36388
+ });
36389
+ } else if (entry.isDirectory() && depth < MAX_SCAN_DEPTH) {
36390
+ await visit(childPath, depth + 1);
36391
+ }
36392
+ }
36393
+ }
36394
+ await visit(rootPath, 0);
36395
+ return results;
36396
+ }
36397
+ function isSummarySidecar(name) {
36398
+ return name === ".abstract.md" || name === ".overview.md";
36399
+ }
36400
+ function isStaleSummary(content) {
36401
+ return content.includes("[Directory overview is not ready]") || content.includes("[Directory abstract is not ready]");
36402
+ }
36403
+ function trimLocalRootUri(uri) {
36404
+ return uri.endsWith("/") ? uri.slice(0, -1) : uri;
36405
+ }
36406
+ async function readAutoRepairState(config2) {
36407
+ const raw = await readFileIfExists(autoRepairStatePath(config2));
36408
+ if (!raw) {
36409
+ return { entries: {}, version: 1 };
36410
+ }
36411
+ try {
36412
+ const parsed = JSON.parse(raw);
36413
+ if (!isJsonObject(parsed) || parsed.version !== 1 || !isJsonObject(parsed.entries)) {
36414
+ return { entries: {}, version: 1 };
36415
+ }
36416
+ const entries = {};
36417
+ for (const [uri, entry] of Object.entries(parsed.entries)) {
36418
+ if (isJsonObject(entry) && typeof entry.signature === "string" && typeof entry.repairedAt === "string") {
36419
+ entries[uri] = { repairedAt: entry.repairedAt, signature: entry.signature };
36420
+ }
36421
+ }
36422
+ return { entries, version: 1 };
36423
+ } catch (_err) {
36424
+ return { entries: {}, version: 1 };
36425
+ }
36426
+ }
36427
+ async function writeAutoRepairState(config2, state) {
36428
+ const path = autoRepairStatePath(config2);
36429
+ await ensureDirectory((0, import_node_path2.dirname)(path), false);
36430
+ await (0, import_promises3.writeFile)(path, `${JSON.stringify(state, void 0, 2)}
36431
+ `, { encoding: "utf8", mode: 384 });
36432
+ }
36433
+ function autoRepairStatePath(config2) {
36434
+ return (0, import_node_path2.join)(config2.agentContextHome, AUTO_REPAIR_STATE_FILE);
36435
+ }
36436
+ function indexRepairWarning(uri, result) {
36437
+ return `${uri}: ${result.stderr.trim() || result.stdout.trim() || "reindex failed"}`;
36438
+ }
36439
+
34046
36440
  // src/memory_hygiene.ts
34047
- var import_node_path2 = require("node:path");
36441
+ var import_node_path3 = require("node:path");
34048
36442
  var HYGIENE_SOURCES_HEADING = "## Threadnote Hygiene Sources";
34049
36443
  var STALE_HANDOFF_AGE_MS = 14 * 24 * 60 * 60 * 1e3;
34050
36444
  function parseMemoryDocument(uri, content) {
@@ -34327,7 +36721,7 @@ function branchFromBody(body) {
34327
36721
  return branch?.split(/\s+/)[0]?.replace(/[.,;:]+$/g, "");
34328
36722
  }
34329
36723
  function topicFromUri(uri) {
34330
- const name = (0, import_node_path2.basename)(uri).replace(/\.md$/, "");
36724
+ const name = (0, import_node_path3.basename)(uri).replace(/\.md$/, "");
34331
36725
  return name.startsWith("threadnote-") ? void 0 : name;
34332
36726
  }
34333
36727
  function parseProjectFromUri(uri) {
@@ -34357,7 +36751,7 @@ function preferredKeepRecord(records, topic) {
34357
36751
  }
34358
36752
  function isStableRecord(record2, topic) {
34359
36753
  const recordTopic = topic ?? topicForRecord(record2);
34360
- return recordTopic !== void 0 && (0, import_node_path2.basename)(record2.uri) === `${uriSegment(recordTopic)}.md`;
36754
+ return recordTopic !== void 0 && (0, import_node_path3.basename)(record2.uri) === `${uriSegment(recordTopic)}.md`;
34361
36755
  }
34362
36756
  function sortedNewestFirst(records) {
34363
36757
  return [...records].sort((left, right) => {
@@ -34469,16 +36863,9 @@ function formatPlanSection(title, lines) {
34469
36863
  }
34470
36864
 
34471
36865
  // src/share.ts
34472
- var import_promises3 = require("node:fs/promises");
36866
+ var import_promises4 = require("node:fs/promises");
34473
36867
  var import_node_os2 = require("node:os");
34474
- var import_node_path3 = require("node:path");
34475
-
34476
- // src/runtime.ts
34477
- function withIdentity(config2, args) {
34478
- return [...args, "--account", config2.account, "--user", config2.user, "--agent-id", config2.agentId];
34479
- }
34480
-
34481
- // src/share.ts
36868
+ var import_node_path4 = require("node:path");
34482
36869
  var TEAMS_FILE_VERSION = 1;
34483
36870
  var SHARED_SEGMENT = "shared";
34484
36871
  var SHAREABLE_MEMORY_KIND_DIRS = ["durable"];
@@ -34585,7 +36972,7 @@ function autoShareState(config2) {
34585
36972
  return state;
34586
36973
  }
34587
36974
  function pendingReindexesPath(config2) {
34588
- return (0, import_node_path3.join)(config2.agentContextHome, "share", "auto-sync-pending-reindexes.json");
36975
+ return (0, import_node_path4.join)(config2.agentContextHome, "share", "auto-sync-pending-reindexes.json");
34589
36976
  }
34590
36977
  async function loadPendingReindexes(config2, state) {
34591
36978
  const raw = await readFileIfExists(pendingReindexesPath(config2));
@@ -34622,18 +37009,18 @@ async function loadPendingReindexes(config2, state) {
34622
37009
  async function writePendingReindexes(config2, state) {
34623
37010
  const path = pendingReindexesPath(config2);
34624
37011
  if (state.pendingReindexes.size === 0) {
34625
- await (0, import_promises3.rm)(path, { force: true });
37012
+ await (0, import_promises4.rm)(path, { force: true });
34626
37013
  return;
34627
37014
  }
34628
37015
  const contents = {
34629
37016
  teams: Object.fromEntries(state.pendingReindexes),
34630
37017
  version: 1
34631
37018
  };
34632
- await (0, import_promises3.mkdir)((0, import_node_path3.dirname)(path), { recursive: true });
37019
+ await (0, import_promises4.mkdir)((0, import_node_path4.dirname)(path), { recursive: true });
34633
37020
  const tempPath = `${path}.${process.pid}.tmp`;
34634
- await (0, import_promises3.writeFile)(tempPath, `${JSON.stringify(contents, void 0, 2)}
37021
+ await (0, import_promises4.writeFile)(tempPath, `${JSON.stringify(contents, void 0, 2)}
34635
37022
  `, { encoding: "utf8", mode: 384 });
34636
- await (0, import_promises3.rename)(tempPath, path);
37023
+ await (0, import_promises4.rename)(tempPath, path);
34637
37024
  }
34638
37025
  async function refreshShareUpdateState(config2, options) {
34639
37026
  const state = autoShareState(config2);
@@ -34729,7 +37116,7 @@ async function runShareSyncQuiet(config2, state, options) {
34729
37116
  const beforeRev = await gitOutput(worktree, ["rev-parse", "HEAD"], false);
34730
37117
  const pullResult = await runCommand(git, ["-C", worktree, "rebase", "@{u}"], { allowFailure: true });
34731
37118
  if (pullResult.exitCode !== 0) {
34732
- if (await exists((0, import_node_path3.join)(team.config.gitdir, "rebase-merge")) || await exists((0, import_node_path3.join)(team.config.gitdir, "rebase-apply"))) {
37119
+ if (await exists((0, import_node_path4.join)(team.config.gitdir, "rebase-merge")) || await exists((0, import_node_path4.join)(team.config.gitdir, "rebase-apply"))) {
34733
37120
  throw new Error(
34734
37121
  `Automatic share sync hit git conflicts in ${worktree}. Resolve them in-place, run \`git -C ${worktree} rebase --continue\` (or --abort), then rerun recall/read.`
34735
37122
  );
@@ -34814,10 +37201,10 @@ function normalizeTeamName(input) {
34814
37201
  return candidate;
34815
37202
  }
34816
37203
  function teamsFilePath(config2) {
34817
- return (0, import_node_path3.join)(config2.agentContextHome, "share", "teams.json");
37204
+ return (0, import_node_path4.join)(config2.agentContextHome, "share", "teams.json");
34818
37205
  }
34819
37206
  function teamWorktreePath(config2, team) {
34820
- return (0, import_node_path3.join)(
37207
+ return (0, import_node_path4.join)(
34821
37208
  config2.agentContextHome,
34822
37209
  "data",
34823
37210
  "viking",
@@ -34830,7 +37217,7 @@ function teamWorktreePath(config2, team) {
34830
37217
  );
34831
37218
  }
34832
37219
  function teamGitdirPath(config2, team) {
34833
- return (0, import_node_path3.join)(config2.agentContextHome, "share", "teams", `${team}.gitdir`);
37220
+ return (0, import_node_path4.join)(config2.agentContextHome, "share", "teams", `${team}.gitdir`);
34834
37221
  }
34835
37222
  async function readTeamsFile(config2) {
34836
37223
  const path = teamsFilePath(config2);
@@ -34886,7 +37273,7 @@ async function resolveTeam(config2, requested) {
34886
37273
  return { config: found, name: wantName };
34887
37274
  }
34888
37275
  function workfileToVikingUri(config2, team, filePath) {
34889
- const rel = (0, import_node_path3.relative)(team.worktree, filePath).split(import_node_path3.sep).join("/");
37276
+ const rel = (0, import_node_path4.relative)(team.worktree, filePath).split(import_node_path4.sep).join("/");
34890
37277
  return `viking://user/${uriSegment(config2.user)}/memories/${SHARED_SEGMENT}/${team.name}/${rel}`;
34891
37278
  }
34892
37279
  function isInSharedNamespace(config2, uri) {
@@ -35011,13 +37398,14 @@ async function writeMemoryFile(config2, ov, uri, content, initialMode, dryRun, o
35011
37398
  }
35012
37399
  return;
35013
37400
  }
35014
- const stagingDir = await (0, import_promises3.mkdtemp)((0, import_node_path3.join)((0, import_node_os2.tmpdir)(), "threadnote-share-"));
35015
- const tempPath = (0, import_node_path3.join)(stagingDir, "body.txt");
37401
+ const stagingDir = await (0, import_promises4.mkdtemp)((0, import_node_path4.join)((0, import_node_os2.tmpdir)(), "threadnote-share-"));
37402
+ const tempPath = (0, import_node_path4.join)(stagingDir, "body.txt");
35016
37403
  try {
35017
- await (0, import_promises3.writeFile)(tempPath, content, { encoding: "utf8", mode: 384 });
37404
+ await (0, import_promises4.writeFile)(tempPath, content, { encoding: "utf8", mode: 384 });
35018
37405
  await writeOvFileWithRetry(config2, ov, uri, tempPath, initialMode, options);
37406
+ await refreshMemoryIndex(config2, ov, uri, options);
35019
37407
  } finally {
35020
- await (0, import_promises3.rm)(stagingDir, { force: true, recursive: true });
37408
+ await (0, import_promises4.rm)(stagingDir, { force: true, recursive: true });
35021
37409
  }
35022
37410
  }
35023
37411
  var BUSY_RETRY_BACKOFF_MS = [2e3, 5e3, 1e4, 2e4, 3e4];
@@ -35072,6 +37460,27 @@ async function writeOvFileWithRetry(config2, ov, uri, fromFile, initialMode, opt
35072
37460
  }
35073
37461
  }
35074
37462
  }
37463
+ async function refreshMemoryIndex(config2, ov, uri, options = {}) {
37464
+ const result = await runCommand(
37465
+ ov,
37466
+ withIdentity(config2, ["reindex", uri, "--mode", "semantic_and_vectors", "--wait", "true"]),
37467
+ { allowFailure: true }
37468
+ );
37469
+ if (result.exitCode === 0) {
37470
+ if (options.quiet !== true && result.stdout.trim()) {
37471
+ console.log(result.stdout.trim());
37472
+ }
37473
+ if (options.quiet !== true && result.stderr.trim()) {
37474
+ console.error(result.stderr.trim());
37475
+ }
37476
+ return;
37477
+ }
37478
+ if (options.quiet !== true) {
37479
+ console.error(
37480
+ `Memory stored, but index refresh failed for ${uri}: ${result.stderr.trim() || result.stdout.trim()}`
37481
+ );
37482
+ }
37483
+ }
35075
37484
  async function waitForOvQueue(ov, config2, options = {}) {
35076
37485
  const result = await runCommand(ov, withIdentity(config2, ["wait", "--timeout", "120"]), { allowFailure: true });
35077
37486
  if (options.quiet !== true && result.stdout.trim()) {
@@ -35092,7 +37501,7 @@ ${stdout2}`.toLowerCase();
35092
37501
  return output.includes("resource is busy") || output.includes("resource is being processed");
35093
37502
  }
35094
37503
  async function ingestSingleFile(ov, config2, uri, filePath, initialMode, options = {}) {
35095
- const content = await (0, import_promises3.readFile)(filePath, "utf8");
37504
+ const content = await (0, import_promises4.readFile)(filePath, "utf8");
35096
37505
  await writeMemoryFile(config2, ov, uri, content, initialMode, false, options);
35097
37506
  }
35098
37507
  async function removeMemoryUri(config2, ov, uri, dryRun, options = {}) {
@@ -35157,8 +37566,8 @@ async function listChangedFiles(worktree, beforeRev, afterRev) {
35157
37566
  const oldRel = entries[index + 1];
35158
37567
  const newRel = entries[index + 2];
35159
37568
  if (oldRel && newRel) {
35160
- changes.push({ path: (0, import_node_path3.join)(worktree, oldRel), relativePath: oldRel, status: "removed" });
35161
- changes.push({ path: (0, import_node_path3.join)(worktree, newRel), relativePath: newRel, status: "added" });
37569
+ changes.push({ path: (0, import_node_path4.join)(worktree, oldRel), relativePath: oldRel, status: "removed" });
37570
+ changes.push({ path: (0, import_node_path4.join)(worktree, newRel), relativePath: newRel, status: "added" });
35162
37571
  }
35163
37572
  index += 3;
35164
37573
  continue;
@@ -35166,7 +37575,7 @@ async function listChangedFiles(worktree, beforeRev, afterRev) {
35166
37575
  const rel = entries[index + 1];
35167
37576
  if (rel) {
35168
37577
  const status = head === "A" ? "added" : head === "D" ? "removed" : "modified";
35169
- changes.push({ path: (0, import_node_path3.join)(worktree, rel), relativePath: rel, status });
37578
+ changes.push({ path: (0, import_node_path4.join)(worktree, rel), relativePath: rel, status });
35170
37579
  }
35171
37580
  index += 2;
35172
37581
  }
@@ -35267,11 +37676,14 @@ async function main() {
35267
37676
  process.stderr.write("Threadnote local MCP adapter running\n");
35268
37677
  }
35269
37678
  function getRuntimeConfig() {
37679
+ const host = process.env.THREADNOTE_HOST ?? DEFAULT_HOST;
37680
+ const port = parsePort(process.env.THREADNOTE_PORT ?? String(DEFAULT_PORT));
35270
37681
  return {
35271
37682
  account: process.env.THREADNOTE_ACCOUNT ?? DEFAULT_ACCOUNT,
35272
37683
  agentContextHome: expandPath(process.env.THREADNOTE_HOME ?? "~/.openviking"),
35273
37684
  agentId: process.env.THREADNOTE_AGENT_ID ?? DEFAULT_AGENT_ID,
35274
37685
  manifestPath: expandPath(process.env.THREADNOTE_MANIFEST ?? "~/.openviking/seed-manifest.yaml"),
37686
+ openVikingMcpUrl: process.env.THREADNOTE_OPENVIKING_MCP_URL ?? `http://${host}:${port}/mcp`,
35275
37687
  user: process.env.THREADNOTE_USER ?? process.env.USER ?? "unknown"
35276
37688
  };
35277
37689
  }
@@ -35318,29 +37730,16 @@ function registerTools(server, config2) {
35318
37730
  annotations: { readOnlyHint: false, destructiveHint: true },
35319
37731
  description: "Remove a viking:// URI from OpenViking.",
35320
37732
  inputSchema: {
37733
+ recursive: external_exports.boolean().optional().describe("Remove a directory recursively"),
35321
37734
  uri: external_exports.string().optional().describe("Required viking:// URI to remove")
35322
37735
  }
35323
37736
  },
35324
- async ({ uri }) => {
37737
+ async ({ recursive, uri }) => {
35325
37738
  const checkedUri = requiredVikingUri(uri, "forget", "viking://agent/threadnote/memories/example.md");
35326
37739
  if (!checkedUri.ok) {
35327
37740
  return checkedUri.error;
35328
37741
  }
35329
- try {
35330
- const ov = await requiredOpenVikingCli2();
35331
- const removed = await removeVikingResourceWithRetry(ov, config2, checkedUri.value);
35332
- return {
35333
- content: [
35334
- {
35335
- type: "text",
35336
- text: removed ? `Removed: ${checkedUri.value}` : `Resource is still being processed; retry later: ${checkedUri.value}`
35337
- }
35338
- ],
35339
- isError: !removed
35340
- };
35341
- } catch (err) {
35342
- return { content: [{ type: "text", text: errorMessage(err) }], isError: true };
35343
- }
37742
+ return runOpenVikingRemoveTool(config2, checkedUri.value, recursive === true);
35344
37743
  }
35345
37744
  );
35346
37745
  server.registerTool(
@@ -35349,31 +37748,26 @@ function registerTools(server, config2) {
35349
37748
  annotations: { readOnlyHint: false, destructiveHint: false },
35350
37749
  description: "Add a local file or directory to OpenViking as a resource.",
35351
37750
  inputSchema: {
37751
+ description: external_exports.string().optional().describe("Optional import reason/description"),
37752
+ path: external_exports.string().optional().describe("Local source file/directory or URL; native OpenViking MCP name"),
35352
37753
  sourcePath: external_exports.string().optional().describe("Required local source file or directory"),
35353
- to: external_exports.string().optional().describe("Required destination viking:// URI"),
35354
- wait: external_exports.boolean().optional().describe("Wait for processing to finish")
37754
+ source_path: external_exports.string().optional().describe("Compatibility alias for path"),
37755
+ tempFileId: external_exports.string().optional().describe("Native progressive upload temp file id"),
37756
+ temp_file_id: external_exports.string().optional().describe("Native progressive upload temp file id"),
37757
+ to: external_exports.string().optional().describe("Optional destination viking:// URI"),
37758
+ wait: external_exports.boolean().optional().describe("Wait for processing to finish"),
37759
+ watchInterval: external_exports.number().int().min(0).optional().describe("Watch interval in minutes"),
37760
+ watch_interval: external_exports.number().int().min(0).optional().describe("Watch interval in minutes")
35355
37761
  }
35356
37762
  },
35357
- async ({ sourcePath, to, wait }) => {
35358
- const checkedSourcePath = requiredText(sourcePath, "add_resource", "sourcePath", {
35359
- sourcePath: "/path/to/README.md",
35360
- to: "viking://resource/my-repo/README.md"
35361
- });
35362
- if (!checkedSourcePath.ok) {
35363
- return checkedSourcePath.error;
35364
- }
35365
- const checkedTo = requiredVikingUri(to, "add_resource", "viking://resource/my-repo/README.md");
35366
- if (!checkedTo.ok) {
35367
- return checkedTo.error;
35368
- }
35369
- return runOpenVikingTool(config2, [
35370
- "add-resource",
35371
- checkedSourcePath.value,
35372
- "--to",
35373
- checkedTo.value,
35374
- ...wait === false ? [] : ["--wait"]
35375
- ]);
35376
- }
37763
+ async (args) => runOpenVikingAddResourceTool(config2, "add_resource", {
37764
+ description: args.description,
37765
+ path: args.sourcePath ?? args.path ?? args.source_path,
37766
+ tempFileId: args.tempFileId ?? args.temp_file_id,
37767
+ to: args.to,
37768
+ wait: args.wait,
37769
+ watchInterval: args.watchInterval ?? args.watch_interval
37770
+ })
35377
37771
  );
35378
37772
  server.registerTool(
35379
37773
  "grep",
@@ -35381,11 +37775,15 @@ function registerTools(server, config2) {
35381
37775
  annotations: { readOnlyHint: true, destructiveHint: false },
35382
37776
  description: "Run exact text search in OpenViking.",
35383
37777
  inputSchema: {
37778
+ caseInsensitive: external_exports.boolean().optional().describe("Case-insensitive search"),
37779
+ case_insensitive: external_exports.boolean().optional().describe("Case-insensitive search"),
37780
+ nodeLimit: external_exports.number().int().positive().max(1e3).optional().describe("Maximum result count"),
37781
+ node_limit: external_exports.number().int().positive().max(1e3).optional().describe("Maximum result count"),
35384
37782
  pattern: external_exports.string().optional().describe("Required text or regex pattern"),
35385
37783
  uri: external_exports.string().optional().describe("Optional viking:// subtree")
35386
37784
  }
35387
37785
  },
35388
- async ({ pattern, uri }) => {
37786
+ async ({ caseInsensitive, case_insensitive, nodeLimit, node_limit, pattern, uri }) => {
35389
37787
  const checkedPattern = requiredText(pattern, "grep", "pattern", { pattern: "unity-ui-ccc" });
35390
37788
  if (!checkedPattern.ok) {
35391
37789
  return checkedPattern.error;
@@ -35394,11 +37792,12 @@ function registerTools(server, config2) {
35394
37792
  if (!checkedUri.ok) {
35395
37793
  return checkedUri.error;
35396
37794
  }
35397
- return runOpenVikingTool(config2, [
35398
- "grep",
35399
- checkedPattern.value,
35400
- ...checkedUri.value ? ["--uri", checkedUri.value] : []
35401
- ]);
37795
+ return runOpenVikingMcpTool(config2, "grep", {
37796
+ case_insensitive: caseInsensitive ?? case_insensitive,
37797
+ node_limit: nodeLimit ?? node_limit,
37798
+ pattern: checkedPattern.value,
37799
+ uri: checkedUri.value
37800
+ });
35402
37801
  }
35403
37802
  );
35404
37803
  server.registerTool(
@@ -35407,11 +37806,13 @@ function registerTools(server, config2) {
35407
37806
  annotations: { readOnlyHint: true, destructiveHint: false },
35408
37807
  description: "Run glob file search in OpenViking.",
35409
37808
  inputSchema: {
37809
+ nodeLimit: external_exports.number().int().positive().max(1e3).optional().describe("Maximum result count"),
37810
+ node_limit: external_exports.number().int().positive().max(1e3).optional().describe("Maximum result count"),
35410
37811
  pattern: external_exports.string().optional().describe("Required glob pattern"),
35411
37812
  uri: external_exports.string().optional().describe("Optional viking:// subtree")
35412
37813
  }
35413
37814
  },
35414
- async ({ pattern, uri }) => {
37815
+ async ({ nodeLimit, node_limit, pattern, uri }) => {
35415
37816
  const checkedPattern = requiredText(pattern, "glob", "pattern", { pattern: "**/AGENTS.md" });
35416
37817
  if (!checkedPattern.ok) {
35417
37818
  return checkedPattern.error;
@@ -35420,11 +37821,11 @@ function registerTools(server, config2) {
35420
37821
  if (!checkedUri.ok) {
35421
37822
  return checkedUri.error;
35422
37823
  }
35423
- return runOpenVikingTool(config2, [
35424
- "glob",
35425
- checkedPattern.value,
35426
- ...checkedUri.value ? ["--uri", checkedUri.value] : []
35427
- ]);
37824
+ return runOpenVikingMcpTool(config2, "glob", {
37825
+ node_limit: nodeLimit ?? node_limit,
37826
+ pattern: checkedPattern.value,
37827
+ uri: checkedUri.value
37828
+ });
35428
37829
  }
35429
37830
  );
35430
37831
  server.registerTool(
@@ -35434,8 +37835,9 @@ function registerTools(server, config2) {
35434
37835
  description: "Check OpenViking server health through the CLI.",
35435
37836
  inputSchema: {}
35436
37837
  },
35437
- async () => runOpenVikingTool(config2, ["health"])
37838
+ async () => runOpenVikingMcpTool(config2, "health", {})
35438
37839
  );
37840
+ registerOpenVikingParityTools(server, config2);
35439
37841
  server.registerTool(
35440
37842
  "share_publish",
35441
37843
  {
@@ -35465,6 +37867,341 @@ function registerTools(server, config2) {
35465
37867
  }
35466
37868
  );
35467
37869
  }
37870
+ function registerOpenVikingParityTools(server, config2) {
37871
+ server.registerTool(
37872
+ "ov_search",
37873
+ {
37874
+ annotations: { readOnlyHint: true, destructiveHint: false },
37875
+ description: "Raw OpenViking MCP search parity. Unlike search/recall_context, this does not enrich the query.",
37876
+ inputSchema: {
37877
+ limit: external_exports.number().int().positive().max(1e3).optional().describe("Maximum result count"),
37878
+ minScore: external_exports.number().min(0).max(1).optional().describe("Minimum score threshold"),
37879
+ min_score: external_exports.number().min(0).max(1).optional().describe("Minimum score threshold"),
37880
+ peerId: external_exports.string().optional().describe("Optional native peer id"),
37881
+ peer_id: external_exports.string().optional().describe("Optional native peer id"),
37882
+ query: external_exports.string().optional().describe("Required search query"),
37883
+ sessionId: external_exports.string().optional().describe("Optional native session id"),
37884
+ session_id: external_exports.string().optional().describe("Optional native session id"),
37885
+ targetUri: external_exports.string().optional().describe("Optional target viking:// subtree"),
37886
+ target_uri: external_exports.string().optional().describe("Optional target viking:// subtree"),
37887
+ uri: external_exports.string().optional().describe("Compatibility alias for target_uri")
37888
+ }
37889
+ },
37890
+ async ({ limit, minScore, min_score, query, sessionId, session_id, targetUri, target_uri, uri }) => {
37891
+ const checkedQuery = requiredText(query, "ov_search", "query", { query: "current repo release notes" });
37892
+ if (!checkedQuery.ok) {
37893
+ return checkedQuery.error;
37894
+ }
37895
+ const checkedUri = optionalVikingUri(targetUri ?? target_uri ?? uri, "ov_search");
37896
+ if (!checkedUri.ok) {
37897
+ return checkedUri.error;
37898
+ }
37899
+ const normalizedSessionId = (sessionId ?? session_id)?.trim();
37900
+ return runOpenVikingMcpTool(config2, "search", {
37901
+ limit,
37902
+ min_score: minScore ?? min_score,
37903
+ query: checkedQuery.value,
37904
+ session_id: normalizedSessionId || void 0,
37905
+ target_uri: checkedUri.value
37906
+ });
37907
+ }
37908
+ );
37909
+ server.registerTool(
37910
+ "ov_read",
37911
+ {
37912
+ annotations: { readOnlyHint: true, destructiveHint: false },
37913
+ description: "Raw OpenViking MCP read parity. Reads one or more viking:// URIs without Threadnote shared-memory sync.",
37914
+ inputSchema: {
37915
+ uri: external_exports.string().optional().describe("Single viking:// URI"),
37916
+ uris: external_exports.union([external_exports.string(), external_exports.array(external_exports.string())]).optional().describe("Single viking:// URI or array of URIs")
37917
+ }
37918
+ },
37919
+ async ({ uri, uris }) => {
37920
+ const checkedUris = requiredVikingUriList(
37921
+ uris ?? uri,
37922
+ "ov_read",
37923
+ "viking://resources/repos/threadnote/README.md"
37924
+ );
37925
+ if (!checkedUris.ok) {
37926
+ return checkedUris.error;
37927
+ }
37928
+ return runOpenVikingReadTool(config2, checkedUris.value);
37929
+ }
37930
+ );
37931
+ server.registerTool(
37932
+ "ov_list",
37933
+ {
37934
+ annotations: { readOnlyHint: true, destructiveHint: false },
37935
+ description: "Raw OpenViking MCP list parity.",
37936
+ inputSchema: {
37937
+ all: external_exports.boolean().optional().describe("Show hidden files like .abstract.md and .overview.md"),
37938
+ nodeLimit: external_exports.number().int().positive().max(1e3).optional().describe("Maximum node count"),
37939
+ node_limit: external_exports.number().int().positive().max(1e3).optional().describe("Maximum node count"),
37940
+ recursive: external_exports.boolean().optional().describe("List recursively"),
37941
+ simple: external_exports.boolean().optional().describe("Only return paths"),
37942
+ uri: external_exports.string().optional().describe("Optional viking:// directory URI; defaults to viking://")
37943
+ }
37944
+ },
37945
+ async ({ recursive, uri }) => {
37946
+ const checkedUri = optionalVikingUri(uri, "ov_list");
37947
+ if (!checkedUri.ok) {
37948
+ return checkedUri.error;
37949
+ }
37950
+ return runOpenVikingMcpTool(config2, "list", {
37951
+ recursive,
37952
+ uri: checkedUri.value ?? "viking://"
37953
+ });
37954
+ }
37955
+ );
37956
+ registerOpenVikingStoreTool(server, config2, "ov_store");
37957
+ registerOpenVikingStoreTool(server, config2, "ov_remember");
37958
+ server.registerTool(
37959
+ "ov_add_resource",
37960
+ {
37961
+ annotations: { readOnlyHint: false, destructiveHint: false },
37962
+ description: "Raw OpenViking MCP add_resource parity.",
37963
+ inputSchema: {
37964
+ description: external_exports.string().optional().describe("Optional import reason/description"),
37965
+ path: external_exports.string().optional().describe("Local source file/directory or URL"),
37966
+ sourcePath: external_exports.string().optional().describe("Compatibility alias for path"),
37967
+ source_path: external_exports.string().optional().describe("Compatibility alias for path"),
37968
+ tempFileId: external_exports.string().optional().describe("Native progressive upload temp file id"),
37969
+ temp_file_id: external_exports.string().optional().describe("Native progressive upload temp file id"),
37970
+ to: external_exports.string().optional().describe("Optional destination viking:// URI"),
37971
+ wait: external_exports.boolean().optional().describe("Wait for processing to finish"),
37972
+ watchInterval: external_exports.number().int().min(0).optional().describe("Watch interval in minutes"),
37973
+ watch_interval: external_exports.number().int().min(0).optional().describe("Watch interval in minutes")
37974
+ }
37975
+ },
37976
+ async (args) => runOpenVikingAddResourceTool(config2, "ov_add_resource", {
37977
+ description: args.description,
37978
+ path: args.path ?? args.sourcePath ?? args.source_path,
37979
+ tempFileId: args.tempFileId ?? args.temp_file_id,
37980
+ to: args.to,
37981
+ wait: args.wait,
37982
+ watchInterval: args.watchInterval ?? args.watch_interval
37983
+ })
37984
+ );
37985
+ server.registerTool(
37986
+ "ov_list_watches",
37987
+ {
37988
+ annotations: { readOnlyHint: true, destructiveHint: false },
37989
+ description: "Raw OpenViking MCP list_watches parity.",
37990
+ inputSchema: {
37991
+ activeOnly: external_exports.boolean().optional().describe("Only show active watch tasks"),
37992
+ active_only: external_exports.boolean().optional().describe("Only show active watch tasks")
37993
+ }
37994
+ },
37995
+ async ({ activeOnly, active_only }) => runOpenVikingMcpTool(config2, "list_watches", { active_only: activeOnly ?? active_only })
37996
+ );
37997
+ server.registerTool(
37998
+ "ov_cancel_watch",
37999
+ {
38000
+ annotations: { readOnlyHint: false, destructiveHint: true },
38001
+ description: "Raw OpenViking MCP cancel_watch parity. Accepts to_uri, toUri, or uri.",
38002
+ inputSchema: {
38003
+ toUri: external_exports.string().optional().describe("Watch target viking:// URI"),
38004
+ to_uri: external_exports.string().optional().describe("Watch target viking:// URI"),
38005
+ uri: external_exports.string().optional().describe("Compatibility alias for to_uri")
38006
+ }
38007
+ },
38008
+ async ({ toUri, to_uri, uri }) => {
38009
+ const checkedUri = requiredVikingUri(
38010
+ toUri ?? to_uri ?? uri,
38011
+ "ov_cancel_watch",
38012
+ "viking://resources/repos/threadnote"
38013
+ );
38014
+ if (!checkedUri.ok) {
38015
+ return checkedUri.error;
38016
+ }
38017
+ return runOpenVikingMcpTool(config2, "cancel_watch", { to_uri: checkedUri.value });
38018
+ }
38019
+ );
38020
+ server.registerTool(
38021
+ "ov_grep",
38022
+ {
38023
+ annotations: { readOnlyHint: true, destructiveHint: false },
38024
+ description: "Raw OpenViking MCP grep parity.",
38025
+ inputSchema: {
38026
+ caseInsensitive: external_exports.boolean().optional().describe("Case-insensitive search"),
38027
+ case_insensitive: external_exports.boolean().optional().describe("Case-insensitive search"),
38028
+ nodeLimit: external_exports.number().int().positive().max(1e3).optional().describe("Maximum result count"),
38029
+ node_limit: external_exports.number().int().positive().max(1e3).optional().describe("Maximum result count"),
38030
+ pattern: external_exports.string().optional().describe("Required regex pattern"),
38031
+ uri: external_exports.string().optional().describe("Optional viking:// subtree")
38032
+ }
38033
+ },
38034
+ async ({ caseInsensitive, case_insensitive, nodeLimit, node_limit, pattern, uri }) => {
38035
+ const checkedPattern = requiredText(pattern, "ov_grep", "pattern", { pattern: "threadnote" });
38036
+ if (!checkedPattern.ok) {
38037
+ return checkedPattern.error;
38038
+ }
38039
+ const checkedUri = optionalVikingUri(uri, "ov_grep");
38040
+ if (!checkedUri.ok) {
38041
+ return checkedUri.error;
38042
+ }
38043
+ return runOpenVikingMcpTool(config2, "grep", {
38044
+ case_insensitive: caseInsensitive ?? case_insensitive,
38045
+ node_limit: nodeLimit ?? node_limit,
38046
+ pattern: checkedPattern.value,
38047
+ uri: checkedUri.value
38048
+ });
38049
+ }
38050
+ );
38051
+ server.registerTool(
38052
+ "ov_glob",
38053
+ {
38054
+ annotations: { readOnlyHint: true, destructiveHint: false },
38055
+ description: "Raw OpenViking MCP glob parity.",
38056
+ inputSchema: {
38057
+ nodeLimit: external_exports.number().int().positive().max(1e3).optional().describe("Maximum result count"),
38058
+ node_limit: external_exports.number().int().positive().max(1e3).optional().describe("Maximum result count"),
38059
+ pattern: external_exports.string().optional().describe("Required glob pattern"),
38060
+ uri: external_exports.string().optional().describe("Optional viking:// subtree")
38061
+ }
38062
+ },
38063
+ async ({ nodeLimit, node_limit, pattern, uri }) => {
38064
+ const checkedPattern = requiredText(pattern, "ov_glob", "pattern", { pattern: "**/AGENTS.md" });
38065
+ if (!checkedPattern.ok) {
38066
+ return checkedPattern.error;
38067
+ }
38068
+ const checkedUri = optionalVikingUri(uri, "ov_glob");
38069
+ if (!checkedUri.ok) {
38070
+ return checkedUri.error;
38071
+ }
38072
+ return runOpenVikingMcpTool(config2, "glob", {
38073
+ node_limit: nodeLimit ?? node_limit,
38074
+ pattern: checkedPattern.value,
38075
+ uri: checkedUri.value
38076
+ });
38077
+ }
38078
+ );
38079
+ server.registerTool(
38080
+ "ov_forget",
38081
+ {
38082
+ annotations: { readOnlyHint: false, destructiveHint: true },
38083
+ description: "Raw OpenViking MCP forget parity.",
38084
+ inputSchema: {
38085
+ recursive: external_exports.boolean().optional().describe("Remove a directory recursively"),
38086
+ uri: external_exports.string().optional().describe("Required viking:// URI to remove")
38087
+ }
38088
+ },
38089
+ async ({ recursive, uri }) => {
38090
+ const checkedUri = requiredVikingUri(uri, "ov_forget", "viking://resources/repos/threadnote/tmp");
38091
+ if (!checkedUri.ok) {
38092
+ return checkedUri.error;
38093
+ }
38094
+ return runOpenVikingRemoveTool(config2, checkedUri.value, recursive === true);
38095
+ }
38096
+ );
38097
+ server.registerTool(
38098
+ "ov_code_outline",
38099
+ {
38100
+ annotations: { readOnlyHint: true, destructiveHint: false },
38101
+ description: "Raw OpenViking MCP code_outline parity. Requires a viking:// file URI.",
38102
+ inputSchema: {
38103
+ uri: external_exports.string().optional().describe("Required viking:// file URI")
38104
+ }
38105
+ },
38106
+ async ({ uri }) => {
38107
+ const checkedUri = requiredVikingUri(
38108
+ uri,
38109
+ "ov_code_outline",
38110
+ "viking://resources/repos/threadnote/src/mcp_server.ts"
38111
+ );
38112
+ if (!checkedUri.ok) {
38113
+ return checkedUri.error;
38114
+ }
38115
+ return runOpenVikingMcpTool(config2, "code_outline", { uri: checkedUri.value });
38116
+ }
38117
+ );
38118
+ server.registerTool(
38119
+ "ov_code_search",
38120
+ {
38121
+ annotations: { readOnlyHint: true, destructiveHint: false },
38122
+ description: "Raw OpenViking MCP code_search parity. Requires a query and viking:// directory URI.",
38123
+ inputSchema: {
38124
+ query: external_exports.string().optional().describe("Required symbol-name substring"),
38125
+ uri: external_exports.string().optional().describe("Required viking:// directory URI")
38126
+ }
38127
+ },
38128
+ async ({ query, uri }) => {
38129
+ const checkedQuery = requiredText(query, "ov_code_search", "query", { query: "registerTools" });
38130
+ if (!checkedQuery.ok) {
38131
+ return checkedQuery.error;
38132
+ }
38133
+ const checkedUri = requiredVikingUri(uri, "ov_code_search", "viking://resources/repos/threadnote/src");
38134
+ if (!checkedUri.ok) {
38135
+ return checkedUri.error;
38136
+ }
38137
+ return runOpenVikingMcpTool(config2, "code_search", {
38138
+ query: checkedQuery.value,
38139
+ uri: checkedUri.value
38140
+ });
38141
+ }
38142
+ );
38143
+ server.registerTool(
38144
+ "ov_code_expand",
38145
+ {
38146
+ annotations: { readOnlyHint: true, destructiveHint: false },
38147
+ description: "Raw OpenViking MCP code_expand parity. Requires a viking:// file URI and symbol.",
38148
+ inputSchema: {
38149
+ symbol: external_exports.string().optional().describe("Required symbol name, e.g. bar or Foo.bar"),
38150
+ uri: external_exports.string().optional().describe("Required viking:// file URI")
38151
+ }
38152
+ },
38153
+ async ({ symbol: symbol2, uri }) => {
38154
+ const checkedUri = requiredVikingUri(
38155
+ uri,
38156
+ "ov_code_expand",
38157
+ "viking://resources/repos/threadnote/src/mcp_server.ts"
38158
+ );
38159
+ if (!checkedUri.ok) {
38160
+ return checkedUri.error;
38161
+ }
38162
+ const checkedSymbol = requiredText(symbol2, "ov_code_expand", "symbol", { symbol: "registerTools" });
38163
+ if (!checkedSymbol.ok) {
38164
+ return checkedSymbol.error;
38165
+ }
38166
+ return runOpenVikingMcpTool(config2, "code_expand", { symbol: checkedSymbol.value, uri: checkedUri.value });
38167
+ }
38168
+ );
38169
+ server.registerTool(
38170
+ "ov_health",
38171
+ {
38172
+ annotations: { readOnlyHint: true, destructiveHint: false },
38173
+ description: "Raw OpenViking MCP health parity.",
38174
+ inputSchema: {}
38175
+ },
38176
+ async () => runOpenVikingMcpTool(config2, "health", {})
38177
+ );
38178
+ }
38179
+ function registerOpenVikingStoreTool(server, config2, name) {
38180
+ server.registerTool(
38181
+ name,
38182
+ {
38183
+ annotations: { readOnlyHint: false, destructiveHint: true },
38184
+ description: `Raw OpenViking MCP ${name === "ov_remember" ? "remember" : "store"} parity. Stores message(s) through ov add-memory.`,
38185
+ inputSchema: {
38186
+ content: external_exports.string().optional().describe("Compatibility shortcut for a single user message"),
38187
+ messages: external_exports.array(external_exports.object({ content: external_exports.string(), role: external_exports.string() })).optional().describe("Native messages array of {role, content}"),
38188
+ text: external_exports.string().optional().describe("Compatibility shortcut for a single user message")
38189
+ }
38190
+ },
38191
+ async ({ content, messages, text }) => {
38192
+ if (messages && messages.length > 0) {
38193
+ return runOpenVikingMcpTool(config2, "remember", { messages });
38194
+ }
38195
+ const checkedContent = requiredText(content ?? text, name, "content", { content: "Remember this note" });
38196
+ if (!checkedContent.ok) {
38197
+ return checkedContent.error;
38198
+ }
38199
+ return runOpenVikingMcpTool(config2, "remember", {
38200
+ messages: [{ content: checkedContent.value, role: "user" }]
38201
+ });
38202
+ }
38203
+ );
38204
+ }
35468
38205
  function registerSearchTool(server, config2, name, description) {
35469
38206
  server.registerTool(
35470
38207
  name,
@@ -35516,14 +38253,20 @@ async function runRecallTool(config2, params) {
35516
38253
  cwd: params.callerCwd,
35517
38254
  includeProcessCwd: false
35518
38255
  });
38256
+ let indexRepairMessages;
38257
+ try {
38258
+ const ov = await requiredOpenVikingCli2();
38259
+ const indexRepair = await repairStaleRecallIndex(config2, ov, { query: projectQuery });
38260
+ indexRepairMessages = formatRecallIndexRepairMessages(indexRepair);
38261
+ } catch (err) {
38262
+ indexRepairMessages = [`Auto-index repair warning: ${errorMessage(err)}`];
38263
+ }
35519
38264
  const contextualParams = { ...params, query };
35520
- const baseArgs = [
35521
- "search",
38265
+ const semanticResult = await runOpenVikingMcpTool(config2, "search", {
38266
+ limit: params.nodeLimit,
35522
38267
  query,
35523
- ...params.pinnedUri ? ["--uri", params.pinnedUri] : [],
35524
- ...params.nodeLimit ? ["--node-limit", String(params.nodeLimit)] : []
35525
- ];
35526
- const semanticResult = await runOpenVikingTool(config2, baseArgs);
38268
+ target_uri: params.pinnedUri
38269
+ });
35527
38270
  if (semanticResult.isError === true) {
35528
38271
  return semanticResult;
35529
38272
  }
@@ -35532,8 +38275,13 @@ async function runRecallTool(config2, params) {
35532
38275
  return semanticResult;
35533
38276
  }
35534
38277
  const sections = [];
35535
- if (firstContent.text) {
35536
- sections.push(firstContent.text);
38278
+ const semanticText = filterStaleRecallSummaryRows(firstContent.text);
38279
+ const filteredSemanticText = semanticText !== firstContent.text.trim();
38280
+ if (semanticText) {
38281
+ sections.push(semanticText);
38282
+ }
38283
+ if (indexRepairMessages.length > 0) {
38284
+ sections.push(indexRepairMessages.join("\n"));
35537
38285
  }
35538
38286
  const seededSection = await seededResourcesSection(config2, contextualParams, projectQuery);
35539
38287
  if (seededSection) {
@@ -35554,7 +38302,7 @@ ${exactMatches}`);
35554
38302
  for (const warning2 of syncWarnings) {
35555
38303
  sections.push(`Auto-sync warning: ${warning2}`);
35556
38304
  }
35557
- if (sections.length <= 1) {
38305
+ if (sections.length <= 1 && !filteredSemanticText) {
35558
38306
  return semanticResult;
35559
38307
  }
35560
38308
  return { ...semanticResult, content: [{ type: "text", text: sections.join("\n\n") }] };
@@ -35580,19 +38328,15 @@ async function seededResourcesSection(config2, params, projectQuery) {
35580
38328
  if (!projectResourceUri.startsWith("viking://")) {
35581
38329
  return void 0;
35582
38330
  }
35583
- const ov = await requiredOpenVikingCli2();
35584
- const args = [
35585
- "search",
35586
- params.query,
35587
- "--uri",
35588
- projectResourceUri,
35589
- ...params.nodeLimit ? ["--node-limit", String(params.nodeLimit)] : []
35590
- ];
35591
- const result = await runCommand(ov, withIdentity2(config2, args), { allowFailure: true });
35592
- if (result.exitCode !== 0) {
38331
+ const result = await runOpenVikingMcpTool(config2, "search", {
38332
+ limit: params.nodeLimit,
38333
+ query: params.query,
38334
+ target_uri: projectResourceUri
38335
+ });
38336
+ if (result.isError === true) {
35593
38337
  return void 0;
35594
38338
  }
35595
- const body = [result.stdout.trim(), result.stderr.trim()].filter(Boolean).join("\n");
38339
+ const body = filterStaleRecallSummaryRows(textFromCallToolResult(result));
35596
38340
  if (!body) {
35597
38341
  return void 0;
35598
38342
  }
@@ -35604,16 +38348,13 @@ async function exactMemoryMatchesText(config2, query, includeArchived) {
35604
38348
  if (terms.length === 0) {
35605
38349
  return void 0;
35606
38350
  }
35607
- const ov = await requiredOpenVikingCli2();
35608
38351
  const scopes = exactMemoryScopes(config2, includeArchived);
35609
38352
  const outputs = [];
35610
38353
  for (const term of terms) {
35611
38354
  for (const scope of scopes) {
35612
- const result = await runCommand(ov, withIdentity2(config2, ["grep", term, "--uri", scope, "--node-limit", "5"]), {
35613
- allowFailure: true
35614
- });
35615
- const output = [result.stdout.trim(), result.stderr.trim()].filter(Boolean).join("\n");
35616
- if (result.exitCode === 0 && grepOutputHasMatches(output)) {
38355
+ const result = await runOpenVikingMcpTool(config2, "grep", { node_limit: 5, pattern: term, uri: scope });
38356
+ const output = textFromCallToolResult(result);
38357
+ if (result.isError !== true && grepOutputHasMatches(output)) {
35617
38358
  outputs.push(output);
35618
38359
  }
35619
38360
  }
@@ -35625,15 +38366,16 @@ function registerReadTool(server, config2, name, description) {
35625
38366
  name,
35626
38367
  {
35627
38368
  annotations: { readOnlyHint: true, destructiveHint: false },
35628
- description: `${description} Required: pass JSON arguments with uri.`,
38369
+ description: `${description} Required: pass JSON arguments with uri, or native OpenViking uris.`,
35629
38370
  inputSchema: {
35630
- uri: external_exports.string().optional().describe("Required viking:// file URI")
38371
+ uri: external_exports.string().optional().describe("Required viking:// file URI"),
38372
+ uris: external_exports.union([external_exports.string(), external_exports.array(external_exports.string())]).optional().describe("Native OpenViking MCP read input: a single viking:// URI or array of URIs")
35631
38373
  }
35632
38374
  },
35633
- async ({ uri }) => {
35634
- const checkedUri = requiredVikingUri(uri, name, "viking://agent/threadnote/memories/.abstract.md");
35635
- if (!checkedUri.ok) {
35636
- return checkedUri.error;
38375
+ async ({ uri, uris }) => {
38376
+ const checkedUris = requiredVikingUriList(uris ?? uri, name, "viking://agent/threadnote/memories/.abstract.md");
38377
+ if (!checkedUris.ok) {
38378
+ return checkedUris.error;
35637
38379
  }
35638
38380
  let syncedTeams = [];
35639
38381
  const syncWarnings = [];
@@ -35644,7 +38386,7 @@ function registerReadTool(server, config2, name, description) {
35644
38386
  } catch (err) {
35645
38387
  syncWarnings.push(errorMessage(err));
35646
38388
  }
35647
- const result = await runOpenVikingTool(config2, ["read", checkedUri.value]);
38389
+ const result = await runOpenVikingReadTool(config2, checkedUris.value);
35648
38390
  if (result.isError === true || syncedTeams.length === 0 && syncWarnings.length === 0) {
35649
38391
  return result;
35650
38392
  }
@@ -35670,22 +38412,19 @@ function registerListTool(server, config2, name, description) {
35670
38412
  all: external_exports.boolean().optional().describe("Show hidden files like .abstract.md and .overview.md"),
35671
38413
  recursive: external_exports.boolean().optional().describe("List recursively"),
35672
38414
  simple: external_exports.boolean().optional().describe("Only return paths"),
35673
- nodeLimit: external_exports.number().int().positive().max(1e3).optional().describe("Maximum node count")
38415
+ nodeLimit: external_exports.number().int().positive().max(1e3).optional().describe("Maximum node count"),
38416
+ node_limit: external_exports.number().int().positive().max(1e3).optional().describe("Maximum node count")
35674
38417
  }
35675
38418
  },
35676
- async ({ all, nodeLimit, recursive, simple, uri }) => {
38419
+ async ({ recursive, uri }) => {
35677
38420
  const checkedUri = optionalVikingUri(uri, name);
35678
38421
  if (!checkedUri.ok) {
35679
38422
  return checkedUri.error;
35680
38423
  }
35681
- return runOpenVikingTool(config2, [
35682
- "ls",
35683
- checkedUri.value ?? "viking://",
35684
- ...all === true ? ["--all"] : [],
35685
- ...recursive === true ? ["--recursive"] : [],
35686
- ...simple === true ? ["--simple"] : [],
35687
- ...nodeLimit ? ["--node-limit", String(nodeLimit)] : []
35688
- ]);
38424
+ return runOpenVikingMcpTool(config2, "list", {
38425
+ recursive,
38426
+ uri: checkedUri.value ?? "viking://"
38427
+ });
35689
38428
  }
35690
38429
  );
35691
38430
  }
@@ -35751,9 +38490,8 @@ function registerArchiveTool(server, config2, name, description) {
35751
38490
  return checkedUri.error;
35752
38491
  }
35753
38492
  try {
35754
- const ov = await requiredOpenVikingCli2();
35755
- const readResult = await runCommand(ov, withIdentity2(config2, ["read", checkedUri.value]));
35756
- const original = readResult.stdout.trim();
38493
+ const readResult = await runOpenVikingReadTool(config2, [checkedUri.value]);
38494
+ const original = textFromCallToolResult(readResult);
35757
38495
  if (!original) {
35758
38496
  return {
35759
38497
  content: [{ type: "text", text: `Could not read ${checkedUri.value} before archiving.` }],
@@ -35776,7 +38514,7 @@ function registerArchiveTool(server, config2, name, description) {
35776
38514
  if (archiveResult.isError === true) {
35777
38515
  return archiveResult;
35778
38516
  }
35779
- const removedOriginal = await removeVikingResourceWithRetry(ov, config2, checkedUri.value);
38517
+ const removedOriginal = await forgetVikingResourceWithRetry(config2, checkedUri.value);
35780
38518
  const [content] = archiveResult.content;
35781
38519
  const text = content?.type === "text" ? content.text : "Archived memory stored.";
35782
38520
  return {
@@ -35842,7 +38580,7 @@ function registerCompactTool(server, config2) {
35842
38580
  appliedMessages.push(`Updated kept memory: ${action.uri}`);
35843
38581
  }
35844
38582
  for (const action of plan.archives) {
35845
- const archiveResult = await archiveMemoryForCompact(config2, ov, action);
38583
+ const archiveResult = await archiveMemoryForCompact(config2, action);
35846
38584
  if (archiveResult.isError === true) {
35847
38585
  return archiveResult;
35848
38586
  }
@@ -35852,7 +38590,7 @@ function registerCompactTool(server, config2) {
35852
38590
  }
35853
38591
  }
35854
38592
  for (const action of plan.forgets) {
35855
- const removed = await removeVikingResourceWithRetry(ov, config2, action.uri);
38593
+ const removed = await forgetVikingResourceWithRetry(config2, action.uri);
35856
38594
  appliedMessages.push(
35857
38595
  removed ? `Forgot exact duplicate: ${action.uri}` : `Exact duplicate is still processing; retry later with forget: ${action.uri}`
35858
38596
  );
@@ -35871,9 +38609,9 @@ function registerCompactTool(server, config2) {
35871
38609
  }
35872
38610
  );
35873
38611
  }
35874
- async function archiveMemoryForCompact(config2, ov, action) {
35875
- const readResult = await runCommand(ov, withIdentity2(config2, ["read", action.uri]));
35876
- const original = readResult.stdout.trim();
38612
+ async function archiveMemoryForCompact(config2, action) {
38613
+ const readResult = await runOpenVikingReadTool(config2, [action.uri]);
38614
+ const original = textFromCallToolResult(readResult);
35877
38615
  if (!original) {
35878
38616
  return { content: [{ type: "text", text: `Could not read ${action.uri} before archiving.` }], isError: true };
35879
38617
  }
@@ -35892,7 +38630,7 @@ async function archiveMemoryForCompact(config2, ov, action) {
35892
38630
  if (archiveResult.isError === true) {
35893
38631
  return archiveResult;
35894
38632
  }
35895
- const removedOriginal = await removeVikingResourceWithRetry(ov, config2, action.uri);
38633
+ const removedOriginal = await forgetVikingResourceWithRetry(config2, action.uri);
35896
38634
  const [content] = archiveResult.content;
35897
38635
  const text = content?.type === "text" ? content.text : "Archived memory stored.";
35898
38636
  return {
@@ -35914,7 +38652,7 @@ async function scopedCompactRecords(config2, options) {
35914
38652
  const uriDirectory = memoryUriDirectoryForCompact(config2, kind, options.project);
35915
38653
  let entries;
35916
38654
  try {
35917
- entries = await (0, import_promises4.readdir)(directory, { withFileTypes: true });
38655
+ entries = await (0, import_promises5.readdir)(directory, { withFileTypes: true });
35918
38656
  } catch (_err) {
35919
38657
  continue;
35920
38658
  }
@@ -35922,7 +38660,7 @@ async function scopedCompactRecords(config2, options) {
35922
38660
  if (!entry.isFile() || entry.name.startsWith(".") || !entry.name.endsWith(".md")) {
35923
38661
  continue;
35924
38662
  }
35925
- const content = await readTextIfExists((0, import_node_path4.join)(directory, entry.name));
38663
+ const content = await readTextIfExists((0, import_node_path5.join)(directory, entry.name));
35926
38664
  if (!content) {
35927
38665
  continue;
35928
38666
  }
@@ -35957,11 +38695,11 @@ function localMemoryDirectoryForCompact(config2, kind, project) {
35957
38695
  const projectSegment = uriSegment2(project);
35958
38696
  switch (kind) {
35959
38697
  case "durable":
35960
- return (0, import_node_path4.join)(root, "durable", "projects", projectSegment);
38698
+ return (0, import_node_path5.join)(root, "durable", "projects", projectSegment);
35961
38699
  case "handoff":
35962
- return (0, import_node_path4.join)(root, "handoffs", "active", projectSegment);
38700
+ return (0, import_node_path5.join)(root, "handoffs", "active", projectSegment);
35963
38701
  case "incident":
35964
- return (0, import_node_path4.join)(root, "incidents", "active", projectSegment);
38702
+ return (0, import_node_path5.join)(root, "incidents", "active", projectSegment);
35965
38703
  }
35966
38704
  }
35967
38705
  function memoryUriDirectoryForCompact(config2, kind, project) {
@@ -35981,18 +38719,18 @@ function localMemoryPathForUri(config2, uri) {
35981
38719
  if (!uri.startsWith(prefix) || uri.includes("/shared/")) {
35982
38720
  return void 0;
35983
38721
  }
35984
- const relative2 = uri.slice(prefix.length);
35985
- if (relative2.includes("..") || relative2.startsWith("/")) {
38722
+ const relative3 = uri.slice(prefix.length);
38723
+ if (relative3.includes("..") || relative3.startsWith("/")) {
35986
38724
  return void 0;
35987
38725
  }
35988
- return (0, import_node_path4.join)(localUserMemoriesRoot(config2), ...relative2.split("/"));
38726
+ return (0, import_node_path5.join)(localUserMemoriesRoot(config2), ...relative3.split("/"));
35989
38727
  }
35990
38728
  function localUserMemoriesRoot(config2) {
35991
- return (0, import_node_path4.join)(config2.agentContextHome, "data", "viking", config2.account, "user", uriSegment2(config2.user), "memories");
38729
+ return (0, import_node_path5.join)(config2.agentContextHome, "data", "viking", config2.account, "user", uriSegment2(config2.user), "memories");
35992
38730
  }
35993
38731
  async function readTextIfExists(path) {
35994
38732
  try {
35995
- return await (0, import_promises4.readFile)(path, "utf8");
38733
+ return await (0, import_promises5.readFile)(path, "utf8");
35996
38734
  } catch (_err) {
35997
38735
  return void 0;
35998
38736
  }
@@ -36065,8 +38803,8 @@ async function vikingResourceExists2(ov, config2, uri) {
36065
38803
  const stat2 = await runCommand(ov, withIdentity2(config2, ["stat", uri]), { allowFailure: true });
36066
38804
  return stat2.exitCode === 0;
36067
38805
  }
36068
- async function removeVikingResourceWithRetry(ov, config2, uri) {
36069
- const args = withIdentity2(config2, ["rm", uri]);
38806
+ async function removeVikingResourceWithRetry(ov, config2, uri, recursive = false) {
38807
+ const args = withIdentity2(config2, ["rm", uri, ...recursive ? ["--recursive"] : []]);
36070
38808
  for (let attempt = 0; attempt < 4; attempt += 1) {
36071
38809
  const result = await runCommand(ov, args, { allowFailure: true });
36072
38810
  if (result.exitCode === 0) {
@@ -36082,6 +38820,23 @@ async function removeVikingResourceWithRetry(ov, config2, uri) {
36082
38820
  }
36083
38821
  return false;
36084
38822
  }
38823
+ async function runOpenVikingRemoveTool(config2, uri, recursive) {
38824
+ try {
38825
+ const ov = await requiredOpenVikingCli2();
38826
+ const removed = await removeVikingResourceWithRetry(ov, config2, uri, recursive);
38827
+ return {
38828
+ content: [
38829
+ {
38830
+ type: "text",
38831
+ text: removed ? `Removed: ${uri}` : `Resource is still being processed; retry later: ${uri}`
38832
+ }
38833
+ ],
38834
+ isError: !removed
38835
+ };
38836
+ } catch (err) {
38837
+ return { content: [{ type: "text", text: errorMessage(err) }], isError: true };
38838
+ }
38839
+ }
36085
38840
  function isResourceBusy(stderr, stdout2) {
36086
38841
  const output = `${stderr}
36087
38842
  ${stdout2}`.toLowerCase();
@@ -36223,19 +38978,161 @@ function optionalVikingUri(value, toolName) {
36223
38978
  ok: false
36224
38979
  };
36225
38980
  }
38981
+ function requiredVikingUriList(value, toolName, exampleUri) {
38982
+ const rawValues = Array.isArray(value) ? value : value === void 0 ? [] : [value];
38983
+ const uris = rawValues.map((uri) => uri.trim()).filter(Boolean);
38984
+ if (uris.length === 0) {
38985
+ return {
38986
+ error: argumentError(
38987
+ [
38988
+ `Threadnote MCP tool "${toolName}" needs a non-empty "uri" or "uris" argument.`,
38989
+ "Pass JSON arguments to the tool call.",
38990
+ `Example: ${toolName}(${JSON.stringify({ uris: [exampleUri] })})`
38991
+ ].join("\n")
38992
+ ),
38993
+ ok: false
38994
+ };
38995
+ }
38996
+ const invalid = uris.find((uri) => !uri.startsWith("viking://"));
38997
+ if (invalid) {
38998
+ return {
38999
+ error: argumentError(`Threadnote MCP tool "${toolName}" needs viking:// URI values. Received: ${invalid}`),
39000
+ ok: false
39001
+ };
39002
+ }
39003
+ return { ok: true, value: uris };
39004
+ }
36226
39005
  function argumentError(text) {
36227
39006
  return { content: [{ type: "text", text }], isError: true };
36228
39007
  }
36229
- async function runOpenVikingTool(config2, args) {
39008
+ async function runOpenVikingAddResourceTool(config2, toolName, params) {
39009
+ const tempFileId = params.tempFileId?.trim();
39010
+ const source = params.path?.trim();
39011
+ if (!source && !tempFileId) {
39012
+ return argumentError(
39013
+ [
39014
+ `Threadnote MCP tool "${toolName}" needs a non-empty "path" argument.`,
39015
+ "Pass JSON arguments to the tool call.",
39016
+ `Example: ${toolName}(${JSON.stringify({ path: "/path/to/README.md", to: "viking://resources/my-repo/README.md" })})`
39017
+ ].join("\n")
39018
+ );
39019
+ }
39020
+ if (tempFileId) {
39021
+ const checkedTo2 = optionalVikingUri(params.to, toolName);
39022
+ if (!checkedTo2.ok) {
39023
+ return checkedTo2.error;
39024
+ }
39025
+ return runOpenVikingMcpTool(config2, "add_resource", {
39026
+ description: params.description,
39027
+ temp_file_id: tempFileId,
39028
+ to: checkedTo2.value,
39029
+ watch_interval: params.watchInterval
39030
+ });
39031
+ }
39032
+ const checkedTo = optionalVikingUri(params.to, toolName);
39033
+ if (!checkedTo.ok) {
39034
+ return checkedTo.error;
39035
+ }
39036
+ const description = params.description?.trim();
39037
+ return runOpenVikingMcpTool(config2, "add_resource", {
39038
+ description,
39039
+ path: source,
39040
+ to: checkedTo.value,
39041
+ watch_interval: params.watchInterval
39042
+ });
39043
+ }
39044
+ async function runOpenVikingReadTool(config2, uris) {
39045
+ const result = await runOpenVikingMcpTool(config2, "read", { uris });
39046
+ if (result.isError !== true && !nativeReadMissedAnyUri(result, uris)) {
39047
+ return result;
39048
+ }
39049
+ return runOpenVikingReadToolWithCliFallback(config2, uris);
39050
+ }
39051
+ function nativeReadMissedAnyUri(result, uris) {
39052
+ const text = textFromCallToolResult(result);
39053
+ return uris.some((uri) => text.includes(`(nothing found at ${uri})`));
39054
+ }
39055
+ async function runOpenVikingReadToolWithCliFallback(config2, uris) {
39056
+ const outputs = [];
39057
+ for (const uri of uris) {
39058
+ const nativeResult = await runOpenVikingMcpTool(config2, "read", { uris: [uri] });
39059
+ const nativeText = textFromCallToolResult(nativeResult);
39060
+ let text = nativeText;
39061
+ if (nativeResult.isError === true || nativeText.includes(`(nothing found at ${uri})`)) {
39062
+ const cliResult = await runOpenVikingCliReadTool(config2, uri);
39063
+ if (cliResult.isError === true) {
39064
+ return cliResult;
39065
+ }
39066
+ text = textFromCallToolResult(cliResult);
39067
+ }
39068
+ outputs.push(uris.length === 1 ? text : `=== ${uri} ===
39069
+ ${text}`);
39070
+ }
39071
+ return { content: [{ type: "text", text: outputs.filter(Boolean).join("\n\n") || "OK" }] };
39072
+ }
39073
+ async function runOpenVikingCliReadTool(config2, uri) {
36230
39074
  try {
36231
39075
  const ov = await requiredOpenVikingCli2();
36232
- const result = await runCommand(ov, withIdentity2(config2, args));
39076
+ const result = await runCommand(ov, withIdentity2(config2, ["read", uri]));
36233
39077
  const text = [result.stdout.trim(), result.stderr.trim()].filter(Boolean).join("\n");
36234
39078
  return { content: [{ type: "text", text: text || "OK" }] };
36235
39079
  } catch (err) {
36236
39080
  return { content: [{ type: "text", text: errorMessage(err) }], isError: true };
36237
39081
  }
36238
39082
  }
39083
+ async function runOpenVikingMcpTool(config2, toolName, args) {
39084
+ const client = new Client({ name: "threadnote-openviking-proxy", version: "1.1.0" });
39085
+ try {
39086
+ const transport = new StreamableHTTPClientTransport(new URL(config2.openVikingMcpUrl), {
39087
+ requestInit: {
39088
+ headers: {
39089
+ "X-OpenViking-Account": config2.account,
39090
+ "X-OpenViking-Agent": config2.agentId,
39091
+ "X-OpenViking-User": config2.user
39092
+ }
39093
+ }
39094
+ });
39095
+ await client.connect(transport);
39096
+ const result = await client.callTool({ arguments: stripUndefinedValues(args), name: toolName }, void 0, {
39097
+ timeout: 3e4
39098
+ });
39099
+ return normalizeCallToolResult(result);
39100
+ } catch (err) {
39101
+ return {
39102
+ content: [
39103
+ {
39104
+ type: "text",
39105
+ text: `OpenViking native MCP tool "${toolName}" failed at ${config2.openVikingMcpUrl}: ${errorMessage(err)}`
39106
+ }
39107
+ ],
39108
+ isError: true
39109
+ };
39110
+ } finally {
39111
+ await client.close().catch(() => void 0);
39112
+ }
39113
+ }
39114
+ function stripUndefinedValues(values) {
39115
+ return Object.fromEntries(
39116
+ Object.entries(values).filter((entry) => entry[1] !== void 0)
39117
+ );
39118
+ }
39119
+ function normalizeCallToolResult(result) {
39120
+ const maybeResult = result;
39121
+ if (Array.isArray(maybeResult.content)) {
39122
+ return {
39123
+ content: maybeResult.content,
39124
+ isError: maybeResult.isError
39125
+ };
39126
+ }
39127
+ return { content: [{ type: "text", text: JSON.stringify(result) }] };
39128
+ }
39129
+ function textFromCallToolResult(result) {
39130
+ return result.content.map((content) => content.type === "text" ? content.text : "").join("\n").trim();
39131
+ }
39132
+ async function forgetVikingResourceWithRetry(config2, uri) {
39133
+ const ov = await requiredOpenVikingCli2();
39134
+ return removeVikingResourceWithRetry(ov, config2, uri);
39135
+ }
36239
39136
  async function runSharePublishTool(config2, sourceUri, options) {
36240
39137
  try {
36241
39138
  if (isInSharedNamespace(config2, sourceUri)) {
@@ -36243,19 +39140,20 @@ async function runSharePublishTool(config2, sourceUri, options) {
36243
39140
  }
36244
39141
  const resolved = await resolveTeam(config2, options.team);
36245
39142
  const ov = await requiredOpenVikingCli2();
36246
- const readResult = await runCommand(ov, withIdentity2(config2, ["read", sourceUri]), { allowFailure: true });
36247
- if (readResult.exitCode !== 0 || !readResult.stdout.trim()) {
39143
+ const readResult = await runOpenVikingReadTool(config2, [sourceUri]);
39144
+ const sourceText = textFromCallToolResult(readResult);
39145
+ if (readResult.isError === true || !sourceText) {
36248
39146
  return {
36249
39147
  content: [
36250
39148
  {
36251
39149
  type: "text",
36252
- text: `Could not read ${sourceUri}: ${readResult.stderr.trim() || readResult.stdout.trim() || "unknown error"}`
39150
+ text: `Could not read ${sourceUri}: ${sourceText || "unknown error"}`
36253
39151
  }
36254
39152
  ],
36255
39153
  isError: true
36256
39154
  };
36257
39155
  }
36258
- const stripped = stripPersonalProvenance(readResult.stdout);
39156
+ const stripped = stripPersonalProvenance(sourceText);
36259
39157
  const scrub = applyScrubber(stripped, { redact: options.redact === true });
36260
39158
  const targetUri = sharedUriFor(config2, sourceUri, resolved.name);
36261
39159
  if (options.preview === true) {
@@ -36297,7 +39195,7 @@ async function runSharePublishTool(config2, sourceUri, options) {
36297
39195
  push: options.push
36298
39196
  });
36299
39197
  try {
36300
- await removeMemoryUri(config2, ov, sourceUri, false, { quiet: true });
39198
+ await forgetVikingResourceWithRetry(config2, sourceUri);
36301
39199
  } catch (sourceErr) {
36302
39200
  return {
36303
39201
  content: [
@@ -36327,7 +39225,7 @@ function withIdentity2(config2, args) {
36327
39225
  return [...args, "--account", config2.account, "--user", config2.user, "--agent-id", config2.agentId];
36328
39226
  }
36329
39227
  async function requiredOpenVikingCli2() {
36330
- const command2 = process.env.THREADNOTE_OV ?? await findExecutable(["ov", "openviking"]) ?? await firstExistingPath([(0, import_node_path4.join)((0, import_node_os3.homedir)(), ".local", "bin", "ov"), (0, import_node_path4.join)((0, import_node_os3.homedir)(), ".local", "bin", "openviking")]);
39228
+ const command2 = process.env.THREADNOTE_OV ?? await findExecutable(["ov", "openviking"]) ?? await firstExistingPath([(0, import_node_path5.join)((0, import_node_os3.homedir)(), ".local", "bin", "ov"), (0, import_node_path5.join)((0, import_node_os3.homedir)(), ".local", "bin", "openviking")]);
36331
39229
  if (!command2) {
36332
39230
  throw new Error("Neither ov nor openviking was found. Run threadnote install first.");
36333
39231
  }
@@ -36336,8 +39234,8 @@ async function requiredOpenVikingCli2() {
36336
39234
  async function firstExistingPath(paths) {
36337
39235
  for (const path of paths) {
36338
39236
  try {
36339
- await (0, import_promises4.access)(path);
36340
- return await (0, import_promises4.realpath)(path);
39237
+ await (0, import_promises5.access)(path);
39238
+ return await (0, import_promises5.realpath)(path);
36341
39239
  } catch (_err) {
36342
39240
  continue;
36343
39241
  }