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/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 types19 = getJSONTypes(schema2.type);
2906
- const hasNull = types19.includes("null");
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 (!types19.length && schema2.nullable !== undefined) {
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
- types19.push("null");
2915
+ types18.push("null");
2916
2916
  }
2917
- return types19;
2917
+ return types18;
2918
2918
  }
2919
2919
  exports.getSchemaTypes = getSchemaTypes;
2920
2920
  function getJSONTypes(ts) {
2921
- const types19 = Array.isArray(ts) ? ts : ts ? [ts] : [];
2922
- if (types19.every(rules_1.isJSONType))
2923
- return types19;
2924
- throw new Error("type must be JSONType or JSONType[]: " + types19.join(","));
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, types19) {
2927
+ function coerceAndCheckDataType(it, types18) {
2928
2928
  const { gen, data, opts } = it;
2929
- const coerceTo = coerceToTypes(types19, opts.coerceTypes);
2930
- const checkTypes = types19.length > 0 && !(coerceTo.length === 0 && types19.length === 1 && (0, applicability_1.schemaHasRulesForType)(it, types19[0]));
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(types19, data, opts.strictNumbers, DataType.Wrong);
2932
+ const wrongType = checkDataTypes(types18, data, opts.strictNumbers, DataType.Wrong);
2933
2933
  gen.if(wrongType, () => {
2934
2934
  if (coerceTo.length)
2935
- coerceData(it, types19, coerceTo);
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(types19, coerceTypes) {
2945
- return coerceTypes ? types19.filter((t) => COERCIBLE.has(t) || coerceTypes === "array" && t === "array") : [];
2944
+ function coerceToTypes(types18, coerceTypes) {
2945
+ return coerceTypes ? types18.filter((t) => COERCIBLE.has(t) || coerceTypes === "array" && t === "array") : [];
2946
2946
  }
2947
- function coerceData(it, types19, coerceTo) {
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(types19, data, opts.strictNumbers), () => gen.assign(coerced, data)));
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 types19 = (0, util_1.toHash)(dataTypes);
3029
- if (types19.array && types19.object) {
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 = types19.null ? notObj : (0, codegen_1._)`!${data} || ${notObj}`;
3032
- delete types19.null;
3033
- delete types19.array;
3034
- delete types19.object;
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 (types19.number)
3039
- delete types19.integer;
3040
- for (const t in types19)
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 types19 = (0, dataType_1.getSchemaTypes)(it.schema);
3829
- const checkedTypes = (0, dataType_1.coerceAndCheckDataType)(it, types19);
3830
- schemaKeywords(it, types19, !checkedTypes, errsCount);
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, types19, typeErrors, errsCount) {
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, types19);
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 (types19.length === 1 && types19[0] === group.type && typeErrors) {
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, types19) {
3924
+ function checkStrictTypes(it, types18) {
3925
3925
  if (it.schemaEnv.meta || !it.opts.strictTypes)
3926
3926
  return;
3927
- checkContextTypes(it, types19);
3927
+ checkContextTypes(it, types18);
3928
3928
  if (!it.opts.allowUnionTypes)
3929
- checkMultipleTypes(it, types19);
3929
+ checkMultipleTypes(it, types18);
3930
3930
  checkKeywordTypes(it, it.dataTypes);
3931
3931
  }
3932
- function checkContextTypes(it, types19) {
3933
- if (!types19.length)
3932
+ function checkContextTypes(it, types18) {
3933
+ if (!types18.length)
3934
3934
  return;
3935
3935
  if (!it.dataTypes.length) {
3936
- it.dataTypes = types19;
3936
+ it.dataTypes = types18;
3937
3937
  return;
3938
3938
  }
3939
- types19.forEach((t) => {
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, types19);
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
- class BackgroundManager {
43602
- tasks;
43603
- notifications;
43604
- client;
43605
- directory;
43606
- pollingInterval;
43607
- constructor(ctx) {
43608
- this.tasks = new Map;
43609
- this.notifications = new Map;
43610
- this.client = ctx.client;
43611
- this.directory = ctx.directory;
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 launch(input) {
43614
- if (!input.agent || input.agent.trim() === "") {
43615
- throw new Error("Agent parameter is required");
43795
+ async add(input) {
43796
+ if (!this.config.enabled) {
43797
+ throw new Error("Letta is not enabled");
43616
43798
  }
43617
- const createResult = await this.client.session.create({
43618
- body: {
43619
- parentID: input.parentSessionID,
43620
- title: `Background: ${input.description}`
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
- if (createResult.error) {
43624
- throw new Error(`Failed to create background session: ${createResult.error}`);
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 sessionID = createResult.data.id;
43627
- subagentSessions.add(sessionID);
43628
- const task = {
43629
- id: `bg_${crypto.randomUUID().slice(0, 8)}`,
43630
- sessionID,
43631
- parentSessionID: input.parentSessionID,
43632
- parentMessageID: input.parentMessageID,
43633
- description: input.description,
43634
- prompt: input.prompt,
43635
- agent: input.agent,
43636
- status: "running",
43637
- startedAt: new Date,
43638
- progress: {
43639
- toolCalls: 0,
43640
- lastUpdate: new Date
43641
- },
43642
- parentModel: input.parentModel
43643
- };
43644
- this.tasks.set(task.id, task);
43645
- this.startPolling();
43646
- log("[background-agent] Launching task:", { taskId: task.id, sessionID, agent: input.agent });
43647
- this.client.session.promptAsync({
43648
- path: { id: sessionID },
43649
- body: {
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
- }).catch((error45) => {
43658
- log("[background-agent] promptAsync error:", error45);
43659
- const existingTask = this.findBySession(sessionID);
43660
- if (existingTask) {
43661
- existingTask.status = "error";
43662
- const errorMessage = error45 instanceof Error ? error45.message : String(error45);
43663
- if (errorMessage.includes("agent.name") || errorMessage.includes("undefined")) {
43664
- existingTask.error = `Agent "${input.agent}" not found. Make sure the agent is registered in your opencode.json or provided by a plugin.`;
43665
- } else {
43666
- existingTask.error = errorMessage;
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
- existingTask.completedAt = new Date;
43669
- this.markForNotification(existingTask);
43670
- this.notifyParentSession(existingTask);
43862
+ } catch {
43863
+ continue;
43671
43864
  }
43672
- });
43673
- return task;
43865
+ }
43866
+ return null;
43674
43867
  }
43675
- getTask(id) {
43676
- return this.tasks.get(id);
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
- getTasksByParentSession(sessionID) {
43679
- const result = [];
43680
- for (const task of this.tasks.values()) {
43681
- if (task.parentSessionID === sessionID) {
43682
- result.push(task);
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
- return result;
43901
+ throw new Error(`Memory not found: ${id}`);
43686
43902
  }
43687
- getAllDescendantTasks(sessionID) {
43688
- const result = [];
43689
- const directChildren = this.getTasksByParentSession(sessionID);
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
- return result;
43696
- }
43697
- findBySession(sessionID) {
43698
- for (const task of this.tasks.values()) {
43699
- if (task.sessionID === sessionID) {
43700
- return task;
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 checkSessionTodos(sessionID) {
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.client.session.todo({
43708
- path: { id: sessionID }
43947
+ const response2 = await fetch(`${this.endpoint}/v1/health`, {
43948
+ method: "GET",
43949
+ signal: AbortSignal.timeout(5000)
43709
43950
  });
43710
- const todos = response2.data ?? response2;
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
- handleEvent(event) {
43720
- const props = event.properties;
43721
- if (event.type === "message.part.updated") {
43722
- if (!props || typeof props !== "object" || !("sessionID" in props))
43723
- return;
43724
- const partInfo = props;
43725
- const sessionID = partInfo?.sessionID;
43726
- if (!sessionID)
43727
- return;
43728
- const task = this.findBySession(sessionID);
43729
- if (!task)
43730
- return;
43731
- if (partInfo?.type === "tool" || partInfo?.tool) {
43732
- if (!task.progress) {
43733
- task.progress = {
43734
- toolCalls: 0,
43735
- lastUpdate: new Date
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
- task.status = "completed";
43756
- task.completedAt = new Date;
43757
- this.markForNotification(task);
43758
- this.notifyParentSession(task);
43759
- log("[background-agent] Task completed via session.idle event:", task.id);
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
- if (event.type === "session.deleted") {
43763
- const info = props?.info;
43764
- if (!info || typeof info.id !== "string")
43765
- return;
43766
- const sessionID = info.id;
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
- markForNotification(task) {
43781
- const queue = this.notifications.get(task.parentSessionID) ?? [];
43782
- queue.push(task);
43783
- this.notifications.set(task.parentSessionID, queue);
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
- getPendingNotifications(sessionID) {
43786
- return this.notifications.get(sessionID) ?? [];
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
- clearNotifications(sessionID) {
43789
- this.notifications.delete(sessionID);
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
- clearNotificationsForTask(taskId) {
43792
- for (const [sessionID, tasks] of this.notifications.entries()) {
43793
- const filtered = tasks.filter((t) => t.id !== taskId);
43794
- if (filtered.length === 0) {
43795
- this.notifications.delete(sessionID);
43796
- } else {
43797
- this.notifications.set(sessionID, filtered);
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
- startPolling() {
43802
- if (this.pollingInterval)
43803
- return;
43804
- this.pollingInterval = setInterval(() => {
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
- stopPolling() {
43810
- if (this.pollingInterval) {
43811
- clearInterval(this.pollingInterval);
43812
- this.pollingInterval = undefined;
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
- cleanup() {
43816
- this.stopPolling();
43817
- this.tasks.clear();
43818
- this.notifications.clear();
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
- notifyParentSession(task) {
43821
- const duration3 = this.formatDuration(task.startedAt, task.completedAt);
43822
- log("[background-agent] notifyParentSession called for task:", task.id);
43823
- const tuiClient = this.client;
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 message = `[BACKGROUND TASK COMPLETED] Task "${task.description}" finished in ${duration3}. Use background_output with task_id="${task.id}" to get results.`;
43835
- log("[background-agent] Sending notification to parent session:", { parentSessionID: task.parentSessionID });
43836
- const taskId = task.id;
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 messageDir = getMessageDir11(task.parentSessionID);
43840
- const prevMessage = messageDir ? findNearestMessageWithFields(messageDir) : null;
43841
- const modelContext = task.parentModel ?? prevMessage?.model;
43842
- const modelField = modelContext?.providerID && modelContext?.modelID ? { providerID: modelContext.providerID, modelID: modelContext.modelID } : undefined;
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
- log("[background-agent] Successfully sent prompt to parent session:", { parentSessionID: task.parentSessionID });
43853
- } catch (error45) {
43854
- log("[background-agent] prompt failed:", String(error45));
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
- }, 200);
43861
- }
43862
- formatDuration(start, end) {
43863
- const duration3 = (end ?? new Date).getTime() - start.getTime();
43864
- const seconds = Math.floor(duration3 / 1000);
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 `${seconds}s`;
44119
+ return merged.slice(0, limit);
43873
44120
  }
43874
- hasRunningTasks() {
43875
- for (const task of this.tasks.values()) {
43876
- if (task.status === "running")
43877
- return true;
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
- return false;
43880
- }
43881
- pruneStaleTasksAndNotifications() {
43882
- const now = Date.now();
43883
- for (const [taskId, task] of this.tasks.entries()) {
43884
- const age = now - task.startedAt.getTime();
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
- for (const [sessionID, notifications] of this.notifications.entries()) {
43896
- if (notifications.length === 0) {
43897
- this.notifications.delete(sessionID);
43898
- continue;
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
- const validNotifications = notifications.filter((task) => {
43901
- const age = now - task.startedAt.getTime();
43902
- return age <= TASK_TTL_MS;
43903
- });
43904
- if (validNotifications.length === 0) {
43905
- this.notifications.delete(sessionID);
43906
- } else if (validNotifications.length !== notifications.length) {
43907
- this.notifications.set(sessionID, validNotifications);
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
- async pollRunningTasks() {
43912
- this.pruneStaleTasksAndNotifications();
43913
- const statusResult = await this.client.session.status();
43914
- const allStatuses = statusResult.data ?? {};
43915
- for (const task of this.tasks.values()) {
43916
- if (task.status !== "running")
43917
- continue;
43918
- try {
43919
- const sessionStatus = allStatuses[task.sessionID];
43920
- if (!sessionStatus) {
43921
- log("[background-agent] Session not found in status:", task.sessionID);
43922
- continue;
43923
- }
43924
- if (sessionStatus.type === "idle") {
43925
- const hasIncompleteTodos2 = await this.checkSessionTodos(task.sessionID);
43926
- if (hasIncompleteTodos2) {
43927
- log("[background-agent] Task has incomplete todos via polling, waiting:", task.id);
43928
- continue;
43929
- }
43930
- task.status = "completed";
43931
- task.completedAt = new Date;
43932
- this.markForNotification(task);
43933
- this.notifyParentSession(task);
43934
- log("[background-agent] Task completed via polling:", task.id);
43935
- continue;
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
- const messagesResult = await this.client.session.messages({
43938
- path: { id: task.sessionID }
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 (!messagesResult.error && messagesResult.data) {
43941
- const messages = messagesResult.data;
43942
- const assistantMsgs = messages.filter((m) => m.info?.role === "assistant");
43943
- let toolCalls = 0;
43944
- let lastTool;
43945
- let lastMessage;
43946
- for (const msg of assistantMsgs) {
43947
- const parts = msg.parts ?? [];
43948
- for (const part of parts) {
43949
- if (part.type === "tool_use" || part.tool) {
43950
- toolCalls++;
43951
- lastTool = part.tool || part.name || "unknown";
43952
- }
43953
- if (part.type === "text" && part.text) {
43954
- lastMessage = part.text;
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
- if (!task.progress) {
43959
- task.progress = { toolCalls: 0, lastUpdate: new Date };
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
- task.progress.toolCalls = toolCalls;
43962
- task.progress.lastTool = lastTool;
43963
- task.progress.lastUpdate = new Date;
43964
- if (lastMessage) {
43965
- task.progress.lastMessage = lastMessage;
43966
- task.progress.lastMessageAt = new Date;
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
- if (!this.hasRunningTasks()) {
43974
- this.stopPolling();
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
- isToolTask(toolName) {
46256
- if (!this._serverCapabilities?.tasks?.requests?.tools?.call) {
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
- isToolTaskRequired(toolName) {
46262
- return this._cachedRequiredTaskTools.has(toolName);
46263
- }
46264
- cacheToolMetadata(tools4) {
46265
- this._cachedToolOutputValidators.clear();
46266
- this._cachedKnownTaskTools.clear();
46267
- this._cachedRequiredTaskTools.clear();
46268
- for (const tool3 of tools4) {
46269
- if (tool3.outputSchema) {
46270
- const toolValidator = this._jsonSchemaValidator.getValidator(tool3.outputSchema);
46271
- this._cachedToolOutputValidators.set(tool3.name, toolValidator);
46272
- }
46273
- const taskSupport = tool3.execution?.taskSupport;
46274
- if (taskSupport === "required" || taskSupport === "optional") {
46275
- this._cachedKnownTaskTools.add(tool3.name);
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
- if (taskSupport === "required") {
46278
- this._cachedRequiredTaskTools.add(tool3.name);
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
- getToolOutputValidator(toolName) {
46283
- return this._cachedToolOutputValidators.get(toolName);
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
- async listTools(params, options) {
46286
- const result = await this.request({ method: "tools/list", params }, ListToolsResultSchema, options);
46287
- this.cacheToolMetadata(result.tools);
46288
- return result;
49245
+ getPendingNotifications(sessionID) {
49246
+ return this.notifications.get(sessionID) ?? [];
46289
49247
  }
46290
- _setupListChangedHandler(listType, notificationSchema, options, fetcher) {
46291
- const parseResult = ListChangedOptionsBaseSchema.safeParse(options);
46292
- if (!parseResult.success) {
46293
- throw new Error(`Invalid ${listType} listChanged options: ${parseResult.error.message}`);
46294
- }
46295
- if (typeof options.onChanged !== "function") {
46296
- throw new Error(`Invalid ${listType} listChanged options: onChanged must be a function`);
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
- refresh();
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
- // node_modules/@modelcontextprotocol/sdk/dist/esm/client/stdio.js
46333
- var import_cross_spawn = __toESM(require_cross_spawn(), 1);
46334
- import process2 from "process";
46335
- import { PassThrough } from "stream";
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
- readMessage() {
46343
- if (!this._buffer) {
46344
- return null;
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
- clear() {
46356
- this._buffer = undefined;
49275
+ cleanup() {
49276
+ this.stopPolling();
49277
+ this.tasks.clear();
49278
+ this.notifications.clear();
46357
49279
  }
46358
- }
46359
- function deserializeMessage(line) {
46360
- return JSONRPCMessageSchema.parse(JSON.parse(line));
46361
- }
46362
- function serializeMessage(message) {
46363
- return JSON.stringify(message) + `
46364
- `;
46365
- }
46366
-
46367
- // node_modules/@modelcontextprotocol/sdk/dist/esm/client/stdio.js
46368
- var DEFAULT_INHERITED_ENV_VARS = process2.platform === "win32" ? [
46369
- "APPDATA",
46370
- "HOMEDRIVE",
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
- if (value.startsWith("()")) {
46390
- continue;
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
- env[key] = value;
49332
+ return `${seconds}s`;
46393
49333
  }
46394
- return env;
46395
- }
46396
-
46397
- class StdioClientTransport {
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
- async start() {
46407
- if (this._process) {
46408
- throw new Error("StdioClientTransport already started! If using Client class, note that connect() calls start() automatically.");
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
- return new Promise((resolve8, reject) => {
46411
- this._process = import_cross_spawn.default(this._serverParams.command, this._serverParams.args ?? [], {
46412
- env: {
46413
- ...getDefaultEnvironment(),
46414
- ...this._serverParams.env
46415
- },
46416
- stdio: ["pipe", "pipe", this._serverParams.stderr ?? "inherit"],
46417
- shell: false,
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 (this._stderrStream && this._process.stderr) {
46443
- this._process.stderr.pipe(this._stderrStream);
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
- processReadBuffer() {
46457
- while (true) {
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 message = this._readBuffer.readMessage();
46460
- if (message === null) {
46461
- break;
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
- this.onmessage?.(message);
46464
- } catch (error45) {
46465
- this.onerror?.(error45);
46466
- }
46467
- }
46468
- }
46469
- async close() {
46470
- if (this._process) {
46471
- const processToClose = this._process;
46472
- this._process = undefined;
46473
- const closePromise = new Promise((resolve8) => {
46474
- processToClose.once("close", () => {
46475
- resolve8();
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
- try {
46479
- processToClose.stdin?.end();
46480
- } catch {}
46481
- await Promise.race([closePromise, new Promise((resolve8) => setTimeout(resolve8, 2000).unref())]);
46482
- if (processToClose.exitCode === null) {
46483
- try {
46484
- processToClose.kill("SIGTERM");
46485
- } catch {}
46486
- await Promise.race([closePromise, new Promise((resolve8) => setTimeout(resolve8, 2000).unref())]);
46487
- }
46488
- if (processToClose.exitCode === null) {
46489
- try {
46490
- processToClose.kill("SIGKILL");
46491
- } catch {}
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._readBuffer.clear();
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
- searchTool: exports_external.string(),
47064
- getTool: exports_external.string().optional(),
47065
- config: exports_external.record(exports_external.string(), exports_external.unknown()).optional()
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 memoryTools = mem0Adapter ? createMemoryTools(mem0Adapter) : {};
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") && mem0Adapter && pluginConfig.mem0?.autoRehydrate !== false ? createMemoryRehydrationHook(mem0Adapter, {
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,