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.
- package/README.md +4 -0
- package/dist/mcp_server.cjs +3171 -273
- package/dist/threadnote.cjs +894 -356
- package/docs/index.html +5 -5
- package/docs/migration.md +1 -1
- package/docs/troubleshooting.md +10 -5
- package/manager/app.css +42 -1
- package/manager/app.js +144 -59
- package/package.json +1 -1
package/dist/mcp_server.cjs
CHANGED
|
@@ -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,
|
|
3648
|
+
function resolveComponent(base, relative3, options, skipNormalization) {
|
|
3649
3649
|
const target = {};
|
|
3650
3650
|
if (!skipNormalization) {
|
|
3651
3651
|
base = parse3(serialize(base, options), options);
|
|
3652
|
-
|
|
3652
|
+
relative3 = parse3(serialize(relative3, options), options);
|
|
3653
3653
|
}
|
|
3654
3654
|
options = options || {};
|
|
3655
|
-
if (!options.tolerant &&
|
|
3656
|
-
target.scheme =
|
|
3657
|
-
target.userinfo =
|
|
3658
|
-
target.host =
|
|
3659
|
-
target.port =
|
|
3660
|
-
target.path = removeDotSegments(
|
|
3661
|
-
target.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 (
|
|
3664
|
-
target.userinfo =
|
|
3665
|
-
target.host =
|
|
3666
|
-
target.port =
|
|
3667
|
-
target.path = removeDotSegments(
|
|
3668
|
-
target.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 (!
|
|
3670
|
+
if (!relative3.path) {
|
|
3671
3671
|
target.path = base.path;
|
|
3672
|
-
if (
|
|
3673
|
-
target.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 (
|
|
3679
|
-
target.path = removeDotSegments(
|
|
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 = "/" +
|
|
3682
|
+
target.path = "/" + relative3.path;
|
|
3683
3683
|
} else if (!base.path) {
|
|
3684
|
-
target.path =
|
|
3684
|
+
target.path = relative3.path;
|
|
3685
3685
|
} else {
|
|
3686
|
-
target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) +
|
|
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 =
|
|
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 =
|
|
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
|
|
33083
|
+
var import_promises5 = require("node:fs/promises");
|
|
30954
33084
|
var import_node_os3 = require("node:os");
|
|
30955
|
-
var
|
|
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 (
|
|
35874
|
+
if (failureMessage) {
|
|
33718
35875
|
return;
|
|
33719
35876
|
}
|
|
33720
|
-
|
|
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
|
|
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,
|
|
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,
|
|
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
|
|
36866
|
+
var import_promises4 = require("node:fs/promises");
|
|
34473
36867
|
var import_node_os2 = require("node:os");
|
|
34474
|
-
var
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
37021
|
+
await (0, import_promises4.writeFile)(tempPath, `${JSON.stringify(contents, void 0, 2)}
|
|
34635
37022
|
`, { encoding: "utf8", mode: 384 });
|
|
34636
|
-
await (0,
|
|
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,
|
|
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,
|
|
37204
|
+
return (0, import_node_path4.join)(config2.agentContextHome, "share", "teams.json");
|
|
34818
37205
|
}
|
|
34819
37206
|
function teamWorktreePath(config2, team) {
|
|
34820
|
-
return (0,
|
|
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,
|
|
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,
|
|
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,
|
|
35015
|
-
const tempPath = (0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
35161
|
-
changes.push({ path: (0,
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
35354
|
-
|
|
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 (
|
|
35358
|
-
|
|
35359
|
-
|
|
35360
|
-
|
|
35361
|
-
|
|
35362
|
-
|
|
35363
|
-
|
|
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
|
|
35398
|
-
|
|
35399
|
-
|
|
35400
|
-
|
|
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
|
|
35424
|
-
|
|
35425
|
-
checkedPattern.value,
|
|
35426
|
-
|
|
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 () =>
|
|
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
|
|
35521
|
-
|
|
38265
|
+
const semanticResult = await runOpenVikingMcpTool(config2, "search", {
|
|
38266
|
+
limit: params.nodeLimit,
|
|
35522
38267
|
query,
|
|
35523
|
-
|
|
35524
|
-
|
|
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
|
-
|
|
35536
|
-
|
|
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
|
|
35584
|
-
|
|
35585
|
-
|
|
35586
|
-
|
|
35587
|
-
|
|
35588
|
-
|
|
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 =
|
|
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
|
|
35613
|
-
|
|
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
|
|
35635
|
-
if (!
|
|
35636
|
-
return
|
|
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
|
|
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 ({
|
|
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
|
|
35682
|
-
|
|
35683
|
-
checkedUri.value ?? "viking://"
|
|
35684
|
-
|
|
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
|
|
35755
|
-
const
|
|
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
|
|
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,
|
|
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
|
|
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,
|
|
35875
|
-
const readResult = await
|
|
35876
|
-
const original = readResult
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
38698
|
+
return (0, import_node_path5.join)(root, "durable", "projects", projectSegment);
|
|
35961
38699
|
case "handoff":
|
|
35962
|
-
return (0,
|
|
38700
|
+
return (0, import_node_path5.join)(root, "handoffs", "active", projectSegment);
|
|
35963
38701
|
case "incident":
|
|
35964
|
-
return (0,
|
|
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
|
|
35985
|
-
if (
|
|
38722
|
+
const relative3 = uri.slice(prefix.length);
|
|
38723
|
+
if (relative3.includes("..") || relative3.startsWith("/")) {
|
|
35986
38724
|
return void 0;
|
|
35987
38725
|
}
|
|
35988
|
-
return (0,
|
|
38726
|
+
return (0, import_node_path5.join)(localUserMemoriesRoot(config2), ...relative3.split("/"));
|
|
35989
38727
|
}
|
|
35990
38728
|
function localUserMemoriesRoot(config2) {
|
|
35991
|
-
return (0,
|
|
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,
|
|
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
|
|
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,
|
|
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
|
|
36247
|
-
|
|
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}: ${
|
|
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(
|
|
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
|
|
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,
|
|
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,
|
|
36340
|
-
return await (0,
|
|
39237
|
+
await (0, import_promises5.access)(path);
|
|
39238
|
+
return await (0, import_promises5.realpath)(path);
|
|
36341
39239
|
} catch (_err) {
|
|
36342
39240
|
continue;
|
|
36343
39241
|
}
|