oh-my-opencode-kikokikok 2.14.2 → 2.15.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/cli/index.js +26 -4
- package/dist/config/schema.d.ts +75 -0
- package/dist/features/knowledge-provider/index.d.ts +1 -0
- package/dist/features/knowledge-provider/mcp-manager.d.ts +67 -0
- package/dist/features/knowledge-provider/mcp-manager.test.d.ts +1 -0
- package/dist/features/knowledge-provider/types.d.ts +22 -2
- package/dist/features/letta-memory/adapter.d.ts +24 -0
- package/dist/features/letta-memory/adapter.test.d.ts +1 -0
- package/dist/features/letta-memory/index.d.ts +2 -0
- package/dist/features/letta-memory/types.d.ts +140 -0
- package/dist/hooks/memory-rehydration/index.d.ts +2 -2
- package/dist/index.js +3630 -631
- package/dist/plugin-config.test.d.ts +1 -0
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/knowledge/index.d.ts +1 -0
- package/dist/tools/knowledge/provider-tools.d.ts +3 -0
- package/dist/tools/knowledge/provider-tools.test.d.ts +1 -0
- package/dist/tools/memory/index.d.ts +1 -1
- package/dist/tools/memory/tools.d.ts +2 -2
- package/dist/tools/memory/types.d.ts +41 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2902,37 +2902,37 @@ var require_dataType = __commonJS((exports) => {
|
|
|
2902
2902
|
DataType2[DataType2["Wrong"] = 1] = "Wrong";
|
|
2903
2903
|
})(DataType || (exports.DataType = DataType = {}));
|
|
2904
2904
|
function getSchemaTypes(schema2) {
|
|
2905
|
-
const
|
|
2906
|
-
const hasNull =
|
|
2905
|
+
const types18 = getJSONTypes(schema2.type);
|
|
2906
|
+
const hasNull = types18.includes("null");
|
|
2907
2907
|
if (hasNull) {
|
|
2908
2908
|
if (schema2.nullable === false)
|
|
2909
2909
|
throw new Error("type: null contradicts nullable: false");
|
|
2910
2910
|
} else {
|
|
2911
|
-
if (!
|
|
2911
|
+
if (!types18.length && schema2.nullable !== undefined) {
|
|
2912
2912
|
throw new Error('"nullable" cannot be used without "type"');
|
|
2913
2913
|
}
|
|
2914
2914
|
if (schema2.nullable === true)
|
|
2915
|
-
|
|
2915
|
+
types18.push("null");
|
|
2916
2916
|
}
|
|
2917
|
-
return
|
|
2917
|
+
return types18;
|
|
2918
2918
|
}
|
|
2919
2919
|
exports.getSchemaTypes = getSchemaTypes;
|
|
2920
2920
|
function getJSONTypes(ts) {
|
|
2921
|
-
const
|
|
2922
|
-
if (
|
|
2923
|
-
return
|
|
2924
|
-
throw new Error("type must be JSONType or JSONType[]: " +
|
|
2921
|
+
const types18 = Array.isArray(ts) ? ts : ts ? [ts] : [];
|
|
2922
|
+
if (types18.every(rules_1.isJSONType))
|
|
2923
|
+
return types18;
|
|
2924
|
+
throw new Error("type must be JSONType or JSONType[]: " + types18.join(","));
|
|
2925
2925
|
}
|
|
2926
2926
|
exports.getJSONTypes = getJSONTypes;
|
|
2927
|
-
function coerceAndCheckDataType(it,
|
|
2927
|
+
function coerceAndCheckDataType(it, types18) {
|
|
2928
2928
|
const { gen, data, opts } = it;
|
|
2929
|
-
const coerceTo = coerceToTypes(
|
|
2930
|
-
const checkTypes =
|
|
2929
|
+
const coerceTo = coerceToTypes(types18, opts.coerceTypes);
|
|
2930
|
+
const checkTypes = types18.length > 0 && !(coerceTo.length === 0 && types18.length === 1 && (0, applicability_1.schemaHasRulesForType)(it, types18[0]));
|
|
2931
2931
|
if (checkTypes) {
|
|
2932
|
-
const wrongType = checkDataTypes(
|
|
2932
|
+
const wrongType = checkDataTypes(types18, data, opts.strictNumbers, DataType.Wrong);
|
|
2933
2933
|
gen.if(wrongType, () => {
|
|
2934
2934
|
if (coerceTo.length)
|
|
2935
|
-
coerceData(it,
|
|
2935
|
+
coerceData(it, types18, coerceTo);
|
|
2936
2936
|
else
|
|
2937
2937
|
reportTypeError(it);
|
|
2938
2938
|
});
|
|
@@ -2941,15 +2941,15 @@ var require_dataType = __commonJS((exports) => {
|
|
|
2941
2941
|
}
|
|
2942
2942
|
exports.coerceAndCheckDataType = coerceAndCheckDataType;
|
|
2943
2943
|
var COERCIBLE = new Set(["string", "number", "integer", "boolean", "null"]);
|
|
2944
|
-
function coerceToTypes(
|
|
2945
|
-
return coerceTypes ?
|
|
2944
|
+
function coerceToTypes(types18, coerceTypes) {
|
|
2945
|
+
return coerceTypes ? types18.filter((t) => COERCIBLE.has(t) || coerceTypes === "array" && t === "array") : [];
|
|
2946
2946
|
}
|
|
2947
|
-
function coerceData(it,
|
|
2947
|
+
function coerceData(it, types18, coerceTo) {
|
|
2948
2948
|
const { gen, data, opts } = it;
|
|
2949
2949
|
const dataType = gen.let("dataType", (0, codegen_1._)`typeof ${data}`);
|
|
2950
2950
|
const coerced = gen.let("coerced", (0, codegen_1._)`undefined`);
|
|
2951
2951
|
if (opts.coerceTypes === "array") {
|
|
2952
|
-
gen.if((0, codegen_1._)`${dataType} == 'object' && Array.isArray(${data}) && ${data}.length == 1`, () => gen.assign(data, (0, codegen_1._)`${data}[0]`).assign(dataType, (0, codegen_1._)`typeof ${data}`).if(checkDataTypes(
|
|
2952
|
+
gen.if((0, codegen_1._)`${dataType} == 'object' && Array.isArray(${data}) && ${data}.length == 1`, () => gen.assign(data, (0, codegen_1._)`${data}[0]`).assign(dataType, (0, codegen_1._)`typeof ${data}`).if(checkDataTypes(types18, data, opts.strictNumbers), () => gen.assign(coerced, data)));
|
|
2953
2953
|
}
|
|
2954
2954
|
gen.if((0, codegen_1._)`${coerced} !== undefined`);
|
|
2955
2955
|
for (const t of coerceTo) {
|
|
@@ -3025,19 +3025,19 @@ var require_dataType = __commonJS((exports) => {
|
|
|
3025
3025
|
return checkDataType(dataTypes[0], data, strictNums, correct);
|
|
3026
3026
|
}
|
|
3027
3027
|
let cond;
|
|
3028
|
-
const
|
|
3029
|
-
if (
|
|
3028
|
+
const types18 = (0, util_1.toHash)(dataTypes);
|
|
3029
|
+
if (types18.array && types18.object) {
|
|
3030
3030
|
const notObj = (0, codegen_1._)`typeof ${data} != "object"`;
|
|
3031
|
-
cond =
|
|
3032
|
-
delete
|
|
3033
|
-
delete
|
|
3034
|
-
delete
|
|
3031
|
+
cond = types18.null ? notObj : (0, codegen_1._)`!${data} || ${notObj}`;
|
|
3032
|
+
delete types18.null;
|
|
3033
|
+
delete types18.array;
|
|
3034
|
+
delete types18.object;
|
|
3035
3035
|
} else {
|
|
3036
3036
|
cond = codegen_1.nil;
|
|
3037
3037
|
}
|
|
3038
|
-
if (
|
|
3039
|
-
delete
|
|
3040
|
-
for (const t in
|
|
3038
|
+
if (types18.number)
|
|
3039
|
+
delete types18.integer;
|
|
3040
|
+
for (const t in types18)
|
|
3041
3041
|
cond = (0, codegen_1.and)(cond, checkDataType(t, data, strictNums, correct));
|
|
3042
3042
|
return cond;
|
|
3043
3043
|
}
|
|
@@ -3825,9 +3825,9 @@ var require_validate = __commonJS((exports) => {
|
|
|
3825
3825
|
function typeAndKeywords(it, errsCount) {
|
|
3826
3826
|
if (it.opts.jtd)
|
|
3827
3827
|
return schemaKeywords(it, [], false, errsCount);
|
|
3828
|
-
const
|
|
3829
|
-
const checkedTypes = (0, dataType_1.coerceAndCheckDataType)(it,
|
|
3830
|
-
schemaKeywords(it,
|
|
3828
|
+
const types18 = (0, dataType_1.getSchemaTypes)(it.schema);
|
|
3829
|
+
const checkedTypes = (0, dataType_1.coerceAndCheckDataType)(it, types18);
|
|
3830
|
+
schemaKeywords(it, types18, !checkedTypes, errsCount);
|
|
3831
3831
|
}
|
|
3832
3832
|
function checkRefsAndKeywords(it) {
|
|
3833
3833
|
const { schema: schema2, errSchemaPath, opts, self } = it;
|
|
@@ -3877,7 +3877,7 @@ var require_validate = __commonJS((exports) => {
|
|
|
3877
3877
|
if (items instanceof codegen_1.Name)
|
|
3878
3878
|
gen.assign((0, codegen_1._)`${evaluated}.items`, items);
|
|
3879
3879
|
}
|
|
3880
|
-
function schemaKeywords(it,
|
|
3880
|
+
function schemaKeywords(it, types18, typeErrors, errsCount) {
|
|
3881
3881
|
const { gen, schema: schema2, data, allErrors, opts, self } = it;
|
|
3882
3882
|
const { RULES } = self;
|
|
3883
3883
|
if (schema2.$ref && (opts.ignoreKeywordsWithRef || !(0, util_1.schemaHasRulesButRef)(schema2, RULES))) {
|
|
@@ -3885,7 +3885,7 @@ var require_validate = __commonJS((exports) => {
|
|
|
3885
3885
|
return;
|
|
3886
3886
|
}
|
|
3887
3887
|
if (!opts.jtd)
|
|
3888
|
-
checkStrictTypes(it,
|
|
3888
|
+
checkStrictTypes(it, types18);
|
|
3889
3889
|
gen.block(() => {
|
|
3890
3890
|
for (const group of RULES.rules)
|
|
3891
3891
|
groupKeywords(group);
|
|
@@ -3897,7 +3897,7 @@ var require_validate = __commonJS((exports) => {
|
|
|
3897
3897
|
if (group.type) {
|
|
3898
3898
|
gen.if((0, dataType_2.checkDataType)(group.type, data, opts.strictNumbers));
|
|
3899
3899
|
iterateKeywords(it, group);
|
|
3900
|
-
if (
|
|
3900
|
+
if (types18.length === 1 && types18[0] === group.type && typeErrors) {
|
|
3901
3901
|
gen.else();
|
|
3902
3902
|
(0, dataType_2.reportTypeError)(it);
|
|
3903
3903
|
}
|
|
@@ -3921,27 +3921,27 @@ var require_validate = __commonJS((exports) => {
|
|
|
3921
3921
|
}
|
|
3922
3922
|
});
|
|
3923
3923
|
}
|
|
3924
|
-
function checkStrictTypes(it,
|
|
3924
|
+
function checkStrictTypes(it, types18) {
|
|
3925
3925
|
if (it.schemaEnv.meta || !it.opts.strictTypes)
|
|
3926
3926
|
return;
|
|
3927
|
-
checkContextTypes(it,
|
|
3927
|
+
checkContextTypes(it, types18);
|
|
3928
3928
|
if (!it.opts.allowUnionTypes)
|
|
3929
|
-
checkMultipleTypes(it,
|
|
3929
|
+
checkMultipleTypes(it, types18);
|
|
3930
3930
|
checkKeywordTypes(it, it.dataTypes);
|
|
3931
3931
|
}
|
|
3932
|
-
function checkContextTypes(it,
|
|
3933
|
-
if (!
|
|
3932
|
+
function checkContextTypes(it, types18) {
|
|
3933
|
+
if (!types18.length)
|
|
3934
3934
|
return;
|
|
3935
3935
|
if (!it.dataTypes.length) {
|
|
3936
|
-
it.dataTypes =
|
|
3936
|
+
it.dataTypes = types18;
|
|
3937
3937
|
return;
|
|
3938
3938
|
}
|
|
3939
|
-
|
|
3939
|
+
types18.forEach((t) => {
|
|
3940
3940
|
if (!includesType(it.dataTypes, t)) {
|
|
3941
3941
|
strictTypesError(it, `type "${t}" not allowed by context "${it.dataTypes.join(",")}"`);
|
|
3942
3942
|
}
|
|
3943
3943
|
});
|
|
3944
|
-
narrowSchemaTypes(it,
|
|
3944
|
+
narrowSchemaTypes(it, types18);
|
|
3945
3945
|
}
|
|
3946
3946
|
function checkMultipleTypes(it, ts) {
|
|
3947
3947
|
if (ts.length > 1 && !(ts.length === 2 && ts.includes("null"))) {
|
|
@@ -42134,6 +42134,203 @@ var knowledge_propose = tool({
|
|
|
42134
42134
|
}
|
|
42135
42135
|
}
|
|
42136
42136
|
});
|
|
42137
|
+
|
|
42138
|
+
// src/tools/knowledge/provider-tools.ts
|
|
42139
|
+
function createKnowledgeProviderTools(registry2) {
|
|
42140
|
+
const knowledge_query2 = tool({
|
|
42141
|
+
description: "Search and query the knowledge repository. " + "Find ADRs, policies, patterns, and specs by keywords, type, layer, or full-text search. " + "Returns summaries to conserve context - use knowledge_show for full details.",
|
|
42142
|
+
args: {
|
|
42143
|
+
query: tool.schema.string().optional().describe("Full-text search query across knowledge summaries"),
|
|
42144
|
+
type: tool.schema.enum(["adr", "policy", "pattern", "spec"]).optional().describe("Filter by knowledge type"),
|
|
42145
|
+
layer: tool.schema.enum(["company", "org", "project"]).optional().describe("Filter by organizational layer"),
|
|
42146
|
+
severity: tool.schema.enum(["info", "warn", "block"]).optional().describe("Filter by severity level"),
|
|
42147
|
+
tags: tool.schema.array(tool.schema.string()).optional().describe("Filter by tags"),
|
|
42148
|
+
limit: tool.schema.number().optional().describe(`Maximum results to return (default: ${DEFAULT_QUERY_LIMIT})`)
|
|
42149
|
+
},
|
|
42150
|
+
execute: async (args) => {
|
|
42151
|
+
try {
|
|
42152
|
+
const types14 = args.type ? [args.type] : undefined;
|
|
42153
|
+
const results = await registry2.search({
|
|
42154
|
+
text: args.query ?? "",
|
|
42155
|
+
types: types14,
|
|
42156
|
+
layers: args.layer ? [args.layer] : undefined,
|
|
42157
|
+
limit: args.limit ?? DEFAULT_QUERY_LIMIT,
|
|
42158
|
+
includeContent: false
|
|
42159
|
+
});
|
|
42160
|
+
if (results.length === 0) {
|
|
42161
|
+
return "No knowledge items found matching the query.";
|
|
42162
|
+
}
|
|
42163
|
+
const lines = [`Found ${results.length} knowledge items:`, ""];
|
|
42164
|
+
for (const { item, score } of results) {
|
|
42165
|
+
const severity = item.metadata.severity ?? "info";
|
|
42166
|
+
lines.push(`**${item.id}** [${item.type}/${item.layer ?? "unknown"}] ${severity.toUpperCase()} (score: ${score.toFixed(2)})`);
|
|
42167
|
+
lines.push(` ${item.title}`);
|
|
42168
|
+
lines.push(` ${item.summary}`);
|
|
42169
|
+
if (item.metadata.tags && item.metadata.tags.length > 0) {
|
|
42170
|
+
lines.push(` Tags: ${item.metadata.tags.join(", ")}`);
|
|
42171
|
+
}
|
|
42172
|
+
lines.push(` Provider: ${item.provider}`);
|
|
42173
|
+
lines.push("");
|
|
42174
|
+
}
|
|
42175
|
+
return lines.join(`
|
|
42176
|
+
`);
|
|
42177
|
+
} catch (e) {
|
|
42178
|
+
return `Error querying knowledge: ${e instanceof Error ? e.message : String(e)}`;
|
|
42179
|
+
}
|
|
42180
|
+
}
|
|
42181
|
+
});
|
|
42182
|
+
const knowledge_list2 = tool({
|
|
42183
|
+
description: "List all knowledge items in the repository with statistics. " + "Provides an overview of ADRs, policies, patterns, and specs organized by layer and type.",
|
|
42184
|
+
args: {
|
|
42185
|
+
layer: tool.schema.enum(["company", "org", "project"]).optional().describe("Filter to specific layer"),
|
|
42186
|
+
type: tool.schema.enum(["adr", "policy", "pattern", "spec"]).optional().describe("Filter to specific type"),
|
|
42187
|
+
verbose: tool.schema.boolean().optional().describe("Include item summaries (default: false)")
|
|
42188
|
+
},
|
|
42189
|
+
execute: async (args) => {
|
|
42190
|
+
try {
|
|
42191
|
+
const health = await registry2.healthCheck();
|
|
42192
|
+
const providers = registry2.getProviders();
|
|
42193
|
+
const types14 = args.type ? [args.type] : undefined;
|
|
42194
|
+
const results = await registry2.search({
|
|
42195
|
+
text: "",
|
|
42196
|
+
types: types14,
|
|
42197
|
+
layers: args.layer ? [args.layer] : undefined,
|
|
42198
|
+
limit: 200,
|
|
42199
|
+
includeContent: false
|
|
42200
|
+
});
|
|
42201
|
+
const lines = [
|
|
42202
|
+
"# Knowledge Provider Statistics",
|
|
42203
|
+
"",
|
|
42204
|
+
`Total providers: ${providers.length}`,
|
|
42205
|
+
"",
|
|
42206
|
+
"## Providers"
|
|
42207
|
+
];
|
|
42208
|
+
for (const provider of providers) {
|
|
42209
|
+
const status = health.get(provider.name);
|
|
42210
|
+
const statusStr = status?.status ?? "unknown";
|
|
42211
|
+
lines.push(`- ${provider.name} (${provider.type}): ${statusStr}`);
|
|
42212
|
+
}
|
|
42213
|
+
lines.push("");
|
|
42214
|
+
lines.push("## Items Found");
|
|
42215
|
+
lines.push(`Total: ${results.length}`);
|
|
42216
|
+
lines.push("");
|
|
42217
|
+
const byType = {};
|
|
42218
|
+
const byLayer = {};
|
|
42219
|
+
const byProvider = {};
|
|
42220
|
+
for (const { item } of results) {
|
|
42221
|
+
byType[item.type] = (byType[item.type] ?? 0) + 1;
|
|
42222
|
+
byLayer[item.layer ?? "unknown"] = (byLayer[item.layer ?? "unknown"] ?? 0) + 1;
|
|
42223
|
+
byProvider[item.provider] = (byProvider[item.provider] ?? 0) + 1;
|
|
42224
|
+
}
|
|
42225
|
+
lines.push("### By Type");
|
|
42226
|
+
for (const [type2, count] of Object.entries(byType)) {
|
|
42227
|
+
lines.push(`- ${type2}: ${count}`);
|
|
42228
|
+
}
|
|
42229
|
+
lines.push("");
|
|
42230
|
+
lines.push("### By Layer");
|
|
42231
|
+
for (const [layer, count] of Object.entries(byLayer)) {
|
|
42232
|
+
lines.push(`- ${layer}: ${count}`);
|
|
42233
|
+
}
|
|
42234
|
+
lines.push("");
|
|
42235
|
+
lines.push("### By Provider");
|
|
42236
|
+
for (const [provider, count] of Object.entries(byProvider)) {
|
|
42237
|
+
lines.push(`- ${provider}: ${count}`);
|
|
42238
|
+
}
|
|
42239
|
+
if (args.verbose && results.length > 0) {
|
|
42240
|
+
lines.push("");
|
|
42241
|
+
lines.push("## Items");
|
|
42242
|
+
for (const { item } of results) {
|
|
42243
|
+
lines.push(`- **${item.id}** [${item.type}/${item.layer ?? "unknown"}] ${item.title}`);
|
|
42244
|
+
}
|
|
42245
|
+
}
|
|
42246
|
+
return lines.join(`
|
|
42247
|
+
`);
|
|
42248
|
+
} catch (e) {
|
|
42249
|
+
return `Error listing knowledge: ${e instanceof Error ? e.message : String(e)}`;
|
|
42250
|
+
}
|
|
42251
|
+
}
|
|
42252
|
+
});
|
|
42253
|
+
const knowledge_show2 = tool({
|
|
42254
|
+
description: "Show full details of a specific knowledge item by ID. " + "Includes complete content, constraints, metadata, and optionally version history.",
|
|
42255
|
+
args: {
|
|
42256
|
+
id: tool.schema.string().describe("The knowledge item ID to retrieve"),
|
|
42257
|
+
includeConstraints: tool.schema.boolean().optional().describe("Include constraint details (default: true)"),
|
|
42258
|
+
includeHistory: tool.schema.boolean().optional().describe("Include version history (default: false)")
|
|
42259
|
+
},
|
|
42260
|
+
execute: async (args) => {
|
|
42261
|
+
try {
|
|
42262
|
+
const item = await registry2.getById(args.id);
|
|
42263
|
+
if (!item) {
|
|
42264
|
+
return `Knowledge item not found: ${args.id}`;
|
|
42265
|
+
}
|
|
42266
|
+
const includeConstraints = args.includeConstraints ?? true;
|
|
42267
|
+
const lines = [
|
|
42268
|
+
`# ${item.title}`,
|
|
42269
|
+
"",
|
|
42270
|
+
`**ID:** ${item.id}`,
|
|
42271
|
+
`**Type:** ${item.type}`,
|
|
42272
|
+
`**Layer:** ${item.layer ?? "unknown"}`,
|
|
42273
|
+
`**Provider:** ${item.provider}`
|
|
42274
|
+
];
|
|
42275
|
+
if (item.metadata.severity) {
|
|
42276
|
+
lines.push(`**Severity:** ${item.metadata.severity}`);
|
|
42277
|
+
}
|
|
42278
|
+
if (item.createdAt) {
|
|
42279
|
+
lines.push(`**Created:** ${item.createdAt}`);
|
|
42280
|
+
}
|
|
42281
|
+
lines.push("");
|
|
42282
|
+
if (item.metadata.tags && item.metadata.tags.length > 0) {
|
|
42283
|
+
lines.push(`**Tags:** ${item.metadata.tags.join(", ")}`);
|
|
42284
|
+
lines.push("");
|
|
42285
|
+
}
|
|
42286
|
+
lines.push("## Summary");
|
|
42287
|
+
lines.push("");
|
|
42288
|
+
lines.push(item.summary);
|
|
42289
|
+
lines.push("");
|
|
42290
|
+
if (item.content) {
|
|
42291
|
+
lines.push("## Content");
|
|
42292
|
+
lines.push("");
|
|
42293
|
+
lines.push(item.content);
|
|
42294
|
+
lines.push("");
|
|
42295
|
+
}
|
|
42296
|
+
if (includeConstraints && item.metadata.extra?.constraints && Array.isArray(item.metadata.extra.constraints)) {
|
|
42297
|
+
const constraints = item.metadata.extra.constraints;
|
|
42298
|
+
if (constraints.length > 0) {
|
|
42299
|
+
lines.push("## Constraints");
|
|
42300
|
+
lines.push("");
|
|
42301
|
+
for (const c of constraints) {
|
|
42302
|
+
lines.push(`### ${c.id ?? "constraint"}`);
|
|
42303
|
+
if (c.operator)
|
|
42304
|
+
lines.push(`- **Operator:** ${c.operator}`);
|
|
42305
|
+
if (c.target)
|
|
42306
|
+
lines.push(`- **Target:** ${c.target}`);
|
|
42307
|
+
if (c.pattern)
|
|
42308
|
+
lines.push(`- **Pattern:** \`${c.pattern}\``);
|
|
42309
|
+
if (c.severity)
|
|
42310
|
+
lines.push(`- **Severity:** ${c.severity}`);
|
|
42311
|
+
if (c.message)
|
|
42312
|
+
lines.push(`- **Message:** ${c.message}`);
|
|
42313
|
+
if (c.appliesTo?.length)
|
|
42314
|
+
lines.push(`- **Applies To:** ${c.appliesTo.join(", ")}`);
|
|
42315
|
+
if (c.excludes?.length)
|
|
42316
|
+
lines.push(`- **Excludes:** ${c.excludes.join(", ")}`);
|
|
42317
|
+
lines.push("");
|
|
42318
|
+
}
|
|
42319
|
+
}
|
|
42320
|
+
}
|
|
42321
|
+
return lines.join(`
|
|
42322
|
+
`);
|
|
42323
|
+
} catch (e) {
|
|
42324
|
+
return `Error showing knowledge: ${e instanceof Error ? e.message : String(e)}`;
|
|
42325
|
+
}
|
|
42326
|
+
}
|
|
42327
|
+
});
|
|
42328
|
+
return {
|
|
42329
|
+
knowledge_query: knowledge_query2,
|
|
42330
|
+
knowledge_list: knowledge_list2,
|
|
42331
|
+
knowledge_show: knowledge_show2
|
|
42332
|
+
};
|
|
42333
|
+
}
|
|
42137
42334
|
// src/tools/interactive-bash/constants.ts
|
|
42138
42335
|
var DEFAULT_TIMEOUT_MS4 = 60000;
|
|
42139
42336
|
var BLOCKED_TMUX_SUBCOMMANDS = [
|
|
@@ -43580,399 +43777,1156 @@ class Mem0Adapter {
|
|
|
43580
43777
|
});
|
|
43581
43778
|
}
|
|
43582
43779
|
}
|
|
43583
|
-
// src/features/background-agent/manager.ts
|
|
43584
|
-
import { existsSync as existsSync48, readdirSync as readdirSync17 } from "fs";
|
|
43585
|
-
import { join as join61 } from "path";
|
|
43586
|
-
var TASK_TTL_MS = 30 * 60 * 1000;
|
|
43587
|
-
function getMessageDir11(sessionID) {
|
|
43588
|
-
if (!existsSync48(MESSAGE_STORAGE))
|
|
43589
|
-
return null;
|
|
43590
|
-
const directPath = join61(MESSAGE_STORAGE, sessionID);
|
|
43591
|
-
if (existsSync48(directPath))
|
|
43592
|
-
return directPath;
|
|
43593
|
-
for (const dir of readdirSync17(MESSAGE_STORAGE)) {
|
|
43594
|
-
const sessionPath = join61(MESSAGE_STORAGE, dir, sessionID);
|
|
43595
|
-
if (existsSync48(sessionPath))
|
|
43596
|
-
return sessionPath;
|
|
43597
|
-
}
|
|
43598
|
-
return null;
|
|
43599
|
-
}
|
|
43600
43780
|
|
|
43601
|
-
|
|
43602
|
-
|
|
43603
|
-
|
|
43604
|
-
|
|
43605
|
-
|
|
43606
|
-
|
|
43607
|
-
|
|
43608
|
-
|
|
43609
|
-
|
|
43610
|
-
|
|
43611
|
-
|
|
43781
|
+
// src/features/letta-memory/adapter.ts
|
|
43782
|
+
var DEFAULT_ENDPOINT2 = "http://localhost:8283";
|
|
43783
|
+
var DEFAULT_AGENT_PREFIX = "opencode";
|
|
43784
|
+
var DEFAULT_LLM_MODEL = "openai/gpt-4.1";
|
|
43785
|
+
var DEFAULT_EMBEDDING_MODEL = "openai/text-embedding-3-small";
|
|
43786
|
+
|
|
43787
|
+
class LettaAdapter {
|
|
43788
|
+
config;
|
|
43789
|
+
endpoint;
|
|
43790
|
+
agentCache = new Map;
|
|
43791
|
+
constructor(config3) {
|
|
43792
|
+
this.config = config3;
|
|
43793
|
+
this.endpoint = config3.endpoint ?? DEFAULT_ENDPOINT2;
|
|
43612
43794
|
}
|
|
43613
|
-
async
|
|
43614
|
-
if (!
|
|
43615
|
-
throw new Error("
|
|
43795
|
+
async add(input) {
|
|
43796
|
+
if (!this.config.enabled) {
|
|
43797
|
+
throw new Error("Letta is not enabled");
|
|
43616
43798
|
}
|
|
43617
|
-
const
|
|
43618
|
-
|
|
43619
|
-
|
|
43620
|
-
|
|
43621
|
-
}
|
|
43799
|
+
const agent = await this.getOrCreateAgent(input.layer);
|
|
43800
|
+
const tags = [
|
|
43801
|
+
`layer:${input.layer}`,
|
|
43802
|
+
...input.tags ?? [],
|
|
43803
|
+
...input.metadata ? Object.entries(input.metadata).map(([k, v]) => `${k}:${v}`) : []
|
|
43804
|
+
];
|
|
43805
|
+
const response2 = await this.request(`/v1/agents/${agent.id}/archival-memory`, {
|
|
43806
|
+
method: "POST",
|
|
43807
|
+
body: JSON.stringify({
|
|
43808
|
+
text: input.content,
|
|
43809
|
+
tags
|
|
43810
|
+
})
|
|
43622
43811
|
});
|
|
43623
|
-
|
|
43624
|
-
|
|
43812
|
+
const passage = await response2.json();
|
|
43813
|
+
return this.passageToMemory(passage, input.layer, agent.id);
|
|
43814
|
+
}
|
|
43815
|
+
async search(input) {
|
|
43816
|
+
if (!this.config.enabled) {
|
|
43817
|
+
throw new Error("Letta is not enabled");
|
|
43625
43818
|
}
|
|
43626
|
-
const
|
|
43627
|
-
|
|
43628
|
-
const
|
|
43629
|
-
|
|
43630
|
-
|
|
43631
|
-
|
|
43632
|
-
|
|
43633
|
-
|
|
43634
|
-
|
|
43635
|
-
|
|
43636
|
-
|
|
43637
|
-
|
|
43638
|
-
|
|
43639
|
-
|
|
43640
|
-
|
|
43641
|
-
|
|
43642
|
-
|
|
43643
|
-
|
|
43644
|
-
|
|
43645
|
-
|
|
43646
|
-
|
|
43647
|
-
|
|
43648
|
-
|
|
43649
|
-
|
|
43650
|
-
agent: input.agent,
|
|
43651
|
-
tools: {
|
|
43652
|
-
task: false,
|
|
43653
|
-
background_task: false
|
|
43654
|
-
},
|
|
43655
|
-
parts: [{ type: "text", text: input.prompt }]
|
|
43819
|
+
const layers = this.normalizeLayers(input.layer);
|
|
43820
|
+
const results = [];
|
|
43821
|
+
for (const layer of layers) {
|
|
43822
|
+
try {
|
|
43823
|
+
const agent = await this.getAgent(layer);
|
|
43824
|
+
if (!agent)
|
|
43825
|
+
continue;
|
|
43826
|
+
const params = new URLSearchParams;
|
|
43827
|
+
params.set("query", input.query);
|
|
43828
|
+
if (input.limit)
|
|
43829
|
+
params.set("limit", String(input.limit));
|
|
43830
|
+
if (input.tags?.length) {
|
|
43831
|
+
params.set("tags", input.tags.join(","));
|
|
43832
|
+
params.set("tag_match_mode", input.tagMatchMode ?? "any");
|
|
43833
|
+
}
|
|
43834
|
+
const response2 = await this.request(`/v1/agents/${agent.id}/archival-memory/search?${params.toString()}`, { method: "GET" });
|
|
43835
|
+
const data = await response2.json();
|
|
43836
|
+
const layerResults = data.map((passage, index) => ({
|
|
43837
|
+
memory: this.passageToMemory(passage, layer, agent.id),
|
|
43838
|
+
score: 1 - index * 0.05
|
|
43839
|
+
}));
|
|
43840
|
+
results.push(...layerResults);
|
|
43841
|
+
} catch {
|
|
43842
|
+
continue;
|
|
43656
43843
|
}
|
|
43657
|
-
}
|
|
43658
|
-
|
|
43659
|
-
|
|
43660
|
-
|
|
43661
|
-
|
|
43662
|
-
|
|
43663
|
-
|
|
43664
|
-
|
|
43665
|
-
|
|
43666
|
-
|
|
43844
|
+
}
|
|
43845
|
+
return results.filter((r) => !input.threshold || r.score >= input.threshold).sort((a, b) => b.score - a.score).slice(0, input.limit ?? 10);
|
|
43846
|
+
}
|
|
43847
|
+
async get(id) {
|
|
43848
|
+
if (!this.config.enabled) {
|
|
43849
|
+
throw new Error("Letta is not enabled");
|
|
43850
|
+
}
|
|
43851
|
+
for (const layer of this.getAllLayers()) {
|
|
43852
|
+
try {
|
|
43853
|
+
const agent = await this.getAgent(layer);
|
|
43854
|
+
if (!agent)
|
|
43855
|
+
continue;
|
|
43856
|
+
const response2 = await this.request(`/v1/agents/${agent.id}/archival-memory`, { method: "GET" });
|
|
43857
|
+
const passages = await response2.json();
|
|
43858
|
+
const passage = passages.find((p) => p.id === id);
|
|
43859
|
+
if (passage) {
|
|
43860
|
+
return this.passageToMemory(passage, layer, agent.id);
|
|
43667
43861
|
}
|
|
43668
|
-
|
|
43669
|
-
|
|
43670
|
-
this.notifyParentSession(existingTask);
|
|
43862
|
+
} catch {
|
|
43863
|
+
continue;
|
|
43671
43864
|
}
|
|
43672
|
-
}
|
|
43673
|
-
return
|
|
43865
|
+
}
|
|
43866
|
+
return null;
|
|
43674
43867
|
}
|
|
43675
|
-
|
|
43676
|
-
|
|
43868
|
+
async update(input) {
|
|
43869
|
+
if (!this.config.enabled) {
|
|
43870
|
+
throw new Error("Letta is not enabled");
|
|
43871
|
+
}
|
|
43872
|
+
const existing = await this.get(input.id);
|
|
43873
|
+
if (!existing) {
|
|
43874
|
+
throw new Error(`Memory not found: ${input.id}`);
|
|
43875
|
+
}
|
|
43876
|
+
await this.delete(input.id);
|
|
43877
|
+
return this.add({
|
|
43878
|
+
content: input.content ?? existing.content,
|
|
43879
|
+
layer: existing.layer,
|
|
43880
|
+
metadata: input.metadata ? { ...existing.metadata, ...input.metadata } : existing.metadata,
|
|
43881
|
+
tags: input.tags
|
|
43882
|
+
});
|
|
43677
43883
|
}
|
|
43678
|
-
|
|
43679
|
-
|
|
43680
|
-
|
|
43681
|
-
|
|
43682
|
-
|
|
43884
|
+
async delete(id) {
|
|
43885
|
+
if (!this.config.enabled) {
|
|
43886
|
+
throw new Error("Letta is not enabled");
|
|
43887
|
+
}
|
|
43888
|
+
for (const layer of this.getAllLayers()) {
|
|
43889
|
+
try {
|
|
43890
|
+
const agent = await this.getAgent(layer);
|
|
43891
|
+
if (!agent)
|
|
43892
|
+
continue;
|
|
43893
|
+
await this.request(`/v1/agents/${agent.id}/archival-memory/${id}`, {
|
|
43894
|
+
method: "DELETE"
|
|
43895
|
+
});
|
|
43896
|
+
return;
|
|
43897
|
+
} catch {
|
|
43898
|
+
continue;
|
|
43683
43899
|
}
|
|
43684
43900
|
}
|
|
43685
|
-
|
|
43901
|
+
throw new Error(`Memory not found: ${id}`);
|
|
43686
43902
|
}
|
|
43687
|
-
|
|
43688
|
-
|
|
43689
|
-
|
|
43690
|
-
for (const child of directChildren) {
|
|
43691
|
-
result.push(child);
|
|
43692
|
-
const descendants = this.getAllDescendantTasks(child.sessionID);
|
|
43693
|
-
result.push(...descendants);
|
|
43903
|
+
async getAll(layer) {
|
|
43904
|
+
if (!this.config.enabled) {
|
|
43905
|
+
throw new Error("Letta is not enabled");
|
|
43694
43906
|
}
|
|
43695
|
-
|
|
43696
|
-
|
|
43697
|
-
|
|
43698
|
-
|
|
43699
|
-
|
|
43700
|
-
|
|
43907
|
+
const layers = layer ? [layer] : this.getAllLayers();
|
|
43908
|
+
const memories = [];
|
|
43909
|
+
for (const l of layers) {
|
|
43910
|
+
try {
|
|
43911
|
+
const agent = await this.getAgent(l);
|
|
43912
|
+
if (!agent)
|
|
43913
|
+
continue;
|
|
43914
|
+
const response2 = await this.request(`/v1/agents/${agent.id}/archival-memory`, { method: "GET" });
|
|
43915
|
+
const passages = await response2.json();
|
|
43916
|
+
memories.push(...passages.map((p) => this.passageToMemory(p, l, agent.id)));
|
|
43917
|
+
} catch {
|
|
43918
|
+
continue;
|
|
43701
43919
|
}
|
|
43702
43920
|
}
|
|
43703
|
-
return;
|
|
43921
|
+
return memories;
|
|
43704
43922
|
}
|
|
43705
|
-
async
|
|
43923
|
+
async getStats() {
|
|
43924
|
+
const memories = await this.getAll();
|
|
43925
|
+
const byLayer = {
|
|
43926
|
+
user: 0,
|
|
43927
|
+
session: 0,
|
|
43928
|
+
project: 0,
|
|
43929
|
+
team: 0,
|
|
43930
|
+
org: 0,
|
|
43931
|
+
company: 0,
|
|
43932
|
+
agent: 0
|
|
43933
|
+
};
|
|
43934
|
+
for (const memory of memories) {
|
|
43935
|
+
byLayer[memory.layer]++;
|
|
43936
|
+
}
|
|
43937
|
+
const agents = await this.listAgents();
|
|
43938
|
+
return {
|
|
43939
|
+
totalMemories: memories.length,
|
|
43940
|
+
byLayer,
|
|
43941
|
+
totalAgents: agents.length,
|
|
43942
|
+
totalPassages: memories.length
|
|
43943
|
+
};
|
|
43944
|
+
}
|
|
43945
|
+
async isAvailable() {
|
|
43706
43946
|
try {
|
|
43707
|
-
const response2 = await this.
|
|
43708
|
-
|
|
43947
|
+
const response2 = await fetch(`${this.endpoint}/v1/health`, {
|
|
43948
|
+
method: "GET",
|
|
43949
|
+
signal: AbortSignal.timeout(5000)
|
|
43709
43950
|
});
|
|
43710
|
-
|
|
43711
|
-
if (!todos || todos.length === 0)
|
|
43712
|
-
return false;
|
|
43713
|
-
const incomplete = todos.filter((t) => t.status !== "completed" && t.status !== "cancelled");
|
|
43714
|
-
return incomplete.length > 0;
|
|
43951
|
+
return response2.ok;
|
|
43715
43952
|
} catch {
|
|
43716
43953
|
return false;
|
|
43717
43954
|
}
|
|
43718
43955
|
}
|
|
43719
|
-
|
|
43720
|
-
const
|
|
43721
|
-
if (
|
|
43722
|
-
|
|
43723
|
-
|
|
43724
|
-
|
|
43725
|
-
|
|
43726
|
-
|
|
43727
|
-
|
|
43728
|
-
|
|
43729
|
-
|
|
43730
|
-
|
|
43731
|
-
|
|
43732
|
-
|
|
43733
|
-
|
|
43734
|
-
|
|
43735
|
-
|
|
43736
|
-
|
|
43737
|
-
|
|
43738
|
-
task.progress.toolCalls += 1;
|
|
43739
|
-
task.progress.lastTool = partInfo.tool;
|
|
43740
|
-
task.progress.lastUpdate = new Date;
|
|
43741
|
-
}
|
|
43742
|
-
}
|
|
43743
|
-
if (event.type === "session.idle") {
|
|
43744
|
-
const sessionID = props?.sessionID;
|
|
43745
|
-
if (!sessionID)
|
|
43746
|
-
return;
|
|
43747
|
-
const task = this.findBySession(sessionID);
|
|
43748
|
-
if (!task || task.status !== "running")
|
|
43749
|
-
return;
|
|
43750
|
-
this.checkSessionTodos(sessionID).then((hasIncompleteTodos2) => {
|
|
43751
|
-
if (hasIncompleteTodos2) {
|
|
43752
|
-
log("[background-agent] Task has incomplete todos, waiting for todo-continuation:", task.id);
|
|
43753
|
-
return;
|
|
43956
|
+
async getOrCreateAgent(layer) {
|
|
43957
|
+
const existing = await this.getAgent(layer);
|
|
43958
|
+
if (existing)
|
|
43959
|
+
return existing;
|
|
43960
|
+
const agentName = this.getAgentName(layer);
|
|
43961
|
+
const response2 = await this.request("/v1/agents", {
|
|
43962
|
+
method: "POST",
|
|
43963
|
+
body: JSON.stringify({
|
|
43964
|
+
name: agentName,
|
|
43965
|
+
model: this.config.llmModel ?? DEFAULT_LLM_MODEL,
|
|
43966
|
+
embedding: this.config.embeddingModel ?? DEFAULT_EMBEDDING_MODEL,
|
|
43967
|
+
memory_blocks: [
|
|
43968
|
+
{ label: "persona", value: `OpenCode memory agent for ${layer} layer` },
|
|
43969
|
+
{ label: "human", value: this.getUserId(layer) }
|
|
43970
|
+
],
|
|
43971
|
+
metadata: {
|
|
43972
|
+
layer,
|
|
43973
|
+
user_id: this.getUserId(layer),
|
|
43974
|
+
created_by: "oh-my-opencode"
|
|
43754
43975
|
}
|
|
43755
|
-
|
|
43756
|
-
|
|
43757
|
-
|
|
43758
|
-
|
|
43759
|
-
|
|
43760
|
-
|
|
43976
|
+
})
|
|
43977
|
+
});
|
|
43978
|
+
const agent = await response2.json();
|
|
43979
|
+
this.agentCache.set(layer, agent);
|
|
43980
|
+
return agent;
|
|
43981
|
+
}
|
|
43982
|
+
async getAgent(layer) {
|
|
43983
|
+
if (this.agentCache.has(layer)) {
|
|
43984
|
+
return this.agentCache.get(layer);
|
|
43761
43985
|
}
|
|
43762
|
-
|
|
43763
|
-
|
|
43764
|
-
|
|
43765
|
-
|
|
43766
|
-
|
|
43767
|
-
const task = this.findBySession(sessionID);
|
|
43768
|
-
if (!task)
|
|
43769
|
-
return;
|
|
43770
|
-
if (task.status === "running") {
|
|
43771
|
-
task.status = "cancelled";
|
|
43772
|
-
task.completedAt = new Date;
|
|
43773
|
-
task.error = "Session deleted";
|
|
43774
|
-
}
|
|
43775
|
-
this.tasks.delete(task.id);
|
|
43776
|
-
this.clearNotificationsForTask(task.id);
|
|
43777
|
-
subagentSessions.delete(sessionID);
|
|
43986
|
+
const agentName = this.getAgentName(layer);
|
|
43987
|
+
const agents = await this.listAgents();
|
|
43988
|
+
const agent = agents.find((a) => a.name === agentName);
|
|
43989
|
+
if (agent) {
|
|
43990
|
+
this.agentCache.set(layer, agent);
|
|
43778
43991
|
}
|
|
43992
|
+
return agent ?? null;
|
|
43779
43993
|
}
|
|
43780
|
-
|
|
43781
|
-
|
|
43782
|
-
|
|
43783
|
-
|
|
43994
|
+
async listAgents() {
|
|
43995
|
+
try {
|
|
43996
|
+
const response2 = await this.request("/v1/agents", { method: "GET" });
|
|
43997
|
+
const data = await response2.json();
|
|
43998
|
+
return Array.isArray(data) ? data : [];
|
|
43999
|
+
} catch {
|
|
44000
|
+
return [];
|
|
44001
|
+
}
|
|
43784
44002
|
}
|
|
43785
|
-
|
|
43786
|
-
|
|
44003
|
+
async request(path7, options) {
|
|
44004
|
+
const headers = {
|
|
44005
|
+
"Content-Type": "application/json"
|
|
44006
|
+
};
|
|
44007
|
+
if (this.config.apiKey) {
|
|
44008
|
+
headers["Authorization"] = `Bearer ${this.config.apiKey}`;
|
|
44009
|
+
}
|
|
44010
|
+
const response2 = await fetch(`${this.endpoint}${path7}`, {
|
|
44011
|
+
method: options.method,
|
|
44012
|
+
headers,
|
|
44013
|
+
body: options.body
|
|
44014
|
+
});
|
|
44015
|
+
if (!response2.ok) {
|
|
44016
|
+
const text = await response2.text().catch(() => "");
|
|
44017
|
+
throw new Error(`Letta API error: ${response2.status} ${response2.statusText} - ${text}`);
|
|
44018
|
+
}
|
|
44019
|
+
return response2;
|
|
43787
44020
|
}
|
|
43788
|
-
|
|
43789
|
-
this.
|
|
44021
|
+
getAgentName(layer) {
|
|
44022
|
+
const prefix = this.config.agentPrefix ?? DEFAULT_AGENT_PREFIX;
|
|
44023
|
+
const userId = this.getUserId(layer);
|
|
44024
|
+
return `${prefix}-${layer}-${userId}`;
|
|
43790
44025
|
}
|
|
43791
|
-
|
|
43792
|
-
|
|
43793
|
-
|
|
43794
|
-
|
|
43795
|
-
|
|
43796
|
-
|
|
43797
|
-
|
|
43798
|
-
|
|
44026
|
+
getUserId(layer) {
|
|
44027
|
+
switch (layer) {
|
|
44028
|
+
case "user":
|
|
44029
|
+
return this.config.userId ?? "default-user";
|
|
44030
|
+
case "session":
|
|
44031
|
+
return `session-${this.config.userId ?? "default"}`;
|
|
44032
|
+
case "project":
|
|
44033
|
+
return this.config.projectId ?? "default-project";
|
|
44034
|
+
case "team":
|
|
44035
|
+
return this.config.teamId ?? "default-team";
|
|
44036
|
+
case "org":
|
|
44037
|
+
return this.config.orgId ?? "default-org";
|
|
44038
|
+
case "company":
|
|
44039
|
+
return this.config.companyId ?? "default-company";
|
|
44040
|
+
case "agent":
|
|
44041
|
+
return "default-agent";
|
|
43799
44042
|
}
|
|
43800
44043
|
}
|
|
43801
|
-
|
|
43802
|
-
if (
|
|
43803
|
-
return;
|
|
43804
|
-
|
|
43805
|
-
this.pollRunningTasks();
|
|
43806
|
-
}, 2000);
|
|
43807
|
-
this.pollingInterval.unref();
|
|
44044
|
+
normalizeLayers(layer) {
|
|
44045
|
+
if (!layer)
|
|
44046
|
+
return this.getAllLayers();
|
|
44047
|
+
return Array.isArray(layer) ? layer : [layer];
|
|
43808
44048
|
}
|
|
43809
|
-
|
|
43810
|
-
|
|
43811
|
-
|
|
43812
|
-
|
|
44049
|
+
getAllLayers() {
|
|
44050
|
+
return ["user", "session", "project", "team", "org", "company", "agent"];
|
|
44051
|
+
}
|
|
44052
|
+
passageToMemory(passage, layer, agentId) {
|
|
44053
|
+
return {
|
|
44054
|
+
id: passage.id,
|
|
44055
|
+
content: passage.text,
|
|
44056
|
+
layer,
|
|
44057
|
+
metadata: passage.metadata,
|
|
44058
|
+
createdAt: passage.created_at,
|
|
44059
|
+
source: "passage",
|
|
44060
|
+
agentId
|
|
44061
|
+
};
|
|
44062
|
+
}
|
|
44063
|
+
}
|
|
44064
|
+
// src/features/knowledge-provider/registry.ts
|
|
44065
|
+
var DEFAULT_CONFIG2 = {
|
|
44066
|
+
defaultLimit: 10,
|
|
44067
|
+
defaultThreshold: 0.5,
|
|
44068
|
+
mergeStrategy: "score",
|
|
44069
|
+
deduplicate: true
|
|
44070
|
+
};
|
|
44071
|
+
|
|
44072
|
+
class KnowledgeProviderRegistry {
|
|
44073
|
+
providers = new Map;
|
|
44074
|
+
config;
|
|
44075
|
+
constructor(config3) {
|
|
44076
|
+
this.config = { ...DEFAULT_CONFIG2, ...config3 };
|
|
44077
|
+
}
|
|
44078
|
+
async register(provider) {
|
|
44079
|
+
if (this.providers.has(provider.name)) {
|
|
44080
|
+
throw new Error(`Provider "${provider.name}" is already registered`);
|
|
43813
44081
|
}
|
|
44082
|
+
await provider.initialize();
|
|
44083
|
+
this.providers.set(provider.name, provider);
|
|
43814
44084
|
}
|
|
43815
|
-
|
|
43816
|
-
this.
|
|
43817
|
-
|
|
43818
|
-
|
|
44085
|
+
async unregister(name) {
|
|
44086
|
+
const provider = this.providers.get(name);
|
|
44087
|
+
if (!provider) {
|
|
44088
|
+
return;
|
|
44089
|
+
}
|
|
44090
|
+
if (provider.dispose) {
|
|
44091
|
+
await provider.dispose();
|
|
44092
|
+
}
|
|
44093
|
+
this.providers.delete(name);
|
|
43819
44094
|
}
|
|
43820
|
-
|
|
43821
|
-
const
|
|
43822
|
-
|
|
43823
|
-
|
|
43824
|
-
if (tuiClient.tui?.showToast) {
|
|
43825
|
-
tuiClient.tui.showToast({
|
|
43826
|
-
body: {
|
|
43827
|
-
title: "Background Task Completed",
|
|
43828
|
-
message: `Task "${task.description}" finished in ${duration3}.`,
|
|
43829
|
-
variant: "success",
|
|
43830
|
-
duration: 5000
|
|
43831
|
-
}
|
|
43832
|
-
}).catch(() => {});
|
|
44095
|
+
async search(query) {
|
|
44096
|
+
const targetProviders = this.getTargetProviders(query.providers);
|
|
44097
|
+
if (targetProviders.length === 0) {
|
|
44098
|
+
return [];
|
|
43833
44099
|
}
|
|
43834
|
-
const
|
|
43835
|
-
|
|
43836
|
-
const
|
|
43837
|
-
setTimeout(async () => {
|
|
44100
|
+
const limit = query.limit ?? this.config.defaultLimit;
|
|
44101
|
+
const threshold = query.threshold ?? this.config.defaultThreshold;
|
|
44102
|
+
const searchPromises = targetProviders.map(async (provider) => {
|
|
43838
44103
|
try {
|
|
43839
|
-
const
|
|
43840
|
-
|
|
43841
|
-
|
|
43842
|
-
|
|
43843
|
-
await this.client.session.prompt({
|
|
43844
|
-
path: { id: task.parentSessionID },
|
|
43845
|
-
body: {
|
|
43846
|
-
agent: prevMessage?.agent,
|
|
43847
|
-
model: modelField,
|
|
43848
|
-
parts: [{ type: "text", text: message }]
|
|
43849
|
-
},
|
|
43850
|
-
query: { directory: this.directory }
|
|
44104
|
+
const results = await provider.search({
|
|
44105
|
+
...query,
|
|
44106
|
+
limit: limit * 2,
|
|
44107
|
+
threshold
|
|
43851
44108
|
});
|
|
43852
|
-
|
|
43853
|
-
} catch
|
|
43854
|
-
|
|
43855
|
-
} finally {
|
|
43856
|
-
this.clearNotificationsForTask(taskId);
|
|
43857
|
-
this.tasks.delete(taskId);
|
|
43858
|
-
log("[background-agent] Removed completed task from memory:", taskId);
|
|
44109
|
+
return { provider: provider.name, results };
|
|
44110
|
+
} catch {
|
|
44111
|
+
return { provider: provider.name, results: [] };
|
|
43859
44112
|
}
|
|
43860
|
-
}
|
|
43861
|
-
|
|
43862
|
-
|
|
43863
|
-
|
|
43864
|
-
|
|
43865
|
-
const minutes = Math.floor(seconds / 60);
|
|
43866
|
-
const hours = Math.floor(minutes / 60);
|
|
43867
|
-
if (hours > 0) {
|
|
43868
|
-
return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
|
|
43869
|
-
} else if (minutes > 0) {
|
|
43870
|
-
return `${minutes}m ${seconds % 60}s`;
|
|
44113
|
+
});
|
|
44114
|
+
const allResults = await Promise.all(searchPromises);
|
|
44115
|
+
const merged = this.mergeResults(allResults.flatMap((r) => r.results), this.config.mergeStrategy, limit);
|
|
44116
|
+
if (this.config.deduplicate) {
|
|
44117
|
+
return this.deduplicateResults(merged);
|
|
43871
44118
|
}
|
|
43872
|
-
return
|
|
44119
|
+
return merged.slice(0, limit);
|
|
43873
44120
|
}
|
|
43874
|
-
|
|
43875
|
-
|
|
43876
|
-
|
|
43877
|
-
|
|
44121
|
+
async getById(id) {
|
|
44122
|
+
const [providerName, itemId] = this.parseId(id);
|
|
44123
|
+
if (providerName) {
|
|
44124
|
+
const provider = this.providers.get(providerName);
|
|
44125
|
+
if (provider?.getById) {
|
|
44126
|
+
return provider.getById(itemId);
|
|
44127
|
+
}
|
|
44128
|
+
return null;
|
|
43878
44129
|
}
|
|
43879
|
-
|
|
43880
|
-
|
|
43881
|
-
|
|
43882
|
-
|
|
43883
|
-
|
|
43884
|
-
|
|
43885
|
-
if (age > TASK_TTL_MS) {
|
|
43886
|
-
log("[background-agent] Pruning stale task:", { taskId, age: Math.round(age / 1000) + "s" });
|
|
43887
|
-
task.status = "error";
|
|
43888
|
-
task.error = "Task timed out after 30 minutes";
|
|
43889
|
-
task.completedAt = new Date;
|
|
43890
|
-
this.clearNotificationsForTask(taskId);
|
|
43891
|
-
this.tasks.delete(taskId);
|
|
43892
|
-
subagentSessions.delete(task.sessionID);
|
|
44130
|
+
for (const provider of this.providers.values()) {
|
|
44131
|
+
if (provider.getById) {
|
|
44132
|
+
const item = await provider.getById(id);
|
|
44133
|
+
if (item) {
|
|
44134
|
+
return item;
|
|
44135
|
+
}
|
|
43893
44136
|
}
|
|
43894
44137
|
}
|
|
43895
|
-
|
|
43896
|
-
|
|
43897
|
-
|
|
43898
|
-
|
|
44138
|
+
return null;
|
|
44139
|
+
}
|
|
44140
|
+
getProviders() {
|
|
44141
|
+
return Array.from(this.providers.values());
|
|
44142
|
+
}
|
|
44143
|
+
getProvider(name) {
|
|
44144
|
+
return this.providers.get(name);
|
|
44145
|
+
}
|
|
44146
|
+
async healthCheck() {
|
|
44147
|
+
const results = new Map;
|
|
44148
|
+
const checks3 = Array.from(this.providers.entries()).map(async ([name, provider]) => {
|
|
44149
|
+
try {
|
|
44150
|
+
const health = await provider.healthCheck();
|
|
44151
|
+
results.set(name, health);
|
|
44152
|
+
} catch (error45) {
|
|
44153
|
+
results.set(name, {
|
|
44154
|
+
status: "unavailable",
|
|
44155
|
+
message: error45 instanceof Error ? error45.message : "Unknown error",
|
|
44156
|
+
lastChecked: new Date().toISOString()
|
|
44157
|
+
});
|
|
43899
44158
|
}
|
|
43900
|
-
|
|
43901
|
-
|
|
43902
|
-
|
|
43903
|
-
|
|
43904
|
-
|
|
43905
|
-
|
|
43906
|
-
|
|
43907
|
-
|
|
44159
|
+
});
|
|
44160
|
+
await Promise.all(checks3);
|
|
44161
|
+
return results;
|
|
44162
|
+
}
|
|
44163
|
+
getTargetProviders(filterNames) {
|
|
44164
|
+
if (!filterNames || filterNames.length === 0) {
|
|
44165
|
+
return Array.from(this.providers.values());
|
|
44166
|
+
}
|
|
44167
|
+
return filterNames.map((name) => this.providers.get(name)).filter((p) => p !== undefined);
|
|
44168
|
+
}
|
|
44169
|
+
mergeResults(results, strategy, limit) {
|
|
44170
|
+
switch (strategy) {
|
|
44171
|
+
case "score":
|
|
44172
|
+
return results.sort((a, b) => b.score - a.score).slice(0, limit);
|
|
44173
|
+
case "round-robin":
|
|
44174
|
+
return this.roundRobinMerge(results, limit);
|
|
44175
|
+
case "provider-priority":
|
|
44176
|
+
return this.priorityMerge(results, limit);
|
|
44177
|
+
default:
|
|
44178
|
+
return results.sort((a, b) => b.score - a.score).slice(0, limit);
|
|
44179
|
+
}
|
|
44180
|
+
}
|
|
44181
|
+
roundRobinMerge(results, limit) {
|
|
44182
|
+
const byProvider = new Map;
|
|
44183
|
+
for (const result of results) {
|
|
44184
|
+
const provider = result.item.provider;
|
|
44185
|
+
const existing = byProvider.get(provider) ?? [];
|
|
44186
|
+
existing.push(result);
|
|
44187
|
+
byProvider.set(provider, existing);
|
|
44188
|
+
}
|
|
44189
|
+
for (const [provider, items] of byProvider) {
|
|
44190
|
+
byProvider.set(provider, items.sort((a, b) => b.score - a.score));
|
|
44191
|
+
}
|
|
44192
|
+
const merged = [];
|
|
44193
|
+
const providers = Array.from(byProvider.keys());
|
|
44194
|
+
let index = 0;
|
|
44195
|
+
while (merged.length < limit) {
|
|
44196
|
+
let added = false;
|
|
44197
|
+
for (const provider of providers) {
|
|
44198
|
+
const items = byProvider.get(provider);
|
|
44199
|
+
if (index < items.length) {
|
|
44200
|
+
merged.push(items[index]);
|
|
44201
|
+
added = true;
|
|
44202
|
+
if (merged.length >= limit)
|
|
44203
|
+
break;
|
|
44204
|
+
}
|
|
43908
44205
|
}
|
|
44206
|
+
if (!added)
|
|
44207
|
+
break;
|
|
44208
|
+
index++;
|
|
43909
44209
|
}
|
|
44210
|
+
return merged;
|
|
43910
44211
|
}
|
|
43911
|
-
|
|
43912
|
-
this.
|
|
43913
|
-
|
|
43914
|
-
|
|
43915
|
-
|
|
43916
|
-
|
|
43917
|
-
|
|
43918
|
-
|
|
43919
|
-
|
|
43920
|
-
|
|
43921
|
-
|
|
43922
|
-
|
|
43923
|
-
|
|
43924
|
-
|
|
43925
|
-
|
|
43926
|
-
|
|
43927
|
-
|
|
43928
|
-
|
|
43929
|
-
|
|
43930
|
-
|
|
43931
|
-
|
|
43932
|
-
|
|
43933
|
-
|
|
43934
|
-
|
|
43935
|
-
|
|
44212
|
+
priorityMerge(results, limit) {
|
|
44213
|
+
const priority = this.config.providerPriority ?? [];
|
|
44214
|
+
return results.sort((a, b) => {
|
|
44215
|
+
const aPriority = priority.indexOf(a.item.provider);
|
|
44216
|
+
const bPriority = priority.indexOf(b.item.provider);
|
|
44217
|
+
const aOrder = aPriority === -1 ? Infinity : aPriority;
|
|
44218
|
+
const bOrder = bPriority === -1 ? Infinity : bPriority;
|
|
44219
|
+
if (aOrder !== bOrder) {
|
|
44220
|
+
return aOrder - bOrder;
|
|
44221
|
+
}
|
|
44222
|
+
return b.score - a.score;
|
|
44223
|
+
}).slice(0, limit);
|
|
44224
|
+
}
|
|
44225
|
+
deduplicateResults(results) {
|
|
44226
|
+
const seen = new Set;
|
|
44227
|
+
const deduplicated = [];
|
|
44228
|
+
for (const result of results) {
|
|
44229
|
+
const hash2 = this.contentHash(result.item);
|
|
44230
|
+
if (!seen.has(hash2)) {
|
|
44231
|
+
seen.add(hash2);
|
|
44232
|
+
deduplicated.push(result);
|
|
44233
|
+
}
|
|
44234
|
+
}
|
|
44235
|
+
return deduplicated;
|
|
44236
|
+
}
|
|
44237
|
+
contentHash(item) {
|
|
44238
|
+
const content = item.content ?? item.summary;
|
|
44239
|
+
return `${item.title}:${content.slice(0, 200)}`;
|
|
44240
|
+
}
|
|
44241
|
+
parseId(id) {
|
|
44242
|
+
const separator = "::";
|
|
44243
|
+
const index = id.indexOf(separator);
|
|
44244
|
+
if (index === -1) {
|
|
44245
|
+
return [null, id];
|
|
44246
|
+
}
|
|
44247
|
+
return [id.slice(0, index), id.slice(index + separator.length)];
|
|
44248
|
+
}
|
|
44249
|
+
}
|
|
44250
|
+
// src/features/knowledge-provider/providers/local.ts
|
|
44251
|
+
var DEFAULT_CONFIG3 = {
|
|
44252
|
+
enabled: true,
|
|
44253
|
+
rootDir: ".opencode/knowledge"
|
|
44254
|
+
};
|
|
44255
|
+
|
|
44256
|
+
class LocalKnowledgeProvider {
|
|
44257
|
+
name = "local";
|
|
44258
|
+
type = "local";
|
|
44259
|
+
description = "Local file-based knowledge repository";
|
|
44260
|
+
config;
|
|
44261
|
+
repository = null;
|
|
44262
|
+
initialized = false;
|
|
44263
|
+
constructor(config3) {
|
|
44264
|
+
this.config = { ...DEFAULT_CONFIG3, ...config3 };
|
|
44265
|
+
}
|
|
44266
|
+
async initialize() {
|
|
44267
|
+
if (!this.config.enabled) {
|
|
44268
|
+
return;
|
|
44269
|
+
}
|
|
44270
|
+
this.repository = new KnowledgeRepository({
|
|
44271
|
+
rootDir: this.config.rootDir ?? DEFAULT_CONFIG3.rootDir
|
|
44272
|
+
});
|
|
44273
|
+
await this.repository.initialize();
|
|
44274
|
+
this.initialized = true;
|
|
44275
|
+
}
|
|
44276
|
+
async search(query) {
|
|
44277
|
+
if (!this.initialized || !this.repository) {
|
|
44278
|
+
return [];
|
|
44279
|
+
}
|
|
44280
|
+
const filter = {
|
|
44281
|
+
search: query.text,
|
|
44282
|
+
limit: query.limit ?? 10
|
|
44283
|
+
};
|
|
44284
|
+
if (query.layers && query.layers.length > 0) {
|
|
44285
|
+
const validLayers = query.layers.filter(this.isKnowledgeLayer);
|
|
44286
|
+
if (validLayers.length > 0) {
|
|
44287
|
+
filter.layer = validLayers;
|
|
44288
|
+
}
|
|
44289
|
+
}
|
|
44290
|
+
if (query.types && query.types.length > 0) {
|
|
44291
|
+
const validTypes = query.types.filter(this.isKnowledgeType);
|
|
44292
|
+
if (validTypes.length > 0) {
|
|
44293
|
+
filter.type = validTypes;
|
|
44294
|
+
}
|
|
44295
|
+
}
|
|
44296
|
+
const result = await this.repository.query(filter);
|
|
44297
|
+
return result.items.map((commit) => ({
|
|
44298
|
+
item: this.commitToItem(commit, query.includeContent),
|
|
44299
|
+
score: this.calculateScore(commit, query.text)
|
|
44300
|
+
}));
|
|
44301
|
+
}
|
|
44302
|
+
async getById(id) {
|
|
44303
|
+
if (!this.initialized || !this.repository) {
|
|
44304
|
+
return null;
|
|
44305
|
+
}
|
|
44306
|
+
const commit = await this.repository.getCommitById(id);
|
|
44307
|
+
if (!commit) {
|
|
44308
|
+
return null;
|
|
44309
|
+
}
|
|
44310
|
+
return this.commitToItem(commit, true);
|
|
44311
|
+
}
|
|
44312
|
+
async healthCheck() {
|
|
44313
|
+
const now = new Date().toISOString();
|
|
44314
|
+
if (!this.config.enabled) {
|
|
44315
|
+
return {
|
|
44316
|
+
status: "unavailable",
|
|
44317
|
+
message: "Provider is disabled",
|
|
44318
|
+
lastChecked: now
|
|
44319
|
+
};
|
|
44320
|
+
}
|
|
44321
|
+
if (!this.initialized || !this.repository) {
|
|
44322
|
+
return {
|
|
44323
|
+
status: "unavailable",
|
|
44324
|
+
message: "Provider not initialized",
|
|
44325
|
+
lastChecked: now
|
|
44326
|
+
};
|
|
44327
|
+
}
|
|
44328
|
+
try {
|
|
44329
|
+
const start = Date.now();
|
|
44330
|
+
await this.repository.getStats();
|
|
44331
|
+
const latencyMs = Date.now() - start;
|
|
44332
|
+
return {
|
|
44333
|
+
status: "healthy",
|
|
44334
|
+
latencyMs,
|
|
44335
|
+
lastChecked: now
|
|
44336
|
+
};
|
|
44337
|
+
} catch (error45) {
|
|
44338
|
+
return {
|
|
44339
|
+
status: "degraded",
|
|
44340
|
+
message: error45 instanceof Error ? error45.message : "Unknown error",
|
|
44341
|
+
lastChecked: now
|
|
44342
|
+
};
|
|
44343
|
+
}
|
|
44344
|
+
}
|
|
44345
|
+
commitToItem(commit, includeContent) {
|
|
44346
|
+
return {
|
|
44347
|
+
id: `local::${commit.id}`,
|
|
44348
|
+
provider: this.name,
|
|
44349
|
+
title: commit.title,
|
|
44350
|
+
summary: commit.summary,
|
|
44351
|
+
content: includeContent ? commit.content : undefined,
|
|
44352
|
+
type: commit.type,
|
|
44353
|
+
layer: commit.layer,
|
|
44354
|
+
metadata: {
|
|
44355
|
+
sourceType: "local",
|
|
44356
|
+
sourceId: commit.id,
|
|
44357
|
+
tags: commit.tags,
|
|
44358
|
+
severity: commit.severity,
|
|
44359
|
+
knowledgeLayer: commit.layer,
|
|
44360
|
+
extra: {
|
|
44361
|
+
constraints: commit.constraints,
|
|
44362
|
+
triggerKeywords: commit.triggerKeywords,
|
|
44363
|
+
author: commit.author
|
|
43936
44364
|
}
|
|
43937
|
-
|
|
43938
|
-
|
|
44365
|
+
},
|
|
44366
|
+
createdAt: commit.createdAt
|
|
44367
|
+
};
|
|
44368
|
+
}
|
|
44369
|
+
calculateScore(commit, searchText) {
|
|
44370
|
+
if (!searchText) {
|
|
44371
|
+
return 0.5;
|
|
44372
|
+
}
|
|
44373
|
+
const lowerSearch = searchText.toLowerCase();
|
|
44374
|
+
const titleMatch = commit.title.toLowerCase().includes(lowerSearch);
|
|
44375
|
+
const summaryMatch = commit.summary.toLowerCase().includes(lowerSearch);
|
|
44376
|
+
const contentMatch = commit.content.toLowerCase().includes(lowerSearch);
|
|
44377
|
+
const tagMatch = commit.tags.some((t) => t.toLowerCase().includes(lowerSearch));
|
|
44378
|
+
const keywordMatch = commit.triggerKeywords.some((k) => k.toLowerCase().includes(lowerSearch));
|
|
44379
|
+
let score = 0.3;
|
|
44380
|
+
if (titleMatch)
|
|
44381
|
+
score += 0.3;
|
|
44382
|
+
if (summaryMatch)
|
|
44383
|
+
score += 0.15;
|
|
44384
|
+
if (contentMatch)
|
|
44385
|
+
score += 0.1;
|
|
44386
|
+
if (tagMatch)
|
|
44387
|
+
score += 0.1;
|
|
44388
|
+
if (keywordMatch)
|
|
44389
|
+
score += 0.05;
|
|
44390
|
+
return Math.min(score, 1);
|
|
44391
|
+
}
|
|
44392
|
+
isKnowledgeType(type2) {
|
|
44393
|
+
return ["adr", "policy", "pattern", "spec"].includes(type2);
|
|
44394
|
+
}
|
|
44395
|
+
isKnowledgeLayer(layer) {
|
|
44396
|
+
return ["company", "org", "team", "project"].includes(layer);
|
|
44397
|
+
}
|
|
44398
|
+
}
|
|
44399
|
+
// src/features/knowledge-provider/providers/mem0.ts
|
|
44400
|
+
var DEFAULT_SEARCH_LAYERS = [
|
|
44401
|
+
"user",
|
|
44402
|
+
"project",
|
|
44403
|
+
"team",
|
|
44404
|
+
"org",
|
|
44405
|
+
"company"
|
|
44406
|
+
];
|
|
44407
|
+
|
|
44408
|
+
class Mem0KnowledgeProvider {
|
|
44409
|
+
mem0Config;
|
|
44410
|
+
name = "mem0";
|
|
44411
|
+
type = "mem0";
|
|
44412
|
+
description = "Vector-based semantic memory via Mem0";
|
|
44413
|
+
config;
|
|
44414
|
+
adapter = null;
|
|
44415
|
+
initialized = false;
|
|
44416
|
+
constructor(config3, mem0Config) {
|
|
44417
|
+
this.mem0Config = mem0Config;
|
|
44418
|
+
this.config = config3;
|
|
44419
|
+
}
|
|
44420
|
+
async initialize() {
|
|
44421
|
+
if (!this.config.enabled || !this.mem0Config.enabled) {
|
|
44422
|
+
return;
|
|
44423
|
+
}
|
|
44424
|
+
this.adapter = new Mem0Adapter(this.mem0Config);
|
|
44425
|
+
this.initialized = true;
|
|
44426
|
+
}
|
|
44427
|
+
async search(query) {
|
|
44428
|
+
if (!this.initialized || !this.adapter) {
|
|
44429
|
+
return [];
|
|
44430
|
+
}
|
|
44431
|
+
const layers = this.resolveSearchLayers(query.layers);
|
|
44432
|
+
const results = await this.adapter.search({
|
|
44433
|
+
query: query.text,
|
|
44434
|
+
layer: layers,
|
|
44435
|
+
limit: query.limit ?? 10,
|
|
44436
|
+
threshold: query.threshold ?? 0.5
|
|
44437
|
+
});
|
|
44438
|
+
return results.map((result) => ({
|
|
44439
|
+
item: this.memoryToItem(result.memory, query.includeContent),
|
|
44440
|
+
score: result.score
|
|
44441
|
+
}));
|
|
44442
|
+
}
|
|
44443
|
+
async getById(id) {
|
|
44444
|
+
if (!this.initialized || !this.adapter) {
|
|
44445
|
+
return null;
|
|
44446
|
+
}
|
|
44447
|
+
const memory = await this.adapter.get(id);
|
|
44448
|
+
if (!memory) {
|
|
44449
|
+
return null;
|
|
44450
|
+
}
|
|
44451
|
+
return this.memoryToItem(memory, true);
|
|
44452
|
+
}
|
|
44453
|
+
async index(item) {
|
|
44454
|
+
if (!this.initialized || !this.adapter) {
|
|
44455
|
+
return;
|
|
44456
|
+
}
|
|
44457
|
+
const layer = this.itemLayerToMemoryLayer(item.layer);
|
|
44458
|
+
if (!layer) {
|
|
44459
|
+
return;
|
|
44460
|
+
}
|
|
44461
|
+
await this.adapter.add({
|
|
44462
|
+
content: `${item.title}
|
|
44463
|
+
|
|
44464
|
+
${item.summary}
|
|
44465
|
+
|
|
44466
|
+
${item.content ?? ""}`,
|
|
44467
|
+
layer,
|
|
44468
|
+
metadata: {
|
|
44469
|
+
sourceProvider: item.provider,
|
|
44470
|
+
sourceId: item.metadata.sourceId,
|
|
44471
|
+
type: item.type,
|
|
44472
|
+
tags: item.metadata.tags
|
|
44473
|
+
}
|
|
44474
|
+
});
|
|
44475
|
+
}
|
|
44476
|
+
async healthCheck() {
|
|
44477
|
+
const now = new Date().toISOString();
|
|
44478
|
+
if (!this.config.enabled) {
|
|
44479
|
+
return {
|
|
44480
|
+
status: "unavailable",
|
|
44481
|
+
message: "Provider is disabled",
|
|
44482
|
+
lastChecked: now
|
|
44483
|
+
};
|
|
44484
|
+
}
|
|
44485
|
+
if (!this.initialized || !this.adapter) {
|
|
44486
|
+
return {
|
|
44487
|
+
status: "unavailable",
|
|
44488
|
+
message: "Provider not initialized",
|
|
44489
|
+
lastChecked: now
|
|
44490
|
+
};
|
|
44491
|
+
}
|
|
44492
|
+
try {
|
|
44493
|
+
const start = Date.now();
|
|
44494
|
+
await this.adapter.getStats();
|
|
44495
|
+
const latencyMs = Date.now() - start;
|
|
44496
|
+
return {
|
|
44497
|
+
status: "healthy",
|
|
44498
|
+
latencyMs,
|
|
44499
|
+
lastChecked: now
|
|
44500
|
+
};
|
|
44501
|
+
} catch (error45) {
|
|
44502
|
+
return {
|
|
44503
|
+
status: "degraded",
|
|
44504
|
+
message: error45 instanceof Error ? error45.message : "Unknown error",
|
|
44505
|
+
lastChecked: now
|
|
44506
|
+
};
|
|
44507
|
+
}
|
|
44508
|
+
}
|
|
44509
|
+
memoryToItem(memory, includeContent) {
|
|
44510
|
+
const metadata = memory.metadata ?? {};
|
|
44511
|
+
return {
|
|
44512
|
+
id: `mem0::${memory.id}`,
|
|
44513
|
+
provider: this.name,
|
|
44514
|
+
title: this.extractTitle(memory.content),
|
|
44515
|
+
summary: this.extractSummary(memory.content),
|
|
44516
|
+
content: includeContent ? memory.content : undefined,
|
|
44517
|
+
type: metadata.type ?? "memory",
|
|
44518
|
+
layer: memory.layer,
|
|
44519
|
+
metadata: {
|
|
44520
|
+
sourceType: "mem0",
|
|
44521
|
+
sourceId: memory.id,
|
|
44522
|
+
tags: metadata.tags,
|
|
44523
|
+
memoryLayer: memory.layer,
|
|
44524
|
+
extra: metadata
|
|
44525
|
+
},
|
|
44526
|
+
createdAt: memory.createdAt,
|
|
44527
|
+
updatedAt: memory.updatedAt
|
|
44528
|
+
};
|
|
44529
|
+
}
|
|
44530
|
+
extractTitle(content) {
|
|
44531
|
+
const firstLine = content.split(`
|
|
44532
|
+
`)[0] ?? "";
|
|
44533
|
+
return firstLine.slice(0, 100).trim() || "Untitled Memory";
|
|
44534
|
+
}
|
|
44535
|
+
extractSummary(content) {
|
|
44536
|
+
const lines = content.split(`
|
|
44537
|
+
`).filter((l) => l.trim());
|
|
44538
|
+
const summary = lines.slice(0, 2).join(" ");
|
|
44539
|
+
return summary.slice(0, 200).trim() || content.slice(0, 200).trim();
|
|
44540
|
+
}
|
|
44541
|
+
resolveSearchLayers(queryLayers) {
|
|
44542
|
+
if (!queryLayers || queryLayers.length === 0) {
|
|
44543
|
+
return this.config.searchLayers ?? DEFAULT_SEARCH_LAYERS;
|
|
44544
|
+
}
|
|
44545
|
+
return queryLayers.filter(this.isMemoryLayer);
|
|
44546
|
+
}
|
|
44547
|
+
itemLayerToMemoryLayer(layer) {
|
|
44548
|
+
if (!layer)
|
|
44549
|
+
return "project";
|
|
44550
|
+
const mapping = {
|
|
44551
|
+
company: "company",
|
|
44552
|
+
org: "org",
|
|
44553
|
+
team: "team",
|
|
44554
|
+
project: "project",
|
|
44555
|
+
user: "user",
|
|
44556
|
+
session: "session",
|
|
44557
|
+
agent: "agent"
|
|
44558
|
+
};
|
|
44559
|
+
return mapping[layer] ?? "project";
|
|
44560
|
+
}
|
|
44561
|
+
isMemoryLayer(layer) {
|
|
44562
|
+
return ["user", "session", "project", "team", "org", "company", "agent"].includes(layer);
|
|
44563
|
+
}
|
|
44564
|
+
}
|
|
44565
|
+
// src/features/knowledge-provider/providers/mcp.ts
|
|
44566
|
+
class MCPKnowledgeProvider {
|
|
44567
|
+
name;
|
|
44568
|
+
type = "mcp";
|
|
44569
|
+
description;
|
|
44570
|
+
config;
|
|
44571
|
+
invoker;
|
|
44572
|
+
initialized = false;
|
|
44573
|
+
constructor(config3, invoker) {
|
|
44574
|
+
this.config = config3;
|
|
44575
|
+
this.invoker = invoker;
|
|
44576
|
+
this.name = `mcp:${config3.name}`;
|
|
44577
|
+
this.description = `MCP knowledge provider via ${config3.name}`;
|
|
44578
|
+
}
|
|
44579
|
+
async initialize() {
|
|
44580
|
+
const available = await this.invoker.isServerAvailable(this.config.name);
|
|
44581
|
+
if (!available) {
|
|
44582
|
+
throw new Error(`MCP server "${this.config.name}" is not available`);
|
|
44583
|
+
}
|
|
44584
|
+
this.initialized = true;
|
|
44585
|
+
}
|
|
44586
|
+
async search(query) {
|
|
44587
|
+
if (!this.initialized) {
|
|
44588
|
+
return [];
|
|
44589
|
+
}
|
|
44590
|
+
try {
|
|
44591
|
+
const result = await this.invoker.invoke(this.config.name, this.config.searchTool, {
|
|
44592
|
+
query: query.text,
|
|
44593
|
+
limit: query.limit ?? 10,
|
|
44594
|
+
...this.config.config
|
|
44595
|
+
});
|
|
44596
|
+
return this.parseSearchResponse(result, query.includeContent);
|
|
44597
|
+
} catch {
|
|
44598
|
+
return [];
|
|
44599
|
+
}
|
|
44600
|
+
}
|
|
44601
|
+
async getById(id) {
|
|
44602
|
+
if (!this.initialized || !this.config.getTool) {
|
|
44603
|
+
return null;
|
|
44604
|
+
}
|
|
44605
|
+
try {
|
|
44606
|
+
const result = await this.invoker.invoke(this.config.name, this.config.getTool, { id });
|
|
44607
|
+
return this.parseGetResponse(result);
|
|
44608
|
+
} catch {
|
|
44609
|
+
return null;
|
|
44610
|
+
}
|
|
44611
|
+
}
|
|
44612
|
+
async healthCheck() {
|
|
44613
|
+
const now = new Date().toISOString();
|
|
44614
|
+
try {
|
|
44615
|
+
const start = Date.now();
|
|
44616
|
+
const available = await this.invoker.isServerAvailable(this.config.name);
|
|
44617
|
+
const latencyMs = Date.now() - start;
|
|
44618
|
+
if (!available) {
|
|
44619
|
+
return {
|
|
44620
|
+
status: "unavailable",
|
|
44621
|
+
message: `MCP server "${this.config.name}" is not available`,
|
|
44622
|
+
lastChecked: now
|
|
44623
|
+
};
|
|
44624
|
+
}
|
|
44625
|
+
return {
|
|
44626
|
+
status: "healthy",
|
|
44627
|
+
latencyMs,
|
|
44628
|
+
lastChecked: now
|
|
44629
|
+
};
|
|
44630
|
+
} catch (error45) {
|
|
44631
|
+
return {
|
|
44632
|
+
status: "degraded",
|
|
44633
|
+
message: error45 instanceof Error ? error45.message : "Unknown error",
|
|
44634
|
+
lastChecked: now
|
|
44635
|
+
};
|
|
44636
|
+
}
|
|
44637
|
+
}
|
|
44638
|
+
async dispose() {
|
|
44639
|
+
this.initialized = false;
|
|
44640
|
+
}
|
|
44641
|
+
parseSearchResponse(response2, includeContent) {
|
|
44642
|
+
if (!response2) {
|
|
44643
|
+
return [];
|
|
44644
|
+
}
|
|
44645
|
+
if (Array.isArray(response2)) {
|
|
44646
|
+
return response2.map((item, index) => this.responseItemToSearchResult(item, index, includeContent));
|
|
44647
|
+
}
|
|
44648
|
+
const obj = response2;
|
|
44649
|
+
if (obj.results && Array.isArray(obj.results)) {
|
|
44650
|
+
return obj.results.map((item, index) => this.responseItemToSearchResult(item, index, includeContent));
|
|
44651
|
+
}
|
|
44652
|
+
if (obj.items && Array.isArray(obj.items)) {
|
|
44653
|
+
return obj.items.map((item, index) => this.responseItemToSearchResult(item, index, includeContent));
|
|
44654
|
+
}
|
|
44655
|
+
return [this.responseItemToSearchResult(response2, 0, includeContent)];
|
|
44656
|
+
}
|
|
44657
|
+
responseItemToSearchResult(item, index, includeContent) {
|
|
44658
|
+
const obj = item ?? {};
|
|
44659
|
+
const id = String(obj.id ?? obj.document_id ?? obj.url ?? `result-${index}`);
|
|
44660
|
+
const title = String(obj.title ?? obj.name ?? "Untitled");
|
|
44661
|
+
const summary = String(obj.summary ?? obj.snippet ?? obj.excerpt ?? obj.description ?? "");
|
|
44662
|
+
const content = obj.content ?? obj.text ?? obj.body;
|
|
44663
|
+
const score = Number(obj.score ?? obj.relevance ?? obj.similarity ?? 0.5);
|
|
44664
|
+
const url2 = obj.url ? String(obj.url) : undefined;
|
|
44665
|
+
const knowledgeItem = {
|
|
44666
|
+
id: `${this.name}::${id}`,
|
|
44667
|
+
provider: this.name,
|
|
44668
|
+
title,
|
|
44669
|
+
summary: summary.slice(0, 200),
|
|
44670
|
+
content: includeContent && content ? String(content) : undefined,
|
|
44671
|
+
type: this.inferType(obj),
|
|
44672
|
+
metadata: {
|
|
44673
|
+
sourceType: "mcp",
|
|
44674
|
+
sourceId: id,
|
|
44675
|
+
url: url2,
|
|
44676
|
+
extra: obj
|
|
44677
|
+
}
|
|
44678
|
+
};
|
|
44679
|
+
return {
|
|
44680
|
+
item: knowledgeItem,
|
|
44681
|
+
score: Math.min(Math.max(score, 0), 1),
|
|
44682
|
+
highlights: obj.highlights ? obj.highlights : obj.snippet ? [String(obj.snippet)] : undefined
|
|
44683
|
+
};
|
|
44684
|
+
}
|
|
44685
|
+
parseGetResponse(response2) {
|
|
44686
|
+
if (!response2) {
|
|
44687
|
+
return null;
|
|
44688
|
+
}
|
|
44689
|
+
const obj = response2;
|
|
44690
|
+
const id = String(obj.id ?? obj.document_id ?? "unknown");
|
|
44691
|
+
const title = String(obj.title ?? obj.name ?? "Untitled");
|
|
44692
|
+
const content = String(obj.content ?? obj.text ?? obj.body ?? "");
|
|
44693
|
+
return {
|
|
44694
|
+
id: `${this.name}::${id}`,
|
|
44695
|
+
provider: this.name,
|
|
44696
|
+
title,
|
|
44697
|
+
summary: content.slice(0, 200),
|
|
44698
|
+
content,
|
|
44699
|
+
type: this.inferType(obj),
|
|
44700
|
+
metadata: {
|
|
44701
|
+
sourceType: "mcp",
|
|
44702
|
+
sourceId: id,
|
|
44703
|
+
url: obj.url ? String(obj.url) : undefined,
|
|
44704
|
+
extra: obj
|
|
44705
|
+
}
|
|
44706
|
+
};
|
|
44707
|
+
}
|
|
44708
|
+
inferType(obj) {
|
|
44709
|
+
const typeField = obj.type ?? obj.kind ?? obj.category;
|
|
44710
|
+
if (typeof typeField === "string") {
|
|
44711
|
+
const lowerType = typeField.toLowerCase();
|
|
44712
|
+
if (["adr", "policy", "pattern", "spec"].includes(lowerType)) {
|
|
44713
|
+
return lowerType;
|
|
44714
|
+
}
|
|
44715
|
+
if (lowerType.includes("doc"))
|
|
44716
|
+
return "document";
|
|
44717
|
+
if (lowerType.includes("article"))
|
|
44718
|
+
return "article";
|
|
44719
|
+
if (lowerType.includes("snippet") || lowerType.includes("code"))
|
|
44720
|
+
return "snippet";
|
|
44721
|
+
}
|
|
44722
|
+
if (obj.url && String(obj.url).includes("github")) {
|
|
44723
|
+
return "snippet";
|
|
44724
|
+
}
|
|
44725
|
+
return "document";
|
|
44726
|
+
}
|
|
44727
|
+
}
|
|
44728
|
+
// src/features/knowledge-provider/providers/notebooklm.ts
|
|
44729
|
+
class NotebookLMKnowledgeProvider {
|
|
44730
|
+
name = "notebooklm";
|
|
44731
|
+
type = "mcp";
|
|
44732
|
+
description = "Google NotebookLM AI-powered knowledge notebooks";
|
|
44733
|
+
config;
|
|
44734
|
+
invoker;
|
|
44735
|
+
initialized = false;
|
|
44736
|
+
notebooks = new Map;
|
|
44737
|
+
constructor(config3, invoker) {
|
|
44738
|
+
this.config = config3;
|
|
44739
|
+
this.invoker = invoker;
|
|
44740
|
+
}
|
|
44741
|
+
async initialize() {
|
|
44742
|
+
if (!this.config.enabled) {
|
|
44743
|
+
return;
|
|
44744
|
+
}
|
|
44745
|
+
const available = await this.invoker.isServerAvailable("notebooklm-mcp");
|
|
44746
|
+
if (!available) {
|
|
44747
|
+
throw new Error("NotebookLM MCP server is not available");
|
|
44748
|
+
}
|
|
44749
|
+
await this.refreshNotebooks();
|
|
44750
|
+
this.initialized = true;
|
|
44751
|
+
}
|
|
44752
|
+
async search(query) {
|
|
44753
|
+
if (!this.initialized) {
|
|
44754
|
+
return [];
|
|
44755
|
+
}
|
|
44756
|
+
const results = [];
|
|
44757
|
+
const notebookIds = this.getTargetNotebooks(query);
|
|
44758
|
+
for (const notebookId of notebookIds) {
|
|
44759
|
+
try {
|
|
44760
|
+
const response2 = await this.invoker.invoke("notebooklm-mcp", "notebook_query", {
|
|
44761
|
+
notebook_id: notebookId,
|
|
44762
|
+
query: query.text
|
|
43939
44763
|
});
|
|
43940
|
-
if (
|
|
43941
|
-
const
|
|
43942
|
-
|
|
43943
|
-
|
|
43944
|
-
|
|
43945
|
-
|
|
43946
|
-
|
|
43947
|
-
|
|
43948
|
-
|
|
43949
|
-
|
|
43950
|
-
|
|
43951
|
-
|
|
43952
|
-
|
|
43953
|
-
|
|
43954
|
-
|
|
44764
|
+
if (response2?.answer) {
|
|
44765
|
+
const notebook = this.notebooks.get(notebookId);
|
|
44766
|
+
results.push({
|
|
44767
|
+
item: {
|
|
44768
|
+
id: `notebooklm::${notebookId}::query`,
|
|
44769
|
+
provider: this.name,
|
|
44770
|
+
title: `Answer from "${notebook?.title ?? notebookId}"`,
|
|
44771
|
+
summary: response2.answer.slice(0, 200),
|
|
44772
|
+
content: query.includeContent ? response2.answer : undefined,
|
|
44773
|
+
type: "document",
|
|
44774
|
+
metadata: {
|
|
44775
|
+
sourceType: "mcp",
|
|
44776
|
+
sourceId: notebookId,
|
|
44777
|
+
extra: {
|
|
44778
|
+
notebookId,
|
|
44779
|
+
notebookTitle: notebook?.title,
|
|
44780
|
+
citedSources: response2.sources
|
|
44781
|
+
}
|
|
43955
44782
|
}
|
|
43956
|
-
}
|
|
43957
|
-
|
|
43958
|
-
|
|
43959
|
-
|
|
44783
|
+
},
|
|
44784
|
+
score: 0.9,
|
|
44785
|
+
highlights: response2.sources?.map((s) => s.snippet).filter(Boolean)
|
|
44786
|
+
});
|
|
44787
|
+
}
|
|
44788
|
+
} catch {
|
|
44789
|
+
continue;
|
|
44790
|
+
}
|
|
44791
|
+
}
|
|
44792
|
+
return results.slice(0, query.limit ?? 10);
|
|
44793
|
+
}
|
|
44794
|
+
async getById(id) {
|
|
44795
|
+
if (!this.initialized) {
|
|
44796
|
+
return null;
|
|
44797
|
+
}
|
|
44798
|
+
const parts = id.split("::");
|
|
44799
|
+
if (parts.length < 2) {
|
|
44800
|
+
return null;
|
|
44801
|
+
}
|
|
44802
|
+
const notebookId = parts[0];
|
|
44803
|
+
const itemType = parts[1];
|
|
44804
|
+
try {
|
|
44805
|
+
if (itemType === "notebook") {
|
|
44806
|
+
const response2 = await this.invoker.invoke("notebooklm-mcp", "notebook_describe", { notebook_id: notebookId });
|
|
44807
|
+
const notebook = this.notebooks.get(notebookId);
|
|
44808
|
+
return {
|
|
44809
|
+
id: `notebooklm::${notebookId}::notebook`,
|
|
44810
|
+
provider: this.name,
|
|
44811
|
+
title: notebook?.title ?? "Notebook",
|
|
44812
|
+
summary: response2.description?.slice(0, 200) ?? "",
|
|
44813
|
+
content: response2.description,
|
|
44814
|
+
type: "document",
|
|
44815
|
+
metadata: {
|
|
44816
|
+
sourceType: "mcp",
|
|
44817
|
+
sourceId: notebookId,
|
|
44818
|
+
tags: response2.keywords,
|
|
44819
|
+
extra: { notebookId }
|
|
43960
44820
|
}
|
|
43961
|
-
|
|
43962
|
-
|
|
43963
|
-
|
|
43964
|
-
|
|
43965
|
-
|
|
43966
|
-
|
|
44821
|
+
};
|
|
44822
|
+
}
|
|
44823
|
+
if (itemType === "source") {
|
|
44824
|
+
const sourceId = parts[2];
|
|
44825
|
+
const response2 = await this.invoker.invoke("notebooklm-mcp", "source_describe", { notebook_id: notebookId, source_id: sourceId });
|
|
44826
|
+
return {
|
|
44827
|
+
id: `notebooklm::${notebookId}::source::${sourceId}`,
|
|
44828
|
+
provider: this.name,
|
|
44829
|
+
title: `Source ${sourceId}`,
|
|
44830
|
+
summary: response2.summary?.slice(0, 200) ?? "",
|
|
44831
|
+
content: response2.summary,
|
|
44832
|
+
type: "document",
|
|
44833
|
+
metadata: {
|
|
44834
|
+
sourceType: "mcp",
|
|
44835
|
+
sourceId: `${notebookId}/${sourceId}`,
|
|
44836
|
+
tags: response2.keywords,
|
|
44837
|
+
extra: { notebookId, sourceId }
|
|
43967
44838
|
}
|
|
43968
|
-
}
|
|
43969
|
-
} catch (error45) {
|
|
43970
|
-
log("[background-agent] Poll error for task:", { taskId: task.id, error: error45 });
|
|
44839
|
+
};
|
|
43971
44840
|
}
|
|
44841
|
+
} catch {
|
|
44842
|
+
return null;
|
|
43972
44843
|
}
|
|
43973
|
-
|
|
43974
|
-
|
|
44844
|
+
return null;
|
|
44845
|
+
}
|
|
44846
|
+
async index(item) {
|
|
44847
|
+
if (!this.initialized) {
|
|
44848
|
+
return;
|
|
44849
|
+
}
|
|
44850
|
+
const notebookId = this.config.defaultNotebookId;
|
|
44851
|
+
if (!notebookId) {
|
|
44852
|
+
return;
|
|
44853
|
+
}
|
|
44854
|
+
try {
|
|
44855
|
+
if (item.metadata.url) {
|
|
44856
|
+
await this.invoker.invoke("notebooklm-mcp", "notebook_add_url", {
|
|
44857
|
+
notebook_id: notebookId,
|
|
44858
|
+
url: item.metadata.url
|
|
44859
|
+
});
|
|
44860
|
+
} else if (item.content) {
|
|
44861
|
+
await this.invoker.invoke("notebooklm-mcp", "notebook_add_text", {
|
|
44862
|
+
notebook_id: notebookId,
|
|
44863
|
+
text: `# ${item.title}
|
|
44864
|
+
|
|
44865
|
+
${item.content}`,
|
|
44866
|
+
title: item.title
|
|
44867
|
+
});
|
|
44868
|
+
}
|
|
44869
|
+
} catch {}
|
|
44870
|
+
}
|
|
44871
|
+
async healthCheck() {
|
|
44872
|
+
const now = new Date().toISOString();
|
|
44873
|
+
if (!this.config.enabled) {
|
|
44874
|
+
return {
|
|
44875
|
+
status: "unavailable",
|
|
44876
|
+
message: "Provider is disabled",
|
|
44877
|
+
lastChecked: now
|
|
44878
|
+
};
|
|
44879
|
+
}
|
|
44880
|
+
try {
|
|
44881
|
+
const start = Date.now();
|
|
44882
|
+
const available = await this.invoker.isServerAvailable("notebooklm-mcp");
|
|
44883
|
+
const latencyMs = Date.now() - start;
|
|
44884
|
+
if (!available) {
|
|
44885
|
+
return {
|
|
44886
|
+
status: "unavailable",
|
|
44887
|
+
message: "NotebookLM MCP server is not available",
|
|
44888
|
+
lastChecked: now
|
|
44889
|
+
};
|
|
44890
|
+
}
|
|
44891
|
+
return {
|
|
44892
|
+
status: "healthy",
|
|
44893
|
+
latencyMs,
|
|
44894
|
+
message: `${this.notebooks.size} notebooks cached`,
|
|
44895
|
+
lastChecked: now
|
|
44896
|
+
};
|
|
44897
|
+
} catch (error45) {
|
|
44898
|
+
return {
|
|
44899
|
+
status: "degraded",
|
|
44900
|
+
message: error45 instanceof Error ? error45.message : "Unknown error",
|
|
44901
|
+
lastChecked: now
|
|
44902
|
+
};
|
|
44903
|
+
}
|
|
44904
|
+
}
|
|
44905
|
+
async dispose() {
|
|
44906
|
+
this.initialized = false;
|
|
44907
|
+
this.notebooks.clear();
|
|
44908
|
+
}
|
|
44909
|
+
async listNotebooks() {
|
|
44910
|
+
await this.refreshNotebooks();
|
|
44911
|
+
return Array.from(this.notebooks.values());
|
|
44912
|
+
}
|
|
44913
|
+
async refreshNotebooks() {
|
|
44914
|
+
try {
|
|
44915
|
+
const response2 = await this.invoker.invoke("notebooklm-mcp", "notebook_list", {});
|
|
44916
|
+
this.notebooks.clear();
|
|
44917
|
+
if (response2?.notebooks) {
|
|
44918
|
+
for (const nb of response2.notebooks) {
|
|
44919
|
+
this.notebooks.set(nb.id, nb);
|
|
44920
|
+
}
|
|
44921
|
+
}
|
|
44922
|
+
} catch {}
|
|
44923
|
+
}
|
|
44924
|
+
getTargetNotebooks(query) {
|
|
44925
|
+
if (this.config.defaultNotebookId) {
|
|
44926
|
+
return [this.config.defaultNotebookId];
|
|
43975
44927
|
}
|
|
44928
|
+
const notebookIds = Array.from(this.notebooks.keys());
|
|
44929
|
+
return notebookIds.slice(0, 3);
|
|
43976
44930
|
}
|
|
43977
44931
|
}
|
|
43978
44932
|
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js
|
|
@@ -46250,289 +47204,2237 @@ class Client extends Protocol {
|
|
|
46250
47204
|
}
|
|
46251
47205
|
}
|
|
46252
47206
|
}
|
|
46253
|
-
return result;
|
|
47207
|
+
return result;
|
|
47208
|
+
}
|
|
47209
|
+
isToolTask(toolName) {
|
|
47210
|
+
if (!this._serverCapabilities?.tasks?.requests?.tools?.call) {
|
|
47211
|
+
return false;
|
|
47212
|
+
}
|
|
47213
|
+
return this._cachedKnownTaskTools.has(toolName);
|
|
47214
|
+
}
|
|
47215
|
+
isToolTaskRequired(toolName) {
|
|
47216
|
+
return this._cachedRequiredTaskTools.has(toolName);
|
|
47217
|
+
}
|
|
47218
|
+
cacheToolMetadata(tools4) {
|
|
47219
|
+
this._cachedToolOutputValidators.clear();
|
|
47220
|
+
this._cachedKnownTaskTools.clear();
|
|
47221
|
+
this._cachedRequiredTaskTools.clear();
|
|
47222
|
+
for (const tool3 of tools4) {
|
|
47223
|
+
if (tool3.outputSchema) {
|
|
47224
|
+
const toolValidator = this._jsonSchemaValidator.getValidator(tool3.outputSchema);
|
|
47225
|
+
this._cachedToolOutputValidators.set(tool3.name, toolValidator);
|
|
47226
|
+
}
|
|
47227
|
+
const taskSupport = tool3.execution?.taskSupport;
|
|
47228
|
+
if (taskSupport === "required" || taskSupport === "optional") {
|
|
47229
|
+
this._cachedKnownTaskTools.add(tool3.name);
|
|
47230
|
+
}
|
|
47231
|
+
if (taskSupport === "required") {
|
|
47232
|
+
this._cachedRequiredTaskTools.add(tool3.name);
|
|
47233
|
+
}
|
|
47234
|
+
}
|
|
47235
|
+
}
|
|
47236
|
+
getToolOutputValidator(toolName) {
|
|
47237
|
+
return this._cachedToolOutputValidators.get(toolName);
|
|
47238
|
+
}
|
|
47239
|
+
async listTools(params, options) {
|
|
47240
|
+
const result = await this.request({ method: "tools/list", params }, ListToolsResultSchema, options);
|
|
47241
|
+
this.cacheToolMetadata(result.tools);
|
|
47242
|
+
return result;
|
|
47243
|
+
}
|
|
47244
|
+
_setupListChangedHandler(listType, notificationSchema, options, fetcher) {
|
|
47245
|
+
const parseResult = ListChangedOptionsBaseSchema.safeParse(options);
|
|
47246
|
+
if (!parseResult.success) {
|
|
47247
|
+
throw new Error(`Invalid ${listType} listChanged options: ${parseResult.error.message}`);
|
|
47248
|
+
}
|
|
47249
|
+
if (typeof options.onChanged !== "function") {
|
|
47250
|
+
throw new Error(`Invalid ${listType} listChanged options: onChanged must be a function`);
|
|
47251
|
+
}
|
|
47252
|
+
const { autoRefresh, debounceMs } = parseResult.data;
|
|
47253
|
+
const { onChanged } = options;
|
|
47254
|
+
const refresh = async () => {
|
|
47255
|
+
if (!autoRefresh) {
|
|
47256
|
+
onChanged(null, null);
|
|
47257
|
+
return;
|
|
47258
|
+
}
|
|
47259
|
+
try {
|
|
47260
|
+
const items = await fetcher();
|
|
47261
|
+
onChanged(null, items);
|
|
47262
|
+
} catch (e) {
|
|
47263
|
+
const error45 = e instanceof Error ? e : new Error(String(e));
|
|
47264
|
+
onChanged(error45, null);
|
|
47265
|
+
}
|
|
47266
|
+
};
|
|
47267
|
+
const handler = () => {
|
|
47268
|
+
if (debounceMs) {
|
|
47269
|
+
const existingTimer = this._listChangedDebounceTimers.get(listType);
|
|
47270
|
+
if (existingTimer) {
|
|
47271
|
+
clearTimeout(existingTimer);
|
|
47272
|
+
}
|
|
47273
|
+
const timer = setTimeout(refresh, debounceMs);
|
|
47274
|
+
this._listChangedDebounceTimers.set(listType, timer);
|
|
47275
|
+
} else {
|
|
47276
|
+
refresh();
|
|
47277
|
+
}
|
|
47278
|
+
};
|
|
47279
|
+
this.setNotificationHandler(notificationSchema, handler);
|
|
47280
|
+
}
|
|
47281
|
+
async sendRootsListChanged() {
|
|
47282
|
+
return this.notification({ method: "notifications/roots/list_changed" });
|
|
47283
|
+
}
|
|
47284
|
+
}
|
|
47285
|
+
|
|
47286
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/client/stdio.js
|
|
47287
|
+
var import_cross_spawn = __toESM(require_cross_spawn(), 1);
|
|
47288
|
+
import process2 from "process";
|
|
47289
|
+
import { PassThrough } from "stream";
|
|
47290
|
+
|
|
47291
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
|
|
47292
|
+
class ReadBuffer {
|
|
47293
|
+
append(chunk) {
|
|
47294
|
+
this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
|
|
47295
|
+
}
|
|
47296
|
+
readMessage() {
|
|
47297
|
+
if (!this._buffer) {
|
|
47298
|
+
return null;
|
|
47299
|
+
}
|
|
47300
|
+
const index = this._buffer.indexOf(`
|
|
47301
|
+
`);
|
|
47302
|
+
if (index === -1) {
|
|
47303
|
+
return null;
|
|
47304
|
+
}
|
|
47305
|
+
const line = this._buffer.toString("utf8", 0, index).replace(/\r$/, "");
|
|
47306
|
+
this._buffer = this._buffer.subarray(index + 1);
|
|
47307
|
+
return deserializeMessage(line);
|
|
47308
|
+
}
|
|
47309
|
+
clear() {
|
|
47310
|
+
this._buffer = undefined;
|
|
47311
|
+
}
|
|
47312
|
+
}
|
|
47313
|
+
function deserializeMessage(line) {
|
|
47314
|
+
return JSONRPCMessageSchema.parse(JSON.parse(line));
|
|
47315
|
+
}
|
|
47316
|
+
function serializeMessage(message) {
|
|
47317
|
+
return JSON.stringify(message) + `
|
|
47318
|
+
`;
|
|
47319
|
+
}
|
|
47320
|
+
|
|
47321
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/client/stdio.js
|
|
47322
|
+
var DEFAULT_INHERITED_ENV_VARS = process2.platform === "win32" ? [
|
|
47323
|
+
"APPDATA",
|
|
47324
|
+
"HOMEDRIVE",
|
|
47325
|
+
"HOMEPATH",
|
|
47326
|
+
"LOCALAPPDATA",
|
|
47327
|
+
"PATH",
|
|
47328
|
+
"PROCESSOR_ARCHITECTURE",
|
|
47329
|
+
"SYSTEMDRIVE",
|
|
47330
|
+
"SYSTEMROOT",
|
|
47331
|
+
"TEMP",
|
|
47332
|
+
"USERNAME",
|
|
47333
|
+
"USERPROFILE",
|
|
47334
|
+
"PROGRAMFILES"
|
|
47335
|
+
] : ["HOME", "LOGNAME", "PATH", "SHELL", "TERM", "USER"];
|
|
47336
|
+
function getDefaultEnvironment() {
|
|
47337
|
+
const env = {};
|
|
47338
|
+
for (const key of DEFAULT_INHERITED_ENV_VARS) {
|
|
47339
|
+
const value = process2.env[key];
|
|
47340
|
+
if (value === undefined) {
|
|
47341
|
+
continue;
|
|
47342
|
+
}
|
|
47343
|
+
if (value.startsWith("()")) {
|
|
47344
|
+
continue;
|
|
47345
|
+
}
|
|
47346
|
+
env[key] = value;
|
|
47347
|
+
}
|
|
47348
|
+
return env;
|
|
47349
|
+
}
|
|
47350
|
+
|
|
47351
|
+
class StdioClientTransport {
|
|
47352
|
+
constructor(server) {
|
|
47353
|
+
this._readBuffer = new ReadBuffer;
|
|
47354
|
+
this._stderrStream = null;
|
|
47355
|
+
this._serverParams = server;
|
|
47356
|
+
if (server.stderr === "pipe" || server.stderr === "overlapped") {
|
|
47357
|
+
this._stderrStream = new PassThrough;
|
|
47358
|
+
}
|
|
47359
|
+
}
|
|
47360
|
+
async start() {
|
|
47361
|
+
if (this._process) {
|
|
47362
|
+
throw new Error("StdioClientTransport already started! If using Client class, note that connect() calls start() automatically.");
|
|
47363
|
+
}
|
|
47364
|
+
return new Promise((resolve8, reject) => {
|
|
47365
|
+
this._process = import_cross_spawn.default(this._serverParams.command, this._serverParams.args ?? [], {
|
|
47366
|
+
env: {
|
|
47367
|
+
...getDefaultEnvironment(),
|
|
47368
|
+
...this._serverParams.env
|
|
47369
|
+
},
|
|
47370
|
+
stdio: ["pipe", "pipe", this._serverParams.stderr ?? "inherit"],
|
|
47371
|
+
shell: false,
|
|
47372
|
+
windowsHide: process2.platform === "win32" && isElectron(),
|
|
47373
|
+
cwd: this._serverParams.cwd
|
|
47374
|
+
});
|
|
47375
|
+
this._process.on("error", (error45) => {
|
|
47376
|
+
reject(error45);
|
|
47377
|
+
this.onerror?.(error45);
|
|
47378
|
+
});
|
|
47379
|
+
this._process.on("spawn", () => {
|
|
47380
|
+
resolve8();
|
|
47381
|
+
});
|
|
47382
|
+
this._process.on("close", (_code) => {
|
|
47383
|
+
this._process = undefined;
|
|
47384
|
+
this.onclose?.();
|
|
47385
|
+
});
|
|
47386
|
+
this._process.stdin?.on("error", (error45) => {
|
|
47387
|
+
this.onerror?.(error45);
|
|
47388
|
+
});
|
|
47389
|
+
this._process.stdout?.on("data", (chunk) => {
|
|
47390
|
+
this._readBuffer.append(chunk);
|
|
47391
|
+
this.processReadBuffer();
|
|
47392
|
+
});
|
|
47393
|
+
this._process.stdout?.on("error", (error45) => {
|
|
47394
|
+
this.onerror?.(error45);
|
|
47395
|
+
});
|
|
47396
|
+
if (this._stderrStream && this._process.stderr) {
|
|
47397
|
+
this._process.stderr.pipe(this._stderrStream);
|
|
47398
|
+
}
|
|
47399
|
+
});
|
|
47400
|
+
}
|
|
47401
|
+
get stderr() {
|
|
47402
|
+
if (this._stderrStream) {
|
|
47403
|
+
return this._stderrStream;
|
|
47404
|
+
}
|
|
47405
|
+
return this._process?.stderr ?? null;
|
|
47406
|
+
}
|
|
47407
|
+
get pid() {
|
|
47408
|
+
return this._process?.pid ?? null;
|
|
47409
|
+
}
|
|
47410
|
+
processReadBuffer() {
|
|
47411
|
+
while (true) {
|
|
47412
|
+
try {
|
|
47413
|
+
const message = this._readBuffer.readMessage();
|
|
47414
|
+
if (message === null) {
|
|
47415
|
+
break;
|
|
47416
|
+
}
|
|
47417
|
+
this.onmessage?.(message);
|
|
47418
|
+
} catch (error45) {
|
|
47419
|
+
this.onerror?.(error45);
|
|
47420
|
+
}
|
|
47421
|
+
}
|
|
47422
|
+
}
|
|
47423
|
+
async close() {
|
|
47424
|
+
if (this._process) {
|
|
47425
|
+
const processToClose = this._process;
|
|
47426
|
+
this._process = undefined;
|
|
47427
|
+
const closePromise = new Promise((resolve8) => {
|
|
47428
|
+
processToClose.once("close", () => {
|
|
47429
|
+
resolve8();
|
|
47430
|
+
});
|
|
47431
|
+
});
|
|
47432
|
+
try {
|
|
47433
|
+
processToClose.stdin?.end();
|
|
47434
|
+
} catch {}
|
|
47435
|
+
await Promise.race([closePromise, new Promise((resolve8) => setTimeout(resolve8, 2000).unref())]);
|
|
47436
|
+
if (processToClose.exitCode === null) {
|
|
47437
|
+
try {
|
|
47438
|
+
processToClose.kill("SIGTERM");
|
|
47439
|
+
} catch {}
|
|
47440
|
+
await Promise.race([closePromise, new Promise((resolve8) => setTimeout(resolve8, 2000).unref())]);
|
|
47441
|
+
}
|
|
47442
|
+
if (processToClose.exitCode === null) {
|
|
47443
|
+
try {
|
|
47444
|
+
processToClose.kill("SIGKILL");
|
|
47445
|
+
} catch {}
|
|
47446
|
+
}
|
|
47447
|
+
}
|
|
47448
|
+
this._readBuffer.clear();
|
|
47449
|
+
}
|
|
47450
|
+
send(message) {
|
|
47451
|
+
return new Promise((resolve8) => {
|
|
47452
|
+
if (!this._process?.stdin) {
|
|
47453
|
+
throw new Error("Not connected");
|
|
47454
|
+
}
|
|
47455
|
+
const json3 = serializeMessage(message);
|
|
47456
|
+
if (this._process.stdin.write(json3)) {
|
|
47457
|
+
resolve8();
|
|
47458
|
+
} else {
|
|
47459
|
+
this._process.stdin.once("drain", resolve8);
|
|
47460
|
+
}
|
|
47461
|
+
});
|
|
47462
|
+
}
|
|
47463
|
+
}
|
|
47464
|
+
function isElectron() {
|
|
47465
|
+
return "type" in process2;
|
|
47466
|
+
}
|
|
47467
|
+
|
|
47468
|
+
// node_modules/eventsource-parser/dist/index.js
|
|
47469
|
+
class ParseError2 extends Error {
|
|
47470
|
+
constructor(message, options) {
|
|
47471
|
+
super(message), this.name = "ParseError", this.type = options.type, this.field = options.field, this.value = options.value, this.line = options.line;
|
|
47472
|
+
}
|
|
47473
|
+
}
|
|
47474
|
+
function noop(_arg) {}
|
|
47475
|
+
function createParser(callbacks) {
|
|
47476
|
+
if (typeof callbacks == "function")
|
|
47477
|
+
throw new TypeError("`callbacks` must be an object, got a function instead. Did you mean `{onEvent: fn}`?");
|
|
47478
|
+
const { onEvent = noop, onError = noop, onRetry = noop, onComment } = callbacks;
|
|
47479
|
+
let incompleteLine = "", isFirstChunk = true, id, data = "", eventType = "";
|
|
47480
|
+
function feed(newChunk) {
|
|
47481
|
+
const chunk = isFirstChunk ? newChunk.replace(/^\xEF\xBB\xBF/, "") : newChunk, [complete, incomplete] = splitLines(`${incompleteLine}${chunk}`);
|
|
47482
|
+
for (const line of complete)
|
|
47483
|
+
parseLine(line);
|
|
47484
|
+
incompleteLine = incomplete, isFirstChunk = false;
|
|
47485
|
+
}
|
|
47486
|
+
function parseLine(line) {
|
|
47487
|
+
if (line === "") {
|
|
47488
|
+
dispatchEvent();
|
|
47489
|
+
return;
|
|
47490
|
+
}
|
|
47491
|
+
if (line.startsWith(":")) {
|
|
47492
|
+
onComment && onComment(line.slice(line.startsWith(": ") ? 2 : 1));
|
|
47493
|
+
return;
|
|
47494
|
+
}
|
|
47495
|
+
const fieldSeparatorIndex = line.indexOf(":");
|
|
47496
|
+
if (fieldSeparatorIndex !== -1) {
|
|
47497
|
+
const field = line.slice(0, fieldSeparatorIndex), offset = line[fieldSeparatorIndex + 1] === " " ? 2 : 1, value = line.slice(fieldSeparatorIndex + offset);
|
|
47498
|
+
processField(field, value, line);
|
|
47499
|
+
return;
|
|
47500
|
+
}
|
|
47501
|
+
processField(line, "", line);
|
|
47502
|
+
}
|
|
47503
|
+
function processField(field, value, line) {
|
|
47504
|
+
switch (field) {
|
|
47505
|
+
case "event":
|
|
47506
|
+
eventType = value;
|
|
47507
|
+
break;
|
|
47508
|
+
case "data":
|
|
47509
|
+
data = `${data}${value}
|
|
47510
|
+
`;
|
|
47511
|
+
break;
|
|
47512
|
+
case "id":
|
|
47513
|
+
id = value.includes("\x00") ? undefined : value;
|
|
47514
|
+
break;
|
|
47515
|
+
case "retry":
|
|
47516
|
+
/^\d+$/.test(value) ? onRetry(parseInt(value, 10)) : onError(new ParseError2(`Invalid \`retry\` value: "${value}"`, {
|
|
47517
|
+
type: "invalid-retry",
|
|
47518
|
+
value,
|
|
47519
|
+
line
|
|
47520
|
+
}));
|
|
47521
|
+
break;
|
|
47522
|
+
default:
|
|
47523
|
+
onError(new ParseError2(`Unknown field "${field.length > 20 ? `${field.slice(0, 20)}\u2026` : field}"`, { type: "unknown-field", field, value, line }));
|
|
47524
|
+
break;
|
|
47525
|
+
}
|
|
47526
|
+
}
|
|
47527
|
+
function dispatchEvent() {
|
|
47528
|
+
data.length > 0 && onEvent({
|
|
47529
|
+
id,
|
|
47530
|
+
event: eventType || undefined,
|
|
47531
|
+
data: data.endsWith(`
|
|
47532
|
+
`) ? data.slice(0, -1) : data
|
|
47533
|
+
}), id = undefined, data = "", eventType = "";
|
|
47534
|
+
}
|
|
47535
|
+
function reset(options = {}) {
|
|
47536
|
+
incompleteLine && options.consume && parseLine(incompleteLine), isFirstChunk = true, id = undefined, data = "", eventType = "", incompleteLine = "";
|
|
47537
|
+
}
|
|
47538
|
+
return { feed, reset };
|
|
47539
|
+
}
|
|
47540
|
+
function splitLines(chunk) {
|
|
47541
|
+
const lines = [];
|
|
47542
|
+
let incompleteLine = "", searchIndex = 0;
|
|
47543
|
+
for (;searchIndex < chunk.length; ) {
|
|
47544
|
+
const crIndex = chunk.indexOf("\r", searchIndex), lfIndex = chunk.indexOf(`
|
|
47545
|
+
`, searchIndex);
|
|
47546
|
+
let lineEnd = -1;
|
|
47547
|
+
if (crIndex !== -1 && lfIndex !== -1 ? lineEnd = Math.min(crIndex, lfIndex) : crIndex !== -1 ? crIndex === chunk.length - 1 ? lineEnd = -1 : lineEnd = crIndex : lfIndex !== -1 && (lineEnd = lfIndex), lineEnd === -1) {
|
|
47548
|
+
incompleteLine = chunk.slice(searchIndex);
|
|
47549
|
+
break;
|
|
47550
|
+
} else {
|
|
47551
|
+
const line = chunk.slice(searchIndex, lineEnd);
|
|
47552
|
+
lines.push(line), searchIndex = lineEnd + 1, chunk[searchIndex - 1] === "\r" && chunk[searchIndex] === `
|
|
47553
|
+
` && searchIndex++;
|
|
47554
|
+
}
|
|
47555
|
+
}
|
|
47556
|
+
return [lines, incompleteLine];
|
|
47557
|
+
}
|
|
47558
|
+
|
|
47559
|
+
// node_modules/eventsource/dist/index.js
|
|
47560
|
+
class ErrorEvent extends Event {
|
|
47561
|
+
constructor(type2, errorEventInitDict) {
|
|
47562
|
+
var _a, _b;
|
|
47563
|
+
super(type2), this.code = (_a = errorEventInitDict == null ? undefined : errorEventInitDict.code) != null ? _a : undefined, this.message = (_b = errorEventInitDict == null ? undefined : errorEventInitDict.message) != null ? _b : undefined;
|
|
47564
|
+
}
|
|
47565
|
+
[Symbol.for("nodejs.util.inspect.custom")](_depth, options, inspect) {
|
|
47566
|
+
return inspect(inspectableError(this), options);
|
|
47567
|
+
}
|
|
47568
|
+
[Symbol.for("Deno.customInspect")](inspect, options) {
|
|
47569
|
+
return inspect(inspectableError(this), options);
|
|
47570
|
+
}
|
|
47571
|
+
}
|
|
47572
|
+
function syntaxError(message) {
|
|
47573
|
+
const DomException = globalThis.DOMException;
|
|
47574
|
+
return typeof DomException == "function" ? new DomException(message, "SyntaxError") : new SyntaxError(message);
|
|
47575
|
+
}
|
|
47576
|
+
function flattenError2(err) {
|
|
47577
|
+
return err instanceof Error ? "errors" in err && Array.isArray(err.errors) ? err.errors.map(flattenError2).join(", ") : ("cause" in err) && err.cause instanceof Error ? `${err}: ${flattenError2(err.cause)}` : err.message : `${err}`;
|
|
47578
|
+
}
|
|
47579
|
+
function inspectableError(err) {
|
|
47580
|
+
return {
|
|
47581
|
+
type: err.type,
|
|
47582
|
+
message: err.message,
|
|
47583
|
+
code: err.code,
|
|
47584
|
+
defaultPrevented: err.defaultPrevented,
|
|
47585
|
+
cancelable: err.cancelable,
|
|
47586
|
+
timeStamp: err.timeStamp
|
|
47587
|
+
};
|
|
47588
|
+
}
|
|
47589
|
+
var __typeError = (msg) => {
|
|
47590
|
+
throw TypeError(msg);
|
|
47591
|
+
};
|
|
47592
|
+
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
47593
|
+
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
47594
|
+
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
47595
|
+
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
|
|
47596
|
+
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
47597
|
+
var _readyState;
|
|
47598
|
+
var _url2;
|
|
47599
|
+
var _redirectUrl;
|
|
47600
|
+
var _withCredentials;
|
|
47601
|
+
var _fetch;
|
|
47602
|
+
var _reconnectInterval;
|
|
47603
|
+
var _reconnectTimer;
|
|
47604
|
+
var _lastEventId;
|
|
47605
|
+
var _controller;
|
|
47606
|
+
var _parser;
|
|
47607
|
+
var _onError;
|
|
47608
|
+
var _onMessage;
|
|
47609
|
+
var _onOpen;
|
|
47610
|
+
var _EventSource_instances;
|
|
47611
|
+
var connect_fn;
|
|
47612
|
+
var _onFetchResponse;
|
|
47613
|
+
var _onFetchError;
|
|
47614
|
+
var getRequestOptions_fn;
|
|
47615
|
+
var _onEvent;
|
|
47616
|
+
var _onRetryChange;
|
|
47617
|
+
var failConnection_fn;
|
|
47618
|
+
var scheduleReconnect_fn;
|
|
47619
|
+
var _reconnect;
|
|
47620
|
+
|
|
47621
|
+
class EventSource extends EventTarget {
|
|
47622
|
+
constructor(url2, eventSourceInitDict) {
|
|
47623
|
+
var _a, _b;
|
|
47624
|
+
super(), __privateAdd(this, _EventSource_instances), this.CONNECTING = 0, this.OPEN = 1, this.CLOSED = 2, __privateAdd(this, _readyState), __privateAdd(this, _url2), __privateAdd(this, _redirectUrl), __privateAdd(this, _withCredentials), __privateAdd(this, _fetch), __privateAdd(this, _reconnectInterval), __privateAdd(this, _reconnectTimer), __privateAdd(this, _lastEventId, null), __privateAdd(this, _controller), __privateAdd(this, _parser), __privateAdd(this, _onError, null), __privateAdd(this, _onMessage, null), __privateAdd(this, _onOpen, null), __privateAdd(this, _onFetchResponse, async (response2) => {
|
|
47625
|
+
var _a2;
|
|
47626
|
+
__privateGet(this, _parser).reset();
|
|
47627
|
+
const { body, redirected, status, headers } = response2;
|
|
47628
|
+
if (status === 204) {
|
|
47629
|
+
__privateMethod(this, _EventSource_instances, failConnection_fn).call(this, "Server sent HTTP 204, not reconnecting", 204), this.close();
|
|
47630
|
+
return;
|
|
47631
|
+
}
|
|
47632
|
+
if (redirected ? __privateSet(this, _redirectUrl, new URL(response2.url)) : __privateSet(this, _redirectUrl, undefined), status !== 200) {
|
|
47633
|
+
__privateMethod(this, _EventSource_instances, failConnection_fn).call(this, `Non-200 status code (${status})`, status);
|
|
47634
|
+
return;
|
|
47635
|
+
}
|
|
47636
|
+
if (!(headers.get("content-type") || "").startsWith("text/event-stream")) {
|
|
47637
|
+
__privateMethod(this, _EventSource_instances, failConnection_fn).call(this, 'Invalid content type, expected "text/event-stream"', status);
|
|
47638
|
+
return;
|
|
47639
|
+
}
|
|
47640
|
+
if (__privateGet(this, _readyState) === this.CLOSED)
|
|
47641
|
+
return;
|
|
47642
|
+
__privateSet(this, _readyState, this.OPEN);
|
|
47643
|
+
const openEvent = new Event("open");
|
|
47644
|
+
if ((_a2 = __privateGet(this, _onOpen)) == null || _a2.call(this, openEvent), this.dispatchEvent(openEvent), typeof body != "object" || !body || !("getReader" in body)) {
|
|
47645
|
+
__privateMethod(this, _EventSource_instances, failConnection_fn).call(this, "Invalid response body, expected a web ReadableStream", status), this.close();
|
|
47646
|
+
return;
|
|
47647
|
+
}
|
|
47648
|
+
const decoder2 = new TextDecoder, reader = body.getReader();
|
|
47649
|
+
let open = true;
|
|
47650
|
+
do {
|
|
47651
|
+
const { done, value } = await reader.read();
|
|
47652
|
+
value && __privateGet(this, _parser).feed(decoder2.decode(value, { stream: !done })), done && (open = false, __privateGet(this, _parser).reset(), __privateMethod(this, _EventSource_instances, scheduleReconnect_fn).call(this));
|
|
47653
|
+
} while (open);
|
|
47654
|
+
}), __privateAdd(this, _onFetchError, (err) => {
|
|
47655
|
+
__privateSet(this, _controller, undefined), !(err.name === "AbortError" || err.type === "aborted") && __privateMethod(this, _EventSource_instances, scheduleReconnect_fn).call(this, flattenError2(err));
|
|
47656
|
+
}), __privateAdd(this, _onEvent, (event) => {
|
|
47657
|
+
typeof event.id == "string" && __privateSet(this, _lastEventId, event.id);
|
|
47658
|
+
const messageEvent = new MessageEvent(event.event || "message", {
|
|
47659
|
+
data: event.data,
|
|
47660
|
+
origin: __privateGet(this, _redirectUrl) ? __privateGet(this, _redirectUrl).origin : __privateGet(this, _url2).origin,
|
|
47661
|
+
lastEventId: event.id || ""
|
|
47662
|
+
});
|
|
47663
|
+
__privateGet(this, _onMessage) && (!event.event || event.event === "message") && __privateGet(this, _onMessage).call(this, messageEvent), this.dispatchEvent(messageEvent);
|
|
47664
|
+
}), __privateAdd(this, _onRetryChange, (value) => {
|
|
47665
|
+
__privateSet(this, _reconnectInterval, value);
|
|
47666
|
+
}), __privateAdd(this, _reconnect, () => {
|
|
47667
|
+
__privateSet(this, _reconnectTimer, undefined), __privateGet(this, _readyState) === this.CONNECTING && __privateMethod(this, _EventSource_instances, connect_fn).call(this);
|
|
47668
|
+
});
|
|
47669
|
+
try {
|
|
47670
|
+
if (url2 instanceof URL)
|
|
47671
|
+
__privateSet(this, _url2, url2);
|
|
47672
|
+
else if (typeof url2 == "string")
|
|
47673
|
+
__privateSet(this, _url2, new URL(url2, getBaseURL()));
|
|
47674
|
+
else
|
|
47675
|
+
throw new Error("Invalid URL");
|
|
47676
|
+
} catch {
|
|
47677
|
+
throw syntaxError("An invalid or illegal string was specified");
|
|
47678
|
+
}
|
|
47679
|
+
__privateSet(this, _parser, createParser({
|
|
47680
|
+
onEvent: __privateGet(this, _onEvent),
|
|
47681
|
+
onRetry: __privateGet(this, _onRetryChange)
|
|
47682
|
+
})), __privateSet(this, _readyState, this.CONNECTING), __privateSet(this, _reconnectInterval, 3000), __privateSet(this, _fetch, (_a = eventSourceInitDict == null ? undefined : eventSourceInitDict.fetch) != null ? _a : globalThis.fetch), __privateSet(this, _withCredentials, (_b = eventSourceInitDict == null ? undefined : eventSourceInitDict.withCredentials) != null ? _b : false), __privateMethod(this, _EventSource_instances, connect_fn).call(this);
|
|
47683
|
+
}
|
|
47684
|
+
get readyState() {
|
|
47685
|
+
return __privateGet(this, _readyState);
|
|
47686
|
+
}
|
|
47687
|
+
get url() {
|
|
47688
|
+
return __privateGet(this, _url2).href;
|
|
47689
|
+
}
|
|
47690
|
+
get withCredentials() {
|
|
47691
|
+
return __privateGet(this, _withCredentials);
|
|
47692
|
+
}
|
|
47693
|
+
get onerror() {
|
|
47694
|
+
return __privateGet(this, _onError);
|
|
47695
|
+
}
|
|
47696
|
+
set onerror(value) {
|
|
47697
|
+
__privateSet(this, _onError, value);
|
|
47698
|
+
}
|
|
47699
|
+
get onmessage() {
|
|
47700
|
+
return __privateGet(this, _onMessage);
|
|
47701
|
+
}
|
|
47702
|
+
set onmessage(value) {
|
|
47703
|
+
__privateSet(this, _onMessage, value);
|
|
47704
|
+
}
|
|
47705
|
+
get onopen() {
|
|
47706
|
+
return __privateGet(this, _onOpen);
|
|
47707
|
+
}
|
|
47708
|
+
set onopen(value) {
|
|
47709
|
+
__privateSet(this, _onOpen, value);
|
|
47710
|
+
}
|
|
47711
|
+
addEventListener(type2, listener, options) {
|
|
47712
|
+
const listen = listener;
|
|
47713
|
+
super.addEventListener(type2, listen, options);
|
|
47714
|
+
}
|
|
47715
|
+
removeEventListener(type2, listener, options) {
|
|
47716
|
+
const listen = listener;
|
|
47717
|
+
super.removeEventListener(type2, listen, options);
|
|
47718
|
+
}
|
|
47719
|
+
close() {
|
|
47720
|
+
__privateGet(this, _reconnectTimer) && clearTimeout(__privateGet(this, _reconnectTimer)), __privateGet(this, _readyState) !== this.CLOSED && (__privateGet(this, _controller) && __privateGet(this, _controller).abort(), __privateSet(this, _readyState, this.CLOSED), __privateSet(this, _controller, undefined));
|
|
47721
|
+
}
|
|
47722
|
+
}
|
|
47723
|
+
_readyState = /* @__PURE__ */ new WeakMap, _url2 = /* @__PURE__ */ new WeakMap, _redirectUrl = /* @__PURE__ */ new WeakMap, _withCredentials = /* @__PURE__ */ new WeakMap, _fetch = /* @__PURE__ */ new WeakMap, _reconnectInterval = /* @__PURE__ */ new WeakMap, _reconnectTimer = /* @__PURE__ */ new WeakMap, _lastEventId = /* @__PURE__ */ new WeakMap, _controller = /* @__PURE__ */ new WeakMap, _parser = /* @__PURE__ */ new WeakMap, _onError = /* @__PURE__ */ new WeakMap, _onMessage = /* @__PURE__ */ new WeakMap, _onOpen = /* @__PURE__ */ new WeakMap, _EventSource_instances = /* @__PURE__ */ new WeakSet, connect_fn = function() {
|
|
47724
|
+
__privateSet(this, _readyState, this.CONNECTING), __privateSet(this, _controller, new AbortController), __privateGet(this, _fetch)(__privateGet(this, _url2), __privateMethod(this, _EventSource_instances, getRequestOptions_fn).call(this)).then(__privateGet(this, _onFetchResponse)).catch(__privateGet(this, _onFetchError));
|
|
47725
|
+
}, _onFetchResponse = /* @__PURE__ */ new WeakMap, _onFetchError = /* @__PURE__ */ new WeakMap, getRequestOptions_fn = function() {
|
|
47726
|
+
var _a;
|
|
47727
|
+
const init = {
|
|
47728
|
+
mode: "cors",
|
|
47729
|
+
redirect: "follow",
|
|
47730
|
+
headers: { Accept: "text/event-stream", ...__privateGet(this, _lastEventId) ? { "Last-Event-ID": __privateGet(this, _lastEventId) } : undefined },
|
|
47731
|
+
cache: "no-store",
|
|
47732
|
+
signal: (_a = __privateGet(this, _controller)) == null ? undefined : _a.signal
|
|
47733
|
+
};
|
|
47734
|
+
return "window" in globalThis && (init.credentials = this.withCredentials ? "include" : "same-origin"), init;
|
|
47735
|
+
}, _onEvent = /* @__PURE__ */ new WeakMap, _onRetryChange = /* @__PURE__ */ new WeakMap, failConnection_fn = function(message, code) {
|
|
47736
|
+
var _a;
|
|
47737
|
+
__privateGet(this, _readyState) !== this.CLOSED && __privateSet(this, _readyState, this.CLOSED);
|
|
47738
|
+
const errorEvent = new ErrorEvent("error", { code, message });
|
|
47739
|
+
(_a = __privateGet(this, _onError)) == null || _a.call(this, errorEvent), this.dispatchEvent(errorEvent);
|
|
47740
|
+
}, scheduleReconnect_fn = function(message, code) {
|
|
47741
|
+
var _a;
|
|
47742
|
+
if (__privateGet(this, _readyState) === this.CLOSED)
|
|
47743
|
+
return;
|
|
47744
|
+
__privateSet(this, _readyState, this.CONNECTING);
|
|
47745
|
+
const errorEvent = new ErrorEvent("error", { code, message });
|
|
47746
|
+
(_a = __privateGet(this, _onError)) == null || _a.call(this, errorEvent), this.dispatchEvent(errorEvent), __privateSet(this, _reconnectTimer, setTimeout(__privateGet(this, _reconnect), __privateGet(this, _reconnectInterval)));
|
|
47747
|
+
}, _reconnect = /* @__PURE__ */ new WeakMap, EventSource.CONNECTING = 0, EventSource.OPEN = 1, EventSource.CLOSED = 2;
|
|
47748
|
+
function getBaseURL() {
|
|
47749
|
+
const doc2 = "document" in globalThis ? globalThis.document : undefined;
|
|
47750
|
+
return doc2 && typeof doc2 == "object" && "baseURI" in doc2 && typeof doc2.baseURI == "string" ? doc2.baseURI : undefined;
|
|
47751
|
+
}
|
|
47752
|
+
|
|
47753
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/shared/transport.js
|
|
47754
|
+
function normalizeHeaders(headers) {
|
|
47755
|
+
if (!headers)
|
|
47756
|
+
return {};
|
|
47757
|
+
if (headers instanceof Headers) {
|
|
47758
|
+
return Object.fromEntries(headers.entries());
|
|
47759
|
+
}
|
|
47760
|
+
if (Array.isArray(headers)) {
|
|
47761
|
+
return Object.fromEntries(headers);
|
|
47762
|
+
}
|
|
47763
|
+
return { ...headers };
|
|
47764
|
+
}
|
|
47765
|
+
function createFetchWithInit(baseFetch = fetch, baseInit) {
|
|
47766
|
+
if (!baseInit) {
|
|
47767
|
+
return baseFetch;
|
|
47768
|
+
}
|
|
47769
|
+
return async (url2, init) => {
|
|
47770
|
+
const mergedInit = {
|
|
47771
|
+
...baseInit,
|
|
47772
|
+
...init,
|
|
47773
|
+
headers: init?.headers ? { ...normalizeHeaders(baseInit.headers), ...normalizeHeaders(init.headers) } : baseInit.headers
|
|
47774
|
+
};
|
|
47775
|
+
return baseFetch(url2, mergedInit);
|
|
47776
|
+
};
|
|
47777
|
+
}
|
|
47778
|
+
|
|
47779
|
+
// node_modules/pkce-challenge/dist/index.node.js
|
|
47780
|
+
var crypto2;
|
|
47781
|
+
crypto2 = globalThis.crypto?.webcrypto ?? globalThis.crypto ?? import("crypto").then((m) => m.webcrypto);
|
|
47782
|
+
async function getRandomValues(size) {
|
|
47783
|
+
return (await crypto2).getRandomValues(new Uint8Array(size));
|
|
47784
|
+
}
|
|
47785
|
+
async function random(size) {
|
|
47786
|
+
const mask = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._~";
|
|
47787
|
+
const evenDistCutoff = Math.pow(2, 8) - Math.pow(2, 8) % mask.length;
|
|
47788
|
+
let result = "";
|
|
47789
|
+
while (result.length < size) {
|
|
47790
|
+
const randomBytes = await getRandomValues(size - result.length);
|
|
47791
|
+
for (const randomByte of randomBytes) {
|
|
47792
|
+
if (randomByte < evenDistCutoff) {
|
|
47793
|
+
result += mask[randomByte % mask.length];
|
|
47794
|
+
}
|
|
47795
|
+
}
|
|
47796
|
+
}
|
|
47797
|
+
return result;
|
|
47798
|
+
}
|
|
47799
|
+
async function generateVerifier2(length) {
|
|
47800
|
+
return await random(length);
|
|
47801
|
+
}
|
|
47802
|
+
async function generateChallenge2(code_verifier) {
|
|
47803
|
+
const buffer = await (await crypto2).subtle.digest("SHA-256", new TextEncoder().encode(code_verifier));
|
|
47804
|
+
return btoa(String.fromCharCode(...new Uint8Array(buffer))).replace(/\//g, "_").replace(/\+/g, "-").replace(/=/g, "");
|
|
47805
|
+
}
|
|
47806
|
+
async function pkceChallenge(length) {
|
|
47807
|
+
if (!length)
|
|
47808
|
+
length = 43;
|
|
47809
|
+
if (length < 43 || length > 128) {
|
|
47810
|
+
throw `Expected a length between 43 and 128. Received ${length}.`;
|
|
47811
|
+
}
|
|
47812
|
+
const verifier = await generateVerifier2(length);
|
|
47813
|
+
const challenge = await generateChallenge2(verifier);
|
|
47814
|
+
return {
|
|
47815
|
+
code_verifier: verifier,
|
|
47816
|
+
code_challenge: challenge
|
|
47817
|
+
};
|
|
47818
|
+
}
|
|
47819
|
+
|
|
47820
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/shared/auth.js
|
|
47821
|
+
var SafeUrlSchema = url().superRefine((val, ctx) => {
|
|
47822
|
+
if (!URL.canParse(val)) {
|
|
47823
|
+
ctx.addIssue({
|
|
47824
|
+
code: ZodIssueCode.custom,
|
|
47825
|
+
message: "URL must be parseable",
|
|
47826
|
+
fatal: true
|
|
47827
|
+
});
|
|
47828
|
+
return NEVER;
|
|
47829
|
+
}
|
|
47830
|
+
}).refine((url2) => {
|
|
47831
|
+
const u = new URL(url2);
|
|
47832
|
+
return u.protocol !== "javascript:" && u.protocol !== "data:" && u.protocol !== "vbscript:";
|
|
47833
|
+
}, { message: "URL cannot use javascript:, data:, or vbscript: scheme" });
|
|
47834
|
+
var OAuthProtectedResourceMetadataSchema = looseObject({
|
|
47835
|
+
resource: string2().url(),
|
|
47836
|
+
authorization_servers: array(SafeUrlSchema).optional(),
|
|
47837
|
+
jwks_uri: string2().url().optional(),
|
|
47838
|
+
scopes_supported: array(string2()).optional(),
|
|
47839
|
+
bearer_methods_supported: array(string2()).optional(),
|
|
47840
|
+
resource_signing_alg_values_supported: array(string2()).optional(),
|
|
47841
|
+
resource_name: string2().optional(),
|
|
47842
|
+
resource_documentation: string2().optional(),
|
|
47843
|
+
resource_policy_uri: string2().url().optional(),
|
|
47844
|
+
resource_tos_uri: string2().url().optional(),
|
|
47845
|
+
tls_client_certificate_bound_access_tokens: boolean2().optional(),
|
|
47846
|
+
authorization_details_types_supported: array(string2()).optional(),
|
|
47847
|
+
dpop_signing_alg_values_supported: array(string2()).optional(),
|
|
47848
|
+
dpop_bound_access_tokens_required: boolean2().optional()
|
|
47849
|
+
});
|
|
47850
|
+
var OAuthMetadataSchema = looseObject({
|
|
47851
|
+
issuer: string2(),
|
|
47852
|
+
authorization_endpoint: SafeUrlSchema,
|
|
47853
|
+
token_endpoint: SafeUrlSchema,
|
|
47854
|
+
registration_endpoint: SafeUrlSchema.optional(),
|
|
47855
|
+
scopes_supported: array(string2()).optional(),
|
|
47856
|
+
response_types_supported: array(string2()),
|
|
47857
|
+
response_modes_supported: array(string2()).optional(),
|
|
47858
|
+
grant_types_supported: array(string2()).optional(),
|
|
47859
|
+
token_endpoint_auth_methods_supported: array(string2()).optional(),
|
|
47860
|
+
token_endpoint_auth_signing_alg_values_supported: array(string2()).optional(),
|
|
47861
|
+
service_documentation: SafeUrlSchema.optional(),
|
|
47862
|
+
revocation_endpoint: SafeUrlSchema.optional(),
|
|
47863
|
+
revocation_endpoint_auth_methods_supported: array(string2()).optional(),
|
|
47864
|
+
revocation_endpoint_auth_signing_alg_values_supported: array(string2()).optional(),
|
|
47865
|
+
introspection_endpoint: string2().optional(),
|
|
47866
|
+
introspection_endpoint_auth_methods_supported: array(string2()).optional(),
|
|
47867
|
+
introspection_endpoint_auth_signing_alg_values_supported: array(string2()).optional(),
|
|
47868
|
+
code_challenge_methods_supported: array(string2()).optional(),
|
|
47869
|
+
client_id_metadata_document_supported: boolean2().optional()
|
|
47870
|
+
});
|
|
47871
|
+
var OpenIdProviderMetadataSchema = looseObject({
|
|
47872
|
+
issuer: string2(),
|
|
47873
|
+
authorization_endpoint: SafeUrlSchema,
|
|
47874
|
+
token_endpoint: SafeUrlSchema,
|
|
47875
|
+
userinfo_endpoint: SafeUrlSchema.optional(),
|
|
47876
|
+
jwks_uri: SafeUrlSchema,
|
|
47877
|
+
registration_endpoint: SafeUrlSchema.optional(),
|
|
47878
|
+
scopes_supported: array(string2()).optional(),
|
|
47879
|
+
response_types_supported: array(string2()),
|
|
47880
|
+
response_modes_supported: array(string2()).optional(),
|
|
47881
|
+
grant_types_supported: array(string2()).optional(),
|
|
47882
|
+
acr_values_supported: array(string2()).optional(),
|
|
47883
|
+
subject_types_supported: array(string2()),
|
|
47884
|
+
id_token_signing_alg_values_supported: array(string2()),
|
|
47885
|
+
id_token_encryption_alg_values_supported: array(string2()).optional(),
|
|
47886
|
+
id_token_encryption_enc_values_supported: array(string2()).optional(),
|
|
47887
|
+
userinfo_signing_alg_values_supported: array(string2()).optional(),
|
|
47888
|
+
userinfo_encryption_alg_values_supported: array(string2()).optional(),
|
|
47889
|
+
userinfo_encryption_enc_values_supported: array(string2()).optional(),
|
|
47890
|
+
request_object_signing_alg_values_supported: array(string2()).optional(),
|
|
47891
|
+
request_object_encryption_alg_values_supported: array(string2()).optional(),
|
|
47892
|
+
request_object_encryption_enc_values_supported: array(string2()).optional(),
|
|
47893
|
+
token_endpoint_auth_methods_supported: array(string2()).optional(),
|
|
47894
|
+
token_endpoint_auth_signing_alg_values_supported: array(string2()).optional(),
|
|
47895
|
+
display_values_supported: array(string2()).optional(),
|
|
47896
|
+
claim_types_supported: array(string2()).optional(),
|
|
47897
|
+
claims_supported: array(string2()).optional(),
|
|
47898
|
+
service_documentation: string2().optional(),
|
|
47899
|
+
claims_locales_supported: array(string2()).optional(),
|
|
47900
|
+
ui_locales_supported: array(string2()).optional(),
|
|
47901
|
+
claims_parameter_supported: boolean2().optional(),
|
|
47902
|
+
request_parameter_supported: boolean2().optional(),
|
|
47903
|
+
request_uri_parameter_supported: boolean2().optional(),
|
|
47904
|
+
require_request_uri_registration: boolean2().optional(),
|
|
47905
|
+
op_policy_uri: SafeUrlSchema.optional(),
|
|
47906
|
+
op_tos_uri: SafeUrlSchema.optional(),
|
|
47907
|
+
client_id_metadata_document_supported: boolean2().optional()
|
|
47908
|
+
});
|
|
47909
|
+
var OpenIdProviderDiscoveryMetadataSchema = object({
|
|
47910
|
+
...OpenIdProviderMetadataSchema.shape,
|
|
47911
|
+
...OAuthMetadataSchema.pick({
|
|
47912
|
+
code_challenge_methods_supported: true
|
|
47913
|
+
}).shape
|
|
47914
|
+
});
|
|
47915
|
+
var OAuthTokensSchema = object({
|
|
47916
|
+
access_token: string2(),
|
|
47917
|
+
id_token: string2().optional(),
|
|
47918
|
+
token_type: string2(),
|
|
47919
|
+
expires_in: exports_coerce.number().optional(),
|
|
47920
|
+
scope: string2().optional(),
|
|
47921
|
+
refresh_token: string2().optional()
|
|
47922
|
+
}).strip();
|
|
47923
|
+
var OAuthErrorResponseSchema = object({
|
|
47924
|
+
error: string2(),
|
|
47925
|
+
error_description: string2().optional(),
|
|
47926
|
+
error_uri: string2().optional()
|
|
47927
|
+
});
|
|
47928
|
+
var OptionalSafeUrlSchema = SafeUrlSchema.optional().or(literal("").transform(() => {
|
|
47929
|
+
return;
|
|
47930
|
+
}));
|
|
47931
|
+
var OAuthClientMetadataSchema = object({
|
|
47932
|
+
redirect_uris: array(SafeUrlSchema),
|
|
47933
|
+
token_endpoint_auth_method: string2().optional(),
|
|
47934
|
+
grant_types: array(string2()).optional(),
|
|
47935
|
+
response_types: array(string2()).optional(),
|
|
47936
|
+
client_name: string2().optional(),
|
|
47937
|
+
client_uri: SafeUrlSchema.optional(),
|
|
47938
|
+
logo_uri: OptionalSafeUrlSchema,
|
|
47939
|
+
scope: string2().optional(),
|
|
47940
|
+
contacts: array(string2()).optional(),
|
|
47941
|
+
tos_uri: OptionalSafeUrlSchema,
|
|
47942
|
+
policy_uri: string2().optional(),
|
|
47943
|
+
jwks_uri: SafeUrlSchema.optional(),
|
|
47944
|
+
jwks: any().optional(),
|
|
47945
|
+
software_id: string2().optional(),
|
|
47946
|
+
software_version: string2().optional(),
|
|
47947
|
+
software_statement: string2().optional()
|
|
47948
|
+
}).strip();
|
|
47949
|
+
var OAuthClientInformationSchema = object({
|
|
47950
|
+
client_id: string2(),
|
|
47951
|
+
client_secret: string2().optional(),
|
|
47952
|
+
client_id_issued_at: number2().optional(),
|
|
47953
|
+
client_secret_expires_at: number2().optional()
|
|
47954
|
+
}).strip();
|
|
47955
|
+
var OAuthClientInformationFullSchema = OAuthClientMetadataSchema.merge(OAuthClientInformationSchema);
|
|
47956
|
+
var OAuthClientRegistrationErrorSchema = object({
|
|
47957
|
+
error: string2(),
|
|
47958
|
+
error_description: string2().optional()
|
|
47959
|
+
}).strip();
|
|
47960
|
+
var OAuthTokenRevocationRequestSchema = object({
|
|
47961
|
+
token: string2(),
|
|
47962
|
+
token_type_hint: string2().optional()
|
|
47963
|
+
}).strip();
|
|
47964
|
+
|
|
47965
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/shared/auth-utils.js
|
|
47966
|
+
function resourceUrlFromServerUrl(url2) {
|
|
47967
|
+
const resourceURL = typeof url2 === "string" ? new URL(url2) : new URL(url2.href);
|
|
47968
|
+
resourceURL.hash = "";
|
|
47969
|
+
return resourceURL;
|
|
47970
|
+
}
|
|
47971
|
+
function checkResourceAllowed({ requestedResource, configuredResource }) {
|
|
47972
|
+
const requested = typeof requestedResource === "string" ? new URL(requestedResource) : new URL(requestedResource.href);
|
|
47973
|
+
const configured = typeof configuredResource === "string" ? new URL(configuredResource) : new URL(configuredResource.href);
|
|
47974
|
+
if (requested.origin !== configured.origin) {
|
|
47975
|
+
return false;
|
|
47976
|
+
}
|
|
47977
|
+
if (requested.pathname.length < configured.pathname.length) {
|
|
47978
|
+
return false;
|
|
47979
|
+
}
|
|
47980
|
+
const requestedPath = requested.pathname.endsWith("/") ? requested.pathname : requested.pathname + "/";
|
|
47981
|
+
const configuredPath = configured.pathname.endsWith("/") ? configured.pathname : configured.pathname + "/";
|
|
47982
|
+
return requestedPath.startsWith(configuredPath);
|
|
47983
|
+
}
|
|
47984
|
+
|
|
47985
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/server/auth/errors.js
|
|
47986
|
+
class OAuthError extends Error {
|
|
47987
|
+
constructor(message, errorUri) {
|
|
47988
|
+
super(message);
|
|
47989
|
+
this.errorUri = errorUri;
|
|
47990
|
+
this.name = this.constructor.name;
|
|
47991
|
+
}
|
|
47992
|
+
toResponseObject() {
|
|
47993
|
+
const response2 = {
|
|
47994
|
+
error: this.errorCode,
|
|
47995
|
+
error_description: this.message
|
|
47996
|
+
};
|
|
47997
|
+
if (this.errorUri) {
|
|
47998
|
+
response2.error_uri = this.errorUri;
|
|
47999
|
+
}
|
|
48000
|
+
return response2;
|
|
48001
|
+
}
|
|
48002
|
+
get errorCode() {
|
|
48003
|
+
return this.constructor.errorCode;
|
|
48004
|
+
}
|
|
48005
|
+
}
|
|
48006
|
+
|
|
48007
|
+
class InvalidRequestError extends OAuthError {
|
|
48008
|
+
}
|
|
48009
|
+
InvalidRequestError.errorCode = "invalid_request";
|
|
48010
|
+
|
|
48011
|
+
class InvalidClientError extends OAuthError {
|
|
48012
|
+
}
|
|
48013
|
+
InvalidClientError.errorCode = "invalid_client";
|
|
48014
|
+
|
|
48015
|
+
class InvalidGrantError extends OAuthError {
|
|
48016
|
+
}
|
|
48017
|
+
InvalidGrantError.errorCode = "invalid_grant";
|
|
48018
|
+
|
|
48019
|
+
class UnauthorizedClientError extends OAuthError {
|
|
48020
|
+
}
|
|
48021
|
+
UnauthorizedClientError.errorCode = "unauthorized_client";
|
|
48022
|
+
|
|
48023
|
+
class UnsupportedGrantTypeError extends OAuthError {
|
|
48024
|
+
}
|
|
48025
|
+
UnsupportedGrantTypeError.errorCode = "unsupported_grant_type";
|
|
48026
|
+
|
|
48027
|
+
class InvalidScopeError extends OAuthError {
|
|
48028
|
+
}
|
|
48029
|
+
InvalidScopeError.errorCode = "invalid_scope";
|
|
48030
|
+
|
|
48031
|
+
class AccessDeniedError extends OAuthError {
|
|
48032
|
+
}
|
|
48033
|
+
AccessDeniedError.errorCode = "access_denied";
|
|
48034
|
+
|
|
48035
|
+
class ServerError extends OAuthError {
|
|
48036
|
+
}
|
|
48037
|
+
ServerError.errorCode = "server_error";
|
|
48038
|
+
|
|
48039
|
+
class TemporarilyUnavailableError extends OAuthError {
|
|
48040
|
+
}
|
|
48041
|
+
TemporarilyUnavailableError.errorCode = "temporarily_unavailable";
|
|
48042
|
+
|
|
48043
|
+
class UnsupportedResponseTypeError extends OAuthError {
|
|
48044
|
+
}
|
|
48045
|
+
UnsupportedResponseTypeError.errorCode = "unsupported_response_type";
|
|
48046
|
+
|
|
48047
|
+
class UnsupportedTokenTypeError extends OAuthError {
|
|
48048
|
+
}
|
|
48049
|
+
UnsupportedTokenTypeError.errorCode = "unsupported_token_type";
|
|
48050
|
+
|
|
48051
|
+
class InvalidTokenError extends OAuthError {
|
|
48052
|
+
}
|
|
48053
|
+
InvalidTokenError.errorCode = "invalid_token";
|
|
48054
|
+
|
|
48055
|
+
class MethodNotAllowedError extends OAuthError {
|
|
48056
|
+
}
|
|
48057
|
+
MethodNotAllowedError.errorCode = "method_not_allowed";
|
|
48058
|
+
|
|
48059
|
+
class TooManyRequestsError extends OAuthError {
|
|
48060
|
+
}
|
|
48061
|
+
TooManyRequestsError.errorCode = "too_many_requests";
|
|
48062
|
+
|
|
48063
|
+
class InvalidClientMetadataError extends OAuthError {
|
|
48064
|
+
}
|
|
48065
|
+
InvalidClientMetadataError.errorCode = "invalid_client_metadata";
|
|
48066
|
+
|
|
48067
|
+
class InsufficientScopeError extends OAuthError {
|
|
48068
|
+
}
|
|
48069
|
+
InsufficientScopeError.errorCode = "insufficient_scope";
|
|
48070
|
+
|
|
48071
|
+
class InvalidTargetError extends OAuthError {
|
|
48072
|
+
}
|
|
48073
|
+
InvalidTargetError.errorCode = "invalid_target";
|
|
48074
|
+
var OAUTH_ERRORS = {
|
|
48075
|
+
[InvalidRequestError.errorCode]: InvalidRequestError,
|
|
48076
|
+
[InvalidClientError.errorCode]: InvalidClientError,
|
|
48077
|
+
[InvalidGrantError.errorCode]: InvalidGrantError,
|
|
48078
|
+
[UnauthorizedClientError.errorCode]: UnauthorizedClientError,
|
|
48079
|
+
[UnsupportedGrantTypeError.errorCode]: UnsupportedGrantTypeError,
|
|
48080
|
+
[InvalidScopeError.errorCode]: InvalidScopeError,
|
|
48081
|
+
[AccessDeniedError.errorCode]: AccessDeniedError,
|
|
48082
|
+
[ServerError.errorCode]: ServerError,
|
|
48083
|
+
[TemporarilyUnavailableError.errorCode]: TemporarilyUnavailableError,
|
|
48084
|
+
[UnsupportedResponseTypeError.errorCode]: UnsupportedResponseTypeError,
|
|
48085
|
+
[UnsupportedTokenTypeError.errorCode]: UnsupportedTokenTypeError,
|
|
48086
|
+
[InvalidTokenError.errorCode]: InvalidTokenError,
|
|
48087
|
+
[MethodNotAllowedError.errorCode]: MethodNotAllowedError,
|
|
48088
|
+
[TooManyRequestsError.errorCode]: TooManyRequestsError,
|
|
48089
|
+
[InvalidClientMetadataError.errorCode]: InvalidClientMetadataError,
|
|
48090
|
+
[InsufficientScopeError.errorCode]: InsufficientScopeError,
|
|
48091
|
+
[InvalidTargetError.errorCode]: InvalidTargetError
|
|
48092
|
+
};
|
|
48093
|
+
|
|
48094
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/client/auth.js
|
|
48095
|
+
class UnauthorizedError extends Error {
|
|
48096
|
+
constructor(message) {
|
|
48097
|
+
super(message ?? "Unauthorized");
|
|
48098
|
+
}
|
|
48099
|
+
}
|
|
48100
|
+
function isClientAuthMethod(method) {
|
|
48101
|
+
return ["client_secret_basic", "client_secret_post", "none"].includes(method);
|
|
48102
|
+
}
|
|
48103
|
+
var AUTHORIZATION_CODE_RESPONSE_TYPE = "code";
|
|
48104
|
+
var AUTHORIZATION_CODE_CHALLENGE_METHOD = "S256";
|
|
48105
|
+
function selectClientAuthMethod(clientInformation, supportedMethods) {
|
|
48106
|
+
const hasClientSecret = clientInformation.client_secret !== undefined;
|
|
48107
|
+
if (supportedMethods.length === 0) {
|
|
48108
|
+
return hasClientSecret ? "client_secret_post" : "none";
|
|
48109
|
+
}
|
|
48110
|
+
if ("token_endpoint_auth_method" in clientInformation && clientInformation.token_endpoint_auth_method && isClientAuthMethod(clientInformation.token_endpoint_auth_method) && supportedMethods.includes(clientInformation.token_endpoint_auth_method)) {
|
|
48111
|
+
return clientInformation.token_endpoint_auth_method;
|
|
48112
|
+
}
|
|
48113
|
+
if (hasClientSecret && supportedMethods.includes("client_secret_basic")) {
|
|
48114
|
+
return "client_secret_basic";
|
|
48115
|
+
}
|
|
48116
|
+
if (hasClientSecret && supportedMethods.includes("client_secret_post")) {
|
|
48117
|
+
return "client_secret_post";
|
|
48118
|
+
}
|
|
48119
|
+
if (supportedMethods.includes("none")) {
|
|
48120
|
+
return "none";
|
|
48121
|
+
}
|
|
48122
|
+
return hasClientSecret ? "client_secret_post" : "none";
|
|
48123
|
+
}
|
|
48124
|
+
function applyClientAuthentication(method, clientInformation, headers, params) {
|
|
48125
|
+
const { client_id, client_secret } = clientInformation;
|
|
48126
|
+
switch (method) {
|
|
48127
|
+
case "client_secret_basic":
|
|
48128
|
+
applyBasicAuth(client_id, client_secret, headers);
|
|
48129
|
+
return;
|
|
48130
|
+
case "client_secret_post":
|
|
48131
|
+
applyPostAuth(client_id, client_secret, params);
|
|
48132
|
+
return;
|
|
48133
|
+
case "none":
|
|
48134
|
+
applyPublicAuth(client_id, params);
|
|
48135
|
+
return;
|
|
48136
|
+
default:
|
|
48137
|
+
throw new Error(`Unsupported client authentication method: ${method}`);
|
|
48138
|
+
}
|
|
48139
|
+
}
|
|
48140
|
+
function applyBasicAuth(clientId, clientSecret, headers) {
|
|
48141
|
+
if (!clientSecret) {
|
|
48142
|
+
throw new Error("client_secret_basic authentication requires a client_secret");
|
|
48143
|
+
}
|
|
48144
|
+
const credentials = btoa(`${clientId}:${clientSecret}`);
|
|
48145
|
+
headers.set("Authorization", `Basic ${credentials}`);
|
|
48146
|
+
}
|
|
48147
|
+
function applyPostAuth(clientId, clientSecret, params) {
|
|
48148
|
+
params.set("client_id", clientId);
|
|
48149
|
+
if (clientSecret) {
|
|
48150
|
+
params.set("client_secret", clientSecret);
|
|
48151
|
+
}
|
|
48152
|
+
}
|
|
48153
|
+
function applyPublicAuth(clientId, params) {
|
|
48154
|
+
params.set("client_id", clientId);
|
|
48155
|
+
}
|
|
48156
|
+
async function parseErrorResponse(input) {
|
|
48157
|
+
const statusCode = input instanceof Response ? input.status : undefined;
|
|
48158
|
+
const body = input instanceof Response ? await input.text() : input;
|
|
48159
|
+
try {
|
|
48160
|
+
const result = OAuthErrorResponseSchema.parse(JSON.parse(body));
|
|
48161
|
+
const { error: error45, error_description, error_uri } = result;
|
|
48162
|
+
const errorClass = OAUTH_ERRORS[error45] || ServerError;
|
|
48163
|
+
return new errorClass(error_description || "", error_uri);
|
|
48164
|
+
} catch (error45) {
|
|
48165
|
+
const errorMessage = `${statusCode ? `HTTP ${statusCode}: ` : ""}Invalid OAuth error response: ${error45}. Raw body: ${body}`;
|
|
48166
|
+
return new ServerError(errorMessage);
|
|
48167
|
+
}
|
|
48168
|
+
}
|
|
48169
|
+
async function auth(provider, options) {
|
|
48170
|
+
try {
|
|
48171
|
+
return await authInternal(provider, options);
|
|
48172
|
+
} catch (error45) {
|
|
48173
|
+
if (error45 instanceof InvalidClientError || error45 instanceof UnauthorizedClientError) {
|
|
48174
|
+
await provider.invalidateCredentials?.("all");
|
|
48175
|
+
return await authInternal(provider, options);
|
|
48176
|
+
} else if (error45 instanceof InvalidGrantError) {
|
|
48177
|
+
await provider.invalidateCredentials?.("tokens");
|
|
48178
|
+
return await authInternal(provider, options);
|
|
48179
|
+
}
|
|
48180
|
+
throw error45;
|
|
48181
|
+
}
|
|
48182
|
+
}
|
|
48183
|
+
async function authInternal(provider, { serverUrl, authorizationCode, scope, resourceMetadataUrl, fetchFn }) {
|
|
48184
|
+
let resourceMetadata;
|
|
48185
|
+
let authorizationServerUrl;
|
|
48186
|
+
try {
|
|
48187
|
+
resourceMetadata = await discoverOAuthProtectedResourceMetadata(serverUrl, { resourceMetadataUrl }, fetchFn);
|
|
48188
|
+
if (resourceMetadata.authorization_servers && resourceMetadata.authorization_servers.length > 0) {
|
|
48189
|
+
authorizationServerUrl = resourceMetadata.authorization_servers[0];
|
|
48190
|
+
}
|
|
48191
|
+
} catch {}
|
|
48192
|
+
if (!authorizationServerUrl) {
|
|
48193
|
+
authorizationServerUrl = new URL("/", serverUrl);
|
|
48194
|
+
}
|
|
48195
|
+
const resource = await selectResourceURL(serverUrl, provider, resourceMetadata);
|
|
48196
|
+
const metadata = await discoverAuthorizationServerMetadata(authorizationServerUrl, {
|
|
48197
|
+
fetchFn
|
|
48198
|
+
});
|
|
48199
|
+
let clientInformation = await Promise.resolve(provider.clientInformation());
|
|
48200
|
+
if (!clientInformation) {
|
|
48201
|
+
if (authorizationCode !== undefined) {
|
|
48202
|
+
throw new Error("Existing OAuth client information is required when exchanging an authorization code");
|
|
48203
|
+
}
|
|
48204
|
+
const supportsUrlBasedClientId = metadata?.client_id_metadata_document_supported === true;
|
|
48205
|
+
const clientMetadataUrl = provider.clientMetadataUrl;
|
|
48206
|
+
if (clientMetadataUrl && !isHttpsUrl(clientMetadataUrl)) {
|
|
48207
|
+
throw new InvalidClientMetadataError(`clientMetadataUrl must be a valid HTTPS URL with a non-root pathname, got: ${clientMetadataUrl}`);
|
|
48208
|
+
}
|
|
48209
|
+
const shouldUseUrlBasedClientId = supportsUrlBasedClientId && clientMetadataUrl;
|
|
48210
|
+
if (shouldUseUrlBasedClientId) {
|
|
48211
|
+
clientInformation = {
|
|
48212
|
+
client_id: clientMetadataUrl
|
|
48213
|
+
};
|
|
48214
|
+
await provider.saveClientInformation?.(clientInformation);
|
|
48215
|
+
} else {
|
|
48216
|
+
if (!provider.saveClientInformation) {
|
|
48217
|
+
throw new Error("OAuth client information must be saveable for dynamic registration");
|
|
48218
|
+
}
|
|
48219
|
+
const fullInformation = await registerClient(authorizationServerUrl, {
|
|
48220
|
+
metadata,
|
|
48221
|
+
clientMetadata: provider.clientMetadata,
|
|
48222
|
+
fetchFn
|
|
48223
|
+
});
|
|
48224
|
+
await provider.saveClientInformation(fullInformation);
|
|
48225
|
+
clientInformation = fullInformation;
|
|
48226
|
+
}
|
|
48227
|
+
}
|
|
48228
|
+
const nonInteractiveFlow = !provider.redirectUrl;
|
|
48229
|
+
if (authorizationCode !== undefined || nonInteractiveFlow) {
|
|
48230
|
+
const tokens2 = await fetchToken(provider, authorizationServerUrl, {
|
|
48231
|
+
metadata,
|
|
48232
|
+
resource,
|
|
48233
|
+
authorizationCode,
|
|
48234
|
+
fetchFn
|
|
48235
|
+
});
|
|
48236
|
+
await provider.saveTokens(tokens2);
|
|
48237
|
+
return "AUTHORIZED";
|
|
48238
|
+
}
|
|
48239
|
+
const tokens = await provider.tokens();
|
|
48240
|
+
if (tokens?.refresh_token) {
|
|
48241
|
+
try {
|
|
48242
|
+
const newTokens = await refreshAuthorization(authorizationServerUrl, {
|
|
48243
|
+
metadata,
|
|
48244
|
+
clientInformation,
|
|
48245
|
+
refreshToken: tokens.refresh_token,
|
|
48246
|
+
resource,
|
|
48247
|
+
addClientAuthentication: provider.addClientAuthentication,
|
|
48248
|
+
fetchFn
|
|
48249
|
+
});
|
|
48250
|
+
await provider.saveTokens(newTokens);
|
|
48251
|
+
return "AUTHORIZED";
|
|
48252
|
+
} catch (error45) {
|
|
48253
|
+
if (!(error45 instanceof OAuthError) || error45 instanceof ServerError) {} else {
|
|
48254
|
+
throw error45;
|
|
48255
|
+
}
|
|
48256
|
+
}
|
|
48257
|
+
}
|
|
48258
|
+
const state2 = provider.state ? await provider.state() : undefined;
|
|
48259
|
+
const { authorizationUrl, codeVerifier } = await startAuthorization(authorizationServerUrl, {
|
|
48260
|
+
metadata,
|
|
48261
|
+
clientInformation,
|
|
48262
|
+
state: state2,
|
|
48263
|
+
redirectUrl: provider.redirectUrl,
|
|
48264
|
+
scope: scope || resourceMetadata?.scopes_supported?.join(" ") || provider.clientMetadata.scope,
|
|
48265
|
+
resource
|
|
48266
|
+
});
|
|
48267
|
+
await provider.saveCodeVerifier(codeVerifier);
|
|
48268
|
+
await provider.redirectToAuthorization(authorizationUrl);
|
|
48269
|
+
return "REDIRECT";
|
|
48270
|
+
}
|
|
48271
|
+
function isHttpsUrl(value) {
|
|
48272
|
+
if (!value)
|
|
48273
|
+
return false;
|
|
48274
|
+
try {
|
|
48275
|
+
const url2 = new URL(value);
|
|
48276
|
+
return url2.protocol === "https:" && url2.pathname !== "/";
|
|
48277
|
+
} catch {
|
|
48278
|
+
return false;
|
|
48279
|
+
}
|
|
48280
|
+
}
|
|
48281
|
+
async function selectResourceURL(serverUrl, provider, resourceMetadata) {
|
|
48282
|
+
const defaultResource = resourceUrlFromServerUrl(serverUrl);
|
|
48283
|
+
if (provider.validateResourceURL) {
|
|
48284
|
+
return await provider.validateResourceURL(defaultResource, resourceMetadata?.resource);
|
|
48285
|
+
}
|
|
48286
|
+
if (!resourceMetadata) {
|
|
48287
|
+
return;
|
|
48288
|
+
}
|
|
48289
|
+
if (!checkResourceAllowed({ requestedResource: defaultResource, configuredResource: resourceMetadata.resource })) {
|
|
48290
|
+
throw new Error(`Protected resource ${resourceMetadata.resource} does not match expected ${defaultResource} (or origin)`);
|
|
48291
|
+
}
|
|
48292
|
+
return new URL(resourceMetadata.resource);
|
|
48293
|
+
}
|
|
48294
|
+
function extractWWWAuthenticateParams(res) {
|
|
48295
|
+
const authenticateHeader = res.headers.get("WWW-Authenticate");
|
|
48296
|
+
if (!authenticateHeader) {
|
|
48297
|
+
return {};
|
|
48298
|
+
}
|
|
48299
|
+
const [type2, scheme] = authenticateHeader.split(" ");
|
|
48300
|
+
if (type2.toLowerCase() !== "bearer" || !scheme) {
|
|
48301
|
+
return {};
|
|
48302
|
+
}
|
|
48303
|
+
const resourceMetadataMatch = extractFieldFromWwwAuth(res, "resource_metadata") || undefined;
|
|
48304
|
+
let resourceMetadataUrl;
|
|
48305
|
+
if (resourceMetadataMatch) {
|
|
48306
|
+
try {
|
|
48307
|
+
resourceMetadataUrl = new URL(resourceMetadataMatch);
|
|
48308
|
+
} catch {}
|
|
48309
|
+
}
|
|
48310
|
+
const scope = extractFieldFromWwwAuth(res, "scope") || undefined;
|
|
48311
|
+
const error45 = extractFieldFromWwwAuth(res, "error") || undefined;
|
|
48312
|
+
return {
|
|
48313
|
+
resourceMetadataUrl,
|
|
48314
|
+
scope,
|
|
48315
|
+
error: error45
|
|
48316
|
+
};
|
|
48317
|
+
}
|
|
48318
|
+
function extractFieldFromWwwAuth(response2, fieldName) {
|
|
48319
|
+
const wwwAuthHeader = response2.headers.get("WWW-Authenticate");
|
|
48320
|
+
if (!wwwAuthHeader) {
|
|
48321
|
+
return null;
|
|
48322
|
+
}
|
|
48323
|
+
const pattern = new RegExp(`${fieldName}=(?:"([^"]+)"|([^\\s,]+))`);
|
|
48324
|
+
const match = wwwAuthHeader.match(pattern);
|
|
48325
|
+
if (match) {
|
|
48326
|
+
return match[1] || match[2];
|
|
48327
|
+
}
|
|
48328
|
+
return null;
|
|
48329
|
+
}
|
|
48330
|
+
async function discoverOAuthProtectedResourceMetadata(serverUrl, opts, fetchFn = fetch) {
|
|
48331
|
+
const response2 = await discoverMetadataWithFallback(serverUrl, "oauth-protected-resource", fetchFn, {
|
|
48332
|
+
protocolVersion: opts?.protocolVersion,
|
|
48333
|
+
metadataUrl: opts?.resourceMetadataUrl
|
|
48334
|
+
});
|
|
48335
|
+
if (!response2 || response2.status === 404) {
|
|
48336
|
+
await response2?.body?.cancel();
|
|
48337
|
+
throw new Error(`Resource server does not implement OAuth 2.0 Protected Resource Metadata.`);
|
|
48338
|
+
}
|
|
48339
|
+
if (!response2.ok) {
|
|
48340
|
+
await response2.body?.cancel();
|
|
48341
|
+
throw new Error(`HTTP ${response2.status} trying to load well-known OAuth protected resource metadata.`);
|
|
48342
|
+
}
|
|
48343
|
+
return OAuthProtectedResourceMetadataSchema.parse(await response2.json());
|
|
48344
|
+
}
|
|
48345
|
+
async function fetchWithCorsRetry(url2, headers, fetchFn = fetch) {
|
|
48346
|
+
try {
|
|
48347
|
+
return await fetchFn(url2, { headers });
|
|
48348
|
+
} catch (error45) {
|
|
48349
|
+
if (error45 instanceof TypeError) {
|
|
48350
|
+
if (headers) {
|
|
48351
|
+
return fetchWithCorsRetry(url2, undefined, fetchFn);
|
|
48352
|
+
} else {
|
|
48353
|
+
return;
|
|
48354
|
+
}
|
|
48355
|
+
}
|
|
48356
|
+
throw error45;
|
|
48357
|
+
}
|
|
48358
|
+
}
|
|
48359
|
+
function buildWellKnownPath(wellKnownPrefix, pathname = "", options = {}) {
|
|
48360
|
+
if (pathname.endsWith("/")) {
|
|
48361
|
+
pathname = pathname.slice(0, -1);
|
|
48362
|
+
}
|
|
48363
|
+
return options.prependPathname ? `${pathname}/.well-known/${wellKnownPrefix}` : `/.well-known/${wellKnownPrefix}${pathname}`;
|
|
48364
|
+
}
|
|
48365
|
+
async function tryMetadataDiscovery(url2, protocolVersion, fetchFn = fetch) {
|
|
48366
|
+
const headers = {
|
|
48367
|
+
"MCP-Protocol-Version": protocolVersion
|
|
48368
|
+
};
|
|
48369
|
+
return await fetchWithCorsRetry(url2, headers, fetchFn);
|
|
48370
|
+
}
|
|
48371
|
+
function shouldAttemptFallback(response2, pathname) {
|
|
48372
|
+
return !response2 || response2.status >= 400 && response2.status < 500 && pathname !== "/";
|
|
48373
|
+
}
|
|
48374
|
+
async function discoverMetadataWithFallback(serverUrl, wellKnownType, fetchFn, opts) {
|
|
48375
|
+
const issuer = new URL(serverUrl);
|
|
48376
|
+
const protocolVersion = opts?.protocolVersion ?? LATEST_PROTOCOL_VERSION;
|
|
48377
|
+
let url2;
|
|
48378
|
+
if (opts?.metadataUrl) {
|
|
48379
|
+
url2 = new URL(opts.metadataUrl);
|
|
48380
|
+
} else {
|
|
48381
|
+
const wellKnownPath = buildWellKnownPath(wellKnownType, issuer.pathname);
|
|
48382
|
+
url2 = new URL(wellKnownPath, opts?.metadataServerUrl ?? issuer);
|
|
48383
|
+
url2.search = issuer.search;
|
|
48384
|
+
}
|
|
48385
|
+
let response2 = await tryMetadataDiscovery(url2, protocolVersion, fetchFn);
|
|
48386
|
+
if (!opts?.metadataUrl && shouldAttemptFallback(response2, issuer.pathname)) {
|
|
48387
|
+
const rootUrl = new URL(`/.well-known/${wellKnownType}`, issuer);
|
|
48388
|
+
response2 = await tryMetadataDiscovery(rootUrl, protocolVersion, fetchFn);
|
|
48389
|
+
}
|
|
48390
|
+
return response2;
|
|
48391
|
+
}
|
|
48392
|
+
function buildDiscoveryUrls(authorizationServerUrl) {
|
|
48393
|
+
const url2 = typeof authorizationServerUrl === "string" ? new URL(authorizationServerUrl) : authorizationServerUrl;
|
|
48394
|
+
const hasPath = url2.pathname !== "/";
|
|
48395
|
+
const urlsToTry = [];
|
|
48396
|
+
if (!hasPath) {
|
|
48397
|
+
urlsToTry.push({
|
|
48398
|
+
url: new URL("/.well-known/oauth-authorization-server", url2.origin),
|
|
48399
|
+
type: "oauth"
|
|
48400
|
+
});
|
|
48401
|
+
urlsToTry.push({
|
|
48402
|
+
url: new URL(`/.well-known/openid-configuration`, url2.origin),
|
|
48403
|
+
type: "oidc"
|
|
48404
|
+
});
|
|
48405
|
+
return urlsToTry;
|
|
48406
|
+
}
|
|
48407
|
+
let pathname = url2.pathname;
|
|
48408
|
+
if (pathname.endsWith("/")) {
|
|
48409
|
+
pathname = pathname.slice(0, -1);
|
|
48410
|
+
}
|
|
48411
|
+
urlsToTry.push({
|
|
48412
|
+
url: new URL(`/.well-known/oauth-authorization-server${pathname}`, url2.origin),
|
|
48413
|
+
type: "oauth"
|
|
48414
|
+
});
|
|
48415
|
+
urlsToTry.push({
|
|
48416
|
+
url: new URL(`/.well-known/openid-configuration${pathname}`, url2.origin),
|
|
48417
|
+
type: "oidc"
|
|
48418
|
+
});
|
|
48419
|
+
urlsToTry.push({
|
|
48420
|
+
url: new URL(`${pathname}/.well-known/openid-configuration`, url2.origin),
|
|
48421
|
+
type: "oidc"
|
|
48422
|
+
});
|
|
48423
|
+
return urlsToTry;
|
|
48424
|
+
}
|
|
48425
|
+
async function discoverAuthorizationServerMetadata(authorizationServerUrl, { fetchFn = fetch, protocolVersion = LATEST_PROTOCOL_VERSION } = {}) {
|
|
48426
|
+
const headers = {
|
|
48427
|
+
"MCP-Protocol-Version": protocolVersion,
|
|
48428
|
+
Accept: "application/json"
|
|
48429
|
+
};
|
|
48430
|
+
const urlsToTry = buildDiscoveryUrls(authorizationServerUrl);
|
|
48431
|
+
for (const { url: endpointUrl, type: type2 } of urlsToTry) {
|
|
48432
|
+
const response2 = await fetchWithCorsRetry(endpointUrl, headers, fetchFn);
|
|
48433
|
+
if (!response2) {
|
|
48434
|
+
continue;
|
|
48435
|
+
}
|
|
48436
|
+
if (!response2.ok) {
|
|
48437
|
+
await response2.body?.cancel();
|
|
48438
|
+
if (response2.status >= 400 && response2.status < 500) {
|
|
48439
|
+
continue;
|
|
48440
|
+
}
|
|
48441
|
+
throw new Error(`HTTP ${response2.status} trying to load ${type2 === "oauth" ? "OAuth" : "OpenID provider"} metadata from ${endpointUrl}`);
|
|
48442
|
+
}
|
|
48443
|
+
if (type2 === "oauth") {
|
|
48444
|
+
return OAuthMetadataSchema.parse(await response2.json());
|
|
48445
|
+
} else {
|
|
48446
|
+
return OpenIdProviderDiscoveryMetadataSchema.parse(await response2.json());
|
|
48447
|
+
}
|
|
48448
|
+
}
|
|
48449
|
+
return;
|
|
48450
|
+
}
|
|
48451
|
+
async function startAuthorization(authorizationServerUrl, { metadata, clientInformation, redirectUrl, scope, state: state2, resource }) {
|
|
48452
|
+
let authorizationUrl;
|
|
48453
|
+
if (metadata) {
|
|
48454
|
+
authorizationUrl = new URL(metadata.authorization_endpoint);
|
|
48455
|
+
if (!metadata.response_types_supported.includes(AUTHORIZATION_CODE_RESPONSE_TYPE)) {
|
|
48456
|
+
throw new Error(`Incompatible auth server: does not support response type ${AUTHORIZATION_CODE_RESPONSE_TYPE}`);
|
|
48457
|
+
}
|
|
48458
|
+
if (metadata.code_challenge_methods_supported && !metadata.code_challenge_methods_supported.includes(AUTHORIZATION_CODE_CHALLENGE_METHOD)) {
|
|
48459
|
+
throw new Error(`Incompatible auth server: does not support code challenge method ${AUTHORIZATION_CODE_CHALLENGE_METHOD}`);
|
|
48460
|
+
}
|
|
48461
|
+
} else {
|
|
48462
|
+
authorizationUrl = new URL("/authorize", authorizationServerUrl);
|
|
48463
|
+
}
|
|
48464
|
+
const challenge = await pkceChallenge();
|
|
48465
|
+
const codeVerifier = challenge.code_verifier;
|
|
48466
|
+
const codeChallenge = challenge.code_challenge;
|
|
48467
|
+
authorizationUrl.searchParams.set("response_type", AUTHORIZATION_CODE_RESPONSE_TYPE);
|
|
48468
|
+
authorizationUrl.searchParams.set("client_id", clientInformation.client_id);
|
|
48469
|
+
authorizationUrl.searchParams.set("code_challenge", codeChallenge);
|
|
48470
|
+
authorizationUrl.searchParams.set("code_challenge_method", AUTHORIZATION_CODE_CHALLENGE_METHOD);
|
|
48471
|
+
authorizationUrl.searchParams.set("redirect_uri", String(redirectUrl));
|
|
48472
|
+
if (state2) {
|
|
48473
|
+
authorizationUrl.searchParams.set("state", state2);
|
|
48474
|
+
}
|
|
48475
|
+
if (scope) {
|
|
48476
|
+
authorizationUrl.searchParams.set("scope", scope);
|
|
48477
|
+
}
|
|
48478
|
+
if (scope?.includes("offline_access")) {
|
|
48479
|
+
authorizationUrl.searchParams.append("prompt", "consent");
|
|
48480
|
+
}
|
|
48481
|
+
if (resource) {
|
|
48482
|
+
authorizationUrl.searchParams.set("resource", resource.href);
|
|
48483
|
+
}
|
|
48484
|
+
return { authorizationUrl, codeVerifier };
|
|
48485
|
+
}
|
|
48486
|
+
function prepareAuthorizationCodeRequest(authorizationCode, codeVerifier, redirectUri) {
|
|
48487
|
+
return new URLSearchParams({
|
|
48488
|
+
grant_type: "authorization_code",
|
|
48489
|
+
code: authorizationCode,
|
|
48490
|
+
code_verifier: codeVerifier,
|
|
48491
|
+
redirect_uri: String(redirectUri)
|
|
48492
|
+
});
|
|
48493
|
+
}
|
|
48494
|
+
async function executeTokenRequest(authorizationServerUrl, { metadata, tokenRequestParams, clientInformation, addClientAuthentication, resource, fetchFn }) {
|
|
48495
|
+
const tokenUrl = metadata?.token_endpoint ? new URL(metadata.token_endpoint) : new URL("/token", authorizationServerUrl);
|
|
48496
|
+
const headers = new Headers({
|
|
48497
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
48498
|
+
Accept: "application/json"
|
|
48499
|
+
});
|
|
48500
|
+
if (resource) {
|
|
48501
|
+
tokenRequestParams.set("resource", resource.href);
|
|
48502
|
+
}
|
|
48503
|
+
if (addClientAuthentication) {
|
|
48504
|
+
await addClientAuthentication(headers, tokenRequestParams, tokenUrl, metadata);
|
|
48505
|
+
} else if (clientInformation) {
|
|
48506
|
+
const supportedMethods = metadata?.token_endpoint_auth_methods_supported ?? [];
|
|
48507
|
+
const authMethod = selectClientAuthMethod(clientInformation, supportedMethods);
|
|
48508
|
+
applyClientAuthentication(authMethod, clientInformation, headers, tokenRequestParams);
|
|
48509
|
+
}
|
|
48510
|
+
const response2 = await (fetchFn ?? fetch)(tokenUrl, {
|
|
48511
|
+
method: "POST",
|
|
48512
|
+
headers,
|
|
48513
|
+
body: tokenRequestParams
|
|
48514
|
+
});
|
|
48515
|
+
if (!response2.ok) {
|
|
48516
|
+
throw await parseErrorResponse(response2);
|
|
48517
|
+
}
|
|
48518
|
+
return OAuthTokensSchema.parse(await response2.json());
|
|
48519
|
+
}
|
|
48520
|
+
async function refreshAuthorization(authorizationServerUrl, { metadata, clientInformation, refreshToken, resource, addClientAuthentication, fetchFn }) {
|
|
48521
|
+
const tokenRequestParams = new URLSearchParams({
|
|
48522
|
+
grant_type: "refresh_token",
|
|
48523
|
+
refresh_token: refreshToken
|
|
48524
|
+
});
|
|
48525
|
+
const tokens = await executeTokenRequest(authorizationServerUrl, {
|
|
48526
|
+
metadata,
|
|
48527
|
+
tokenRequestParams,
|
|
48528
|
+
clientInformation,
|
|
48529
|
+
addClientAuthentication,
|
|
48530
|
+
resource,
|
|
48531
|
+
fetchFn
|
|
48532
|
+
});
|
|
48533
|
+
return { refresh_token: refreshToken, ...tokens };
|
|
48534
|
+
}
|
|
48535
|
+
async function fetchToken(provider, authorizationServerUrl, { metadata, resource, authorizationCode, fetchFn } = {}) {
|
|
48536
|
+
const scope = provider.clientMetadata.scope;
|
|
48537
|
+
let tokenRequestParams;
|
|
48538
|
+
if (provider.prepareTokenRequest) {
|
|
48539
|
+
tokenRequestParams = await provider.prepareTokenRequest(scope);
|
|
48540
|
+
}
|
|
48541
|
+
if (!tokenRequestParams) {
|
|
48542
|
+
if (!authorizationCode) {
|
|
48543
|
+
throw new Error("Either provider.prepareTokenRequest() or authorizationCode is required");
|
|
48544
|
+
}
|
|
48545
|
+
if (!provider.redirectUrl) {
|
|
48546
|
+
throw new Error("redirectUrl is required for authorization_code flow");
|
|
48547
|
+
}
|
|
48548
|
+
const codeVerifier = await provider.codeVerifier();
|
|
48549
|
+
tokenRequestParams = prepareAuthorizationCodeRequest(authorizationCode, codeVerifier, provider.redirectUrl);
|
|
48550
|
+
}
|
|
48551
|
+
const clientInformation = await provider.clientInformation();
|
|
48552
|
+
return executeTokenRequest(authorizationServerUrl, {
|
|
48553
|
+
metadata,
|
|
48554
|
+
tokenRequestParams,
|
|
48555
|
+
clientInformation: clientInformation ?? undefined,
|
|
48556
|
+
addClientAuthentication: provider.addClientAuthentication,
|
|
48557
|
+
resource,
|
|
48558
|
+
fetchFn
|
|
48559
|
+
});
|
|
48560
|
+
}
|
|
48561
|
+
async function registerClient(authorizationServerUrl, { metadata, clientMetadata, fetchFn }) {
|
|
48562
|
+
let registrationUrl;
|
|
48563
|
+
if (metadata) {
|
|
48564
|
+
if (!metadata.registration_endpoint) {
|
|
48565
|
+
throw new Error("Incompatible auth server: does not support dynamic client registration");
|
|
48566
|
+
}
|
|
48567
|
+
registrationUrl = new URL(metadata.registration_endpoint);
|
|
48568
|
+
} else {
|
|
48569
|
+
registrationUrl = new URL("/register", authorizationServerUrl);
|
|
48570
|
+
}
|
|
48571
|
+
const response2 = await (fetchFn ?? fetch)(registrationUrl, {
|
|
48572
|
+
method: "POST",
|
|
48573
|
+
headers: {
|
|
48574
|
+
"Content-Type": "application/json"
|
|
48575
|
+
},
|
|
48576
|
+
body: JSON.stringify(clientMetadata)
|
|
48577
|
+
});
|
|
48578
|
+
if (!response2.ok) {
|
|
48579
|
+
throw await parseErrorResponse(response2);
|
|
48580
|
+
}
|
|
48581
|
+
return OAuthClientInformationFullSchema.parse(await response2.json());
|
|
48582
|
+
}
|
|
48583
|
+
|
|
48584
|
+
// node_modules/@modelcontextprotocol/sdk/dist/esm/client/sse.js
|
|
48585
|
+
class SseError extends Error {
|
|
48586
|
+
constructor(code, message, event) {
|
|
48587
|
+
super(`SSE error: ${message}`);
|
|
48588
|
+
this.code = code;
|
|
48589
|
+
this.event = event;
|
|
48590
|
+
}
|
|
48591
|
+
}
|
|
48592
|
+
|
|
48593
|
+
class SSEClientTransport {
|
|
48594
|
+
constructor(url2, opts) {
|
|
48595
|
+
this._url = url2;
|
|
48596
|
+
this._resourceMetadataUrl = undefined;
|
|
48597
|
+
this._scope = undefined;
|
|
48598
|
+
this._eventSourceInit = opts?.eventSourceInit;
|
|
48599
|
+
this._requestInit = opts?.requestInit;
|
|
48600
|
+
this._authProvider = opts?.authProvider;
|
|
48601
|
+
this._fetch = opts?.fetch;
|
|
48602
|
+
this._fetchWithInit = createFetchWithInit(opts?.fetch, opts?.requestInit);
|
|
48603
|
+
}
|
|
48604
|
+
async _authThenStart() {
|
|
48605
|
+
if (!this._authProvider) {
|
|
48606
|
+
throw new UnauthorizedError("No auth provider");
|
|
48607
|
+
}
|
|
48608
|
+
let result;
|
|
48609
|
+
try {
|
|
48610
|
+
result = await auth(this._authProvider, {
|
|
48611
|
+
serverUrl: this._url,
|
|
48612
|
+
resourceMetadataUrl: this._resourceMetadataUrl,
|
|
48613
|
+
scope: this._scope,
|
|
48614
|
+
fetchFn: this._fetchWithInit
|
|
48615
|
+
});
|
|
48616
|
+
} catch (error45) {
|
|
48617
|
+
this.onerror?.(error45);
|
|
48618
|
+
throw error45;
|
|
48619
|
+
}
|
|
48620
|
+
if (result !== "AUTHORIZED") {
|
|
48621
|
+
throw new UnauthorizedError;
|
|
48622
|
+
}
|
|
48623
|
+
return await this._startOrAuth();
|
|
48624
|
+
}
|
|
48625
|
+
async _commonHeaders() {
|
|
48626
|
+
const headers = {};
|
|
48627
|
+
if (this._authProvider) {
|
|
48628
|
+
const tokens = await this._authProvider.tokens();
|
|
48629
|
+
if (tokens) {
|
|
48630
|
+
headers["Authorization"] = `Bearer ${tokens.access_token}`;
|
|
48631
|
+
}
|
|
48632
|
+
}
|
|
48633
|
+
if (this._protocolVersion) {
|
|
48634
|
+
headers["mcp-protocol-version"] = this._protocolVersion;
|
|
48635
|
+
}
|
|
48636
|
+
const extraHeaders = normalizeHeaders(this._requestInit?.headers);
|
|
48637
|
+
return new Headers({
|
|
48638
|
+
...headers,
|
|
48639
|
+
...extraHeaders
|
|
48640
|
+
});
|
|
48641
|
+
}
|
|
48642
|
+
_startOrAuth() {
|
|
48643
|
+
const fetchImpl = this?._eventSourceInit?.fetch ?? this._fetch ?? fetch;
|
|
48644
|
+
return new Promise((resolve8, reject) => {
|
|
48645
|
+
this._eventSource = new EventSource(this._url.href, {
|
|
48646
|
+
...this._eventSourceInit,
|
|
48647
|
+
fetch: async (url2, init) => {
|
|
48648
|
+
const headers = await this._commonHeaders();
|
|
48649
|
+
headers.set("Accept", "text/event-stream");
|
|
48650
|
+
const response2 = await fetchImpl(url2, {
|
|
48651
|
+
...init,
|
|
48652
|
+
headers
|
|
48653
|
+
});
|
|
48654
|
+
if (response2.status === 401 && response2.headers.has("www-authenticate")) {
|
|
48655
|
+
const { resourceMetadataUrl, scope } = extractWWWAuthenticateParams(response2);
|
|
48656
|
+
this._resourceMetadataUrl = resourceMetadataUrl;
|
|
48657
|
+
this._scope = scope;
|
|
48658
|
+
}
|
|
48659
|
+
return response2;
|
|
48660
|
+
}
|
|
48661
|
+
});
|
|
48662
|
+
this._abortController = new AbortController;
|
|
48663
|
+
this._eventSource.onerror = (event) => {
|
|
48664
|
+
if (event.code === 401 && this._authProvider) {
|
|
48665
|
+
this._authThenStart().then(resolve8, reject);
|
|
48666
|
+
return;
|
|
48667
|
+
}
|
|
48668
|
+
const error45 = new SseError(event.code, event.message, event);
|
|
48669
|
+
reject(error45);
|
|
48670
|
+
this.onerror?.(error45);
|
|
48671
|
+
};
|
|
48672
|
+
this._eventSource.onopen = () => {};
|
|
48673
|
+
this._eventSource.addEventListener("endpoint", (event) => {
|
|
48674
|
+
const messageEvent = event;
|
|
48675
|
+
try {
|
|
48676
|
+
this._endpoint = new URL(messageEvent.data, this._url);
|
|
48677
|
+
if (this._endpoint.origin !== this._url.origin) {
|
|
48678
|
+
throw new Error(`Endpoint origin does not match connection origin: ${this._endpoint.origin}`);
|
|
48679
|
+
}
|
|
48680
|
+
} catch (error45) {
|
|
48681
|
+
reject(error45);
|
|
48682
|
+
this.onerror?.(error45);
|
|
48683
|
+
this.close();
|
|
48684
|
+
return;
|
|
48685
|
+
}
|
|
48686
|
+
resolve8();
|
|
48687
|
+
});
|
|
48688
|
+
this._eventSource.onmessage = (event) => {
|
|
48689
|
+
const messageEvent = event;
|
|
48690
|
+
let message;
|
|
48691
|
+
try {
|
|
48692
|
+
message = JSONRPCMessageSchema.parse(JSON.parse(messageEvent.data));
|
|
48693
|
+
} catch (error45) {
|
|
48694
|
+
this.onerror?.(error45);
|
|
48695
|
+
return;
|
|
48696
|
+
}
|
|
48697
|
+
this.onmessage?.(message);
|
|
48698
|
+
};
|
|
48699
|
+
});
|
|
48700
|
+
}
|
|
48701
|
+
async start() {
|
|
48702
|
+
if (this._eventSource) {
|
|
48703
|
+
throw new Error("SSEClientTransport already started! If using Client class, note that connect() calls start() automatically.");
|
|
48704
|
+
}
|
|
48705
|
+
return await this._startOrAuth();
|
|
48706
|
+
}
|
|
48707
|
+
async finishAuth(authorizationCode) {
|
|
48708
|
+
if (!this._authProvider) {
|
|
48709
|
+
throw new UnauthorizedError("No auth provider");
|
|
48710
|
+
}
|
|
48711
|
+
const result = await auth(this._authProvider, {
|
|
48712
|
+
serverUrl: this._url,
|
|
48713
|
+
authorizationCode,
|
|
48714
|
+
resourceMetadataUrl: this._resourceMetadataUrl,
|
|
48715
|
+
scope: this._scope,
|
|
48716
|
+
fetchFn: this._fetchWithInit
|
|
48717
|
+
});
|
|
48718
|
+
if (result !== "AUTHORIZED") {
|
|
48719
|
+
throw new UnauthorizedError("Failed to authorize");
|
|
48720
|
+
}
|
|
48721
|
+
}
|
|
48722
|
+
async close() {
|
|
48723
|
+
this._abortController?.abort();
|
|
48724
|
+
this._eventSource?.close();
|
|
48725
|
+
this.onclose?.();
|
|
48726
|
+
}
|
|
48727
|
+
async send(message) {
|
|
48728
|
+
if (!this._endpoint) {
|
|
48729
|
+
throw new Error("Not connected");
|
|
48730
|
+
}
|
|
48731
|
+
try {
|
|
48732
|
+
const headers = await this._commonHeaders();
|
|
48733
|
+
headers.set("content-type", "application/json");
|
|
48734
|
+
const init = {
|
|
48735
|
+
...this._requestInit,
|
|
48736
|
+
method: "POST",
|
|
48737
|
+
headers,
|
|
48738
|
+
body: JSON.stringify(message),
|
|
48739
|
+
signal: this._abortController?.signal
|
|
48740
|
+
};
|
|
48741
|
+
const response2 = await (this._fetch ?? fetch)(this._endpoint, init);
|
|
48742
|
+
if (!response2.ok) {
|
|
48743
|
+
const text = await response2.text().catch(() => null);
|
|
48744
|
+
if (response2.status === 401 && this._authProvider) {
|
|
48745
|
+
const { resourceMetadataUrl, scope } = extractWWWAuthenticateParams(response2);
|
|
48746
|
+
this._resourceMetadataUrl = resourceMetadataUrl;
|
|
48747
|
+
this._scope = scope;
|
|
48748
|
+
const result = await auth(this._authProvider, {
|
|
48749
|
+
serverUrl: this._url,
|
|
48750
|
+
resourceMetadataUrl: this._resourceMetadataUrl,
|
|
48751
|
+
scope: this._scope,
|
|
48752
|
+
fetchFn: this._fetchWithInit
|
|
48753
|
+
});
|
|
48754
|
+
if (result !== "AUTHORIZED") {
|
|
48755
|
+
throw new UnauthorizedError;
|
|
48756
|
+
}
|
|
48757
|
+
return this.send(message);
|
|
48758
|
+
}
|
|
48759
|
+
throw new Error(`Error POSTing to endpoint (HTTP ${response2.status}): ${text}`);
|
|
48760
|
+
}
|
|
48761
|
+
await response2.body?.cancel();
|
|
48762
|
+
} catch (error45) {
|
|
48763
|
+
this.onerror?.(error45);
|
|
48764
|
+
throw error45;
|
|
48765
|
+
}
|
|
48766
|
+
}
|
|
48767
|
+
setProtocolVersion(version2) {
|
|
48768
|
+
this._protocolVersion = version2;
|
|
48769
|
+
}
|
|
48770
|
+
}
|
|
48771
|
+
|
|
48772
|
+
// src/features/skill-mcp-manager/env-cleaner.ts
|
|
48773
|
+
var EXCLUDED_ENV_PATTERNS = [
|
|
48774
|
+
/^NPM_CONFIG_/i,
|
|
48775
|
+
/^npm_config_/,
|
|
48776
|
+
/^YARN_/,
|
|
48777
|
+
/^PNPM_/,
|
|
48778
|
+
/^NO_UPDATE_NOTIFIER$/
|
|
48779
|
+
];
|
|
48780
|
+
function createCleanMcpEnvironment(customEnv = {}) {
|
|
48781
|
+
const cleanEnv = {};
|
|
48782
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
48783
|
+
if (value === undefined)
|
|
48784
|
+
continue;
|
|
48785
|
+
const shouldExclude = EXCLUDED_ENV_PATTERNS.some((pattern) => pattern.test(key));
|
|
48786
|
+
if (!shouldExclude) {
|
|
48787
|
+
cleanEnv[key] = value;
|
|
48788
|
+
}
|
|
48789
|
+
}
|
|
48790
|
+
Object.assign(cleanEnv, customEnv);
|
|
48791
|
+
return cleanEnv;
|
|
48792
|
+
}
|
|
48793
|
+
|
|
48794
|
+
// src/features/knowledge-provider/mcp-manager.ts
|
|
48795
|
+
class KnowledgeMcpManager {
|
|
48796
|
+
clients = new Map;
|
|
48797
|
+
pendingConnections = new Map;
|
|
48798
|
+
serverConfigs = new Map;
|
|
48799
|
+
cleanupRegistered = false;
|
|
48800
|
+
cleanupInterval = null;
|
|
48801
|
+
IDLE_TIMEOUT = 5 * 60 * 1000;
|
|
48802
|
+
registerServer(config3) {
|
|
48803
|
+
this.serverConfigs.set(config3.name, config3);
|
|
48804
|
+
}
|
|
48805
|
+
async unregisterServer(serverName) {
|
|
48806
|
+
this.serverConfigs.delete(serverName);
|
|
48807
|
+
await this.disconnectServer(serverName);
|
|
48808
|
+
}
|
|
48809
|
+
async isServerAvailable(serverName) {
|
|
48810
|
+
const config3 = this.serverConfigs.get(serverName);
|
|
48811
|
+
if (!config3) {
|
|
48812
|
+
return false;
|
|
48813
|
+
}
|
|
48814
|
+
try {
|
|
48815
|
+
const client2 = await this.getOrCreateClient(serverName);
|
|
48816
|
+
return client2 !== null;
|
|
48817
|
+
} catch {
|
|
48818
|
+
return false;
|
|
48819
|
+
}
|
|
48820
|
+
}
|
|
48821
|
+
async invoke(serverName, toolName, args) {
|
|
48822
|
+
const client2 = await this.getOrCreateClient(serverName);
|
|
48823
|
+
if (!client2) {
|
|
48824
|
+
throw new Error(`MCP server "${serverName}" is not available`);
|
|
48825
|
+
}
|
|
48826
|
+
const result = await client2.callTool({ name: toolName, arguments: args });
|
|
48827
|
+
return result.content;
|
|
48828
|
+
}
|
|
48829
|
+
async getOrCreateClient(serverName) {
|
|
48830
|
+
const existing = this.clients.get(serverName);
|
|
48831
|
+
if (existing) {
|
|
48832
|
+
existing.lastUsedAt = Date.now();
|
|
48833
|
+
return existing.client;
|
|
48834
|
+
}
|
|
48835
|
+
const pending = this.pendingConnections.get(serverName);
|
|
48836
|
+
if (pending) {
|
|
48837
|
+
return pending;
|
|
48838
|
+
}
|
|
48839
|
+
const config3 = this.serverConfigs.get(serverName);
|
|
48840
|
+
if (!config3) {
|
|
48841
|
+
return null;
|
|
48842
|
+
}
|
|
48843
|
+
const expandedConfig = expandEnvVarsInObject(config3);
|
|
48844
|
+
const connectionPromise = this.createClient(serverName, expandedConfig);
|
|
48845
|
+
this.pendingConnections.set(serverName, connectionPromise);
|
|
48846
|
+
try {
|
|
48847
|
+
const client2 = await connectionPromise;
|
|
48848
|
+
return client2;
|
|
48849
|
+
} finally {
|
|
48850
|
+
this.pendingConnections.delete(serverName);
|
|
48851
|
+
}
|
|
48852
|
+
}
|
|
48853
|
+
async createClient(serverName, config3) {
|
|
48854
|
+
const transportType = config3.transport ?? "stdio";
|
|
48855
|
+
this.registerProcessCleanup();
|
|
48856
|
+
const client2 = new Client({ name: `knowledge-mcp-${serverName}`, version: "1.0.0" }, { capabilities: {} });
|
|
48857
|
+
let transport;
|
|
48858
|
+
if (transportType === "sse") {
|
|
48859
|
+
transport = await this.createSseTransport(serverName, config3, client2);
|
|
48860
|
+
} else {
|
|
48861
|
+
transport = await this.createStdioTransport(serverName, config3, client2);
|
|
48862
|
+
}
|
|
48863
|
+
this.clients.set(serverName, {
|
|
48864
|
+
client: client2,
|
|
48865
|
+
transport,
|
|
48866
|
+
transportType,
|
|
48867
|
+
serverName,
|
|
48868
|
+
lastUsedAt: Date.now()
|
|
48869
|
+
});
|
|
48870
|
+
this.startCleanupTimer();
|
|
48871
|
+
return client2;
|
|
48872
|
+
}
|
|
48873
|
+
async createStdioTransport(serverName, config3, client2) {
|
|
48874
|
+
if (!config3.command) {
|
|
48875
|
+
throw new Error(`MCP server "${serverName}" is missing required 'command' field for stdio transport.
|
|
48876
|
+
|
|
48877
|
+
` + `Example:
|
|
48878
|
+
` + ` {
|
|
48879
|
+
` + ` "name": "${serverName}",
|
|
48880
|
+
` + ` "command": "npx",
|
|
48881
|
+
` + ` "args": ["-y", "@some/mcp-server"],
|
|
48882
|
+
` + ` "searchTool": "search"
|
|
48883
|
+
` + ` }`);
|
|
48884
|
+
}
|
|
48885
|
+
const command = config3.command;
|
|
48886
|
+
const args = config3.args || [];
|
|
48887
|
+
const mergedEnv = createCleanMcpEnvironment(config3.env);
|
|
48888
|
+
const transport = new StdioClientTransport({
|
|
48889
|
+
command,
|
|
48890
|
+
args,
|
|
48891
|
+
env: mergedEnv,
|
|
48892
|
+
stderr: "ignore"
|
|
48893
|
+
});
|
|
48894
|
+
try {
|
|
48895
|
+
await client2.connect(transport);
|
|
48896
|
+
} catch (error45) {
|
|
48897
|
+
try {
|
|
48898
|
+
await transport.close();
|
|
48899
|
+
} catch {}
|
|
48900
|
+
const errorMessage = error45 instanceof Error ? error45.message : String(error45);
|
|
48901
|
+
throw new Error(`Failed to connect to MCP server "${serverName}" via stdio.
|
|
48902
|
+
|
|
48903
|
+
` + `Command: ${command} ${args.join(" ")}
|
|
48904
|
+
` + `Reason: ${errorMessage}
|
|
48905
|
+
|
|
48906
|
+
` + `Hints:
|
|
48907
|
+
` + ` - Ensure the command is installed and available in PATH
|
|
48908
|
+
` + ` - Check if the MCP server package exists
|
|
48909
|
+
` + ` - Verify the args are correct for this server`);
|
|
48910
|
+
}
|
|
48911
|
+
return transport;
|
|
48912
|
+
}
|
|
48913
|
+
async createSseTransport(serverName, config3, client2) {
|
|
48914
|
+
if (!config3.url) {
|
|
48915
|
+
throw new Error(`MCP server "${serverName}" is missing required 'url' field for SSE transport.
|
|
48916
|
+
|
|
48917
|
+
` + `Example:
|
|
48918
|
+
` + ` {
|
|
48919
|
+
` + ` "name": "${serverName}",
|
|
48920
|
+
` + ` "transport": "sse",
|
|
48921
|
+
` + ` "url": "http://localhost:60062/sse",
|
|
48922
|
+
` + ` "searchTool": "search"
|
|
48923
|
+
` + ` }
|
|
48924
|
+
|
|
48925
|
+
` + `Note: SSE servers must be started manually before connecting.`);
|
|
48926
|
+
}
|
|
48927
|
+
const transport = new SSEClientTransport(new URL(config3.url));
|
|
48928
|
+
try {
|
|
48929
|
+
await client2.connect(transport);
|
|
48930
|
+
} catch (error45) {
|
|
48931
|
+
try {
|
|
48932
|
+
await transport.close();
|
|
48933
|
+
} catch {}
|
|
48934
|
+
const errorMessage = error45 instanceof Error ? error45.message : String(error45);
|
|
48935
|
+
throw new Error(`Failed to connect to MCP server "${serverName}" via SSE.
|
|
48936
|
+
|
|
48937
|
+
` + `URL: ${config3.url}
|
|
48938
|
+
` + `Reason: ${errorMessage}
|
|
48939
|
+
|
|
48940
|
+
` + `Hints:
|
|
48941
|
+
` + ` - Ensure the MCP server is running at ${config3.url}
|
|
48942
|
+
` + ` - SSE servers (like Dust CLI) must be started manually
|
|
48943
|
+
` + ` - Check if the port is correct (Dust uses dynamic ports)
|
|
48944
|
+
` + ` - Verify the URL ends with /sse if required by the server`);
|
|
48945
|
+
}
|
|
48946
|
+
return transport;
|
|
48947
|
+
}
|
|
48948
|
+
async disconnectServer(serverName) {
|
|
48949
|
+
const managed = this.clients.get(serverName);
|
|
48950
|
+
if (!managed) {
|
|
48951
|
+
return;
|
|
48952
|
+
}
|
|
48953
|
+
this.clients.delete(serverName);
|
|
48954
|
+
try {
|
|
48955
|
+
await managed.client.close();
|
|
48956
|
+
} catch {}
|
|
48957
|
+
try {
|
|
48958
|
+
await managed.transport.close();
|
|
48959
|
+
} catch {}
|
|
48960
|
+
}
|
|
48961
|
+
async disconnectAll() {
|
|
48962
|
+
this.stopCleanupTimer();
|
|
48963
|
+
const clients = Array.from(this.clients.values());
|
|
48964
|
+
this.clients.clear();
|
|
48965
|
+
for (const managed of clients) {
|
|
48966
|
+
try {
|
|
48967
|
+
await managed.client.close();
|
|
48968
|
+
} catch {}
|
|
48969
|
+
try {
|
|
48970
|
+
await managed.transport.close();
|
|
48971
|
+
} catch {}
|
|
48972
|
+
}
|
|
48973
|
+
}
|
|
48974
|
+
registerProcessCleanup() {
|
|
48975
|
+
if (this.cleanupRegistered)
|
|
48976
|
+
return;
|
|
48977
|
+
this.cleanupRegistered = true;
|
|
48978
|
+
const cleanup = async () => {
|
|
48979
|
+
for (const [, managed] of this.clients) {
|
|
48980
|
+
try {
|
|
48981
|
+
await managed.client.close();
|
|
48982
|
+
} catch {}
|
|
48983
|
+
try {
|
|
48984
|
+
await managed.transport.close();
|
|
48985
|
+
} catch {}
|
|
48986
|
+
}
|
|
48987
|
+
this.clients.clear();
|
|
48988
|
+
this.pendingConnections.clear();
|
|
48989
|
+
};
|
|
48990
|
+
process.on("SIGINT", async () => {
|
|
48991
|
+
await cleanup();
|
|
48992
|
+
process.exit(0);
|
|
48993
|
+
});
|
|
48994
|
+
process.on("SIGTERM", async () => {
|
|
48995
|
+
await cleanup();
|
|
48996
|
+
process.exit(0);
|
|
48997
|
+
});
|
|
48998
|
+
if (process.platform === "win32") {
|
|
48999
|
+
process.on("SIGBREAK", async () => {
|
|
49000
|
+
await cleanup();
|
|
49001
|
+
process.exit(0);
|
|
49002
|
+
});
|
|
49003
|
+
}
|
|
49004
|
+
}
|
|
49005
|
+
startCleanupTimer() {
|
|
49006
|
+
if (this.cleanupInterval)
|
|
49007
|
+
return;
|
|
49008
|
+
this.cleanupInterval = setInterval(() => {
|
|
49009
|
+
this.cleanupIdleClients();
|
|
49010
|
+
}, 60000);
|
|
49011
|
+
this.cleanupInterval.unref();
|
|
49012
|
+
}
|
|
49013
|
+
stopCleanupTimer() {
|
|
49014
|
+
if (this.cleanupInterval) {
|
|
49015
|
+
clearInterval(this.cleanupInterval);
|
|
49016
|
+
this.cleanupInterval = null;
|
|
49017
|
+
}
|
|
49018
|
+
}
|
|
49019
|
+
async cleanupIdleClients() {
|
|
49020
|
+
const now = Date.now();
|
|
49021
|
+
for (const [serverName, managed] of this.clients) {
|
|
49022
|
+
if (now - managed.lastUsedAt > this.IDLE_TIMEOUT) {
|
|
49023
|
+
this.clients.delete(serverName);
|
|
49024
|
+
try {
|
|
49025
|
+
await managed.client.close();
|
|
49026
|
+
} catch {}
|
|
49027
|
+
try {
|
|
49028
|
+
await managed.transport.close();
|
|
49029
|
+
} catch {}
|
|
49030
|
+
}
|
|
49031
|
+
}
|
|
49032
|
+
}
|
|
49033
|
+
getRegisteredServers() {
|
|
49034
|
+
return Array.from(this.serverConfigs.keys());
|
|
49035
|
+
}
|
|
49036
|
+
getConnectedServers() {
|
|
49037
|
+
return Array.from(this.clients.keys());
|
|
49038
|
+
}
|
|
49039
|
+
isConnected(serverName) {
|
|
49040
|
+
return this.clients.has(serverName);
|
|
49041
|
+
}
|
|
49042
|
+
}
|
|
49043
|
+
// src/features/background-agent/manager.ts
|
|
49044
|
+
import { existsSync as existsSync48, readdirSync as readdirSync17 } from "fs";
|
|
49045
|
+
import { join as join61 } from "path";
|
|
49046
|
+
var TASK_TTL_MS = 30 * 60 * 1000;
|
|
49047
|
+
function getMessageDir11(sessionID) {
|
|
49048
|
+
if (!existsSync48(MESSAGE_STORAGE))
|
|
49049
|
+
return null;
|
|
49050
|
+
const directPath = join61(MESSAGE_STORAGE, sessionID);
|
|
49051
|
+
if (existsSync48(directPath))
|
|
49052
|
+
return directPath;
|
|
49053
|
+
for (const dir of readdirSync17(MESSAGE_STORAGE)) {
|
|
49054
|
+
const sessionPath = join61(MESSAGE_STORAGE, dir, sessionID);
|
|
49055
|
+
if (existsSync48(sessionPath))
|
|
49056
|
+
return sessionPath;
|
|
49057
|
+
}
|
|
49058
|
+
return null;
|
|
49059
|
+
}
|
|
49060
|
+
|
|
49061
|
+
class BackgroundManager {
|
|
49062
|
+
tasks;
|
|
49063
|
+
notifications;
|
|
49064
|
+
client;
|
|
49065
|
+
directory;
|
|
49066
|
+
pollingInterval;
|
|
49067
|
+
constructor(ctx) {
|
|
49068
|
+
this.tasks = new Map;
|
|
49069
|
+
this.notifications = new Map;
|
|
49070
|
+
this.client = ctx.client;
|
|
49071
|
+
this.directory = ctx.directory;
|
|
49072
|
+
}
|
|
49073
|
+
async launch(input) {
|
|
49074
|
+
if (!input.agent || input.agent.trim() === "") {
|
|
49075
|
+
throw new Error("Agent parameter is required");
|
|
49076
|
+
}
|
|
49077
|
+
const createResult = await this.client.session.create({
|
|
49078
|
+
body: {
|
|
49079
|
+
parentID: input.parentSessionID,
|
|
49080
|
+
title: `Background: ${input.description}`
|
|
49081
|
+
}
|
|
49082
|
+
});
|
|
49083
|
+
if (createResult.error) {
|
|
49084
|
+
throw new Error(`Failed to create background session: ${createResult.error}`);
|
|
49085
|
+
}
|
|
49086
|
+
const sessionID = createResult.data.id;
|
|
49087
|
+
subagentSessions.add(sessionID);
|
|
49088
|
+
const task = {
|
|
49089
|
+
id: `bg_${crypto.randomUUID().slice(0, 8)}`,
|
|
49090
|
+
sessionID,
|
|
49091
|
+
parentSessionID: input.parentSessionID,
|
|
49092
|
+
parentMessageID: input.parentMessageID,
|
|
49093
|
+
description: input.description,
|
|
49094
|
+
prompt: input.prompt,
|
|
49095
|
+
agent: input.agent,
|
|
49096
|
+
status: "running",
|
|
49097
|
+
startedAt: new Date,
|
|
49098
|
+
progress: {
|
|
49099
|
+
toolCalls: 0,
|
|
49100
|
+
lastUpdate: new Date
|
|
49101
|
+
},
|
|
49102
|
+
parentModel: input.parentModel
|
|
49103
|
+
};
|
|
49104
|
+
this.tasks.set(task.id, task);
|
|
49105
|
+
this.startPolling();
|
|
49106
|
+
log("[background-agent] Launching task:", { taskId: task.id, sessionID, agent: input.agent });
|
|
49107
|
+
this.client.session.promptAsync({
|
|
49108
|
+
path: { id: sessionID },
|
|
49109
|
+
body: {
|
|
49110
|
+
agent: input.agent,
|
|
49111
|
+
tools: {
|
|
49112
|
+
task: false,
|
|
49113
|
+
background_task: false
|
|
49114
|
+
},
|
|
49115
|
+
parts: [{ type: "text", text: input.prompt }]
|
|
49116
|
+
}
|
|
49117
|
+
}).catch((error45) => {
|
|
49118
|
+
log("[background-agent] promptAsync error:", error45);
|
|
49119
|
+
const existingTask = this.findBySession(sessionID);
|
|
49120
|
+
if (existingTask) {
|
|
49121
|
+
existingTask.status = "error";
|
|
49122
|
+
const errorMessage = error45 instanceof Error ? error45.message : String(error45);
|
|
49123
|
+
if (errorMessage.includes("agent.name") || errorMessage.includes("undefined")) {
|
|
49124
|
+
existingTask.error = `Agent "${input.agent}" not found. Make sure the agent is registered in your opencode.json or provided by a plugin.`;
|
|
49125
|
+
} else {
|
|
49126
|
+
existingTask.error = errorMessage;
|
|
49127
|
+
}
|
|
49128
|
+
existingTask.completedAt = new Date;
|
|
49129
|
+
this.markForNotification(existingTask);
|
|
49130
|
+
this.notifyParentSession(existingTask);
|
|
49131
|
+
}
|
|
49132
|
+
});
|
|
49133
|
+
return task;
|
|
49134
|
+
}
|
|
49135
|
+
getTask(id) {
|
|
49136
|
+
return this.tasks.get(id);
|
|
49137
|
+
}
|
|
49138
|
+
getTasksByParentSession(sessionID) {
|
|
49139
|
+
const result = [];
|
|
49140
|
+
for (const task of this.tasks.values()) {
|
|
49141
|
+
if (task.parentSessionID === sessionID) {
|
|
49142
|
+
result.push(task);
|
|
49143
|
+
}
|
|
49144
|
+
}
|
|
49145
|
+
return result;
|
|
49146
|
+
}
|
|
49147
|
+
getAllDescendantTasks(sessionID) {
|
|
49148
|
+
const result = [];
|
|
49149
|
+
const directChildren = this.getTasksByParentSession(sessionID);
|
|
49150
|
+
for (const child of directChildren) {
|
|
49151
|
+
result.push(child);
|
|
49152
|
+
const descendants = this.getAllDescendantTasks(child.sessionID);
|
|
49153
|
+
result.push(...descendants);
|
|
49154
|
+
}
|
|
49155
|
+
return result;
|
|
49156
|
+
}
|
|
49157
|
+
findBySession(sessionID) {
|
|
49158
|
+
for (const task of this.tasks.values()) {
|
|
49159
|
+
if (task.sessionID === sessionID) {
|
|
49160
|
+
return task;
|
|
49161
|
+
}
|
|
49162
|
+
}
|
|
49163
|
+
return;
|
|
46254
49164
|
}
|
|
46255
|
-
|
|
46256
|
-
|
|
49165
|
+
async checkSessionTodos(sessionID) {
|
|
49166
|
+
try {
|
|
49167
|
+
const response2 = await this.client.session.todo({
|
|
49168
|
+
path: { id: sessionID }
|
|
49169
|
+
});
|
|
49170
|
+
const todos = response2.data ?? response2;
|
|
49171
|
+
if (!todos || todos.length === 0)
|
|
49172
|
+
return false;
|
|
49173
|
+
const incomplete = todos.filter((t) => t.status !== "completed" && t.status !== "cancelled");
|
|
49174
|
+
return incomplete.length > 0;
|
|
49175
|
+
} catch {
|
|
46257
49176
|
return false;
|
|
46258
49177
|
}
|
|
46259
|
-
return this._cachedKnownTaskTools.has(toolName);
|
|
46260
49178
|
}
|
|
46261
|
-
|
|
46262
|
-
|
|
46263
|
-
|
|
46264
|
-
|
|
46265
|
-
|
|
46266
|
-
|
|
46267
|
-
|
|
46268
|
-
|
|
46269
|
-
|
|
46270
|
-
|
|
46271
|
-
|
|
46272
|
-
|
|
46273
|
-
|
|
46274
|
-
|
|
46275
|
-
|
|
49179
|
+
handleEvent(event) {
|
|
49180
|
+
const props = event.properties;
|
|
49181
|
+
if (event.type === "message.part.updated") {
|
|
49182
|
+
if (!props || typeof props !== "object" || !("sessionID" in props))
|
|
49183
|
+
return;
|
|
49184
|
+
const partInfo = props;
|
|
49185
|
+
const sessionID = partInfo?.sessionID;
|
|
49186
|
+
if (!sessionID)
|
|
49187
|
+
return;
|
|
49188
|
+
const task = this.findBySession(sessionID);
|
|
49189
|
+
if (!task)
|
|
49190
|
+
return;
|
|
49191
|
+
if (partInfo?.type === "tool" || partInfo?.tool) {
|
|
49192
|
+
if (!task.progress) {
|
|
49193
|
+
task.progress = {
|
|
49194
|
+
toolCalls: 0,
|
|
49195
|
+
lastUpdate: new Date
|
|
49196
|
+
};
|
|
49197
|
+
}
|
|
49198
|
+
task.progress.toolCalls += 1;
|
|
49199
|
+
task.progress.lastTool = partInfo.tool;
|
|
49200
|
+
task.progress.lastUpdate = new Date;
|
|
46276
49201
|
}
|
|
46277
|
-
|
|
46278
|
-
|
|
49202
|
+
}
|
|
49203
|
+
if (event.type === "session.idle") {
|
|
49204
|
+
const sessionID = props?.sessionID;
|
|
49205
|
+
if (!sessionID)
|
|
49206
|
+
return;
|
|
49207
|
+
const task = this.findBySession(sessionID);
|
|
49208
|
+
if (!task || task.status !== "running")
|
|
49209
|
+
return;
|
|
49210
|
+
this.checkSessionTodos(sessionID).then((hasIncompleteTodos2) => {
|
|
49211
|
+
if (hasIncompleteTodos2) {
|
|
49212
|
+
log("[background-agent] Task has incomplete todos, waiting for todo-continuation:", task.id);
|
|
49213
|
+
return;
|
|
49214
|
+
}
|
|
49215
|
+
task.status = "completed";
|
|
49216
|
+
task.completedAt = new Date;
|
|
49217
|
+
this.markForNotification(task);
|
|
49218
|
+
this.notifyParentSession(task);
|
|
49219
|
+
log("[background-agent] Task completed via session.idle event:", task.id);
|
|
49220
|
+
});
|
|
49221
|
+
}
|
|
49222
|
+
if (event.type === "session.deleted") {
|
|
49223
|
+
const info = props?.info;
|
|
49224
|
+
if (!info || typeof info.id !== "string")
|
|
49225
|
+
return;
|
|
49226
|
+
const sessionID = info.id;
|
|
49227
|
+
const task = this.findBySession(sessionID);
|
|
49228
|
+
if (!task)
|
|
49229
|
+
return;
|
|
49230
|
+
if (task.status === "running") {
|
|
49231
|
+
task.status = "cancelled";
|
|
49232
|
+
task.completedAt = new Date;
|
|
49233
|
+
task.error = "Session deleted";
|
|
46279
49234
|
}
|
|
49235
|
+
this.tasks.delete(task.id);
|
|
49236
|
+
this.clearNotificationsForTask(task.id);
|
|
49237
|
+
subagentSessions.delete(sessionID);
|
|
46280
49238
|
}
|
|
46281
49239
|
}
|
|
46282
|
-
|
|
46283
|
-
|
|
49240
|
+
markForNotification(task) {
|
|
49241
|
+
const queue = this.notifications.get(task.parentSessionID) ?? [];
|
|
49242
|
+
queue.push(task);
|
|
49243
|
+
this.notifications.set(task.parentSessionID, queue);
|
|
46284
49244
|
}
|
|
46285
|
-
|
|
46286
|
-
|
|
46287
|
-
this.cacheToolMetadata(result.tools);
|
|
46288
|
-
return result;
|
|
49245
|
+
getPendingNotifications(sessionID) {
|
|
49246
|
+
return this.notifications.get(sessionID) ?? [];
|
|
46289
49247
|
}
|
|
46290
|
-
|
|
46291
|
-
|
|
46292
|
-
|
|
46293
|
-
|
|
46294
|
-
|
|
46295
|
-
|
|
46296
|
-
|
|
46297
|
-
|
|
46298
|
-
const { autoRefresh, debounceMs } = parseResult.data;
|
|
46299
|
-
const { onChanged } = options;
|
|
46300
|
-
const refresh = async () => {
|
|
46301
|
-
if (!autoRefresh) {
|
|
46302
|
-
onChanged(null, null);
|
|
46303
|
-
return;
|
|
46304
|
-
}
|
|
46305
|
-
try {
|
|
46306
|
-
const items = await fetcher();
|
|
46307
|
-
onChanged(null, items);
|
|
46308
|
-
} catch (e) {
|
|
46309
|
-
const error45 = e instanceof Error ? e : new Error(String(e));
|
|
46310
|
-
onChanged(error45, null);
|
|
46311
|
-
}
|
|
46312
|
-
};
|
|
46313
|
-
const handler = () => {
|
|
46314
|
-
if (debounceMs) {
|
|
46315
|
-
const existingTimer = this._listChangedDebounceTimers.get(listType);
|
|
46316
|
-
if (existingTimer) {
|
|
46317
|
-
clearTimeout(existingTimer);
|
|
46318
|
-
}
|
|
46319
|
-
const timer = setTimeout(refresh, debounceMs);
|
|
46320
|
-
this._listChangedDebounceTimers.set(listType, timer);
|
|
49248
|
+
clearNotifications(sessionID) {
|
|
49249
|
+
this.notifications.delete(sessionID);
|
|
49250
|
+
}
|
|
49251
|
+
clearNotificationsForTask(taskId) {
|
|
49252
|
+
for (const [sessionID, tasks] of this.notifications.entries()) {
|
|
49253
|
+
const filtered = tasks.filter((t) => t.id !== taskId);
|
|
49254
|
+
if (filtered.length === 0) {
|
|
49255
|
+
this.notifications.delete(sessionID);
|
|
46321
49256
|
} else {
|
|
46322
|
-
|
|
49257
|
+
this.notifications.set(sessionID, filtered);
|
|
46323
49258
|
}
|
|
46324
|
-
}
|
|
46325
|
-
this.setNotificationHandler(notificationSchema, handler);
|
|
46326
|
-
}
|
|
46327
|
-
async sendRootsListChanged() {
|
|
46328
|
-
return this.notification({ method: "notifications/roots/list_changed" });
|
|
49259
|
+
}
|
|
46329
49260
|
}
|
|
46330
|
-
|
|
46331
|
-
|
|
46332
|
-
|
|
46333
|
-
|
|
46334
|
-
|
|
46335
|
-
|
|
46336
|
-
|
|
46337
|
-
// node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
|
|
46338
|
-
class ReadBuffer {
|
|
46339
|
-
append(chunk) {
|
|
46340
|
-
this._buffer = this._buffer ? Buffer.concat([this._buffer, chunk]) : chunk;
|
|
49261
|
+
startPolling() {
|
|
49262
|
+
if (this.pollingInterval)
|
|
49263
|
+
return;
|
|
49264
|
+
this.pollingInterval = setInterval(() => {
|
|
49265
|
+
this.pollRunningTasks();
|
|
49266
|
+
}, 2000);
|
|
49267
|
+
this.pollingInterval.unref();
|
|
46341
49268
|
}
|
|
46342
|
-
|
|
46343
|
-
if (
|
|
46344
|
-
|
|
46345
|
-
|
|
46346
|
-
const index = this._buffer.indexOf(`
|
|
46347
|
-
`);
|
|
46348
|
-
if (index === -1) {
|
|
46349
|
-
return null;
|
|
49269
|
+
stopPolling() {
|
|
49270
|
+
if (this.pollingInterval) {
|
|
49271
|
+
clearInterval(this.pollingInterval);
|
|
49272
|
+
this.pollingInterval = undefined;
|
|
46350
49273
|
}
|
|
46351
|
-
const line = this._buffer.toString("utf8", 0, index).replace(/\r$/, "");
|
|
46352
|
-
this._buffer = this._buffer.subarray(index + 1);
|
|
46353
|
-
return deserializeMessage(line);
|
|
46354
49274
|
}
|
|
46355
|
-
|
|
46356
|
-
this.
|
|
49275
|
+
cleanup() {
|
|
49276
|
+
this.stopPolling();
|
|
49277
|
+
this.tasks.clear();
|
|
49278
|
+
this.notifications.clear();
|
|
46357
49279
|
}
|
|
46358
|
-
|
|
46359
|
-
|
|
46360
|
-
|
|
46361
|
-
|
|
46362
|
-
|
|
46363
|
-
|
|
46364
|
-
|
|
46365
|
-
|
|
46366
|
-
|
|
46367
|
-
|
|
46368
|
-
|
|
46369
|
-
|
|
46370
|
-
|
|
46371
|
-
"HOMEPATH",
|
|
46372
|
-
"LOCALAPPDATA",
|
|
46373
|
-
"PATH",
|
|
46374
|
-
"PROCESSOR_ARCHITECTURE",
|
|
46375
|
-
"SYSTEMDRIVE",
|
|
46376
|
-
"SYSTEMROOT",
|
|
46377
|
-
"TEMP",
|
|
46378
|
-
"USERNAME",
|
|
46379
|
-
"USERPROFILE",
|
|
46380
|
-
"PROGRAMFILES"
|
|
46381
|
-
] : ["HOME", "LOGNAME", "PATH", "SHELL", "TERM", "USER"];
|
|
46382
|
-
function getDefaultEnvironment() {
|
|
46383
|
-
const env = {};
|
|
46384
|
-
for (const key of DEFAULT_INHERITED_ENV_VARS) {
|
|
46385
|
-
const value = process2.env[key];
|
|
46386
|
-
if (value === undefined) {
|
|
46387
|
-
continue;
|
|
49280
|
+
notifyParentSession(task) {
|
|
49281
|
+
const duration3 = this.formatDuration(task.startedAt, task.completedAt);
|
|
49282
|
+
log("[background-agent] notifyParentSession called for task:", task.id);
|
|
49283
|
+
const tuiClient = this.client;
|
|
49284
|
+
if (tuiClient.tui?.showToast) {
|
|
49285
|
+
tuiClient.tui.showToast({
|
|
49286
|
+
body: {
|
|
49287
|
+
title: "Background Task Completed",
|
|
49288
|
+
message: `Task "${task.description}" finished in ${duration3}.`,
|
|
49289
|
+
variant: "success",
|
|
49290
|
+
duration: 5000
|
|
49291
|
+
}
|
|
49292
|
+
}).catch(() => {});
|
|
46388
49293
|
}
|
|
46389
|
-
|
|
46390
|
-
|
|
49294
|
+
const message = `[BACKGROUND TASK COMPLETED] Task "${task.description}" finished in ${duration3}. Use background_output with task_id="${task.id}" to get results.`;
|
|
49295
|
+
log("[background-agent] Sending notification to parent session:", { parentSessionID: task.parentSessionID });
|
|
49296
|
+
const taskId = task.id;
|
|
49297
|
+
setTimeout(async () => {
|
|
49298
|
+
try {
|
|
49299
|
+
const messageDir = getMessageDir11(task.parentSessionID);
|
|
49300
|
+
const prevMessage = messageDir ? findNearestMessageWithFields(messageDir) : null;
|
|
49301
|
+
const modelContext = task.parentModel ?? prevMessage?.model;
|
|
49302
|
+
const modelField = modelContext?.providerID && modelContext?.modelID ? { providerID: modelContext.providerID, modelID: modelContext.modelID } : undefined;
|
|
49303
|
+
await this.client.session.prompt({
|
|
49304
|
+
path: { id: task.parentSessionID },
|
|
49305
|
+
body: {
|
|
49306
|
+
agent: prevMessage?.agent,
|
|
49307
|
+
model: modelField,
|
|
49308
|
+
parts: [{ type: "text", text: message }]
|
|
49309
|
+
},
|
|
49310
|
+
query: { directory: this.directory }
|
|
49311
|
+
});
|
|
49312
|
+
log("[background-agent] Successfully sent prompt to parent session:", { parentSessionID: task.parentSessionID });
|
|
49313
|
+
} catch (error45) {
|
|
49314
|
+
log("[background-agent] prompt failed:", String(error45));
|
|
49315
|
+
} finally {
|
|
49316
|
+
this.clearNotificationsForTask(taskId);
|
|
49317
|
+
this.tasks.delete(taskId);
|
|
49318
|
+
log("[background-agent] Removed completed task from memory:", taskId);
|
|
49319
|
+
}
|
|
49320
|
+
}, 200);
|
|
49321
|
+
}
|
|
49322
|
+
formatDuration(start, end) {
|
|
49323
|
+
const duration3 = (end ?? new Date).getTime() - start.getTime();
|
|
49324
|
+
const seconds = Math.floor(duration3 / 1000);
|
|
49325
|
+
const minutes = Math.floor(seconds / 60);
|
|
49326
|
+
const hours = Math.floor(minutes / 60);
|
|
49327
|
+
if (hours > 0) {
|
|
49328
|
+
return `${hours}h ${minutes % 60}m ${seconds % 60}s`;
|
|
49329
|
+
} else if (minutes > 0) {
|
|
49330
|
+
return `${minutes}m ${seconds % 60}s`;
|
|
46391
49331
|
}
|
|
46392
|
-
|
|
49332
|
+
return `${seconds}s`;
|
|
46393
49333
|
}
|
|
46394
|
-
|
|
46395
|
-
|
|
46396
|
-
|
|
46397
|
-
|
|
46398
|
-
constructor(server) {
|
|
46399
|
-
this._readBuffer = new ReadBuffer;
|
|
46400
|
-
this._stderrStream = null;
|
|
46401
|
-
this._serverParams = server;
|
|
46402
|
-
if (server.stderr === "pipe" || server.stderr === "overlapped") {
|
|
46403
|
-
this._stderrStream = new PassThrough;
|
|
49334
|
+
hasRunningTasks() {
|
|
49335
|
+
for (const task of this.tasks.values()) {
|
|
49336
|
+
if (task.status === "running")
|
|
49337
|
+
return true;
|
|
46404
49338
|
}
|
|
49339
|
+
return false;
|
|
46405
49340
|
}
|
|
46406
|
-
|
|
46407
|
-
|
|
46408
|
-
|
|
49341
|
+
pruneStaleTasksAndNotifications() {
|
|
49342
|
+
const now = Date.now();
|
|
49343
|
+
for (const [taskId, task] of this.tasks.entries()) {
|
|
49344
|
+
const age = now - task.startedAt.getTime();
|
|
49345
|
+
if (age > TASK_TTL_MS) {
|
|
49346
|
+
log("[background-agent] Pruning stale task:", { taskId, age: Math.round(age / 1000) + "s" });
|
|
49347
|
+
task.status = "error";
|
|
49348
|
+
task.error = "Task timed out after 30 minutes";
|
|
49349
|
+
task.completedAt = new Date;
|
|
49350
|
+
this.clearNotificationsForTask(taskId);
|
|
49351
|
+
this.tasks.delete(taskId);
|
|
49352
|
+
subagentSessions.delete(task.sessionID);
|
|
49353
|
+
}
|
|
46409
49354
|
}
|
|
46410
|
-
|
|
46411
|
-
|
|
46412
|
-
|
|
46413
|
-
|
|
46414
|
-
|
|
46415
|
-
|
|
46416
|
-
|
|
46417
|
-
|
|
46418
|
-
windowsHide: process2.platform === "win32" && isElectron(),
|
|
46419
|
-
cwd: this._serverParams.cwd
|
|
46420
|
-
});
|
|
46421
|
-
this._process.on("error", (error45) => {
|
|
46422
|
-
reject(error45);
|
|
46423
|
-
this.onerror?.(error45);
|
|
46424
|
-
});
|
|
46425
|
-
this._process.on("spawn", () => {
|
|
46426
|
-
resolve8();
|
|
46427
|
-
});
|
|
46428
|
-
this._process.on("close", (_code) => {
|
|
46429
|
-
this._process = undefined;
|
|
46430
|
-
this.onclose?.();
|
|
46431
|
-
});
|
|
46432
|
-
this._process.stdin?.on("error", (error45) => {
|
|
46433
|
-
this.onerror?.(error45);
|
|
46434
|
-
});
|
|
46435
|
-
this._process.stdout?.on("data", (chunk) => {
|
|
46436
|
-
this._readBuffer.append(chunk);
|
|
46437
|
-
this.processReadBuffer();
|
|
46438
|
-
});
|
|
46439
|
-
this._process.stdout?.on("error", (error45) => {
|
|
46440
|
-
this.onerror?.(error45);
|
|
49355
|
+
for (const [sessionID, notifications] of this.notifications.entries()) {
|
|
49356
|
+
if (notifications.length === 0) {
|
|
49357
|
+
this.notifications.delete(sessionID);
|
|
49358
|
+
continue;
|
|
49359
|
+
}
|
|
49360
|
+
const validNotifications = notifications.filter((task) => {
|
|
49361
|
+
const age = now - task.startedAt.getTime();
|
|
49362
|
+
return age <= TASK_TTL_MS;
|
|
46441
49363
|
});
|
|
46442
|
-
if (
|
|
46443
|
-
this.
|
|
49364
|
+
if (validNotifications.length === 0) {
|
|
49365
|
+
this.notifications.delete(sessionID);
|
|
49366
|
+
} else if (validNotifications.length !== notifications.length) {
|
|
49367
|
+
this.notifications.set(sessionID, validNotifications);
|
|
46444
49368
|
}
|
|
46445
|
-
});
|
|
46446
|
-
}
|
|
46447
|
-
get stderr() {
|
|
46448
|
-
if (this._stderrStream) {
|
|
46449
|
-
return this._stderrStream;
|
|
46450
49369
|
}
|
|
46451
|
-
return this._process?.stderr ?? null;
|
|
46452
|
-
}
|
|
46453
|
-
get pid() {
|
|
46454
|
-
return this._process?.pid ?? null;
|
|
46455
49370
|
}
|
|
46456
|
-
|
|
46457
|
-
|
|
49371
|
+
async pollRunningTasks() {
|
|
49372
|
+
this.pruneStaleTasksAndNotifications();
|
|
49373
|
+
const statusResult = await this.client.session.status();
|
|
49374
|
+
const allStatuses = statusResult.data ?? {};
|
|
49375
|
+
for (const task of this.tasks.values()) {
|
|
49376
|
+
if (task.status !== "running")
|
|
49377
|
+
continue;
|
|
46458
49378
|
try {
|
|
46459
|
-
const
|
|
46460
|
-
if (
|
|
46461
|
-
|
|
49379
|
+
const sessionStatus = allStatuses[task.sessionID];
|
|
49380
|
+
if (!sessionStatus) {
|
|
49381
|
+
log("[background-agent] Session not found in status:", task.sessionID);
|
|
49382
|
+
continue;
|
|
46462
49383
|
}
|
|
46463
|
-
|
|
46464
|
-
|
|
46465
|
-
|
|
46466
|
-
|
|
46467
|
-
|
|
46468
|
-
|
|
46469
|
-
|
|
46470
|
-
|
|
46471
|
-
|
|
46472
|
-
|
|
46473
|
-
|
|
46474
|
-
|
|
46475
|
-
|
|
49384
|
+
if (sessionStatus.type === "idle") {
|
|
49385
|
+
const hasIncompleteTodos2 = await this.checkSessionTodos(task.sessionID);
|
|
49386
|
+
if (hasIncompleteTodos2) {
|
|
49387
|
+
log("[background-agent] Task has incomplete todos via polling, waiting:", task.id);
|
|
49388
|
+
continue;
|
|
49389
|
+
}
|
|
49390
|
+
task.status = "completed";
|
|
49391
|
+
task.completedAt = new Date;
|
|
49392
|
+
this.markForNotification(task);
|
|
49393
|
+
this.notifyParentSession(task);
|
|
49394
|
+
log("[background-agent] Task completed via polling:", task.id);
|
|
49395
|
+
continue;
|
|
49396
|
+
}
|
|
49397
|
+
const messagesResult = await this.client.session.messages({
|
|
49398
|
+
path: { id: task.sessionID }
|
|
46476
49399
|
});
|
|
46477
|
-
|
|
46478
|
-
|
|
46479
|
-
|
|
46480
|
-
|
|
46481
|
-
|
|
46482
|
-
|
|
46483
|
-
|
|
46484
|
-
|
|
46485
|
-
|
|
46486
|
-
|
|
46487
|
-
|
|
46488
|
-
|
|
46489
|
-
|
|
46490
|
-
|
|
46491
|
-
|
|
49400
|
+
if (!messagesResult.error && messagesResult.data) {
|
|
49401
|
+
const messages = messagesResult.data;
|
|
49402
|
+
const assistantMsgs = messages.filter((m) => m.info?.role === "assistant");
|
|
49403
|
+
let toolCalls = 0;
|
|
49404
|
+
let lastTool;
|
|
49405
|
+
let lastMessage;
|
|
49406
|
+
for (const msg of assistantMsgs) {
|
|
49407
|
+
const parts = msg.parts ?? [];
|
|
49408
|
+
for (const part of parts) {
|
|
49409
|
+
if (part.type === "tool_use" || part.tool) {
|
|
49410
|
+
toolCalls++;
|
|
49411
|
+
lastTool = part.tool || part.name || "unknown";
|
|
49412
|
+
}
|
|
49413
|
+
if (part.type === "text" && part.text) {
|
|
49414
|
+
lastMessage = part.text;
|
|
49415
|
+
}
|
|
49416
|
+
}
|
|
49417
|
+
}
|
|
49418
|
+
if (!task.progress) {
|
|
49419
|
+
task.progress = { toolCalls: 0, lastUpdate: new Date };
|
|
49420
|
+
}
|
|
49421
|
+
task.progress.toolCalls = toolCalls;
|
|
49422
|
+
task.progress.lastTool = lastTool;
|
|
49423
|
+
task.progress.lastUpdate = new Date;
|
|
49424
|
+
if (lastMessage) {
|
|
49425
|
+
task.progress.lastMessage = lastMessage;
|
|
49426
|
+
task.progress.lastMessageAt = new Date;
|
|
49427
|
+
}
|
|
49428
|
+
}
|
|
49429
|
+
} catch (error45) {
|
|
49430
|
+
log("[background-agent] Poll error for task:", { taskId: task.id, error: error45 });
|
|
46492
49431
|
}
|
|
46493
49432
|
}
|
|
46494
|
-
this.
|
|
46495
|
-
|
|
46496
|
-
send(message) {
|
|
46497
|
-
return new Promise((resolve8) => {
|
|
46498
|
-
if (!this._process?.stdin) {
|
|
46499
|
-
throw new Error("Not connected");
|
|
46500
|
-
}
|
|
46501
|
-
const json3 = serializeMessage(message);
|
|
46502
|
-
if (this._process.stdin.write(json3)) {
|
|
46503
|
-
resolve8();
|
|
46504
|
-
} else {
|
|
46505
|
-
this._process.stdin.once("drain", resolve8);
|
|
46506
|
-
}
|
|
46507
|
-
});
|
|
46508
|
-
}
|
|
46509
|
-
}
|
|
46510
|
-
function isElectron() {
|
|
46511
|
-
return "type" in process2;
|
|
46512
|
-
}
|
|
46513
|
-
|
|
46514
|
-
// src/features/skill-mcp-manager/env-cleaner.ts
|
|
46515
|
-
var EXCLUDED_ENV_PATTERNS = [
|
|
46516
|
-
/^NPM_CONFIG_/i,
|
|
46517
|
-
/^npm_config_/,
|
|
46518
|
-
/^YARN_/,
|
|
46519
|
-
/^PNPM_/,
|
|
46520
|
-
/^NO_UPDATE_NOTIFIER$/
|
|
46521
|
-
];
|
|
46522
|
-
function createCleanMcpEnvironment(customEnv = {}) {
|
|
46523
|
-
const cleanEnv = {};
|
|
46524
|
-
for (const [key, value] of Object.entries(process.env)) {
|
|
46525
|
-
if (value === undefined)
|
|
46526
|
-
continue;
|
|
46527
|
-
const shouldExclude = EXCLUDED_ENV_PATTERNS.some((pattern) => pattern.test(key));
|
|
46528
|
-
if (!shouldExclude) {
|
|
46529
|
-
cleanEnv[key] = value;
|
|
49433
|
+
if (!this.hasRunningTasks()) {
|
|
49434
|
+
this.stopPolling();
|
|
46530
49435
|
}
|
|
46531
49436
|
}
|
|
46532
|
-
Object.assign(cleanEnv, customEnv);
|
|
46533
|
-
return cleanEnv;
|
|
46534
49437
|
}
|
|
46535
|
-
|
|
46536
49438
|
// src/features/skill-mcp-manager/manager.ts
|
|
46537
49439
|
class SkillMcpManager {
|
|
46538
49440
|
clients = new Map;
|
|
@@ -47019,6 +49921,21 @@ var Mem0ConfigSchema = exports_external.object({
|
|
|
47019
49921
|
autoRehydrate: exports_external.boolean().default(true),
|
|
47020
49922
|
rehydrateLayers: exports_external.array(MemoryLayerSchema).default(["user", "project", "team"])
|
|
47021
49923
|
});
|
|
49924
|
+
var LettaConfigSchema = exports_external.object({
|
|
49925
|
+
enabled: exports_external.boolean().default(false),
|
|
49926
|
+
endpoint: exports_external.string().url().optional().describe("Letta server endpoint (default: http://localhost:8283)"),
|
|
49927
|
+
apiKey: exports_external.string().optional().describe("Optional API key for cloud Letta (not needed for self-hosted)"),
|
|
49928
|
+
userId: exports_external.string().optional(),
|
|
49929
|
+
projectId: exports_external.string().optional(),
|
|
49930
|
+
teamId: exports_external.string().optional(),
|
|
49931
|
+
orgId: exports_external.string().optional(),
|
|
49932
|
+
companyId: exports_external.string().optional(),
|
|
49933
|
+
agentPrefix: exports_external.string().optional().describe("Agent name prefix (default: opencode)"),
|
|
49934
|
+
llmModel: exports_external.string().optional().describe("LLM model for agent (e.g., openai/gpt-4.1)"),
|
|
49935
|
+
embeddingModel: exports_external.string().optional().describe("Embedding model for semantic search"),
|
|
49936
|
+
autoRehydrate: exports_external.boolean().default(true),
|
|
49937
|
+
rehydrateLayers: exports_external.array(MemoryLayerSchema).default(["user", "project", "team"])
|
|
49938
|
+
});
|
|
47022
49939
|
var CentralHubConfigSchema = exports_external.object({
|
|
47023
49940
|
url: exports_external.string().url(),
|
|
47024
49941
|
branch: exports_external.string().default("main"),
|
|
@@ -47058,11 +49975,17 @@ var OpenSpecConfigSchema = exports_external.object({
|
|
|
47058
49975
|
]),
|
|
47059
49976
|
rootDir: exports_external.string().default(".opencode/openspec")
|
|
47060
49977
|
});
|
|
49978
|
+
var MCPTransportTypeSchema = exports_external.enum(["stdio", "sse"]);
|
|
47061
49979
|
var MCPKnowledgeProviderConfigSchema = exports_external.object({
|
|
47062
49980
|
name: exports_external.string(),
|
|
47063
|
-
|
|
47064
|
-
|
|
47065
|
-
|
|
49981
|
+
transport: MCPTransportTypeSchema.optional().describe("Transport type: 'stdio' (default) or 'sse'"),
|
|
49982
|
+
command: exports_external.string().optional().describe("Command to start the MCP server (required for stdio transport)"),
|
|
49983
|
+
args: exports_external.array(exports_external.string()).optional().describe("Arguments for the command (stdio transport)"),
|
|
49984
|
+
env: exports_external.record(exports_external.string(), exports_external.string()).optional().describe("Environment variables (stdio transport)"),
|
|
49985
|
+
url: exports_external.string().optional().describe("SSE endpoint URL (required for sse transport, e.g., 'http://localhost:60062/sse')"),
|
|
49986
|
+
searchTool: exports_external.string().describe("MCP tool name for search operations"),
|
|
49987
|
+
getTool: exports_external.string().optional().describe("MCP tool name for get-by-id operations"),
|
|
49988
|
+
config: exports_external.record(exports_external.string(), exports_external.unknown()).optional().describe("Additional config passed to MCP tools")
|
|
47066
49989
|
});
|
|
47067
49990
|
var NotebookLMProviderConfigSchema = exports_external.object({
|
|
47068
49991
|
enabled: exports_external.boolean().default(false),
|
|
@@ -47116,6 +50039,7 @@ var OhMyOpenCodeConfigSchema = exports_external.object({
|
|
|
47116
50039
|
skills: SkillsConfigSchema.optional(),
|
|
47117
50040
|
ralph_loop: RalphLoopConfigSchema.optional(),
|
|
47118
50041
|
mem0: Mem0ConfigSchema.optional(),
|
|
50042
|
+
letta: LettaConfigSchema.optional(),
|
|
47119
50043
|
knowledge_repo: KnowledgeRepoConfigSchema.optional(),
|
|
47120
50044
|
knowledge_provider: KnowledgeProviderConfigSchema.optional(),
|
|
47121
50045
|
openspec: OpenSpecConfigSchema.optional()
|
|
@@ -47152,6 +50076,8 @@ function mergeConfigs(base, override) {
|
|
|
47152
50076
|
...base,
|
|
47153
50077
|
...override,
|
|
47154
50078
|
agents: deepMerge(base.agents, override.agents),
|
|
50079
|
+
mem0: deepMerge(base.mem0, override.mem0),
|
|
50080
|
+
letta: deepMerge(base.letta, override.letta),
|
|
47155
50081
|
disabled_agents: [
|
|
47156
50082
|
...new Set([
|
|
47157
50083
|
...base.disabled_agents ?? [],
|
|
@@ -52734,6 +55660,62 @@ function createConfigHandler(deps) {
|
|
|
52734
55660
|
};
|
|
52735
55661
|
}
|
|
52736
55662
|
// src/index.ts
|
|
55663
|
+
async function initializeKnowledgeProviderRegistry(pluginConfig, mem0Adapter) {
|
|
55664
|
+
const config3 = pluginConfig.knowledge_provider;
|
|
55665
|
+
const registry2 = new KnowledgeProviderRegistry({
|
|
55666
|
+
defaultLimit: config3.search?.defaultLimit ?? 10,
|
|
55667
|
+
defaultThreshold: config3.search?.defaultThreshold ?? 0.5,
|
|
55668
|
+
mergeStrategy: config3.search?.mergeStrategy ?? "score",
|
|
55669
|
+
providerPriority: config3.search?.providerPriority,
|
|
55670
|
+
deduplicate: config3.search?.deduplicate ?? true
|
|
55671
|
+
});
|
|
55672
|
+
if (config3.providers?.local?.enabled !== false) {
|
|
55673
|
+
const localProvider = new LocalKnowledgeProvider({
|
|
55674
|
+
enabled: true,
|
|
55675
|
+
rootDir: config3.providers?.local?.rootDir
|
|
55676
|
+
});
|
|
55677
|
+
await registry2.register(localProvider);
|
|
55678
|
+
}
|
|
55679
|
+
if (mem0Adapter && config3.providers?.mem0?.enabled !== false) {
|
|
55680
|
+
const mem0Provider = new Mem0KnowledgeProvider({
|
|
55681
|
+
enabled: true,
|
|
55682
|
+
indexKnowledgeRepo: config3.providers?.mem0?.indexKnowledgeRepo ?? false,
|
|
55683
|
+
searchLayers: config3.providers?.mem0?.searchLayers
|
|
55684
|
+
}, {
|
|
55685
|
+
enabled: true,
|
|
55686
|
+
apiKey: pluginConfig.mem0.apiKey,
|
|
55687
|
+
endpoint: pluginConfig.mem0.endpoint,
|
|
55688
|
+
userId: pluginConfig.mem0.userId,
|
|
55689
|
+
sessionId: pluginConfig.mem0.sessionId,
|
|
55690
|
+
projectId: pluginConfig.mem0.projectId,
|
|
55691
|
+
teamId: pluginConfig.mem0.teamId,
|
|
55692
|
+
orgId: pluginConfig.mem0.orgId,
|
|
55693
|
+
companyId: pluginConfig.mem0.companyId,
|
|
55694
|
+
agentId: pluginConfig.mem0.agentId
|
|
55695
|
+
});
|
|
55696
|
+
await registry2.register(mem0Provider);
|
|
55697
|
+
}
|
|
55698
|
+
const hasMcpServers = config3.providers?.mcp?.enabled && config3.providers?.mcp?.servers?.length;
|
|
55699
|
+
const hasNotebookLM = config3.providers?.notebooklm?.enabled;
|
|
55700
|
+
if (hasMcpServers || hasNotebookLM) {
|
|
55701
|
+
const mcpManager = new KnowledgeMcpManager;
|
|
55702
|
+
if (hasMcpServers) {
|
|
55703
|
+
for (const serverConfig of config3.providers.mcp.servers) {
|
|
55704
|
+
mcpManager.registerServer(serverConfig);
|
|
55705
|
+
const mcpProvider = new MCPKnowledgeProvider(serverConfig, mcpManager);
|
|
55706
|
+
await registry2.register(mcpProvider);
|
|
55707
|
+
}
|
|
55708
|
+
}
|
|
55709
|
+
if (hasNotebookLM) {
|
|
55710
|
+
const notebookLMProvider = new NotebookLMKnowledgeProvider({
|
|
55711
|
+
enabled: true,
|
|
55712
|
+
defaultNotebookId: config3.providers.notebooklm.defaultNotebookId
|
|
55713
|
+
}, mcpManager);
|
|
55714
|
+
await registry2.register(notebookLMProvider);
|
|
55715
|
+
}
|
|
55716
|
+
}
|
|
55717
|
+
return registry2;
|
|
55718
|
+
}
|
|
52737
55719
|
var OhMyOpenCodePlugin = async (ctx) => {
|
|
52738
55720
|
const pluginConfig = loadPluginConfig(ctx.directory, ctx);
|
|
52739
55721
|
const disabledHooks = new Set(pluginConfig.disabled_hooks ?? []);
|
|
@@ -52751,15 +55733,30 @@ var OhMyOpenCodePlugin = async (ctx) => {
|
|
|
52751
55733
|
companyId: pluginConfig.mem0.companyId,
|
|
52752
55734
|
agentId: pluginConfig.mem0.agentId
|
|
52753
55735
|
}) : null;
|
|
52754
|
-
const
|
|
55736
|
+
const lettaAdapter = pluginConfig.letta?.enabled ? new LettaAdapter({
|
|
55737
|
+
enabled: true,
|
|
55738
|
+
endpoint: pluginConfig.letta.endpoint,
|
|
55739
|
+
apiKey: pluginConfig.letta.apiKey,
|
|
55740
|
+
userId: pluginConfig.letta.userId,
|
|
55741
|
+
projectId: pluginConfig.letta.projectId,
|
|
55742
|
+
teamId: pluginConfig.letta.teamId,
|
|
55743
|
+
orgId: pluginConfig.letta.orgId,
|
|
55744
|
+
companyId: pluginConfig.letta.companyId,
|
|
55745
|
+
agentPrefix: pluginConfig.letta.agentPrefix,
|
|
55746
|
+
llmModel: pluginConfig.letta.llmModel,
|
|
55747
|
+
embeddingModel: pluginConfig.letta.embeddingModel
|
|
55748
|
+
}) : null;
|
|
55749
|
+
const memoryAdapter = lettaAdapter ?? mem0Adapter;
|
|
55750
|
+
const memoryTools = memoryAdapter ? createMemoryTools(memoryAdapter) : {};
|
|
55751
|
+
const knowledgeProviderRegistry = pluginConfig.knowledge_provider?.enabled ? await initializeKnowledgeProviderRegistry(pluginConfig, mem0Adapter) : null;
|
|
52755
55752
|
const knowledgeMonitor = isHookEnabled("knowledge-monitor") && pluginConfig.knowledge_repo?.enabled ? createKnowledgeMonitorHook(ctx.directory, {
|
|
52756
55753
|
enabled: true,
|
|
52757
55754
|
checkPreTool: true,
|
|
52758
55755
|
checkPostTool: false
|
|
52759
55756
|
}) : null;
|
|
52760
|
-
const memoryRehydration = isHookEnabled("memory-rehydration") &&
|
|
55757
|
+
const memoryRehydration = isHookEnabled("memory-rehydration") && memoryAdapter && (pluginConfig.letta?.autoRehydrate !== false || pluginConfig.mem0?.autoRehydrate !== false) ? createMemoryRehydrationHook(memoryAdapter, {
|
|
52761
55758
|
enabled: true,
|
|
52762
|
-
layers: pluginConfig.mem0?.rehydrateLayers
|
|
55759
|
+
layers: pluginConfig.letta?.rehydrateLayers ?? pluginConfig.mem0?.rehydrateLayers
|
|
52763
55760
|
}) : null;
|
|
52764
55761
|
const contextWindowMonitor = isHookEnabled("context-window-monitor") ? createContextWindowMonitorHook(ctx) : null;
|
|
52765
55762
|
const sessionRecovery = isHookEnabled("session-recovery") ? createSessionRecoveryHook(ctx, { experimental: pluginConfig.experimental }) : null;
|
|
@@ -52855,12 +55852,14 @@ var OhMyOpenCodePlugin = async (ctx) => {
|
|
|
52855
55852
|
pluginConfig,
|
|
52856
55853
|
modelCacheState
|
|
52857
55854
|
});
|
|
55855
|
+
const knowledgeProviderTools = knowledgeProviderRegistry ? createKnowledgeProviderTools(knowledgeProviderRegistry) : {};
|
|
52858
55856
|
return {
|
|
52859
55857
|
...googleAuthHooks ? { auth: googleAuthHooks.auth } : {},
|
|
52860
55858
|
tool: {
|
|
52861
55859
|
...builtinTools,
|
|
52862
55860
|
...backgroundTools,
|
|
52863
55861
|
...memoryTools,
|
|
55862
|
+
...knowledgeProviderTools,
|
|
52864
55863
|
call_omo_agent: callOmoAgent,
|
|
52865
55864
|
look_at: lookAt,
|
|
52866
55865
|
skill: skillTool,
|