la-machina-engine 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -127,34 +127,34 @@ var init_fetchData = __esm({
127
127
  });
128
128
 
129
129
  // src/orchestrator/types.ts
130
- var import_zod26, PlanStepSchema, PlanSchema;
130
+ var import_zod28, PlanStepSchema, PlanSchema;
131
131
  var init_types = __esm({
132
132
  "src/orchestrator/types.ts"() {
133
133
  "use strict";
134
134
  init_cjs_shims();
135
- import_zod26 = require("zod");
136
- PlanStepSchema = import_zod26.z.object({
137
- id: import_zod26.z.string().min(1),
138
- description: import_zod26.z.string().min(1),
139
- action: import_zod26.z.enum(["research", "implement", "verify", "review", "custom"]),
140
- files: import_zod26.z.array(import_zod26.z.string()).optional(),
141
- spec: import_zod26.z.string().optional(),
142
- dependsOn: import_zod26.z.array(import_zod26.z.string()).optional()
135
+ import_zod28 = require("zod");
136
+ PlanStepSchema = import_zod28.z.object({
137
+ id: import_zod28.z.string().min(1),
138
+ description: import_zod28.z.string().min(1),
139
+ action: import_zod28.z.enum(["research", "implement", "verify", "review", "custom"]),
140
+ files: import_zod28.z.array(import_zod28.z.string()).optional(),
141
+ spec: import_zod28.z.string().optional(),
142
+ dependsOn: import_zod28.z.array(import_zod28.z.string()).optional()
143
143
  });
144
- PlanSchema = import_zod26.z.object({
145
- summary: import_zod26.z.string().min(1),
146
- steps: import_zod26.z.array(PlanStepSchema).min(1)
144
+ PlanSchema = import_zod28.z.object({
145
+ summary: import_zod28.z.string().min(1),
146
+ steps: import_zod28.z.array(PlanStepSchema).min(1)
147
147
  });
148
148
  }
149
149
  });
150
150
 
151
151
  // src/orchestrator/planParser.ts
152
152
  function parsePlan(raw, maxSteps) {
153
- const json = extractJson(raw);
154
- if (json === null) return null;
153
+ const json2 = extractJson(raw);
154
+ if (json2 === null) return null;
155
155
  let parsed;
156
156
  try {
157
- parsed = JSON.parse(json);
157
+ parsed = JSON.parse(json2);
158
158
  } catch {
159
159
  return null;
160
160
  }
@@ -164,23 +164,23 @@ function parsePlan(raw, maxSteps) {
164
164
  if (plan.steps.length > maxSteps) return null;
165
165
  return plan;
166
166
  }
167
- function extractJson(text) {
168
- const fenceMatch = text.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);
167
+ function extractJson(text2) {
168
+ const fenceMatch = text2.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);
169
169
  if (fenceMatch?.[1]) {
170
170
  const inner = fenceMatch[1].trim();
171
171
  if (inner.startsWith("{")) return inner;
172
172
  }
173
173
  let start = -1;
174
174
  let depth = 0;
175
- for (let i = 0; i < text.length; i++) {
176
- const c = text[i];
175
+ for (let i = 0; i < text2.length; i++) {
176
+ const c = text2[i];
177
177
  if (c === "{") {
178
178
  if (depth === 0) start = i;
179
179
  depth++;
180
180
  } else if (c === "}") {
181
181
  depth--;
182
182
  if (depth === 0 && start !== -1) {
183
- return text.slice(start, i + 1);
183
+ return text2.slice(start, i + 1);
184
184
  }
185
185
  }
186
186
  }
@@ -869,6 +869,7 @@ __export(index_exports, {
869
869
  WebhookDispatcher: () => WebhookDispatcher,
870
870
  adaptMcpTool: () => adaptMcpTool,
871
871
  buildForkedMessages: () => buildForkedMessages,
872
+ buildKnowledgeIndex: () => buildKnowledgeIndex,
872
873
  buildPermissionPolicy: () => buildPermissionPolicy,
873
874
  buildSchemaPrompt: () => buildSchemaPrompt,
874
875
  buildSystemPrompt: () => buildSystemPrompt,
@@ -879,6 +880,8 @@ __export(index_exports, {
879
880
  createFetchDataTool: () => createFetchDataTool,
880
881
  createLogger: () => createLogger,
881
882
  createModelAdapter: () => createModelAdapter,
883
+ createReadKnowledgeTool: () => createReadKnowledgeTool,
884
+ createSearchKnowledgeTool: () => createSearchKnowledgeTool,
882
885
  createSendMessageTool: () => createSendMessageTool,
883
886
  createSkillPageTool: () => createSkillPageTool,
884
887
  createSmartMemory: () => createSmartMemory,
@@ -888,6 +891,7 @@ __export(index_exports, {
888
891
  detectRuntime: () => detectRuntime,
889
892
  getCoordinatorBasePrompt: () => getCoordinatorBasePrompt,
890
893
  getCoordinatorSystemPrompt: () => getCoordinatorSystemPrompt,
894
+ getExtractor: () => getExtractor,
891
895
  hasProcessLifecycle: () => hasProcessLifecycle,
892
896
  initEngine: () => initEngine,
893
897
  isCoordinatorMode: () => isCoordinatorMode,
@@ -910,7 +914,8 @@ __export(index_exports, {
910
914
  toResponse: () => toResponse,
911
915
  tryParseJSON: () => tryParseJSON2,
912
916
  validateOutput: () => validateOutput,
913
- withCapabilityCheck: () => withCapabilityCheck
917
+ withCapabilityCheck: () => withCapabilityCheck,
918
+ writeKnowledgeIndex: () => writeKnowledgeIndex
914
919
  });
915
920
  module.exports = __toCommonJS(index_exports);
916
921
  init_cjs_shims();
@@ -1243,6 +1248,11 @@ var ApiConfigResolved = import_zod.z.object({
1243
1248
  services: import_zod.z.array(ApiServiceSchema),
1244
1249
  maxResponseBytes: import_zod.z.number().int().positive().optional()
1245
1250
  }).strict();
1251
+ var KnowledgeConfigResolved = import_zod.z.object({
1252
+ enabled: import_zod.z.boolean(),
1253
+ maxSearchResults: import_zod.z.number().int().positive(),
1254
+ maxReadBytes: import_zod.z.number().int().positive()
1255
+ }).strict();
1246
1256
  var RunnerConfigResolved = import_zod.z.object({
1247
1257
  url: import_zod.z.string().url(),
1248
1258
  secret: import_zod.z.string().min(1, "runner.secret cannot be empty")
@@ -1264,7 +1274,8 @@ var ResolvedConfigSchema = import_zod.z.object({
1264
1274
  coordinator: CoordinatorConfigResolved,
1265
1275
  orchestrator: OrchestratorConfigResolved,
1266
1276
  runner: RunnerConfigResolved.optional(),
1267
- api: ApiConfigResolved.optional()
1277
+ api: ApiConfigResolved.optional(),
1278
+ knowledge: KnowledgeConfigResolved.optional()
1268
1279
  }).strict();
1269
1280
  var R2ConfigUser = R2ConfigResolved.partial();
1270
1281
  var ModelConfigUser = ModelConfigResolved.partial();
@@ -1275,6 +1286,7 @@ var StorageConfigUser = import_zod.z.object({
1275
1286
  r2: R2ConfigUser.optional(),
1276
1287
  r2Binding: R2BucketBindingShape.optional()
1277
1288
  }).strict();
1289
+ var KnowledgeConfigUser = KnowledgeConfigResolved.partial();
1278
1290
  var MemoryConfigUser = import_zod.z.object({
1279
1291
  mode: MemoryModeEnum.optional(),
1280
1292
  scope: MemoryScopeUserEnum.optional()
@@ -1339,7 +1351,8 @@ var UserConfigSchema = import_zod.z.object({
1339
1351
  coordinator: CoordinatorConfigUser.optional(),
1340
1352
  orchestrator: OrchestratorConfigUser.optional(),
1341
1353
  runner: RunnerConfigUser.optional(),
1342
- api: ApiConfigUser.optional()
1354
+ api: ApiConfigUser.optional(),
1355
+ knowledge: KnowledgeConfigUser.optional()
1343
1356
  }).strict();
1344
1357
 
1345
1358
  // src/config/merge.ts
@@ -1431,9 +1444,21 @@ function splitOffloadRuntime(user) {
1431
1444
  };
1432
1445
  return { stripped: clone, summarizer };
1433
1446
  }
1447
+ var KNOWLEDGE_DEFAULTS = { maxSearchResults: 5, maxReadBytes: 1e4 };
1448
+ function fillKnowledgeDefaults(user) {
1449
+ const block = user.knowledge;
1450
+ if (block === void 0) return user;
1451
+ const filled = {
1452
+ enabled: block.enabled ?? false,
1453
+ maxSearchResults: block.maxSearchResults ?? KNOWLEDGE_DEFAULTS.maxSearchResults,
1454
+ maxReadBytes: block.maxReadBytes ?? KNOWLEDGE_DEFAULTS.maxReadBytes
1455
+ };
1456
+ return { ...user, knowledge: filled };
1457
+ }
1434
1458
  function mergeConfig(user) {
1435
1459
  const withCoercedScope = coerceDeprecatedMemoryScope(user);
1436
- const { stripped: afterOffload, summarizer } = splitOffloadRuntime(withCoercedScope);
1460
+ const withKnowledge = fillKnowledgeDefaults(withCoercedScope);
1461
+ const { stripped: afterOffload, summarizer } = splitOffloadRuntime(withKnowledge);
1437
1462
  const { stripped, runtime } = splitApiRuntime(afterOffload);
1438
1463
  const validatedUser = UserConfigSchema.parse(stripped);
1439
1464
  const merged = deepMerge(DEFAULTS, validatedUser);
@@ -2429,8 +2454,8 @@ function compactPreview(value) {
2429
2454
  }
2430
2455
  return str;
2431
2456
  }
2432
- function tryParseJSON(text) {
2433
- const trimmed = text.replace(/^\uFEFF/, "").trim();
2457
+ function tryParseJSON(text2) {
2458
+ const trimmed = text2.replace(/^\uFEFF/, "").trim();
2434
2459
  if (trimmed.length === 0) return { ok: false };
2435
2460
  const first = trimmed[0];
2436
2461
  if (first !== "{" && first !== "[" && first !== '"') return { ok: false };
@@ -2514,8 +2539,8 @@ var INTERNAL_BLOCK_PATTERNS = [
2514
2539
  /<git_signature>[\s\S]*?<\/git_signature>/g,
2515
2540
  /<caller>[\s\S]*?<\/caller>/g
2516
2541
  ];
2517
- function stripInternalBlocks(text) {
2518
- let result = text;
2542
+ function stripInternalBlocks(text2) {
2543
+ let result = text2;
2519
2544
  for (const pattern of INTERNAL_BLOCK_PATTERNS) {
2520
2545
  pattern.lastIndex = 0;
2521
2546
  result = result.replace(pattern, "");
@@ -3163,8 +3188,8 @@ async function agentLoop(options) {
3163
3188
  assistantContent.push({ type: "thinking", thinking });
3164
3189
  }
3165
3190
  }
3166
- for (const text of textBlocks) {
3167
- if (text.length > 0) assistantContent.push({ type: "text", text });
3191
+ for (const text2 of textBlocks) {
3192
+ if (text2.length > 0) assistantContent.push({ type: "text", text: text2 });
3168
3193
  }
3169
3194
  for (const tc of toolCalls) {
3170
3195
  assistantContent.push({
@@ -3403,11 +3428,11 @@ function toAnthropicTool(tool) {
3403
3428
  target: "jsonSchema7",
3404
3429
  $refStrategy: "none"
3405
3430
  });
3406
- const { $schema: _schema, ...inputSchema18 } = schema;
3431
+ const { $schema: _schema, ...inputSchema20 } = schema;
3407
3432
  return {
3408
3433
  name: tool.name,
3409
3434
  description: tool.description,
3410
- input_schema: inputSchema18
3435
+ input_schema: inputSchema20
3411
3436
  };
3412
3437
  }
3413
3438
  function partitionToolCalls(calls, registry) {
@@ -3542,8 +3567,8 @@ var RunContext = class {
3542
3567
  this.episodes = options.episodes ?? null;
3543
3568
  }
3544
3569
  // ---------- message mutators ----------
3545
- async addUserMessage(text) {
3546
- const content = [{ type: "text", text }];
3570
+ async addUserMessage(text2) {
3571
+ const content = [{ type: "text", text: text2 }];
3547
3572
  this.messages.push({ role: "user", content });
3548
3573
  await this.writeEntry({
3549
3574
  type: "user",
@@ -3552,7 +3577,7 @@ var RunContext = class {
3552
3577
  ts: this.now(),
3553
3578
  message: { role: "user", content }
3554
3579
  });
3555
- this.episodes?.logTurn(this.turnCount, "user", text);
3580
+ this.episodes?.logTurn(this.turnCount, "user", text2);
3556
3581
  }
3557
3582
  async addAssistantMessage(content) {
3558
3583
  this.messages.push({ role: "assistant", content });
@@ -5405,8 +5430,8 @@ Make a new WebFetch request with the redirect URL if you want to follow it.`,
5405
5430
  isError: true
5406
5431
  };
5407
5432
  }
5408
- const text = isHtml(contentType) ? htmlToText(raw) : raw;
5409
- const { content, truncated } = truncate(text, MAX_OUTPUT_BYTES2);
5433
+ const text2 = isHtml(contentType) ? htmlToText(raw) : raw;
5434
+ const { content, truncated } = truncate(text2, MAX_OUTPUT_BYTES2);
5410
5435
  return {
5411
5436
  content,
5412
5437
  metadata: {
@@ -5422,24 +5447,24 @@ Make a new WebFetch request with the redirect URL if you want to follow it.`,
5422
5447
  function isHtml(contentType) {
5423
5448
  return contentType.toLowerCase().includes("html");
5424
5449
  }
5425
- function htmlToText(html) {
5426
- return html.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, "").replace(/<[^>]+>/g, " ").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/[ \t]+/g, " ").replace(/\n[ \t]+/g, "\n").replace(/\n{3,}/g, "\n\n").trim();
5450
+ function htmlToText(html2) {
5451
+ return html2.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, "").replace(/<[^>]+>/g, " ").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/[ \t]+/g, " ").replace(/\n[ \t]+/g, "\n").replace(/\n{3,}/g, "\n\n").trim();
5427
5452
  }
5428
- function truncate(text, maxBytes) {
5429
- if (Buffer.byteLength(text, "utf8") <= maxBytes) {
5430
- return { content: text, truncated: false };
5453
+ function truncate(text2, maxBytes) {
5454
+ if (Buffer.byteLength(text2, "utf8") <= maxBytes) {
5455
+ return { content: text2, truncated: false };
5431
5456
  }
5432
5457
  let lo = 0;
5433
- let hi = text.length;
5458
+ let hi = text2.length;
5434
5459
  while (lo < hi) {
5435
5460
  const mid = lo + hi + 1 >>> 1;
5436
- if (Buffer.byteLength(text.slice(0, mid), "utf8") <= maxBytes) {
5461
+ if (Buffer.byteLength(text2.slice(0, mid), "utf8") <= maxBytes) {
5437
5462
  lo = mid;
5438
5463
  } else {
5439
5464
  hi = mid - 1;
5440
5465
  }
5441
5466
  }
5442
- return { content: text.slice(0, lo) + "\n... (truncated)", truncated: true };
5467
+ return { content: text2.slice(0, lo) + "\n... (truncated)", truncated: true };
5443
5468
  }
5444
5469
  async function safeText(response) {
5445
5470
  try {
@@ -5503,17 +5528,17 @@ function createWebSearchTool() {
5503
5528
  isError: true
5504
5529
  };
5505
5530
  }
5506
- let html;
5531
+ let html2;
5507
5532
  try {
5508
- html = await response.text();
5533
+ html2 = await response.text();
5509
5534
  } catch (err) {
5510
5535
  return {
5511
5536
  content: `Failed to read search response: ${err.message}`,
5512
5537
  isError: true
5513
5538
  };
5514
5539
  }
5515
- const text = htmlToText2(html);
5516
- const trimmed = text.slice(0, 8e3);
5540
+ const text2 = htmlToText2(html2);
5541
+ const trimmed = text2.slice(0, 8e3);
5517
5542
  return {
5518
5543
  content: `Search results for "${query}":
5519
5544
 
@@ -5523,8 +5548,8 @@ ${trimmed}`,
5523
5548
  }
5524
5549
  });
5525
5550
  }
5526
- function htmlToText2(html) {
5527
- return html.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, "").replace(/<[^>]+>/g, " ").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/[ \t]+/g, " ").replace(/\n[ \t]+/g, "\n").replace(/\n{3,}/g, "\n\n").trim();
5551
+ function htmlToText2(html2) {
5552
+ return html2.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, "").replace(/<[^>]+>/g, " ").replace(/&nbsp;/g, " ").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/[ \t]+/g, " ").replace(/\n[ \t]+/g, "\n").replace(/\n{3,}/g, "\n\n").trim();
5528
5553
  }
5529
5554
 
5530
5555
  // src/tools/sleep.ts
@@ -5632,7 +5657,7 @@ function createMemorizeTool(memory) {
5632
5657
  name: "Memorize",
5633
5658
  description: 'Save a fact, rule, or lesson to persistent memory. Memories survive across runs and are included in the system prompt of future runs. Use "rule" for behavioral constraints (always/never do X). Use "lesson" for learnings and observations.',
5634
5659
  inputSchema: inputSchema14,
5635
- execute: async ({ text, kind, topic }) => {
5660
+ execute: async ({ text: text2, kind, topic }) => {
5636
5661
  if (memory.mode === "off" || memory.mode === "read-only") {
5637
5662
  return {
5638
5663
  content: `Cannot memorize: memory mode is "${memory.mode}". Set config.memory.mode to "read-write" to enable.`,
@@ -5640,15 +5665,15 @@ function createMemorizeTool(memory) {
5640
5665
  };
5641
5666
  }
5642
5667
  if (kind === "rule") {
5643
- await memory.encodeRule(text, "always");
5668
+ await memory.encodeRule(text2, "always");
5644
5669
  return {
5645
- content: `Memorized rule: "${text.slice(0, 80)}${text.length > 80 ? "\u2026" : ""}"`,
5670
+ content: `Memorized rule: "${text2.slice(0, 80)}${text2.length > 80 ? "\u2026" : ""}"`,
5646
5671
  metadata: { kind: "rule" }
5647
5672
  };
5648
5673
  }
5649
- await memory.encodeLesson(text, topic);
5674
+ await memory.encodeLesson(text2, topic);
5650
5675
  return {
5651
- content: `Memorized lesson: "${text.slice(0, 80)}${text.length > 80 ? "\u2026" : ""}"${topic ? ` (topic: ${topic})` : ""}`,
5676
+ content: `Memorized lesson: "${text2.slice(0, 80)}${text2.length > 80 ? "\u2026" : ""}"${topic ? ` (topic: ${topic})` : ""}`,
5652
5677
  metadata: { kind: "lesson", topic }
5653
5678
  };
5654
5679
  }
@@ -6325,17 +6350,17 @@ var BindingHttpTransport = class {
6325
6350
  }
6326
6351
  if (response.status === 202 || response.status === 204) return;
6327
6352
  if (!response.ok) {
6328
- const text = await safeText2(response);
6353
+ const text2 = await safeText2(response);
6329
6354
  const err = new Error(
6330
- `BindingHttpTransport: HTTP ${String(response.status)} ${response.statusText}${text ? ` \u2014 ${text}` : ""}`
6355
+ `BindingHttpTransport: HTTP ${String(response.status)} ${response.statusText}${text2 ? ` \u2014 ${text2}` : ""}`
6331
6356
  );
6332
6357
  this.onerror?.(err);
6333
6358
  throw err;
6334
6359
  }
6335
6360
  const contentType = response.headers.get("Content-Type") ?? "";
6336
6361
  if (!contentType.includes("application/json")) {
6337
- const text = await response.text();
6338
- const parsed2 = parseSseFrames(text);
6362
+ const text2 = await response.text();
6363
+ const parsed2 = parseSseFrames(text2);
6339
6364
  for (const msg of parsed2) this.onmessage?.(msg);
6340
6365
  return;
6341
6366
  }
@@ -6402,9 +6427,9 @@ async function safeText2(r) {
6402
6427
  return "";
6403
6428
  }
6404
6429
  }
6405
- function parseSseFrames(text) {
6430
+ function parseSseFrames(text2) {
6406
6431
  const out = [];
6407
- for (const block of text.split(/\r?\n\r?\n/)) {
6432
+ for (const block of text2.split(/\r?\n\r?\n/)) {
6408
6433
  const lines = block.split(/\r?\n/).filter((l) => l.startsWith("data:"));
6409
6434
  if (lines.length === 0) continue;
6410
6435
  const raw = lines.map((l) => l.slice(5).trimStart()).join("\n");
@@ -6691,8 +6716,8 @@ function normalizeToolList(response, serverName) {
6691
6716
  const name = typeof obj.name === "string" ? obj.name : null;
6692
6717
  if (name === null) continue;
6693
6718
  const description = typeof obj.description === "string" ? obj.description : "";
6694
- const inputSchema18 = obj.inputSchema !== null && typeof obj.inputSchema === "object" && !Array.isArray(obj.inputSchema) ? obj.inputSchema : { type: "object", properties: {} };
6695
- out.push({ name, description, inputSchema: inputSchema18 });
6719
+ const inputSchema20 = obj.inputSchema !== null && typeof obj.inputSchema === "object" && !Array.isArray(obj.inputSchema) ? obj.inputSchema : { type: "object", properties: {} };
6720
+ out.push({ name, description, inputSchema: inputSchema20 });
6696
6721
  }
6697
6722
  return out;
6698
6723
  }
@@ -7343,15 +7368,15 @@ var Hippocampus = class _Hippocampus {
7343
7368
  return (content ?? "").trim();
7344
7369
  }
7345
7370
  // ---------- encode (write) ----------
7346
- async encodeRule(text, kind, confidence = "medium", source = "llm") {
7371
+ async encodeRule(text2, kind, confidence = "medium", source = "llm") {
7347
7372
  const ts = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
7348
7373
  const metadata = `<!-- confidence:${confidence} source:${source} ts:${ts} -->`;
7349
- const entry = `- ${text} ${metadata}
7374
+ const entry = `- ${text2} ${metadata}
7350
7375
  `;
7351
7376
  const sectionHeader = `## ${kind.charAt(0).toUpperCase()}${kind.slice(1)}`;
7352
7377
  let content = await this.storage.readFile(this.rulesPath);
7353
7378
  if (content === null) content = RULES_SKELETON;
7354
- if (_Hippocampus.extractEntryTexts(content).has(text)) return;
7379
+ if (_Hippocampus.extractEntryTexts(content).has(text2)) return;
7355
7380
  const lines = content.split(/(?<=\n)/);
7356
7381
  const out = [];
7357
7382
  let inserted = false;
@@ -7384,17 +7409,17 @@ ${entry}`);
7384
7409
  }
7385
7410
  await this.storage.writeFile(this.rulesPath, out.join(""));
7386
7411
  }
7387
- async encodeLesson(text, topic = "", source = "llm") {
7412
+ async encodeLesson(text2, topic = "", source = "llm") {
7388
7413
  const ts = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
7389
7414
  const topicTag = topic ? ` topic:${topic}` : "";
7390
7415
  const sourceTag = source !== "llm" ? ` source:${source}` : "";
7391
- const entry = `- ${text} <!--${topicTag}${sourceTag} ts:${ts} -->
7416
+ const entry = `- ${text2} <!--${topicTag}${sourceTag} ts:${ts} -->
7392
7417
  `;
7393
7418
  const existing = await this.storage.readFile(this.lessonsPath);
7394
7419
  if (existing === null) {
7395
7420
  await this.storage.writeFile(this.lessonsPath, `# Lessons
7396
7421
  ${entry}`);
7397
- } else if (!_Hippocampus.extractEntryTexts(existing).has(text)) {
7422
+ } else if (!_Hippocampus.extractEntryTexts(existing).has(text2)) {
7398
7423
  await this.storage.appendFile(this.lessonsPath, entry);
7399
7424
  }
7400
7425
  if (topic) {
@@ -7404,7 +7429,7 @@ ${entry}`);
7404
7429
  if (topicContent === null) {
7405
7430
  await this.storage.writeFile(topicPath, `# ${topic}
7406
7431
  ${entry}`);
7407
- } else if (!_Hippocampus.extractEntryTexts(topicContent).has(text)) {
7432
+ } else if (!_Hippocampus.extractEntryTexts(topicContent).has(text2)) {
7408
7433
  await this.storage.appendFile(topicPath, entry);
7409
7434
  }
7410
7435
  }
@@ -7460,12 +7485,12 @@ ${entries.map((e) => `- ${e}`).join("\n")}
7460
7485
  }
7461
7486
  /** Sanitize a topic name into a safe file slug. */
7462
7487
  static sanitizeSlug(name) {
7463
- let text = name.toLowerCase().trim();
7464
- text = text.replace(/[^a-z0-9\s_-]/g, "");
7465
- text = text.replace(/\s+/g, "-");
7466
- text = text.replace(/-+/g, "-");
7467
- text = text.replace(/^-|-$/g, "");
7468
- return text.length > 0 ? text : "general";
7488
+ let text2 = name.toLowerCase().trim();
7489
+ text2 = text2.replace(/[^a-z0-9\s_-]/g, "");
7490
+ text2 = text2.replace(/\s+/g, "-");
7491
+ text2 = text2.replace(/-+/g, "-");
7492
+ text2 = text2.replace(/^-|-$/g, "");
7493
+ return text2.length > 0 ? text2 : "general";
7469
7494
  }
7470
7495
  };
7471
7496
 
@@ -7497,13 +7522,13 @@ function createSmartMemory(options) {
7497
7522
  if (!readsEnabled) return "";
7498
7523
  return hippocampus.recallTopic(slug);
7499
7524
  },
7500
- async encodeRule(text, kind, confidence, source) {
7525
+ async encodeRule(text2, kind, confidence, source) {
7501
7526
  if (!writesEnabled) return;
7502
- await hippocampus.encodeRule(text, kind, confidence, source);
7527
+ await hippocampus.encodeRule(text2, kind, confidence, source);
7503
7528
  },
7504
- async encodeLesson(text, topic, source) {
7529
+ async encodeLesson(text2, topic, source) {
7505
7530
  if (!writesEnabled) return;
7506
- await hippocampus.encodeLesson(text, topic, source);
7531
+ await hippocampus.encodeLesson(text2, topic, source);
7507
7532
  },
7508
7533
  async rewriteIdentity(entries) {
7509
7534
  if (!writesEnabled) return;
@@ -7869,8 +7894,8 @@ function buildSchemaPrompt(schema) {
7869
7894
  }
7870
7895
  return lines.join("\n");
7871
7896
  }
7872
- function tryParseJSON2(text) {
7873
- const trimmed = text.trim();
7897
+ function tryParseJSON2(text2) {
7898
+ const trimmed = text2.trim();
7874
7899
  try {
7875
7900
  return { ok: true, value: JSON.parse(trimmed) };
7876
7901
  } catch {
@@ -7998,7 +8023,7 @@ function createApiCallTool(opts) {
7998
8023
  }
7999
8024
  const fetchFn = opts.fetch ?? globalThis.fetch.bind(globalThis);
8000
8025
  const maxResponseBytes = opts.maxResponseBytes ?? DEFAULT_MAX_RESPONSE_BYTES;
8001
- const inputSchema18 = import_zod25.z.object({
8026
+ const inputSchema20 = import_zod25.z.object({
8002
8027
  service: import_zod25.z.enum(serviceNames),
8003
8028
  method: import_zod25.z.enum(["GET", "POST", "PUT", "PATCH", "DELETE"]),
8004
8029
  path: import_zod25.z.string().regex(/^\//, "path must start with /"),
@@ -8010,7 +8035,7 @@ function createApiCallTool(opts) {
8010
8035
  return defineTool({
8011
8036
  name: opts.toolName ?? "ApiCall",
8012
8037
  description,
8013
- inputSchema: inputSchema18,
8038
+ inputSchema: inputSchema20,
8014
8039
  execute: async (input) => {
8015
8040
  const svc = services.get(input.service);
8016
8041
  if (!svc) {
@@ -8171,6 +8196,569 @@ async function invokeHook(hook, event) {
8171
8196
  // src/engine/engine.ts
8172
8197
  init_fetchData();
8173
8198
 
8199
+ // src/tools/searchKnowledge.ts
8200
+ init_cjs_shims();
8201
+ var import_zod26 = require("zod");
8202
+ init_contract();
8203
+
8204
+ // src/knowledge/scope.ts
8205
+ init_cjs_shims();
8206
+ var SAFE_PATH_RE = /^[a-zA-Z0-9_\-./]+$/;
8207
+ function parseFolderRef(raw) {
8208
+ if (typeof raw !== "string" || raw.length === 0) {
8209
+ throw new Error(`invalid knowledge folder ref: empty`);
8210
+ }
8211
+ if (raw.startsWith("/")) {
8212
+ throw new Error(`invalid knowledge folder ref: absolute paths not allowed ("${raw}")`);
8213
+ }
8214
+ const trimmed = raw.replace(/\/+$/g, "");
8215
+ if (trimmed.length === 0) {
8216
+ throw new Error(`invalid knowledge folder ref: "${raw}"`);
8217
+ }
8218
+ if (!SAFE_PATH_RE.test(trimmed)) {
8219
+ throw new Error(`invalid knowledge folder ref: unsafe characters in "${raw}"`);
8220
+ }
8221
+ if (trimmed.split("/").some((seg) => seg === ".." || seg === "." || seg === "")) {
8222
+ throw new Error(`invalid knowledge folder ref: traversal in "${raw}"`);
8223
+ }
8224
+ const segs = trimmed.split("/");
8225
+ const base = segs[0];
8226
+ const subPath = segs.slice(1).join("/");
8227
+ return { path: trimmed, base, subPath };
8228
+ }
8229
+ function relPathInScope(folder, relPath) {
8230
+ if (folder.subPath === "") return true;
8231
+ return relPath === folder.subPath || relPath.startsWith(`${folder.subPath}/`);
8232
+ }
8233
+ function parseKnowledgeRef(raw) {
8234
+ if (typeof raw !== "string" || raw.length === 0) {
8235
+ throw new Error("invalid knowledge ref: empty");
8236
+ }
8237
+ if (raw.startsWith("ext:")) {
8238
+ const name = raw.slice("ext:".length);
8239
+ if (!/^[a-zA-Z0-9_-]+$/.test(name) || name.length === 0) {
8240
+ throw new Error(`invalid knowledge ref: external name "${name}" has unsafe characters`);
8241
+ }
8242
+ return { kind: "ext", target: name };
8243
+ }
8244
+ if (raw.startsWith("/")) {
8245
+ throw new Error(`invalid knowledge ref: absolute paths not allowed ("${raw}")`);
8246
+ }
8247
+ const hashAt = raw.indexOf("#");
8248
+ const filePath = hashAt === -1 ? raw : raw.slice(0, hashAt);
8249
+ const section = hashAt === -1 ? void 0 : raw.slice(hashAt + 1);
8250
+ if (!SAFE_PATH_RE.test(filePath)) {
8251
+ throw new Error(`invalid knowledge ref: unsafe characters in "${filePath}"`);
8252
+ }
8253
+ if (filePath.split("/").some((seg) => seg === ".." || seg === "." || seg === "")) {
8254
+ throw new Error(`invalid knowledge ref: traversal in "${filePath}"`);
8255
+ }
8256
+ if (section !== void 0) {
8257
+ if (section.length > 0 && !/^[a-zA-Z0-9_-]+$/.test(section)) {
8258
+ throw new Error(`invalid knowledge ref: unsafe characters in section "${section}"`);
8259
+ }
8260
+ return { kind: "section", target: filePath, section };
8261
+ }
8262
+ return { kind: "file", target: filePath };
8263
+ }
8264
+ function refInScope(folders, filePath) {
8265
+ return folders.some((f) => {
8266
+ if (filePath === f.base || filePath.startsWith(`${f.base}/`)) {
8267
+ const relInBase = filePath === f.base ? "" : filePath.slice(f.base.length + 1);
8268
+ return relPathInScope(f, relInBase);
8269
+ }
8270
+ return false;
8271
+ });
8272
+ }
8273
+
8274
+ // src/knowledge/tokenize.ts
8275
+ init_cjs_shims();
8276
+ var STOP_WORDS = /* @__PURE__ */ new Set([
8277
+ "the",
8278
+ "and",
8279
+ "of",
8280
+ "to",
8281
+ "a",
8282
+ "in",
8283
+ "is",
8284
+ "it",
8285
+ "you",
8286
+ "that",
8287
+ "was",
8288
+ "for",
8289
+ "on",
8290
+ "are",
8291
+ "with",
8292
+ "as",
8293
+ "this",
8294
+ "by",
8295
+ "from",
8296
+ "or",
8297
+ "but",
8298
+ "not",
8299
+ "all",
8300
+ "an",
8301
+ "has",
8302
+ "have",
8303
+ "had",
8304
+ "will",
8305
+ "can",
8306
+ "do",
8307
+ "did",
8308
+ "be",
8309
+ "been",
8310
+ "being",
8311
+ "your",
8312
+ "our",
8313
+ "their",
8314
+ "his",
8315
+ "her",
8316
+ "my",
8317
+ "we",
8318
+ "they",
8319
+ "them",
8320
+ "than",
8321
+ "so",
8322
+ "if",
8323
+ "at",
8324
+ "no",
8325
+ "yes",
8326
+ "me",
8327
+ "us",
8328
+ "i",
8329
+ "he",
8330
+ "she"
8331
+ ]);
8332
+ function tokenize(text2) {
8333
+ if (typeof text2 !== "string" || text2.length === 0) return [];
8334
+ const seen = /* @__PURE__ */ new Set();
8335
+ for (const raw of text2.toLowerCase().split(/[\W_]+/)) {
8336
+ if (raw.length < 2) continue;
8337
+ if (STOP_WORDS.has(raw)) continue;
8338
+ seen.add(raw);
8339
+ }
8340
+ return [...seen].sort();
8341
+ }
8342
+ function scoreOverlap(sectionWords, queryTokens) {
8343
+ const set = sectionWords instanceof Set ? sectionWords : new Set(sectionWords);
8344
+ let n = 0;
8345
+ for (const t of queryTokens) if (set.has(t)) n++;
8346
+ return n;
8347
+ }
8348
+
8349
+ // src/tools/searchKnowledge.ts
8350
+ var DEFAULT_MAX_RESULTS = 5;
8351
+ var inputSchema18 = import_zod26.z.object({
8352
+ query: import_zod26.z.string().min(1),
8353
+ maxResults: import_zod26.z.number().int().positive().optional()
8354
+ });
8355
+ function createSearchKnowledgeTool(opts) {
8356
+ const scoped = opts.folders.map(parseFolderRef);
8357
+ const indexCache = /* @__PURE__ */ new Map();
8358
+ const cap = opts.maxSearchResults ?? DEFAULT_MAX_RESULTS;
8359
+ const externals = opts.external;
8360
+ return defineTool({
8361
+ name: "SearchKnowledge",
8362
+ description: "Search the agent's knowledge base. Returns up to K ranked snippets matching the query (across all configured knowledge folders + any attached external file links). Each result carries a `ref` you can pass back to the `ReadKnowledge` tool to load the full content of that section or file.",
8363
+ inputSchema: inputSchema18,
8364
+ execute: async ({ query, maxResults }) => {
8365
+ const limit = Math.min(maxResults ?? cap, cap);
8366
+ const queryTokens = tokenize(query);
8367
+ if (queryTokens.length === 0) {
8368
+ return { content: "no searchable tokens in query", isError: false };
8369
+ }
8370
+ const sectionHits = [];
8371
+ const seenBases = /* @__PURE__ */ new Set();
8372
+ for (const folder of scoped) {
8373
+ if (!seenBases.has(folder.base)) {
8374
+ seenBases.add(folder.base);
8375
+ }
8376
+ }
8377
+ for (const baseName of seenBases) {
8378
+ const idx = await loadIndex(opts.adapter, baseName, indexCache);
8379
+ if (idx === null) continue;
8380
+ for (const section of idx.sections) {
8381
+ const eligible = scoped.some(
8382
+ (f) => f.base === baseName && relPathInScope(f, section.relPath)
8383
+ );
8384
+ if (!eligible) continue;
8385
+ const score = scoreOverlap(section.words, queryTokens);
8386
+ if (score > 0) sectionHits.push({ section, base: baseName, score });
8387
+ }
8388
+ }
8389
+ const externalHits = [];
8390
+ for (const link of externals) {
8391
+ const score = scoreOverlap(tokenize(link.description), queryTokens);
8392
+ if (score > 0) externalHits.push({ link, score });
8393
+ }
8394
+ const all = [
8395
+ ...sectionHits.map((h) => ({
8396
+ kind: "knowledge",
8397
+ score: h.score,
8398
+ render: () => `[knowledge] ${h.base}/${h.section.relPath} \xA7"${h.section.heading || "(lead-in)"}"
8399
+ ${truncatePreview(h.section.preview)}
8400
+ ref: ${h.base}/${h.section.slug}`
8401
+ })),
8402
+ ...externalHits.map((h) => ({
8403
+ kind: "external",
8404
+ score: h.score,
8405
+ render: () => `[external] ${h.link.name} (${h.link.format})
8406
+ ${h.link.description}
8407
+ ref: ext:${h.link.name}`
8408
+ }))
8409
+ ];
8410
+ if (all.length === 0) {
8411
+ return { content: `no knowledge matches for "${query}"`, isError: false };
8412
+ }
8413
+ all.sort((a, b) => b.score - a.score);
8414
+ const top = all.slice(0, limit);
8415
+ const body = top.map((h, i) => `${i + 1}. ${h.render()}`).join("\n\n");
8416
+ return {
8417
+ content: `Found ${top.length} knowledge match${top.length === 1 ? "" : "es"} (of ${all.length} ranked):
8418
+
8419
+ ${body}`,
8420
+ isError: false,
8421
+ metadata: { hits: all.length, returned: top.length }
8422
+ };
8423
+ }
8424
+ });
8425
+ }
8426
+ function truncatePreview(s) {
8427
+ if (s.length <= 200) return s;
8428
+ return s.slice(0, 200) + "\u2026";
8429
+ }
8430
+ async function loadIndex(adapter, base, cache) {
8431
+ const cached2 = cache.get(base);
8432
+ if (cached2 !== void 0) return cached2;
8433
+ let raw;
8434
+ try {
8435
+ raw = await adapter.readFile(`${base}/_index.json`);
8436
+ } catch {
8437
+ return null;
8438
+ }
8439
+ if (raw === null) return null;
8440
+ try {
8441
+ const parsed = JSON.parse(raw);
8442
+ cache.set(base, parsed);
8443
+ return parsed;
8444
+ } catch {
8445
+ return null;
8446
+ }
8447
+ }
8448
+
8449
+ // src/tools/readKnowledge.ts
8450
+ init_cjs_shims();
8451
+ var import_zod27 = require("zod");
8452
+ init_contract();
8453
+
8454
+ // src/knowledge/extractors.ts
8455
+ init_cjs_shims();
8456
+ var CSV_MAX_ROWS = 100;
8457
+ var HTML_TAG_RE = /<[^>]+>/g;
8458
+ var HTML_ENTITIES = {
8459
+ "&amp;": "&",
8460
+ "&lt;": "<",
8461
+ "&gt;": ">",
8462
+ "&quot;": '"',
8463
+ "&#39;": "'",
8464
+ "&nbsp;": " "
8465
+ };
8466
+ function decodeHtmlEntities(s) {
8467
+ return s.replace(/&(amp|lt|gt|quot|#39|nbsp);/g, (m) => HTML_ENTITIES[m] ?? m);
8468
+ }
8469
+ var text = {
8470
+ format: "txt",
8471
+ requiresNode: false,
8472
+ extract: async (raw) => raw
8473
+ };
8474
+ var md = {
8475
+ format: "md",
8476
+ requiresNode: false,
8477
+ extract: async (raw) => raw
8478
+ };
8479
+ var json = {
8480
+ format: "json",
8481
+ requiresNode: false,
8482
+ extract: async (raw) => {
8483
+ try {
8484
+ return JSON.stringify(JSON.parse(raw), null, 2);
8485
+ } catch {
8486
+ return raw;
8487
+ }
8488
+ }
8489
+ };
8490
+ var csv = {
8491
+ format: "csv",
8492
+ requiresNode: false,
8493
+ extract: async (raw) => {
8494
+ const lines = raw.split(/\r?\n/).filter((l) => l.length > 0);
8495
+ if (lines.length === 0) return "";
8496
+ if (lines.length <= CSV_MAX_ROWS + 1) return lines.join("\n");
8497
+ const head = lines.slice(0, CSV_MAX_ROWS + 1);
8498
+ const remaining = lines.length - head.length;
8499
+ return `${head.join("\n")}
8500
+ \u2026[${remaining.toLocaleString()} more row${remaining === 1 ? "" : "s"} truncated]`;
8501
+ }
8502
+ };
8503
+ var html = {
8504
+ format: "html",
8505
+ requiresNode: false,
8506
+ extract: async (raw) => {
8507
+ const stripped = raw.replace(/<script\b[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<style\b[^>]*>[\s\S]*?<\/style>/gi, "").replace(HTML_TAG_RE, " ");
8508
+ return decodeHtmlEntities(stripped).replace(/\s+/g, " ").trim();
8509
+ }
8510
+ };
8511
+ var pdf = {
8512
+ format: "pdf",
8513
+ requiresNode: true,
8514
+ extract: async (raw) => {
8515
+ let pdfParse;
8516
+ try {
8517
+ const mod = await import("pdf-parse");
8518
+ pdfParse = mod.default ?? mod;
8519
+ } catch {
8520
+ throw new Error(
8521
+ "ERR_KNOWLEDGE_FORMAT_UNSUPPORTED: pdf-parse is not installed. Run `npm install pdf-parse` to enable PDF extraction."
8522
+ );
8523
+ }
8524
+ const buf = Buffer.from(raw, "binary");
8525
+ const result = await pdfParse(buf);
8526
+ return result.text;
8527
+ }
8528
+ };
8529
+ var docx = {
8530
+ format: "docx",
8531
+ requiresNode: true,
8532
+ extract: async (raw) => {
8533
+ let mammoth;
8534
+ try {
8535
+ mammoth = await import("mammoth");
8536
+ } catch {
8537
+ throw new Error(
8538
+ "ERR_KNOWLEDGE_FORMAT_UNSUPPORTED: mammoth is not installed. Run `npm install mammoth` to enable DOCX extraction."
8539
+ );
8540
+ }
8541
+ const buf = Buffer.from(raw, "binary");
8542
+ const result = await mammoth.extractRawText({ buffer: buf });
8543
+ return result.value;
8544
+ }
8545
+ };
8546
+ var EXTRACTORS = {
8547
+ md,
8548
+ txt: text,
8549
+ json,
8550
+ csv,
8551
+ html,
8552
+ pdf,
8553
+ docx
8554
+ };
8555
+ function getExtractor(format) {
8556
+ const e = EXTRACTORS[format];
8557
+ if (e === void 0) throw new Error(`ERR_KNOWLEDGE_FORMAT_UNSUPPORTED: ${format}`);
8558
+ return e;
8559
+ }
8560
+
8561
+ // src/tools/readKnowledge.ts
8562
+ var DEFAULT_MAX_READ_BYTES = 1e4;
8563
+ var inputSchema19 = import_zod27.z.object({
8564
+ ref: import_zod27.z.string().min(1)
8565
+ });
8566
+ function createReadKnowledgeTool(opts) {
8567
+ const scoped = opts.folders.map(parseFolderRef);
8568
+ const indexCache = /* @__PURE__ */ new Map();
8569
+ const fileCache = /* @__PURE__ */ new Map();
8570
+ const cap = opts.maxReadBytes ?? DEFAULT_MAX_READ_BYTES;
8571
+ const externalsByName = new Map(opts.external.map((e) => [e.name, e]));
8572
+ const fetchFn = opts.fetch ?? globalThis.fetch.bind(globalThis);
8573
+ return defineTool({
8574
+ name: "ReadKnowledge",
8575
+ description: "Load the full content of a knowledge ref returned by SearchKnowledge. Use the `ref` value verbatim from the search results \u2014 section refs return one section, file refs return the whole file (with format-specific extraction for non-markdown formats), and `ext:{name}` refs fetch a pre-registered external file.",
8576
+ inputSchema: inputSchema19,
8577
+ execute: async ({ ref }) => {
8578
+ let parsed;
8579
+ try {
8580
+ parsed = parseKnowledgeRef(ref);
8581
+ } catch (err) {
8582
+ return {
8583
+ content: `ERR_KNOWLEDGE_REF_INVALID: ${err instanceof Error ? err.message : String(err)}`,
8584
+ isError: true
8585
+ };
8586
+ }
8587
+ if (parsed.kind === "ext") {
8588
+ return readExternal(parsed.target, externalsByName, fetchFn, cap);
8589
+ }
8590
+ if (!refInScope(scoped, parsed.target)) {
8591
+ return {
8592
+ content: `ERR_KNOWLEDGE_FOLDER_NOT_ALLOWED: ref "${parsed.target}" is outside the run's allowed folders`,
8593
+ isError: true
8594
+ };
8595
+ }
8596
+ const base = parsed.target.split("/")[0];
8597
+ const relPath = parsed.target.slice(base.length + 1);
8598
+ if (parsed.kind === "section") {
8599
+ const idx = await loadIndex2(opts.adapter, base, indexCache);
8600
+ if (idx === null) {
8601
+ return {
8602
+ content: `ERR_KNOWLEDGE_INDEX_MISSING: no _index.json for base "${base}"`,
8603
+ isError: true
8604
+ };
8605
+ }
8606
+ const sectionSlug = parsed.section ?? "";
8607
+ const section = idx.sections.find(
8608
+ (s) => s.relPath === relPath && extractAnchor(s.slug) === sectionSlug
8609
+ );
8610
+ if (section === void 0) {
8611
+ return {
8612
+ content: `ERR_KNOWLEDGE_REF_NOT_FOUND: section ${parsed.target}#${sectionSlug} not in index for "${base}"`,
8613
+ isError: true
8614
+ };
8615
+ }
8616
+ const fullContent = await readFile(opts.adapter, parsed.target, fileCache);
8617
+ if (fullContent === null) {
8618
+ return {
8619
+ content: `ERR_KNOWLEDGE_REF_NOT_FOUND: file ${parsed.target} not found in storage`,
8620
+ isError: true
8621
+ };
8622
+ }
8623
+ const sliced = sliceLines(fullContent, section.startLine, section.endLine);
8624
+ return wrapResult(`[knowledge] ${parsed.target}#${sectionSlug}`, sliced, cap);
8625
+ }
8626
+ const fmt = inferFormat(parsed.target);
8627
+ if (fmt === null) {
8628
+ return {
8629
+ content: `ERR_KNOWLEDGE_FORMAT_UNSUPPORTED: cannot infer format for "${parsed.target}"`,
8630
+ isError: true
8631
+ };
8632
+ }
8633
+ const raw = await readFile(opts.adapter, parsed.target, fileCache);
8634
+ if (raw === null) {
8635
+ return {
8636
+ content: `ERR_KNOWLEDGE_REF_NOT_FOUND: file ${parsed.target} not found in storage`,
8637
+ isError: true
8638
+ };
8639
+ }
8640
+ let extracted;
8641
+ try {
8642
+ extracted = await getExtractor(fmt).extract(raw);
8643
+ } catch (err) {
8644
+ return {
8645
+ content: `ERR_KNOWLEDGE_EXTRACTOR_FAILED: ${err instanceof Error ? err.message : String(err)}`,
8646
+ isError: true
8647
+ };
8648
+ }
8649
+ return wrapResult(`[knowledge] ${parsed.target} (${fmt})`, extracted, cap);
8650
+ }
8651
+ });
8652
+ }
8653
+ async function readExternal(name, registry, fetchFn, cap) {
8654
+ const link = registry.get(name);
8655
+ if (link === void 0) {
8656
+ return {
8657
+ content: `ERR_KNOWLEDGE_REF_NOT_FOUND: no external link named "${name}"`,
8658
+ isError: true
8659
+ };
8660
+ }
8661
+ let res;
8662
+ try {
8663
+ res = await fetchFn(link.url, {
8664
+ headers: link.headers ?? {}
8665
+ });
8666
+ } catch (err) {
8667
+ const msg = err instanceof Error ? err.message : String(err);
8668
+ return {
8669
+ content: `ERR_KNOWLEDGE_NETWORK: ${msg.slice(0, 200)}`,
8670
+ isError: true
8671
+ };
8672
+ }
8673
+ if (!res.ok) {
8674
+ return {
8675
+ content: `ERR_KNOWLEDGE_NETWORK: HTTP ${res.status} fetching ext:${name}`,
8676
+ isError: true
8677
+ };
8678
+ }
8679
+ const raw = await res.text();
8680
+ let extracted;
8681
+ try {
8682
+ extracted = await getExtractor(link.format).extract(raw);
8683
+ } catch (err) {
8684
+ return {
8685
+ content: `ERR_KNOWLEDGE_EXTRACTOR_FAILED: ${err instanceof Error ? err.message : String(err)}`,
8686
+ isError: true
8687
+ };
8688
+ }
8689
+ return wrapResult(`[external] ${name} (${link.format})`, extracted, cap);
8690
+ }
8691
+ function wrapResult(header, body, cap) {
8692
+ let payload = body;
8693
+ if (body.length > cap) {
8694
+ payload = body.slice(0, cap) + `
8695
+ \u2026[+${body.length - cap} more chars truncated]`;
8696
+ }
8697
+ return {
8698
+ content: `${header}
8699
+
8700
+ ${payload}`,
8701
+ isError: false,
8702
+ metadata: { bytes: body.length }
8703
+ };
8704
+ }
8705
+ async function loadIndex2(adapter, base, cache) {
8706
+ const cached2 = cache.get(base);
8707
+ if (cached2 !== void 0) return cached2;
8708
+ let raw;
8709
+ try {
8710
+ raw = await adapter.readFile(`${base}/_index.json`);
8711
+ } catch {
8712
+ return null;
8713
+ }
8714
+ if (raw === null) return null;
8715
+ try {
8716
+ const idx = JSON.parse(raw);
8717
+ cache.set(base, idx);
8718
+ return idx;
8719
+ } catch {
8720
+ return null;
8721
+ }
8722
+ }
8723
+ async function readFile(adapter, path, cache) {
8724
+ const cached2 = cache.get(path);
8725
+ if (cached2 !== void 0) return cached2;
8726
+ const content = await adapter.readFile(path).catch(() => null);
8727
+ if (content === null) return null;
8728
+ cache.set(path, content);
8729
+ return content;
8730
+ }
8731
+ function sliceLines(content, start, end) {
8732
+ const lines = content.split(/\r?\n/);
8733
+ return lines.slice(start - 1, end).join("\n");
8734
+ }
8735
+ function extractAnchor(slug) {
8736
+ const i = slug.indexOf("#");
8737
+ return i === -1 ? "" : slug.slice(i + 1);
8738
+ }
8739
+ function inferFormat(filePath) {
8740
+ const ext = (filePath.split(".").pop() ?? "").toLowerCase();
8741
+ switch (ext) {
8742
+ case "md":
8743
+ case "markdown":
8744
+ return "md";
8745
+ case "txt":
8746
+ return "txt";
8747
+ case "json":
8748
+ return "json";
8749
+ case "csv":
8750
+ return "csv";
8751
+ case "html":
8752
+ case "htm":
8753
+ return "html";
8754
+ case "pdf":
8755
+ return "pdf";
8756
+ case "docx":
8757
+ return "docx";
8758
+ }
8759
+ return null;
8760
+ }
8761
+
8174
8762
  // src/skills/storageSkillSource.ts
8175
8763
  init_cjs_shims();
8176
8764
  var SAFE_NAME4 = /^[a-zA-Z0-9_-]+$/;
@@ -8310,9 +8898,9 @@ var InlineSkillSource = class {
8310
8898
  `InlineSkillSource: fetch ${url} \u2192 HTTP ${String(response.status)} ${response.statusText}`
8311
8899
  );
8312
8900
  }
8313
- const text = await response.text();
8314
- this.cache.set(cacheKey, text);
8315
- return text;
8901
+ const text2 = await response.text();
8902
+ this.cache.set(cacheKey, text2);
8903
+ return text2;
8316
8904
  }
8317
8905
  assertUrlAllowed(url) {
8318
8906
  const hosts = this.allowedHosts;
@@ -8784,47 +9372,60 @@ var R2BindingStorageAdapter = class {
8784
9372
  // src/storage/factory.ts
8785
9373
  var ENGINE_DATA_FOLDER = ".claude";
8786
9374
  var WORKSPACES_FOLDER = "workspaces";
8787
- async function createEngineStorage(config) {
9375
+ var KNOWLEDGE_FOLDER = "knowledge";
9376
+ async function createEngineStorage(config, options = {}) {
8788
9377
  switch (config.provider) {
8789
9378
  case "local":
8790
- return createLocalStorage(config);
9379
+ return createLocalStorage(config, options);
8791
9380
  case "r2":
8792
- return createR2Storage(config);
9381
+ return createR2Storage(config, options);
8793
9382
  case "r2-binding":
8794
- return createR2BindingStorage(config);
9383
+ return createR2BindingStorage(config, options);
8795
9384
  }
8796
9385
  }
8797
- async function createLocalStorage(config) {
9386
+ async function createLocalStorage(config, options) {
8798
9387
  const path = await import("path");
8799
- const workspaceRoot = path.join(
8800
- config.rootPath,
8801
- WORKSPACES_FOLDER,
8802
- config.workspaceId,
8803
- ENGINE_DATA_FOLDER
8804
- );
8805
- return {
8806
- workspace: new LocalStorageAdapter(workspaceRoot)
8807
- };
9388
+ const tenantRoot = path.join(config.rootPath, WORKSPACES_FOLDER, config.workspaceId);
9389
+ const workspaceRoot = path.join(tenantRoot, ENGINE_DATA_FOLDER);
9390
+ const out = { workspace: new LocalStorageAdapter(workspaceRoot) };
9391
+ if (options.withKnowledge) {
9392
+ const knowledgeRoot = path.join(tenantRoot, KNOWLEDGE_FOLDER);
9393
+ return { ...out, knowledge: new LocalStorageAdapter(knowledgeRoot) };
9394
+ }
9395
+ return out;
8808
9396
  }
8809
- function createR2Storage(config) {
9397
+ function createR2Storage(config, options) {
8810
9398
  if (!config.r2) {
8811
9399
  throw new StorageError('storage.r2 is required when storage.provider === "r2"');
8812
9400
  }
8813
9401
  const rootPrefix = config.rootPath.replace(/^\/+|\/+$/g, "");
8814
- const workspacePrefix = `${rootPrefix}/${WORKSPACES_FOLDER}/${config.workspaceId}/${ENGINE_DATA_FOLDER}`;
8815
- return {
8816
- workspace: new R2StorageAdapter(config.r2, workspacePrefix)
8817
- };
9402
+ const tenantPrefix = `${rootPrefix}/${WORKSPACES_FOLDER}/${config.workspaceId}`;
9403
+ const workspacePrefix = `${tenantPrefix}/${ENGINE_DATA_FOLDER}`;
9404
+ const out = { workspace: new R2StorageAdapter(config.r2, workspacePrefix) };
9405
+ if (options.withKnowledge) {
9406
+ const knowledgePrefix = `${tenantPrefix}/${KNOWLEDGE_FOLDER}`;
9407
+ return { ...out, knowledge: new R2StorageAdapter(config.r2, knowledgePrefix) };
9408
+ }
9409
+ return out;
8818
9410
  }
8819
- function createR2BindingStorage(config) {
9411
+ function createR2BindingStorage(config, options) {
8820
9412
  if (!config.r2Binding) {
8821
9413
  throw new StorageError('storage.r2Binding is required when storage.provider === "r2-binding"');
8822
9414
  }
8823
9415
  const rootPrefix = config.rootPath.replace(/^\/+|\/+$/g, "");
8824
- const workspacePrefix = `${rootPrefix}/${WORKSPACES_FOLDER}/${config.workspaceId}/${ENGINE_DATA_FOLDER}`;
8825
- return {
9416
+ const tenantPrefix = `${rootPrefix}/${WORKSPACES_FOLDER}/${config.workspaceId}`;
9417
+ const workspacePrefix = `${tenantPrefix}/${ENGINE_DATA_FOLDER}`;
9418
+ const out = {
8826
9419
  workspace: new R2BindingStorageAdapter(config.r2Binding, workspacePrefix)
8827
9420
  };
9421
+ if (options.withKnowledge) {
9422
+ const knowledgePrefix = `${tenantPrefix}/${KNOWLEDGE_FOLDER}`;
9423
+ return {
9424
+ ...out,
9425
+ knowledge: new R2BindingStorageAdapter(config.r2Binding, knowledgePrefix)
9426
+ };
9427
+ }
9428
+ return out;
8828
9429
  }
8829
9430
 
8830
9431
  // src/transcript/reader.ts
@@ -9329,6 +9930,7 @@ var Engine = class {
9329
9930
  const skillList = skillSource !== void 0 ? await skillSource.list() : void 0;
9330
9931
  const apiConfig = this.resolveApiConfig(options.api);
9331
9932
  const offloadConfig = this.resolveOffloadConfig(options.compaction?.toolResultOffload);
9933
+ const knowledgeRuntime = this.resolveKnowledgeRuntime(options.knowledge, storage);
9332
9934
  let systemPrompt = await buildSystemPrompt({
9333
9935
  ...coordinatorBase !== void 0 ? { base: coordinatorBase } : {},
9334
9936
  memory,
@@ -9362,6 +9964,7 @@ var Engine = class {
9362
9964
  ...skillSource !== void 0 ? { skillSource } : {},
9363
9965
  ...apiConfig !== void 0 ? { apiConfig } : {},
9364
9966
  ...offloadConfig !== void 0 ? { toolResultOffload: offloadConfig } : {},
9967
+ ...knowledgeRuntime !== void 0 ? { knowledge: knowledgeRuntime } : {},
9365
9968
  ...this.internals.fetch !== void 0 ? { fetch: this.internals.fetch } : {}
9366
9969
  });
9367
9970
  const writer = new TranscriptWriter({
@@ -9474,6 +10077,7 @@ var Engine = class {
9474
10077
  const skillList = skillSource !== void 0 ? await skillSource.list() : void 0;
9475
10078
  const apiConfig = this.resolveApiConfig(options.api);
9476
10079
  const offloadConfig = this.resolveOffloadConfig(options.compaction?.toolResultOffload);
10080
+ const knowledgeRuntime = this.resolveKnowledgeRuntime(options.knowledge, storage);
9477
10081
  let systemPrompt = await buildSystemPrompt({
9478
10082
  ...coordinatorBase !== void 0 ? { base: coordinatorBase } : {},
9479
10083
  memory,
@@ -9507,6 +10111,7 @@ var Engine = class {
9507
10111
  ...skillSource !== void 0 ? { skillSource } : {},
9508
10112
  ...apiConfig !== void 0 ? { apiConfig } : {},
9509
10113
  ...offloadConfig !== void 0 ? { toolResultOffload: offloadConfig } : {},
10114
+ ...knowledgeRuntime !== void 0 ? { knowledge: knowledgeRuntime } : {},
9510
10115
  ...this.internals.fetch !== void 0 ? { fetch: this.internals.fetch } : {}
9511
10116
  });
9512
10117
  const priorState = await loadWriterState(storage.workspace, logPath);
@@ -10149,6 +10754,14 @@ ${inputJson}
10149
10754
  names.add("FetchData");
10150
10755
  }
10151
10756
  }
10757
+ if (this.config.knowledge?.enabled === true) {
10758
+ if (!disabled.has("SearchKnowledge") && (wantAll || enabled.has("SearchKnowledge"))) {
10759
+ names.add("SearchKnowledge");
10760
+ }
10761
+ if (!disabled.has("ReadKnowledge") && (wantAll || enabled.has("ReadKnowledge"))) {
10762
+ names.add("ReadKnowledge");
10763
+ }
10764
+ }
10152
10765
  for (const tool of this.config.tools.custom) {
10153
10766
  names.add(tool.name);
10154
10767
  }
@@ -10340,6 +10953,36 @@ ${inputJson}
10340
10953
  ...summarizer !== void 0 ? { summarizer } : {}
10341
10954
  };
10342
10955
  }
10956
+ /**
10957
+ * Plan 023 — resolve the effective runtime knowledge bundle for a
10958
+ * single run.
10959
+ *
10960
+ * Engine-level config (`config.knowledge`) carries the capability
10961
+ * flag + scalar caps. The actual folders + external links are
10962
+ * RUNTIME-only, supplied via `RunOptions.knowledge`. Returning
10963
+ * `undefined` means "don't register the knowledge tools" — callers
10964
+ * skip the bundle entirely.
10965
+ *
10966
+ * Three gates must all pass:
10967
+ * 1. `config.knowledge.enabled === true` (engine opt-in)
10968
+ * 2. `storage.knowledge !== undefined` (adapter was built)
10969
+ * 3. There IS something to look at — at least one folder OR
10970
+ * one external link supplied for this run.
10971
+ */
10972
+ resolveKnowledgeRuntime(override, storage) {
10973
+ if (this.config.knowledge?.enabled !== true) return void 0;
10974
+ if (storage.knowledge === void 0) return void 0;
10975
+ const folders = override?.folders ?? [];
10976
+ const external = override?.external ?? [];
10977
+ if (folders.length === 0 && external.length === 0) return void 0;
10978
+ return {
10979
+ adapter: storage.knowledge,
10980
+ folders,
10981
+ external,
10982
+ maxSearchResults: this.config.knowledge.maxSearchResults,
10983
+ maxReadBytes: this.config.knowledge.maxReadBytes
10984
+ };
10985
+ }
10343
10986
  resolveApiConfig(override) {
10344
10987
  const base = this.config.api;
10345
10988
  if (override === void 0 && base === void 0) return void 0;
@@ -10402,7 +11045,9 @@ ${inputJson}
10402
11045
  if (this.internals.buildStorage !== void 0) {
10403
11046
  return this.internals.buildStorage();
10404
11047
  }
10405
- return createEngineStorage(this.config.storage);
11048
+ return createEngineStorage(this.config.storage, {
11049
+ withKnowledge: this.config.knowledge?.enabled === true
11050
+ });
10406
11051
  }
10407
11052
  buildClient() {
10408
11053
  return createModelAdapter(this.config.model, {
@@ -10523,6 +11168,30 @@ function buildToolRegistry(options) {
10523
11168
  registry.register(fetchDataTool);
10524
11169
  }
10525
11170
  }
11171
+ if (options.knowledge !== void 0) {
11172
+ const k = options.knowledge;
11173
+ if (!disabled.has("SearchKnowledge") && (wantAll || enabled.has("SearchKnowledge"))) {
11174
+ const searchTool = createSearchKnowledgeTool({
11175
+ adapter: k.adapter,
11176
+ folders: k.folders,
11177
+ external: k.external,
11178
+ maxSearchResults: k.maxSearchResults
11179
+ });
11180
+ registry.register(searchTool);
11181
+ childRegistry.register(searchTool);
11182
+ }
11183
+ if (!disabled.has("ReadKnowledge") && (wantAll || enabled.has("ReadKnowledge"))) {
11184
+ const readTool = createReadKnowledgeTool({
11185
+ adapter: k.adapter,
11186
+ folders: k.folders,
11187
+ external: k.external,
11188
+ maxReadBytes: k.maxReadBytes,
11189
+ ...options.fetch !== void 0 ? { fetch: options.fetch } : {}
11190
+ });
11191
+ registry.register(readTool);
11192
+ childRegistry.register(readTool);
11193
+ }
11194
+ }
10526
11195
  const agentTool = createAgentTool({
10527
11196
  storage: storage.workspace,
10528
11197
  client,
@@ -10570,6 +11239,153 @@ function buildToolRegistry(options) {
10570
11239
  // src/index.ts
10571
11240
  init_contract();
10572
11241
  init_fetchData();
11242
+
11243
+ // src/knowledge/indexer.ts
11244
+ init_cjs_shims();
11245
+ var HEADING_RE = /^(#{1,6})[ \t]+(.+?)\s*$/;
11246
+ var WIKI_LINK_RE = /\[\[([^\]|#]+)(?:[#|][^\]]*)?\]\]/g;
11247
+ var FORMAT_BY_EXT = {
11248
+ md: "md",
11249
+ markdown: "md",
11250
+ txt: "txt",
11251
+ json: "json",
11252
+ csv: "csv",
11253
+ html: "html",
11254
+ htm: "html",
11255
+ pdf: "pdf",
11256
+ docx: "docx"
11257
+ };
11258
+ var PREVIEW_CHARS = 200;
11259
+ async function buildKnowledgeIndex(options) {
11260
+ const { adapter, base } = options;
11261
+ const safeBase = base.replace(/^\/+|\/+$/g, "");
11262
+ if (safeBase.length === 0 || safeBase.includes("..")) {
11263
+ throw new Error(`buildKnowledgeIndex: invalid base "${base}"`);
11264
+ }
11265
+ const files = await listFilesRecursive(adapter, safeBase);
11266
+ const sections = [];
11267
+ const filesMeta = {};
11268
+ for (const fileRel of files) {
11269
+ if (fileRel === "_index.json") continue;
11270
+ const fullPath = `${safeBase}/${fileRel}`;
11271
+ const ext = (fileRel.split(".").pop() ?? "").toLowerCase();
11272
+ const format = FORMAT_BY_EXT[ext];
11273
+ if (format === void 0) continue;
11274
+ const raw = await adapter.readFile(fullPath);
11275
+ if (raw === null) continue;
11276
+ const sizeBytes = byteLength3(raw);
11277
+ const meta = { format, size: sizeBytes };
11278
+ if (format === "md" || format === "txt") {
11279
+ const fileSections = splitSections(raw, fileRel);
11280
+ sections.push(...fileSections);
11281
+ const wikiLinks = extractWikiLinks(raw);
11282
+ if (wikiLinks.length > 0) meta.wikiLinks = wikiLinks;
11283
+ }
11284
+ filesMeta[fileRel] = meta;
11285
+ }
11286
+ return {
11287
+ schema: "v1",
11288
+ base: safeBase,
11289
+ builtAt: options.nowIso ?? (/* @__PURE__ */ new Date()).toISOString(),
11290
+ fileCount: Object.keys(filesMeta).length,
11291
+ sections,
11292
+ files: filesMeta
11293
+ };
11294
+ }
11295
+ async function writeKnowledgeIndex(options) {
11296
+ const index = await buildKnowledgeIndex(options);
11297
+ await options.adapter.writeFile(`${index.base}/_index.json`, JSON.stringify(index, null, 2));
11298
+ return index;
11299
+ }
11300
+ async function listFilesRecursive(adapter, dir) {
11301
+ const out = [];
11302
+ const stack = [""];
11303
+ while (stack.length > 0) {
11304
+ const sub = stack.pop();
11305
+ const fullDir = sub === "" ? dir : `${dir}/${sub}`;
11306
+ let entries = [];
11307
+ try {
11308
+ entries = await adapter.listDir(fullDir);
11309
+ } catch {
11310
+ continue;
11311
+ }
11312
+ for (const name of entries) {
11313
+ const childRel = sub === "" ? name : `${sub}/${name}`;
11314
+ const childFull = `${dir}/${childRel}`;
11315
+ const isDir = await adapter.isDirectory(childFull).catch(() => false);
11316
+ if (isDir) {
11317
+ stack.push(childRel);
11318
+ } else {
11319
+ out.push(childRel);
11320
+ }
11321
+ }
11322
+ }
11323
+ return out.sort();
11324
+ }
11325
+ function splitSections(content, relPath) {
11326
+ const lines = content.split(/\r?\n/);
11327
+ const out = [];
11328
+ const heads = [];
11329
+ for (let i = 0; i < lines.length; i++) {
11330
+ const line = lines[i];
11331
+ const m = HEADING_RE.exec(line);
11332
+ if (m) heads.push({ line: i + 1, depth: m[1].length, heading: m[2].trim() });
11333
+ }
11334
+ const leadInEndLine = heads.length > 0 ? heads[0].line - 1 : lines.length;
11335
+ const leadInBody = lines.slice(0, leadInEndLine).join("\n").trim();
11336
+ if (leadInBody.length > 0) {
11337
+ out.push({
11338
+ relPath,
11339
+ heading: "",
11340
+ slug: `${relPath}#`,
11341
+ depth: 0,
11342
+ words: tokenize(leadInBody),
11343
+ preview: makePreview(leadInBody),
11344
+ startLine: 1,
11345
+ endLine: leadInEndLine
11346
+ });
11347
+ }
11348
+ for (let i = 0; i < heads.length; i++) {
11349
+ const h = heads[i];
11350
+ const startLine = h.line;
11351
+ const endLine = i + 1 < heads.length ? heads[i + 1].line - 1 : lines.length;
11352
+ const body = lines.slice(startLine - 1, endLine).join("\n");
11353
+ out.push({
11354
+ relPath,
11355
+ heading: h.heading,
11356
+ slug: `${relPath}#${slugify(h.heading)}`,
11357
+ depth: h.depth,
11358
+ words: tokenize(body),
11359
+ preview: makePreview(body),
11360
+ startLine,
11361
+ endLine
11362
+ });
11363
+ }
11364
+ return out;
11365
+ }
11366
+ function makePreview(body) {
11367
+ const trimmed = body.replace(/^#{1,6}\s+.+$\r?\n?/m, "").trim();
11368
+ if (trimmed.length <= PREVIEW_CHARS) return trimmed;
11369
+ return trimmed.slice(0, PREVIEW_CHARS) + "\u2026";
11370
+ }
11371
+ function slugify(text2) {
11372
+ return text2.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
11373
+ }
11374
+ function extractWikiLinks(text2) {
11375
+ const seen = /* @__PURE__ */ new Set();
11376
+ let m;
11377
+ WIKI_LINK_RE.lastIndex = 0;
11378
+ while ((m = WIKI_LINK_RE.exec(text2)) !== null) {
11379
+ const target = m[1].trim();
11380
+ if (target.length > 0) seen.add(target);
11381
+ }
11382
+ return [...seen].sort();
11383
+ }
11384
+ function byteLength3(s) {
11385
+ return new TextEncoder().encode(s).byteLength;
11386
+ }
11387
+
11388
+ // src/index.ts
10573
11389
  init_orchestrate();
10574
11390
  init_planParser();
10575
11391
  init_retry();
@@ -10643,6 +11459,7 @@ function resolveApiKey(config) {
10643
11459
  WebhookDispatcher,
10644
11460
  adaptMcpTool,
10645
11461
  buildForkedMessages,
11462
+ buildKnowledgeIndex,
10646
11463
  buildPermissionPolicy,
10647
11464
  buildSchemaPrompt,
10648
11465
  buildSystemPrompt,
@@ -10653,6 +11470,8 @@ function resolveApiKey(config) {
10653
11470
  createFetchDataTool,
10654
11471
  createLogger,
10655
11472
  createModelAdapter,
11473
+ createReadKnowledgeTool,
11474
+ createSearchKnowledgeTool,
10656
11475
  createSendMessageTool,
10657
11476
  createSkillPageTool,
10658
11477
  createSmartMemory,
@@ -10662,6 +11481,7 @@ function resolveApiKey(config) {
10662
11481
  detectRuntime,
10663
11482
  getCoordinatorBasePrompt,
10664
11483
  getCoordinatorSystemPrompt,
11484
+ getExtractor,
10665
11485
  hasProcessLifecycle,
10666
11486
  initEngine,
10667
11487
  isCoordinatorMode,
@@ -10684,6 +11504,7 @@ function resolveApiKey(config) {
10684
11504
  toResponse,
10685
11505
  tryParseJSON,
10686
11506
  validateOutput,
10687
- withCapabilityCheck
11507
+ withCapabilityCheck,
11508
+ writeKnowledgeIndex
10688
11509
  });
10689
11510
  //# sourceMappingURL=index.cjs.map