@oss-scout/mcp 0.12.0 → 0.12.1
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/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/mcp-server.bundle.cjs +226 -62
- package/dist/tools.js +6 -0
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export { registerResources } from "./resources.js";
|
|
|
12
12
|
/** Server identity, kept in one place for the bin and any embedding host. */
|
|
13
13
|
export declare const SERVER_INFO: {
|
|
14
14
|
readonly name: "oss-scout-mcp";
|
|
15
|
-
readonly version: "0.12.
|
|
15
|
+
readonly version: "0.12.1";
|
|
16
16
|
};
|
|
17
17
|
/**
|
|
18
18
|
* Build a fully-wired MCP server (tools + resources) around a scout.
|
package/dist/index.js
CHANGED
|
@@ -15,7 +15,7 @@ export { registerResources } from "./resources.js";
|
|
|
15
15
|
/** Server identity, kept in one place for the bin and any embedding host. */
|
|
16
16
|
export const SERVER_INFO = {
|
|
17
17
|
name: "oss-scout-mcp",
|
|
18
|
-
version: "0.12.
|
|
18
|
+
version: "0.12.1", // x-release-please-version
|
|
19
19
|
};
|
|
20
20
|
/**
|
|
21
21
|
* Build a fully-wired MCP server (tools + resources) around a scout.
|
|
@@ -24420,7 +24420,7 @@ function object(shape, params) {
|
|
|
24420
24420
|
return new ZodMiniObject(def);
|
|
24421
24421
|
}
|
|
24422
24422
|
|
|
24423
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
24423
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js
|
|
24424
24424
|
function isZ4Schema(s) {
|
|
24425
24425
|
const schema = s;
|
|
24426
24426
|
return !!schema._zod;
|
|
@@ -24504,17 +24504,33 @@ function normalizeObjectSchema(schema) {
|
|
|
24504
24504
|
}
|
|
24505
24505
|
return void 0;
|
|
24506
24506
|
}
|
|
24507
|
+
function getDotPath(path5) {
|
|
24508
|
+
if (path5.length === 0) {
|
|
24509
|
+
return "object root";
|
|
24510
|
+
}
|
|
24511
|
+
return path5.reduce((acc, seg, index) => {
|
|
24512
|
+
if (index === 0) {
|
|
24513
|
+
return String(seg);
|
|
24514
|
+
}
|
|
24515
|
+
if (typeof seg === "number") {
|
|
24516
|
+
return `${acc}[${seg}]`;
|
|
24517
|
+
}
|
|
24518
|
+
return `${acc}.${seg}`;
|
|
24519
|
+
}, "");
|
|
24520
|
+
}
|
|
24507
24521
|
function getParseErrorMessage(error48) {
|
|
24508
24522
|
if (error48 && typeof error48 === "object") {
|
|
24523
|
+
if ("issues" in error48 && Array.isArray(error48.issues) && error48.issues.length > 0) {
|
|
24524
|
+
return error48.issues.map((i) => {
|
|
24525
|
+
if (!i.path?.length) {
|
|
24526
|
+
return i.message;
|
|
24527
|
+
}
|
|
24528
|
+
return `${i.message} at ${getDotPath(i.path)}`;
|
|
24529
|
+
}).join("\n");
|
|
24530
|
+
}
|
|
24509
24531
|
if ("message" in error48 && typeof error48.message === "string") {
|
|
24510
24532
|
return error48.message;
|
|
24511
24533
|
}
|
|
24512
|
-
if ("issues" in error48 && Array.isArray(error48.issues) && error48.issues.length > 0) {
|
|
24513
|
-
const firstIssue = error48.issues[0];
|
|
24514
|
-
if (firstIssue && typeof firstIssue === "object" && "message" in firstIssue) {
|
|
24515
|
-
return String(firstIssue.message);
|
|
24516
|
-
}
|
|
24517
|
-
}
|
|
24518
24534
|
try {
|
|
24519
24535
|
return JSON.stringify(error48);
|
|
24520
24536
|
} catch {
|
|
@@ -26710,7 +26726,7 @@ function date4(params) {
|
|
|
26710
26726
|
// ../../node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/classic/external.js
|
|
26711
26727
|
config(en_default2());
|
|
26712
26728
|
|
|
26713
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
26729
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
|
|
26714
26730
|
var LATEST_PROTOCOL_VERSION = "2025-11-25";
|
|
26715
26731
|
var SUPPORTED_PROTOCOL_VERSIONS = [LATEST_PROTOCOL_VERSION, "2025-06-18", "2025-03-26", "2024-11-05", "2024-10-07"];
|
|
26716
26732
|
var RELATED_TASK_META_KEY = "io.modelcontextprotocol/related-task";
|
|
@@ -26720,10 +26736,9 @@ var ProgressTokenSchema = union([string2(), number2().int()]);
|
|
|
26720
26736
|
var CursorSchema = string2();
|
|
26721
26737
|
var TaskCreationParamsSchema = looseObject({
|
|
26722
26738
|
/**
|
|
26723
|
-
*
|
|
26724
|
-
* If null, the task has unlimited lifetime until manually cleaned up.
|
|
26739
|
+
* Requested duration in milliseconds to retain task from creation.
|
|
26725
26740
|
*/
|
|
26726
|
-
ttl:
|
|
26741
|
+
ttl: number2().optional(),
|
|
26727
26742
|
/**
|
|
26728
26743
|
* Time in milliseconds to wait between task status requests.
|
|
26729
26744
|
*/
|
|
@@ -27023,7 +27038,11 @@ var ClientCapabilitiesSchema = object2({
|
|
|
27023
27038
|
/**
|
|
27024
27039
|
* Present if the client supports task creation.
|
|
27025
27040
|
*/
|
|
27026
|
-
tasks: ClientTasksCapabilitySchema.optional()
|
|
27041
|
+
tasks: ClientTasksCapabilitySchema.optional(),
|
|
27042
|
+
/**
|
|
27043
|
+
* Extensions that the client supports. Keys are extension identifiers (vendor-prefix/extension-name).
|
|
27044
|
+
*/
|
|
27045
|
+
extensions: record(string2(), AssertObjectSchema).optional()
|
|
27027
27046
|
});
|
|
27028
27047
|
var InitializeRequestParamsSchema = BaseRequestParamsSchema.extend({
|
|
27029
27048
|
/**
|
|
@@ -27084,7 +27103,11 @@ var ServerCapabilitiesSchema = object2({
|
|
|
27084
27103
|
/**
|
|
27085
27104
|
* Present if the server supports task creation.
|
|
27086
27105
|
*/
|
|
27087
|
-
tasks: ServerTasksCapabilitySchema.optional()
|
|
27106
|
+
tasks: ServerTasksCapabilitySchema.optional(),
|
|
27107
|
+
/**
|
|
27108
|
+
* Extensions that the server supports. Keys are extension identifiers (vendor-prefix/extension-name).
|
|
27109
|
+
*/
|
|
27110
|
+
extensions: record(string2(), AssertObjectSchema).optional()
|
|
27088
27111
|
});
|
|
27089
27112
|
var InitializeResultSchema = ResultSchema.extend({
|
|
27090
27113
|
/**
|
|
@@ -27276,6 +27299,12 @@ var ResourceSchema = object2({
|
|
|
27276
27299
|
* The MIME type of this resource, if known.
|
|
27277
27300
|
*/
|
|
27278
27301
|
mimeType: optional(string2()),
|
|
27302
|
+
/**
|
|
27303
|
+
* The size of the raw resource content, in bytes (i.e., before base64 encoding or any tokenization), if known.
|
|
27304
|
+
*
|
|
27305
|
+
* This can be used by Hosts to display file sizes and estimate context window usage.
|
|
27306
|
+
*/
|
|
27307
|
+
size: optional(number2()),
|
|
27279
27308
|
/**
|
|
27280
27309
|
* Optional annotations for the client.
|
|
27281
27310
|
*/
|
|
@@ -28228,7 +28257,7 @@ var UrlElicitationRequiredError = class extends McpError {
|
|
|
28228
28257
|
}
|
|
28229
28258
|
};
|
|
28230
28259
|
|
|
28231
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
28260
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/interfaces.js
|
|
28232
28261
|
function isTerminal(status) {
|
|
28233
28262
|
return status === "completed" || status === "failed" || status === "cancelled";
|
|
28234
28263
|
}
|
|
@@ -29517,7 +29546,7 @@ var zodToJsonSchema = (schema, options) => {
|
|
|
29517
29546
|
return combined;
|
|
29518
29547
|
};
|
|
29519
29548
|
|
|
29520
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
29549
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-json-schema-compat.js
|
|
29521
29550
|
function mapMiniTarget(t) {
|
|
29522
29551
|
if (!t)
|
|
29523
29552
|
return "draft-7";
|
|
@@ -29559,7 +29588,7 @@ function parseWithCompat(schema, data) {
|
|
|
29559
29588
|
return result.data;
|
|
29560
29589
|
}
|
|
29561
29590
|
|
|
29562
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
29591
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js
|
|
29563
29592
|
var DEFAULT_REQUEST_TIMEOUT_MSEC = 6e4;
|
|
29564
29593
|
var Protocol = class {
|
|
29565
29594
|
constructor(_options) {
|
|
@@ -29600,6 +29629,9 @@ var Protocol = class {
|
|
|
29600
29629
|
this.setRequestHandler(GetTaskPayloadRequestSchema, async (request2, extra) => {
|
|
29601
29630
|
const handleTaskResult = async () => {
|
|
29602
29631
|
const taskId = request2.params.taskId;
|
|
29632
|
+
if (!await this._taskStore.getTask(taskId, extra.sessionId)) {
|
|
29633
|
+
throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
|
|
29634
|
+
}
|
|
29603
29635
|
if (this._taskMessageQueue) {
|
|
29604
29636
|
let queuedMessage;
|
|
29605
29637
|
while (queuedMessage = await this._taskMessageQueue.dequeue(taskId, extra.sessionId)) {
|
|
@@ -29630,12 +29662,12 @@ var Protocol = class {
|
|
|
29630
29662
|
throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
|
|
29631
29663
|
}
|
|
29632
29664
|
if (!isTerminal(task.status)) {
|
|
29633
|
-
await this._waitForTaskUpdate(taskId, extra.signal);
|
|
29665
|
+
await this._waitForTaskUpdate(taskId, extra.signal, extra.sessionId);
|
|
29634
29666
|
return await handleTaskResult();
|
|
29635
29667
|
}
|
|
29636
29668
|
if (isTerminal(task.status)) {
|
|
29637
29669
|
const result = await this._taskStore.getTaskResult(taskId, extra.sessionId);
|
|
29638
|
-
this._clearTaskQueue(taskId);
|
|
29670
|
+
this._clearTaskQueue(taskId, extra.sessionId);
|
|
29639
29671
|
return {
|
|
29640
29672
|
...result,
|
|
29641
29673
|
_meta: {
|
|
@@ -29672,7 +29704,7 @@ var Protocol = class {
|
|
|
29672
29704
|
throw new McpError(ErrorCode.InvalidParams, `Cannot cancel task in terminal status: ${task.status}`);
|
|
29673
29705
|
}
|
|
29674
29706
|
await this._taskStore.updateTaskStatus(request2.params.taskId, "cancelled", "Client cancelled task execution.", extra.sessionId);
|
|
29675
|
-
this._clearTaskQueue(request2.params.taskId);
|
|
29707
|
+
this._clearTaskQueue(request2.params.taskId, extra.sessionId);
|
|
29676
29708
|
const cancelledTask = await this._taskStore.getTask(request2.params.taskId, extra.sessionId);
|
|
29677
29709
|
if (!cancelledTask) {
|
|
29678
29710
|
throw new McpError(ErrorCode.InvalidParams, `Task not found after cancellation: ${request2.params.taskId}`);
|
|
@@ -29800,6 +29832,19 @@ var Protocol = class {
|
|
|
29800
29832
|
const handler2 = this._requestHandlers.get(request2.method) ?? this.fallbackRequestHandler;
|
|
29801
29833
|
const capturedTransport = this._transport;
|
|
29802
29834
|
const relatedTaskId = request2.params?._meta?.[RELATED_TASK_META_KEY]?.taskId;
|
|
29835
|
+
const sessionId = capturedTransport?.sessionId;
|
|
29836
|
+
const store = this._taskStore;
|
|
29837
|
+
let relatedTaskFound = true;
|
|
29838
|
+
let relatedTaskLookup;
|
|
29839
|
+
if (relatedTaskId && store && this._taskMessageQueue && sessionId !== void 0) {
|
|
29840
|
+
relatedTaskFound = false;
|
|
29841
|
+
relatedTaskLookup = (async () => {
|
|
29842
|
+
if (!await store.getTask(relatedTaskId, sessionId)) {
|
|
29843
|
+
throw new McpError(ErrorCode.InvalidParams, `Task not found: ${relatedTaskId}`);
|
|
29844
|
+
}
|
|
29845
|
+
relatedTaskFound = true;
|
|
29846
|
+
})();
|
|
29847
|
+
}
|
|
29803
29848
|
if (handler2 === void 0) {
|
|
29804
29849
|
const errorResponse = {
|
|
29805
29850
|
jsonrpc: "2.0",
|
|
@@ -29809,7 +29854,10 @@ var Protocol = class {
|
|
|
29809
29854
|
message: "Method not found"
|
|
29810
29855
|
}
|
|
29811
29856
|
};
|
|
29812
|
-
if (relatedTaskId &&
|
|
29857
|
+
if (relatedTaskId && relatedTaskLookup) {
|
|
29858
|
+
const queuedError = { type: "error", message: errorResponse, timestamp: Date.now() };
|
|
29859
|
+
relatedTaskLookup.then(() => this._enqueueTaskMessage(relatedTaskId, queuedError, sessionId), () => capturedTransport?.send(errorResponse)).catch((error48) => this._onerror(new Error(`Failed to send an error response: ${error48}`)));
|
|
29860
|
+
} else if (relatedTaskId && this._taskMessageQueue) {
|
|
29813
29861
|
this._enqueueTaskMessage(relatedTaskId, {
|
|
29814
29862
|
type: "error",
|
|
29815
29863
|
message: errorResponse,
|
|
@@ -29860,7 +29908,10 @@ var Protocol = class {
|
|
|
29860
29908
|
closeSSEStream: extra?.closeSSEStream,
|
|
29861
29909
|
closeStandaloneSSEStream: extra?.closeStandaloneSSEStream
|
|
29862
29910
|
};
|
|
29863
|
-
Promise.resolve().then(() => {
|
|
29911
|
+
(relatedTaskLookup ?? Promise.resolve()).then(() => {
|
|
29912
|
+
if (relatedTaskLookup && abortController.signal.aborted) {
|
|
29913
|
+
throw new McpError(ErrorCode.ConnectionClosed, "Request was cancelled");
|
|
29914
|
+
}
|
|
29864
29915
|
if (taskCreationParams) {
|
|
29865
29916
|
this.assertTaskHandlerCapability(request2.method);
|
|
29866
29917
|
}
|
|
@@ -29895,7 +29946,7 @@ var Protocol = class {
|
|
|
29895
29946
|
...error48["data"] !== void 0 && { data: error48["data"] }
|
|
29896
29947
|
}
|
|
29897
29948
|
};
|
|
29898
|
-
if (relatedTaskId && this._taskMessageQueue) {
|
|
29949
|
+
if (relatedTaskId && this._taskMessageQueue && relatedTaskFound) {
|
|
29899
29950
|
await this._enqueueTaskMessage(relatedTaskId, {
|
|
29900
29951
|
type: "error",
|
|
29901
29952
|
message: errorResponse,
|
|
@@ -30375,7 +30426,7 @@ var Protocol = class {
|
|
|
30375
30426
|
throw new Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured");
|
|
30376
30427
|
}
|
|
30377
30428
|
const maxQueueSize = this._options?.maxTaskQueueSize;
|
|
30378
|
-
await this._taskMessageQueue.enqueue(taskId, message, sessionId, maxQueueSize);
|
|
30429
|
+
await this._taskMessageQueue.enqueue(taskId, message, sessionId ?? this._transport?.sessionId, maxQueueSize);
|
|
30379
30430
|
}
|
|
30380
30431
|
/**
|
|
30381
30432
|
* Clears the message queue for a task and rejects any pending request resolvers.
|
|
@@ -30404,12 +30455,13 @@ var Protocol = class {
|
|
|
30404
30455
|
* Uses polling to check for updates at the task's configured poll interval.
|
|
30405
30456
|
* @param taskId The task ID to wait for
|
|
30406
30457
|
* @param signal Abort signal to cancel the wait
|
|
30458
|
+
* @param sessionId Session of the request that waits, passed to the task store
|
|
30407
30459
|
* @returns Promise that resolves when an update occurs or rejects if aborted
|
|
30408
30460
|
*/
|
|
30409
|
-
async _waitForTaskUpdate(taskId, signal) {
|
|
30461
|
+
async _waitForTaskUpdate(taskId, signal, sessionId) {
|
|
30410
30462
|
let interval = this._options?.defaultTaskPollInterval ?? 1e3;
|
|
30411
30463
|
try {
|
|
30412
|
-
const task = await this._taskStore?.getTask(taskId);
|
|
30464
|
+
const task = await this._taskStore?.getTask(taskId, sessionId);
|
|
30413
30465
|
if (task?.pollInterval) {
|
|
30414
30466
|
interval = task.pollInterval;
|
|
30415
30467
|
}
|
|
@@ -30513,7 +30565,7 @@ function mergeCapabilities(base, additional) {
|
|
|
30513
30565
|
return result;
|
|
30514
30566
|
}
|
|
30515
30567
|
|
|
30516
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
30568
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/validation/ajv-provider.js
|
|
30517
30569
|
var import_ajv = __toESM(require_ajv(), 1);
|
|
30518
30570
|
var import_ajv_formats = __toESM(require_dist(), 1);
|
|
30519
30571
|
function createDefaultAjvInstance() {
|
|
@@ -30581,7 +30633,7 @@ var AjvJsonSchemaValidator = class {
|
|
|
30581
30633
|
}
|
|
30582
30634
|
};
|
|
30583
30635
|
|
|
30584
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
30636
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/server.js
|
|
30585
30637
|
var ExperimentalServerTasks = class {
|
|
30586
30638
|
constructor(_server) {
|
|
30587
30639
|
this._server = _server;
|
|
@@ -30794,7 +30846,7 @@ var ExperimentalServerTasks = class {
|
|
|
30794
30846
|
}
|
|
30795
30847
|
};
|
|
30796
30848
|
|
|
30797
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
30849
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/helpers.js
|
|
30798
30850
|
function assertToolsCallTaskCapability(requests, method, entityName) {
|
|
30799
30851
|
if (!requests) {
|
|
30800
30852
|
throw new Error(`${entityName} does not support task creation (required for ${method})`);
|
|
@@ -30829,7 +30881,7 @@ function assertClientRequestTaskCapability(requests, method, entityName) {
|
|
|
30829
30881
|
}
|
|
30830
30882
|
}
|
|
30831
30883
|
|
|
30832
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
30884
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js
|
|
30833
30885
|
var Server = class extends Protocol {
|
|
30834
30886
|
/**
|
|
30835
30887
|
* Initializes this server with the given name and version information.
|
|
@@ -30895,16 +30947,7 @@ var Server = class extends Protocol {
|
|
|
30895
30947
|
if (!methodSchema) {
|
|
30896
30948
|
throw new Error("Schema is missing a method literal");
|
|
30897
30949
|
}
|
|
30898
|
-
|
|
30899
|
-
if (isZ4Schema(methodSchema)) {
|
|
30900
|
-
const v4Schema = methodSchema;
|
|
30901
|
-
const v4Def = v4Schema._zod?.def;
|
|
30902
|
-
methodValue = v4Def?.value ?? v4Schema.value;
|
|
30903
|
-
} else {
|
|
30904
|
-
const v3Schema = methodSchema;
|
|
30905
|
-
const legacyDef = v3Schema._def;
|
|
30906
|
-
methodValue = legacyDef?.value ?? v3Schema.value;
|
|
30907
|
-
}
|
|
30950
|
+
const methodValue = getLiteralValue(methodSchema);
|
|
30908
30951
|
if (typeof methodValue !== "string") {
|
|
30909
30952
|
throw new Error("Schema method literal must be a string");
|
|
30910
30953
|
}
|
|
@@ -31209,7 +31252,7 @@ var Server = class extends Protocol {
|
|
|
31209
31252
|
}
|
|
31210
31253
|
};
|
|
31211
31254
|
|
|
31212
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
31255
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/completable.js
|
|
31213
31256
|
var COMPLETABLE_SYMBOL = /* @__PURE__ */ Symbol.for("mcp.completable");
|
|
31214
31257
|
function isCompletable(schema) {
|
|
31215
31258
|
return !!schema && typeof schema === "object" && COMPLETABLE_SYMBOL in schema;
|
|
@@ -31223,7 +31266,7 @@ var McpZodTypeKind;
|
|
|
31223
31266
|
McpZodTypeKind2["Completable"] = "McpCompletable";
|
|
31224
31267
|
})(McpZodTypeKind || (McpZodTypeKind = {}));
|
|
31225
31268
|
|
|
31226
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
31269
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/toolNameValidation.js
|
|
31227
31270
|
var TOOL_NAME_REGEX = /^[A-Za-z0-9._-]{1,128}$/;
|
|
31228
31271
|
function validateToolName(name) {
|
|
31229
31272
|
const warnings = [];
|
|
@@ -31281,7 +31324,7 @@ function validateAndWarnToolName(name) {
|
|
|
31281
31324
|
return result.isValid;
|
|
31282
31325
|
}
|
|
31283
31326
|
|
|
31284
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
31327
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/mcp-server.js
|
|
31285
31328
|
var ExperimentalMcpServerTasks = class {
|
|
31286
31329
|
constructor(_mcpServer) {
|
|
31287
31330
|
this._mcpServer = _mcpServer;
|
|
@@ -31296,7 +31339,43 @@ var ExperimentalMcpServerTasks = class {
|
|
|
31296
31339
|
}
|
|
31297
31340
|
};
|
|
31298
31341
|
|
|
31299
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
31342
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js
|
|
31343
|
+
function toolInputElementCount(value, max) {
|
|
31344
|
+
let count = 0;
|
|
31345
|
+
const stack = [value];
|
|
31346
|
+
while (stack.length > 0) {
|
|
31347
|
+
const node = stack.pop();
|
|
31348
|
+
if (node === null || typeof node !== "object")
|
|
31349
|
+
continue;
|
|
31350
|
+
if (Array.isArray(node)) {
|
|
31351
|
+
for (const child of node) {
|
|
31352
|
+
if (++count > max)
|
|
31353
|
+
return count;
|
|
31354
|
+
if (child !== null && typeof child === "object")
|
|
31355
|
+
stack.push(child);
|
|
31356
|
+
}
|
|
31357
|
+
} else {
|
|
31358
|
+
for (const key in node) {
|
|
31359
|
+
if (!Object.prototype.hasOwnProperty.call(node, key))
|
|
31360
|
+
continue;
|
|
31361
|
+
if (++count > max)
|
|
31362
|
+
return count;
|
|
31363
|
+
const child = node[key];
|
|
31364
|
+
if (child !== null && typeof child === "object")
|
|
31365
|
+
stack.push(child);
|
|
31366
|
+
}
|
|
31367
|
+
}
|
|
31368
|
+
}
|
|
31369
|
+
return count;
|
|
31370
|
+
}
|
|
31371
|
+
function resolveMaxToolInputElements(value) {
|
|
31372
|
+
if (value === void 0 || value === Infinity)
|
|
31373
|
+
return void 0;
|
|
31374
|
+
if (typeof value !== "number" || Number.isNaN(value) || value < 1) {
|
|
31375
|
+
throw new RangeError(`maxToolInputElements must be a number of at least 1, or Infinity, got ${String(value)}`);
|
|
31376
|
+
}
|
|
31377
|
+
return value;
|
|
31378
|
+
}
|
|
31300
31379
|
var McpServer = class {
|
|
31301
31380
|
constructor(serverInfo, options) {
|
|
31302
31381
|
this._registeredResources = {};
|
|
@@ -31308,6 +31387,7 @@ var McpServer = class {
|
|
|
31308
31387
|
this._resourceHandlersInitialized = false;
|
|
31309
31388
|
this._promptHandlersInitialized = false;
|
|
31310
31389
|
this.server = new Server(serverInfo, options);
|
|
31390
|
+
this._maxToolInputElements = resolveMaxToolInputElements(options?.maxToolInputElements);
|
|
31311
31391
|
}
|
|
31312
31392
|
/**
|
|
31313
31393
|
* Access experimental features.
|
|
@@ -31438,12 +31518,15 @@ var McpServer = class {
|
|
|
31438
31518
|
* Validates tool input arguments against the tool's input schema.
|
|
31439
31519
|
*/
|
|
31440
31520
|
async validateToolInput(tool, args, toolName) {
|
|
31521
|
+
if (this._maxToolInputElements !== void 0 && toolInputElementCount(args, this._maxToolInputElements) > this._maxToolInputElements) {
|
|
31522
|
+
throw new McpError(ErrorCode.InvalidParams, `Invalid arguments for tool ${toolName}: arguments contain more than the maximum of ${this._maxToolInputElements} elements`);
|
|
31523
|
+
}
|
|
31441
31524
|
if (!tool.inputSchema) {
|
|
31442
31525
|
return void 0;
|
|
31443
31526
|
}
|
|
31444
31527
|
const inputObj = normalizeObjectSchema(tool.inputSchema);
|
|
31445
31528
|
const schemaToParse = inputObj ?? tool.inputSchema;
|
|
31446
|
-
const parseResult = await safeParseAsync2(schemaToParse, args);
|
|
31529
|
+
const parseResult = await safeParseAsync2(schemaToParse, args ?? {});
|
|
31447
31530
|
if (!parseResult.success) {
|
|
31448
31531
|
const error48 = "error" in parseResult ? parseResult.error : "Unknown error";
|
|
31449
31532
|
const errorMessage2 = getParseErrorMessage(error48);
|
|
@@ -31681,7 +31764,7 @@ var McpServer = class {
|
|
|
31681
31764
|
}
|
|
31682
31765
|
if (prompt.argsSchema) {
|
|
31683
31766
|
const argsObj = normalizeObjectSchema(prompt.argsSchema);
|
|
31684
|
-
const parseResult = await safeParseAsync2(argsObj, request2.params.arguments);
|
|
31767
|
+
const parseResult = await safeParseAsync2(argsObj, request2.params.arguments ?? {});
|
|
31685
31768
|
if (!parseResult.success) {
|
|
31686
31769
|
const error48 = "error" in parseResult ? parseResult.error : "Unknown error";
|
|
31687
31770
|
const errorMessage2 = getParseErrorMessage(error48);
|
|
@@ -32088,12 +32171,21 @@ var EMPTY_COMPLETION_RESULT = {
|
|
|
32088
32171
|
}
|
|
32089
32172
|
};
|
|
32090
32173
|
|
|
32091
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
32174
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
32092
32175
|
var import_node_process = __toESM(require("node:process"), 1);
|
|
32093
32176
|
|
|
32094
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
32177
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
|
|
32178
|
+
var STDIO_DEFAULT_MAX_BUFFER_SIZE = 10 * 1024 * 1024;
|
|
32095
32179
|
var ReadBuffer = class {
|
|
32180
|
+
constructor(options) {
|
|
32181
|
+
this._maxBufferSize = options?.maxBufferSize ?? STDIO_DEFAULT_MAX_BUFFER_SIZE;
|
|
32182
|
+
}
|
|
32096
32183
|
append(chunk) {
|
|
32184
|
+
const newSize = (this._buffer?.length ?? 0) + chunk.length;
|
|
32185
|
+
if (newSize > this._maxBufferSize) {
|
|
32186
|
+
this.clear();
|
|
32187
|
+
throw new Error(`ReadBuffer exceeded maximum size of ${this._maxBufferSize} bytes`);
|
|
32188
|
+
}
|
|
32097
32189
|
this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
|
|
32098
32190
|
}
|
|
32099
32191
|
readMessage() {
|
|
@@ -32119,20 +32211,26 @@ function serializeMessage(message) {
|
|
|
32119
32211
|
return JSON.stringify(message) + "\n";
|
|
32120
32212
|
}
|
|
32121
32213
|
|
|
32122
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
32214
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@4.3.6/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
|
|
32123
32215
|
var StdioServerTransport = class {
|
|
32124
|
-
constructor(_stdin = import_node_process.default.stdin, _stdout = import_node_process.default.stdout) {
|
|
32216
|
+
constructor(_stdin = import_node_process.default.stdin, _stdout = import_node_process.default.stdout, options) {
|
|
32125
32217
|
this._stdin = _stdin;
|
|
32126
32218
|
this._stdout = _stdout;
|
|
32127
|
-
this._readBuffer = new ReadBuffer();
|
|
32128
32219
|
this._started = false;
|
|
32129
32220
|
this._ondata = (chunk) => {
|
|
32130
|
-
|
|
32131
|
-
|
|
32221
|
+
try {
|
|
32222
|
+
this._readBuffer.append(chunk);
|
|
32223
|
+
this.processReadBuffer();
|
|
32224
|
+
} catch (error48) {
|
|
32225
|
+
this.onerror?.(error48);
|
|
32226
|
+
this.close().catch(() => {
|
|
32227
|
+
});
|
|
32228
|
+
}
|
|
32132
32229
|
};
|
|
32133
32230
|
this._onerror = (error48) => {
|
|
32134
32231
|
this.onerror?.(error48);
|
|
32135
32232
|
};
|
|
32233
|
+
this._readBuffer = new ReadBuffer({ maxBufferSize: options?.maxBufferSize });
|
|
32136
32234
|
}
|
|
32137
32235
|
/**
|
|
32138
32236
|
* Starts listening for messages on stdin.
|
|
@@ -36643,7 +36741,15 @@ var SkippedIssueSchema = external_exports3.looseObject({
|
|
|
36643
36741
|
title: external_exports3.string(),
|
|
36644
36742
|
skippedAt: external_exports3.string(),
|
|
36645
36743
|
/** Why it was skipped: the vetter's reasons, or absent for a manual skip (#343). */
|
|
36646
|
-
reason: external_exports3.string().optional()
|
|
36744
|
+
reason: external_exports3.string().optional(),
|
|
36745
|
+
/**
|
|
36746
|
+
* Whether this entry is permanent. Manual skips are permanent (true); vetter-
|
|
36747
|
+
* derived skips for transient conditions (linked PR closed, own PR in flight,
|
|
36748
|
+
* accumulated soft-skips) are non-permanent (false) and eligible for
|
|
36749
|
+
* cullExpiredSkips. Entries without this field (written before #348) default
|
|
36750
|
+
* to true so they are never silently dropped.
|
|
36751
|
+
*/
|
|
36752
|
+
permanent: external_exports3.boolean().default(true)
|
|
36647
36753
|
});
|
|
36648
36754
|
var HorizonSchema = external_exports3.enum(["quick-win", "bigger-bet"]);
|
|
36649
36755
|
var SavedCandidateSchema = external_exports3.looseObject({
|
|
@@ -36745,8 +36851,17 @@ var ScoutPreferencesSchema = external_exports3.looseObject({
|
|
|
36745
36851
|
*/
|
|
36746
36852
|
featuresSplitRatio: external_exports3.number().min(0).max(1).default(0.6)
|
|
36747
36853
|
});
|
|
36854
|
+
var CURRENT_STATE_REVISION = 1;
|
|
36748
36855
|
var ScoutStateSchema = external_exports3.looseObject({
|
|
36749
36856
|
version: external_exports3.literal(1),
|
|
36857
|
+
/**
|
|
36858
|
+
* Highest compatible migration applied to this state (see
|
|
36859
|
+
* `parseScoutState`). Unlike `version`, a bump here never locks out an
|
|
36860
|
+
* older binary: the key round-trips through the loose schema, and every
|
|
36861
|
+
* migration it tracks leaves the shape valid for version 1 readers.
|
|
36862
|
+
* State written before the counter existed reads as 0.
|
|
36863
|
+
*/
|
|
36864
|
+
stateRevision: external_exports3.number().int().min(0).default(CURRENT_STATE_REVISION),
|
|
36750
36865
|
preferences: ScoutPreferencesSchema.default(() => ScoutPreferencesSchema.parse({})),
|
|
36751
36866
|
repoScores: external_exports3.record(external_exports3.string(), RepoScoreSchema).default({}),
|
|
36752
36867
|
starredRepos: external_exports3.array(external_exports3.string()).default([]),
|
|
@@ -36810,7 +36925,32 @@ var ScoutStateSchema = external_exports3.looseObject({
|
|
|
36810
36925
|
}))
|
|
36811
36926
|
});
|
|
36812
36927
|
function parseScoutState(raw) {
|
|
36813
|
-
return ScoutStateSchema.parse(raw);
|
|
36928
|
+
return ScoutStateSchema.parse(migrateScoutState(raw));
|
|
36929
|
+
}
|
|
36930
|
+
var LEGACY_INTER_PHASE_DELAY_MS = 3e4;
|
|
36931
|
+
function migrateScoutState(raw) {
|
|
36932
|
+
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
36933
|
+
return raw;
|
|
36934
|
+
}
|
|
36935
|
+
const state = raw;
|
|
36936
|
+
const revision = typeof state.stateRevision === "number" ? state.stateRevision : 0;
|
|
36937
|
+
if (revision >= CURRENT_STATE_REVISION)
|
|
36938
|
+
return raw;
|
|
36939
|
+
let migrated = state;
|
|
36940
|
+
if (revision < 1)
|
|
36941
|
+
migrated = dropInheritedInterPhaseDelay(migrated);
|
|
36942
|
+
return { ...migrated, stateRevision: CURRENT_STATE_REVISION };
|
|
36943
|
+
}
|
|
36944
|
+
function dropInheritedInterPhaseDelay(state) {
|
|
36945
|
+
const prefs = state.preferences;
|
|
36946
|
+
if (typeof prefs !== "object" || prefs === null || Array.isArray(prefs)) {
|
|
36947
|
+
return state;
|
|
36948
|
+
}
|
|
36949
|
+
const preferences = prefs;
|
|
36950
|
+
if (preferences.interPhaseDelayMs !== LEGACY_INTER_PHASE_DELAY_MS) {
|
|
36951
|
+
return state;
|
|
36952
|
+
}
|
|
36953
|
+
return { ...state, preferences: { ...preferences, interPhaseDelayMs: 0 } };
|
|
36814
36954
|
}
|
|
36815
36955
|
|
|
36816
36956
|
// ../core/dist/core/issue-filtering.js
|
|
@@ -39213,7 +39353,7 @@ async function runPhase3(octokit, vetter, langQuery, minStars, projectCategories
|
|
|
39213
39353
|
const pushedSince = thirtyDaysAgo.toISOString().split("T")[0];
|
|
39214
39354
|
const categoryTopics = getTopicsForCategories(projectCategories);
|
|
39215
39355
|
const topicQuery = categoryTopics.length > 0 ? `topic:${categoryTopics[0]}` : "";
|
|
39216
|
-
const phase3Query = `is:issue is:open no:assignee ${langQuery} ${topicQuery}
|
|
39356
|
+
const phase3Query = `is:issue is:open no:assignee ${langQuery} ${topicQuery} pushed:>=${pushedSince} archived:false`.replace(/ +/g, " ").trim();
|
|
39217
39357
|
try {
|
|
39218
39358
|
const data = await searchIssuesGraphQLFirst(octokit, {
|
|
39219
39359
|
q: phase3Query,
|
|
@@ -40253,6 +40393,7 @@ function mergeStates(local, remote) {
|
|
|
40253
40393
|
...local,
|
|
40254
40394
|
...remote,
|
|
40255
40395
|
version: 1,
|
|
40396
|
+
stateRevision: Math.max(local.stateRevision, remote.stateRevision),
|
|
40256
40397
|
preferences,
|
|
40257
40398
|
preferencesUpdatedAt,
|
|
40258
40399
|
tombstones,
|
|
@@ -40499,10 +40640,12 @@ var OssScout = class {
|
|
|
40499
40640
|
}
|
|
40500
40641
|
/**
|
|
40501
40642
|
* Multi-strategy issue search. Returns scored, sorted candidates.
|
|
40502
|
-
* Skipped issues are excluded;
|
|
40643
|
+
* Skipped issues are excluded; permanent skips never re-surface; transient
|
|
40644
|
+
* vetter skips age out after 90 days (#343, #348).
|
|
40503
40645
|
*/
|
|
40504
40646
|
async search(options) {
|
|
40505
40647
|
this.evictStaleCacheEntries();
|
|
40648
|
+
this.cullExpiredSkips();
|
|
40506
40649
|
const skippedUrls = new Set((this.state.skippedIssues ?? []).map((s) => s.url));
|
|
40507
40650
|
if (options?.excludeRecentlySurfaced ?? true) {
|
|
40508
40651
|
const ttlDays = options?.recentlySurfacedTtlDays ?? 7;
|
|
@@ -41005,11 +41148,17 @@ var OssScout = class {
|
|
|
41005
41148
|
for (const c of candidates) {
|
|
41006
41149
|
if (c.recommendation === "skip") {
|
|
41007
41150
|
existing.delete(c.issue.url);
|
|
41151
|
+
const TERMINAL_REASONS = /* @__PURE__ */ new Set([
|
|
41152
|
+
"Issue is closed",
|
|
41153
|
+
"Linked PR already merged"
|
|
41154
|
+
]);
|
|
41155
|
+
const permanent = c.reasonsToSkip.some((r) => TERMINAL_REASONS.has(r));
|
|
41008
41156
|
this.skipIssue(c.issue.url, {
|
|
41009
41157
|
repo: c.issue.repo,
|
|
41010
41158
|
number: c.issue.number,
|
|
41011
41159
|
title: c.issue.title,
|
|
41012
|
-
reason: c.reasonsToSkip.join("; ") || "vetter: skip"
|
|
41160
|
+
reason: c.reasonsToSkip.join("; ") || "vetter: skip",
|
|
41161
|
+
permanent
|
|
41013
41162
|
});
|
|
41014
41163
|
continue;
|
|
41015
41164
|
}
|
|
@@ -41063,12 +41212,20 @@ var OssScout = class {
|
|
|
41063
41212
|
}
|
|
41064
41213
|
// ── Skip List ───────────────────────────────────────────────────────
|
|
41065
41214
|
/**
|
|
41066
|
-
* Skip an issue
|
|
41215
|
+
* Skip an issue. Pass `permanent: false` for vetter-derived transient skips
|
|
41216
|
+
* so they expire via cullExpiredSkips (#348); manual skips default to permanent.
|
|
41067
41217
|
*/
|
|
41068
41218
|
skipIssue(url2, metadata) {
|
|
41069
41219
|
const existing = this.state.skippedIssues ?? [];
|
|
41070
|
-
|
|
41220
|
+
const hit = existing.find((s) => s.url === url2);
|
|
41221
|
+
if (hit) {
|
|
41222
|
+
if (metadata?.permanent === true && hit.permanent !== true) {
|
|
41223
|
+
hit.permanent = true;
|
|
41224
|
+
this.dirty = true;
|
|
41225
|
+
}
|
|
41071
41226
|
return;
|
|
41227
|
+
}
|
|
41228
|
+
const permanent = metadata?.permanent ?? true;
|
|
41072
41229
|
this.state.skippedIssues = [
|
|
41073
41230
|
...existing,
|
|
41074
41231
|
{
|
|
@@ -41077,6 +41234,7 @@ var OssScout = class {
|
|
|
41077
41234
|
number: metadata?.number ?? 0,
|
|
41078
41235
|
title: metadata?.title ?? "",
|
|
41079
41236
|
skippedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
41237
|
+
permanent,
|
|
41080
41238
|
...metadata?.reason ? { reason: metadata.reason } : {}
|
|
41081
41239
|
}
|
|
41082
41240
|
];
|
|
@@ -41110,8 +41268,11 @@ var OssScout = class {
|
|
|
41110
41268
|
this.dirty = true;
|
|
41111
41269
|
}
|
|
41112
41270
|
/**
|
|
41113
|
-
* Remove skipped issues older than maxDays (default 90).
|
|
41114
|
-
*
|
|
41271
|
+
* Remove non-permanent skipped issues older than maxDays (default 90).
|
|
41272
|
+
* Called at the start of each search (#348) to re-surface issues whose
|
|
41273
|
+
* transient block condition (closed competing PR, own in-flight PR, soft-skip
|
|
41274
|
+
* accumulation) has aged out. Permanent entries (manual skips, terminal vetter
|
|
41275
|
+
* reasons) are never touched.
|
|
41115
41276
|
* @returns The number of expired entries that were removed.
|
|
41116
41277
|
*/
|
|
41117
41278
|
cullExpiredSkips(maxDays = 90) {
|
|
@@ -41119,6 +41280,8 @@ var OssScout = class {
|
|
|
41119
41280
|
cutoff.setDate(cutoff.getDate() - maxDays);
|
|
41120
41281
|
const before = (this.state.skippedIssues ?? []).length;
|
|
41121
41282
|
this.state.skippedIssues = (this.state.skippedIssues ?? []).filter((s) => {
|
|
41283
|
+
if (s.permanent !== false)
|
|
41284
|
+
return true;
|
|
41122
41285
|
const d = new Date(s.skippedAt);
|
|
41123
41286
|
if (isNaN(d.getTime())) {
|
|
41124
41287
|
return true;
|
|
@@ -41441,6 +41604,7 @@ function registerTools(server, scout) {
|
|
|
41441
41604
|
]
|
|
41442
41605
|
};
|
|
41443
41606
|
} catch (err) {
|
|
41607
|
+
if (scout.isDirty()) await scout.checkpoint().catch(() => false);
|
|
41444
41608
|
const msg = err instanceof Error ? err.message : String(err);
|
|
41445
41609
|
return {
|
|
41446
41610
|
content: [{ type: "text", text: `Error: ${msg}` }],
|
|
@@ -41720,7 +41884,7 @@ function registerResources(server, scout) {
|
|
|
41720
41884
|
// src/index.ts
|
|
41721
41885
|
var SERVER_INFO = {
|
|
41722
41886
|
name: "oss-scout-mcp",
|
|
41723
|
-
version: "0.12.
|
|
41887
|
+
version: "0.12.1"
|
|
41724
41888
|
// x-release-please-version
|
|
41725
41889
|
};
|
|
41726
41890
|
function createServer(scout) {
|
package/dist/tools.js
CHANGED
|
@@ -106,6 +106,12 @@ export function registerTools(server, scout) {
|
|
|
106
106
|
};
|
|
107
107
|
}
|
|
108
108
|
catch (err) {
|
|
109
|
+
// State mutated before the failure (notably the search-rotation
|
|
110
|
+
// cursors, which advance even when a run finds nothing) would
|
|
111
|
+
// otherwise be dropped, so the same dry strategy/repo window leads
|
|
112
|
+
// every retry. The CLI persists this in its own catch; mirror it.
|
|
113
|
+
if (scout.isDirty())
|
|
114
|
+
await scout.checkpoint().catch(() => false);
|
|
109
115
|
const msg = err instanceof Error ? err.message : String(err);
|
|
110
116
|
return {
|
|
111
117
|
content: [{ type: "text", text: `Error: ${msg}` }],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oss-scout/mcp",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.1",
|
|
4
4
|
"description": "MCP server for oss-scout — exposes issue discovery and vetting as MCP tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
"dist/"
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@modelcontextprotocol/sdk": "^1.
|
|
19
|
+
"@modelcontextprotocol/sdk": "^1.32.1",
|
|
20
20
|
"zod": "^4.3.6",
|
|
21
|
-
"@oss-scout/core": "^1.8.
|
|
21
|
+
"@oss-scout/core": "^1.8.1"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/node": "^25.5.0",
|