la-machina-engine 0.7.0 → 0.7.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +273 -23
- package/dist/index.cjs +250 -244
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +250 -244
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1974,6 +1974,10 @@ function toAISdkTools(tools) {
|
|
|
1974
1974
|
}
|
|
1975
1975
|
|
|
1976
1976
|
// src/model/aiSdkAdapter.ts
|
|
1977
|
+
var import_anthropic = require("@ai-sdk/anthropic");
|
|
1978
|
+
var import_openai = require("@ai-sdk/openai");
|
|
1979
|
+
var import_google = require("@ai-sdk/google");
|
|
1980
|
+
var import_openai_compatible = require("@ai-sdk/openai-compatible");
|
|
1977
1981
|
var AISdkAdapter = class {
|
|
1978
1982
|
options;
|
|
1979
1983
|
model = null;
|
|
@@ -2034,23 +2038,18 @@ var AISdkAdapter = class {
|
|
|
2034
2038
|
async getModel() {
|
|
2035
2039
|
if (this.model !== null) return this.model;
|
|
2036
2040
|
const { provider, modelId, apiKey, baseURL } = this.options;
|
|
2037
|
-
let mod;
|
|
2038
2041
|
switch (provider) {
|
|
2039
2042
|
case "anthropic":
|
|
2040
|
-
|
|
2041
|
-
this.model = mod.createAnthropic({ apiKey })(modelId);
|
|
2043
|
+
this.model = (0, import_anthropic.createAnthropic)({ apiKey })(modelId);
|
|
2042
2044
|
break;
|
|
2043
2045
|
case "openai":
|
|
2044
|
-
|
|
2045
|
-
this.model = mod.createOpenAI({ apiKey, ...baseURL ? { baseURL } : {} })(modelId);
|
|
2046
|
+
this.model = (0, import_openai.createOpenAI)({ apiKey, ...baseURL ? { baseURL } : {} })(modelId);
|
|
2046
2047
|
break;
|
|
2047
2048
|
case "google":
|
|
2048
|
-
|
|
2049
|
-
this.model = mod.createGoogleGenerativeAI({ apiKey })(modelId);
|
|
2049
|
+
this.model = (0, import_google.createGoogleGenerativeAI)({ apiKey })(modelId);
|
|
2050
2050
|
break;
|
|
2051
2051
|
case "openai-compatible":
|
|
2052
|
-
|
|
2053
|
-
this.model = mod.createOpenAICompatible({ name: "custom", apiKey, baseURL: baseURL ?? "" })(
|
|
2052
|
+
this.model = (0, import_openai_compatible.createOpenAICompatible)({ name: "custom", apiKey, baseURL: baseURL ?? "" })(
|
|
2054
2053
|
modelId
|
|
2055
2054
|
);
|
|
2056
2055
|
break;
|
|
@@ -2072,13 +2071,6 @@ function mapFinishReason(reason) {
|
|
|
2072
2071
|
return "end_turn";
|
|
2073
2072
|
}
|
|
2074
2073
|
}
|
|
2075
|
-
async function importOrThrow(pkg, provider) {
|
|
2076
|
-
try {
|
|
2077
|
-
return await import(pkg);
|
|
2078
|
-
} catch {
|
|
2079
|
-
throw new Error(`Provider "${provider}" requires "${pkg}". Install: npm i ${pkg}`);
|
|
2080
|
-
}
|
|
2081
|
-
}
|
|
2082
2074
|
|
|
2083
2075
|
// src/model/factory.ts
|
|
2084
2076
|
function createModelAdapter(config, options = {}) {
|
|
@@ -8201,75 +8193,8 @@ init_cjs_shims();
|
|
|
8201
8193
|
var import_zod26 = require("zod");
|
|
8202
8194
|
init_contract();
|
|
8203
8195
|
|
|
8204
|
-
// src/knowledge/
|
|
8196
|
+
// src/knowledge/indexer.ts
|
|
8205
8197
|
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
8198
|
|
|
8274
8199
|
// src/knowledge/tokenize.ts
|
|
8275
8200
|
init_cjs_shims();
|
|
@@ -8346,6 +8271,220 @@ function scoreOverlap(sectionWords, queryTokens) {
|
|
|
8346
8271
|
return n;
|
|
8347
8272
|
}
|
|
8348
8273
|
|
|
8274
|
+
// src/knowledge/indexer.ts
|
|
8275
|
+
var HEADING_RE = /^(#{1,6})[ \t]+(.+?)\s*$/;
|
|
8276
|
+
var WIKI_LINK_RE = /\[\[([^\]|#]+)(?:[#|][^\]]*)?\]\]/g;
|
|
8277
|
+
var FORMAT_BY_EXT = {
|
|
8278
|
+
md: "md",
|
|
8279
|
+
markdown: "md",
|
|
8280
|
+
txt: "txt",
|
|
8281
|
+
json: "json",
|
|
8282
|
+
csv: "csv",
|
|
8283
|
+
html: "html",
|
|
8284
|
+
htm: "html",
|
|
8285
|
+
pdf: "pdf",
|
|
8286
|
+
docx: "docx"
|
|
8287
|
+
};
|
|
8288
|
+
var PREVIEW_CHARS = 200;
|
|
8289
|
+
async function buildKnowledgeIndex(options) {
|
|
8290
|
+
const { adapter, base } = options;
|
|
8291
|
+
const safeBase = base.replace(/^\/+|\/+$/g, "");
|
|
8292
|
+
if (safeBase.length === 0 || safeBase.includes("..")) {
|
|
8293
|
+
throw new Error(`buildKnowledgeIndex: invalid base "${base}"`);
|
|
8294
|
+
}
|
|
8295
|
+
const files = await listFilesRecursive(adapter, safeBase);
|
|
8296
|
+
const sections = [];
|
|
8297
|
+
const filesMeta = {};
|
|
8298
|
+
for (const fileRel of files) {
|
|
8299
|
+
if (fileRel === "_index.json") continue;
|
|
8300
|
+
const fullPath = `${safeBase}/${fileRel}`;
|
|
8301
|
+
const ext = (fileRel.split(".").pop() ?? "").toLowerCase();
|
|
8302
|
+
const format = FORMAT_BY_EXT[ext];
|
|
8303
|
+
if (format === void 0) continue;
|
|
8304
|
+
const raw = await adapter.readFile(fullPath);
|
|
8305
|
+
if (raw === null) continue;
|
|
8306
|
+
const sizeBytes = byteLength3(raw);
|
|
8307
|
+
const meta = { format, size: sizeBytes };
|
|
8308
|
+
if (format === "md" || format === "txt") {
|
|
8309
|
+
const fileSections = splitSections(raw, fileRel);
|
|
8310
|
+
sections.push(...fileSections);
|
|
8311
|
+
const wikiLinks = extractWikiLinks(raw);
|
|
8312
|
+
if (wikiLinks.length > 0) meta.wikiLinks = wikiLinks;
|
|
8313
|
+
}
|
|
8314
|
+
filesMeta[fileRel] = meta;
|
|
8315
|
+
}
|
|
8316
|
+
return {
|
|
8317
|
+
schema: "v1",
|
|
8318
|
+
base: safeBase,
|
|
8319
|
+
builtAt: options.nowIso ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
8320
|
+
fileCount: Object.keys(filesMeta).length,
|
|
8321
|
+
sections,
|
|
8322
|
+
files: filesMeta
|
|
8323
|
+
};
|
|
8324
|
+
}
|
|
8325
|
+
async function writeKnowledgeIndex(options) {
|
|
8326
|
+
const index = await buildKnowledgeIndex(options);
|
|
8327
|
+
await options.adapter.writeFile(`${index.base}/_index.json`, JSON.stringify(index, null, 2));
|
|
8328
|
+
return index;
|
|
8329
|
+
}
|
|
8330
|
+
async function listFilesRecursive(adapter, dir) {
|
|
8331
|
+
const out = [];
|
|
8332
|
+
const stack = [""];
|
|
8333
|
+
while (stack.length > 0) {
|
|
8334
|
+
const sub = stack.pop();
|
|
8335
|
+
const fullDir = sub === "" ? dir : `${dir}/${sub}`;
|
|
8336
|
+
let entries = [];
|
|
8337
|
+
try {
|
|
8338
|
+
entries = await adapter.listDir(fullDir);
|
|
8339
|
+
} catch {
|
|
8340
|
+
continue;
|
|
8341
|
+
}
|
|
8342
|
+
for (const name of entries) {
|
|
8343
|
+
const childRel = sub === "" ? name : `${sub}/${name}`;
|
|
8344
|
+
const childFull = `${dir}/${childRel}`;
|
|
8345
|
+
const isDir = await adapter.isDirectory(childFull).catch(() => false);
|
|
8346
|
+
if (isDir) {
|
|
8347
|
+
stack.push(childRel);
|
|
8348
|
+
} else {
|
|
8349
|
+
out.push(childRel);
|
|
8350
|
+
}
|
|
8351
|
+
}
|
|
8352
|
+
}
|
|
8353
|
+
return out.sort();
|
|
8354
|
+
}
|
|
8355
|
+
function splitSections(content, relPath) {
|
|
8356
|
+
const lines = content.split(/\r?\n/);
|
|
8357
|
+
const out = [];
|
|
8358
|
+
const heads = [];
|
|
8359
|
+
for (let i = 0; i < lines.length; i++) {
|
|
8360
|
+
const line = lines[i];
|
|
8361
|
+
const m = HEADING_RE.exec(line);
|
|
8362
|
+
if (m) heads.push({ line: i + 1, depth: m[1].length, heading: m[2].trim() });
|
|
8363
|
+
}
|
|
8364
|
+
const leadInEndLine = heads.length > 0 ? heads[0].line - 1 : lines.length;
|
|
8365
|
+
const leadInBody = lines.slice(0, leadInEndLine).join("\n").trim();
|
|
8366
|
+
if (leadInBody.length > 0) {
|
|
8367
|
+
out.push({
|
|
8368
|
+
relPath,
|
|
8369
|
+
heading: "",
|
|
8370
|
+
slug: `${relPath}#`,
|
|
8371
|
+
depth: 0,
|
|
8372
|
+
words: tokenize(leadInBody),
|
|
8373
|
+
preview: makePreview(leadInBody),
|
|
8374
|
+
startLine: 1,
|
|
8375
|
+
endLine: leadInEndLine
|
|
8376
|
+
});
|
|
8377
|
+
}
|
|
8378
|
+
for (let i = 0; i < heads.length; i++) {
|
|
8379
|
+
const h = heads[i];
|
|
8380
|
+
const startLine = h.line;
|
|
8381
|
+
const endLine = i + 1 < heads.length ? heads[i + 1].line - 1 : lines.length;
|
|
8382
|
+
const body = lines.slice(startLine - 1, endLine).join("\n");
|
|
8383
|
+
out.push({
|
|
8384
|
+
relPath,
|
|
8385
|
+
heading: h.heading,
|
|
8386
|
+
slug: `${relPath}#${slugify(h.heading)}`,
|
|
8387
|
+
depth: h.depth,
|
|
8388
|
+
words: tokenize(body),
|
|
8389
|
+
preview: makePreview(body),
|
|
8390
|
+
startLine,
|
|
8391
|
+
endLine
|
|
8392
|
+
});
|
|
8393
|
+
}
|
|
8394
|
+
return out;
|
|
8395
|
+
}
|
|
8396
|
+
function makePreview(body) {
|
|
8397
|
+
const trimmed = body.replace(/^#{1,6}\s+.+$\r?\n?/m, "").trim();
|
|
8398
|
+
if (trimmed.length <= PREVIEW_CHARS) return trimmed;
|
|
8399
|
+
return trimmed.slice(0, PREVIEW_CHARS) + "\u2026";
|
|
8400
|
+
}
|
|
8401
|
+
function slugify(text2) {
|
|
8402
|
+
return text2.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
8403
|
+
}
|
|
8404
|
+
function extractWikiLinks(text2) {
|
|
8405
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8406
|
+
let m;
|
|
8407
|
+
WIKI_LINK_RE.lastIndex = 0;
|
|
8408
|
+
while ((m = WIKI_LINK_RE.exec(text2)) !== null) {
|
|
8409
|
+
const target = m[1].trim();
|
|
8410
|
+
if (target.length > 0) seen.add(target);
|
|
8411
|
+
}
|
|
8412
|
+
return [...seen].sort();
|
|
8413
|
+
}
|
|
8414
|
+
function byteLength3(s) {
|
|
8415
|
+
return new TextEncoder().encode(s).byteLength;
|
|
8416
|
+
}
|
|
8417
|
+
|
|
8418
|
+
// src/knowledge/scope.ts
|
|
8419
|
+
init_cjs_shims();
|
|
8420
|
+
var SAFE_PATH_RE = /^[a-zA-Z0-9_\-./]+$/;
|
|
8421
|
+
function parseFolderRef(raw) {
|
|
8422
|
+
if (typeof raw !== "string" || raw.length === 0) {
|
|
8423
|
+
throw new Error(`invalid knowledge folder ref: empty`);
|
|
8424
|
+
}
|
|
8425
|
+
if (raw.startsWith("/")) {
|
|
8426
|
+
throw new Error(`invalid knowledge folder ref: absolute paths not allowed ("${raw}")`);
|
|
8427
|
+
}
|
|
8428
|
+
const trimmed = raw.replace(/\/+$/g, "");
|
|
8429
|
+
if (trimmed.length === 0) {
|
|
8430
|
+
throw new Error(`invalid knowledge folder ref: "${raw}"`);
|
|
8431
|
+
}
|
|
8432
|
+
if (!SAFE_PATH_RE.test(trimmed)) {
|
|
8433
|
+
throw new Error(`invalid knowledge folder ref: unsafe characters in "${raw}"`);
|
|
8434
|
+
}
|
|
8435
|
+
if (trimmed.split("/").some((seg) => seg === ".." || seg === "." || seg === "")) {
|
|
8436
|
+
throw new Error(`invalid knowledge folder ref: traversal in "${raw}"`);
|
|
8437
|
+
}
|
|
8438
|
+
const segs = trimmed.split("/");
|
|
8439
|
+
const base = segs[0];
|
|
8440
|
+
const subPath = segs.slice(1).join("/");
|
|
8441
|
+
return { path: trimmed, base, subPath };
|
|
8442
|
+
}
|
|
8443
|
+
function relPathInScope(folder, relPath) {
|
|
8444
|
+
if (folder.subPath === "") return true;
|
|
8445
|
+
return relPath === folder.subPath || relPath.startsWith(`${folder.subPath}/`);
|
|
8446
|
+
}
|
|
8447
|
+
function parseKnowledgeRef(raw) {
|
|
8448
|
+
if (typeof raw !== "string" || raw.length === 0) {
|
|
8449
|
+
throw new Error("invalid knowledge ref: empty");
|
|
8450
|
+
}
|
|
8451
|
+
if (raw.startsWith("ext:")) {
|
|
8452
|
+
const name = raw.slice("ext:".length);
|
|
8453
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(name) || name.length === 0) {
|
|
8454
|
+
throw new Error(`invalid knowledge ref: external name "${name}" has unsafe characters`);
|
|
8455
|
+
}
|
|
8456
|
+
return { kind: "ext", target: name };
|
|
8457
|
+
}
|
|
8458
|
+
if (raw.startsWith("/")) {
|
|
8459
|
+
throw new Error(`invalid knowledge ref: absolute paths not allowed ("${raw}")`);
|
|
8460
|
+
}
|
|
8461
|
+
const hashAt = raw.indexOf("#");
|
|
8462
|
+
const filePath = hashAt === -1 ? raw : raw.slice(0, hashAt);
|
|
8463
|
+
const section = hashAt === -1 ? void 0 : raw.slice(hashAt + 1);
|
|
8464
|
+
if (!SAFE_PATH_RE.test(filePath)) {
|
|
8465
|
+
throw new Error(`invalid knowledge ref: unsafe characters in "${filePath}"`);
|
|
8466
|
+
}
|
|
8467
|
+
if (filePath.split("/").some((seg) => seg === ".." || seg === "." || seg === "")) {
|
|
8468
|
+
throw new Error(`invalid knowledge ref: traversal in "${filePath}"`);
|
|
8469
|
+
}
|
|
8470
|
+
if (section !== void 0) {
|
|
8471
|
+
if (section.length > 0 && !/^[a-zA-Z0-9_-]+$/.test(section)) {
|
|
8472
|
+
throw new Error(`invalid knowledge ref: unsafe characters in section "${section}"`);
|
|
8473
|
+
}
|
|
8474
|
+
return { kind: "section", target: filePath, section };
|
|
8475
|
+
}
|
|
8476
|
+
return { kind: "file", target: filePath };
|
|
8477
|
+
}
|
|
8478
|
+
function refInScope(folders, filePath) {
|
|
8479
|
+
return folders.some((f) => {
|
|
8480
|
+
if (filePath === f.base || filePath.startsWith(`${f.base}/`)) {
|
|
8481
|
+
const relInBase = filePath === f.base ? "" : filePath.slice(f.base.length + 1);
|
|
8482
|
+
return relPathInScope(f, relInBase);
|
|
8483
|
+
}
|
|
8484
|
+
return false;
|
|
8485
|
+
});
|
|
8486
|
+
}
|
|
8487
|
+
|
|
8349
8488
|
// src/tools/searchKnowledge.ts
|
|
8350
8489
|
var DEFAULT_MAX_RESULTS = 5;
|
|
8351
8490
|
var inputSchema18 = import_zod26.z.object({
|
|
@@ -8430,17 +8569,24 @@ function truncatePreview(s) {
|
|
|
8430
8569
|
async function loadIndex(adapter, base, cache) {
|
|
8431
8570
|
const cached2 = cache.get(base);
|
|
8432
8571
|
if (cached2 !== void 0) return cached2;
|
|
8433
|
-
let raw;
|
|
8572
|
+
let raw = null;
|
|
8434
8573
|
try {
|
|
8435
8574
|
raw = await adapter.readFile(`${base}/_index.json`);
|
|
8436
8575
|
} catch {
|
|
8437
|
-
|
|
8576
|
+
raw = null;
|
|
8577
|
+
}
|
|
8578
|
+
if (raw !== null) {
|
|
8579
|
+
try {
|
|
8580
|
+
const parsed = JSON.parse(raw);
|
|
8581
|
+
cache.set(base, parsed);
|
|
8582
|
+
return parsed;
|
|
8583
|
+
} catch {
|
|
8584
|
+
}
|
|
8438
8585
|
}
|
|
8439
|
-
if (raw === null) return null;
|
|
8440
8586
|
try {
|
|
8441
|
-
const
|
|
8442
|
-
cache.set(base,
|
|
8443
|
-
return
|
|
8587
|
+
const built = await buildKnowledgeIndex({ adapter, base });
|
|
8588
|
+
cache.set(base, built);
|
|
8589
|
+
return built;
|
|
8444
8590
|
} catch {
|
|
8445
8591
|
return null;
|
|
8446
8592
|
}
|
|
@@ -8599,7 +8745,7 @@ function createReadKnowledgeTool(opts) {
|
|
|
8599
8745
|
const idx = await loadIndex2(opts.adapter, base, indexCache);
|
|
8600
8746
|
if (idx === null) {
|
|
8601
8747
|
return {
|
|
8602
|
-
content: `
|
|
8748
|
+
content: `ERR_KNOWLEDGE_REF_NOT_FOUND: base "${base}" has no readable files`,
|
|
8603
8749
|
isError: true
|
|
8604
8750
|
};
|
|
8605
8751
|
}
|
|
@@ -8705,17 +8851,24 @@ ${payload}`,
|
|
|
8705
8851
|
async function loadIndex2(adapter, base, cache) {
|
|
8706
8852
|
const cached2 = cache.get(base);
|
|
8707
8853
|
if (cached2 !== void 0) return cached2;
|
|
8708
|
-
let raw;
|
|
8854
|
+
let raw = null;
|
|
8709
8855
|
try {
|
|
8710
8856
|
raw = await adapter.readFile(`${base}/_index.json`);
|
|
8711
8857
|
} catch {
|
|
8712
|
-
|
|
8858
|
+
raw = null;
|
|
8859
|
+
}
|
|
8860
|
+
if (raw !== null) {
|
|
8861
|
+
try {
|
|
8862
|
+
const idx = JSON.parse(raw);
|
|
8863
|
+
cache.set(base, idx);
|
|
8864
|
+
return idx;
|
|
8865
|
+
} catch {
|
|
8866
|
+
}
|
|
8713
8867
|
}
|
|
8714
|
-
if (raw === null) return null;
|
|
8715
8868
|
try {
|
|
8716
|
-
const
|
|
8717
|
-
cache.set(base,
|
|
8718
|
-
return
|
|
8869
|
+
const built = await buildKnowledgeIndex({ adapter, base });
|
|
8870
|
+
cache.set(base, built);
|
|
8871
|
+
return built;
|
|
8719
8872
|
} catch {
|
|
8720
8873
|
return null;
|
|
8721
8874
|
}
|
|
@@ -11239,153 +11392,6 @@ function buildToolRegistry(options) {
|
|
|
11239
11392
|
// src/index.ts
|
|
11240
11393
|
init_contract();
|
|
11241
11394
|
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
|
|
11389
11395
|
init_orchestrate();
|
|
11390
11396
|
init_planParser();
|
|
11391
11397
|
init_retry();
|