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.js
CHANGED
|
@@ -1873,6 +1873,10 @@ function toAISdkTools(tools) {
|
|
|
1873
1873
|
}
|
|
1874
1874
|
|
|
1875
1875
|
// src/model/aiSdkAdapter.ts
|
|
1876
|
+
import { createAnthropic } from "@ai-sdk/anthropic";
|
|
1877
|
+
import { createOpenAI } from "@ai-sdk/openai";
|
|
1878
|
+
import { createGoogleGenerativeAI } from "@ai-sdk/google";
|
|
1879
|
+
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
|
|
1876
1880
|
var AISdkAdapter = class {
|
|
1877
1881
|
options;
|
|
1878
1882
|
model = null;
|
|
@@ -1933,23 +1937,18 @@ var AISdkAdapter = class {
|
|
|
1933
1937
|
async getModel() {
|
|
1934
1938
|
if (this.model !== null) return this.model;
|
|
1935
1939
|
const { provider, modelId, apiKey, baseURL } = this.options;
|
|
1936
|
-
let mod;
|
|
1937
1940
|
switch (provider) {
|
|
1938
1941
|
case "anthropic":
|
|
1939
|
-
|
|
1940
|
-
this.model = mod.createAnthropic({ apiKey })(modelId);
|
|
1942
|
+
this.model = createAnthropic({ apiKey })(modelId);
|
|
1941
1943
|
break;
|
|
1942
1944
|
case "openai":
|
|
1943
|
-
|
|
1944
|
-
this.model = mod.createOpenAI({ apiKey, ...baseURL ? { baseURL } : {} })(modelId);
|
|
1945
|
+
this.model = createOpenAI({ apiKey, ...baseURL ? { baseURL } : {} })(modelId);
|
|
1945
1946
|
break;
|
|
1946
1947
|
case "google":
|
|
1947
|
-
|
|
1948
|
-
this.model = mod.createGoogleGenerativeAI({ apiKey })(modelId);
|
|
1948
|
+
this.model = createGoogleGenerativeAI({ apiKey })(modelId);
|
|
1949
1949
|
break;
|
|
1950
1950
|
case "openai-compatible":
|
|
1951
|
-
|
|
1952
|
-
this.model = mod.createOpenAICompatible({ name: "custom", apiKey, baseURL: baseURL ?? "" })(
|
|
1951
|
+
this.model = createOpenAICompatible({ name: "custom", apiKey, baseURL: baseURL ?? "" })(
|
|
1953
1952
|
modelId
|
|
1954
1953
|
);
|
|
1955
1954
|
break;
|
|
@@ -1971,13 +1970,6 @@ function mapFinishReason(reason) {
|
|
|
1971
1970
|
return "end_turn";
|
|
1972
1971
|
}
|
|
1973
1972
|
}
|
|
1974
|
-
async function importOrThrow(pkg, provider) {
|
|
1975
|
-
try {
|
|
1976
|
-
return await import(pkg);
|
|
1977
|
-
} catch {
|
|
1978
|
-
throw new Error(`Provider "${provider}" requires "${pkg}". Install: npm i ${pkg}`);
|
|
1979
|
-
}
|
|
1980
|
-
}
|
|
1981
1973
|
|
|
1982
1974
|
// src/model/factory.ts
|
|
1983
1975
|
function createModelAdapter(config, options = {}) {
|
|
@@ -8102,75 +8094,8 @@ init_esm_shims();
|
|
|
8102
8094
|
init_contract();
|
|
8103
8095
|
import { z as z26 } from "zod";
|
|
8104
8096
|
|
|
8105
|
-
// src/knowledge/
|
|
8097
|
+
// src/knowledge/indexer.ts
|
|
8106
8098
|
init_esm_shims();
|
|
8107
|
-
var SAFE_PATH_RE = /^[a-zA-Z0-9_\-./]+$/;
|
|
8108
|
-
function parseFolderRef(raw) {
|
|
8109
|
-
if (typeof raw !== "string" || raw.length === 0) {
|
|
8110
|
-
throw new Error(`invalid knowledge folder ref: empty`);
|
|
8111
|
-
}
|
|
8112
|
-
if (raw.startsWith("/")) {
|
|
8113
|
-
throw new Error(`invalid knowledge folder ref: absolute paths not allowed ("${raw}")`);
|
|
8114
|
-
}
|
|
8115
|
-
const trimmed = raw.replace(/\/+$/g, "");
|
|
8116
|
-
if (trimmed.length === 0) {
|
|
8117
|
-
throw new Error(`invalid knowledge folder ref: "${raw}"`);
|
|
8118
|
-
}
|
|
8119
|
-
if (!SAFE_PATH_RE.test(trimmed)) {
|
|
8120
|
-
throw new Error(`invalid knowledge folder ref: unsafe characters in "${raw}"`);
|
|
8121
|
-
}
|
|
8122
|
-
if (trimmed.split("/").some((seg) => seg === ".." || seg === "." || seg === "")) {
|
|
8123
|
-
throw new Error(`invalid knowledge folder ref: traversal in "${raw}"`);
|
|
8124
|
-
}
|
|
8125
|
-
const segs = trimmed.split("/");
|
|
8126
|
-
const base = segs[0];
|
|
8127
|
-
const subPath = segs.slice(1).join("/");
|
|
8128
|
-
return { path: trimmed, base, subPath };
|
|
8129
|
-
}
|
|
8130
|
-
function relPathInScope(folder, relPath) {
|
|
8131
|
-
if (folder.subPath === "") return true;
|
|
8132
|
-
return relPath === folder.subPath || relPath.startsWith(`${folder.subPath}/`);
|
|
8133
|
-
}
|
|
8134
|
-
function parseKnowledgeRef(raw) {
|
|
8135
|
-
if (typeof raw !== "string" || raw.length === 0) {
|
|
8136
|
-
throw new Error("invalid knowledge ref: empty");
|
|
8137
|
-
}
|
|
8138
|
-
if (raw.startsWith("ext:")) {
|
|
8139
|
-
const name = raw.slice("ext:".length);
|
|
8140
|
-
if (!/^[a-zA-Z0-9_-]+$/.test(name) || name.length === 0) {
|
|
8141
|
-
throw new Error(`invalid knowledge ref: external name "${name}" has unsafe characters`);
|
|
8142
|
-
}
|
|
8143
|
-
return { kind: "ext", target: name };
|
|
8144
|
-
}
|
|
8145
|
-
if (raw.startsWith("/")) {
|
|
8146
|
-
throw new Error(`invalid knowledge ref: absolute paths not allowed ("${raw}")`);
|
|
8147
|
-
}
|
|
8148
|
-
const hashAt = raw.indexOf("#");
|
|
8149
|
-
const filePath = hashAt === -1 ? raw : raw.slice(0, hashAt);
|
|
8150
|
-
const section = hashAt === -1 ? void 0 : raw.slice(hashAt + 1);
|
|
8151
|
-
if (!SAFE_PATH_RE.test(filePath)) {
|
|
8152
|
-
throw new Error(`invalid knowledge ref: unsafe characters in "${filePath}"`);
|
|
8153
|
-
}
|
|
8154
|
-
if (filePath.split("/").some((seg) => seg === ".." || seg === "." || seg === "")) {
|
|
8155
|
-
throw new Error(`invalid knowledge ref: traversal in "${filePath}"`);
|
|
8156
|
-
}
|
|
8157
|
-
if (section !== void 0) {
|
|
8158
|
-
if (section.length > 0 && !/^[a-zA-Z0-9_-]+$/.test(section)) {
|
|
8159
|
-
throw new Error(`invalid knowledge ref: unsafe characters in section "${section}"`);
|
|
8160
|
-
}
|
|
8161
|
-
return { kind: "section", target: filePath, section };
|
|
8162
|
-
}
|
|
8163
|
-
return { kind: "file", target: filePath };
|
|
8164
|
-
}
|
|
8165
|
-
function refInScope(folders, filePath) {
|
|
8166
|
-
return folders.some((f) => {
|
|
8167
|
-
if (filePath === f.base || filePath.startsWith(`${f.base}/`)) {
|
|
8168
|
-
const relInBase = filePath === f.base ? "" : filePath.slice(f.base.length + 1);
|
|
8169
|
-
return relPathInScope(f, relInBase);
|
|
8170
|
-
}
|
|
8171
|
-
return false;
|
|
8172
|
-
});
|
|
8173
|
-
}
|
|
8174
8099
|
|
|
8175
8100
|
// src/knowledge/tokenize.ts
|
|
8176
8101
|
init_esm_shims();
|
|
@@ -8247,6 +8172,220 @@ function scoreOverlap(sectionWords, queryTokens) {
|
|
|
8247
8172
|
return n;
|
|
8248
8173
|
}
|
|
8249
8174
|
|
|
8175
|
+
// src/knowledge/indexer.ts
|
|
8176
|
+
var HEADING_RE = /^(#{1,6})[ \t]+(.+?)\s*$/;
|
|
8177
|
+
var WIKI_LINK_RE = /\[\[([^\]|#]+)(?:[#|][^\]]*)?\]\]/g;
|
|
8178
|
+
var FORMAT_BY_EXT = {
|
|
8179
|
+
md: "md",
|
|
8180
|
+
markdown: "md",
|
|
8181
|
+
txt: "txt",
|
|
8182
|
+
json: "json",
|
|
8183
|
+
csv: "csv",
|
|
8184
|
+
html: "html",
|
|
8185
|
+
htm: "html",
|
|
8186
|
+
pdf: "pdf",
|
|
8187
|
+
docx: "docx"
|
|
8188
|
+
};
|
|
8189
|
+
var PREVIEW_CHARS = 200;
|
|
8190
|
+
async function buildKnowledgeIndex(options) {
|
|
8191
|
+
const { adapter, base } = options;
|
|
8192
|
+
const safeBase = base.replace(/^\/+|\/+$/g, "");
|
|
8193
|
+
if (safeBase.length === 0 || safeBase.includes("..")) {
|
|
8194
|
+
throw new Error(`buildKnowledgeIndex: invalid base "${base}"`);
|
|
8195
|
+
}
|
|
8196
|
+
const files = await listFilesRecursive(adapter, safeBase);
|
|
8197
|
+
const sections = [];
|
|
8198
|
+
const filesMeta = {};
|
|
8199
|
+
for (const fileRel of files) {
|
|
8200
|
+
if (fileRel === "_index.json") continue;
|
|
8201
|
+
const fullPath = `${safeBase}/${fileRel}`;
|
|
8202
|
+
const ext = (fileRel.split(".").pop() ?? "").toLowerCase();
|
|
8203
|
+
const format = FORMAT_BY_EXT[ext];
|
|
8204
|
+
if (format === void 0) continue;
|
|
8205
|
+
const raw = await adapter.readFile(fullPath);
|
|
8206
|
+
if (raw === null) continue;
|
|
8207
|
+
const sizeBytes = byteLength3(raw);
|
|
8208
|
+
const meta = { format, size: sizeBytes };
|
|
8209
|
+
if (format === "md" || format === "txt") {
|
|
8210
|
+
const fileSections = splitSections(raw, fileRel);
|
|
8211
|
+
sections.push(...fileSections);
|
|
8212
|
+
const wikiLinks = extractWikiLinks(raw);
|
|
8213
|
+
if (wikiLinks.length > 0) meta.wikiLinks = wikiLinks;
|
|
8214
|
+
}
|
|
8215
|
+
filesMeta[fileRel] = meta;
|
|
8216
|
+
}
|
|
8217
|
+
return {
|
|
8218
|
+
schema: "v1",
|
|
8219
|
+
base: safeBase,
|
|
8220
|
+
builtAt: options.nowIso ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
8221
|
+
fileCount: Object.keys(filesMeta).length,
|
|
8222
|
+
sections,
|
|
8223
|
+
files: filesMeta
|
|
8224
|
+
};
|
|
8225
|
+
}
|
|
8226
|
+
async function writeKnowledgeIndex(options) {
|
|
8227
|
+
const index = await buildKnowledgeIndex(options);
|
|
8228
|
+
await options.adapter.writeFile(`${index.base}/_index.json`, JSON.stringify(index, null, 2));
|
|
8229
|
+
return index;
|
|
8230
|
+
}
|
|
8231
|
+
async function listFilesRecursive(adapter, dir) {
|
|
8232
|
+
const out = [];
|
|
8233
|
+
const stack = [""];
|
|
8234
|
+
while (stack.length > 0) {
|
|
8235
|
+
const sub = stack.pop();
|
|
8236
|
+
const fullDir = sub === "" ? dir : `${dir}/${sub}`;
|
|
8237
|
+
let entries = [];
|
|
8238
|
+
try {
|
|
8239
|
+
entries = await adapter.listDir(fullDir);
|
|
8240
|
+
} catch {
|
|
8241
|
+
continue;
|
|
8242
|
+
}
|
|
8243
|
+
for (const name of entries) {
|
|
8244
|
+
const childRel = sub === "" ? name : `${sub}/${name}`;
|
|
8245
|
+
const childFull = `${dir}/${childRel}`;
|
|
8246
|
+
const isDir = await adapter.isDirectory(childFull).catch(() => false);
|
|
8247
|
+
if (isDir) {
|
|
8248
|
+
stack.push(childRel);
|
|
8249
|
+
} else {
|
|
8250
|
+
out.push(childRel);
|
|
8251
|
+
}
|
|
8252
|
+
}
|
|
8253
|
+
}
|
|
8254
|
+
return out.sort();
|
|
8255
|
+
}
|
|
8256
|
+
function splitSections(content, relPath) {
|
|
8257
|
+
const lines = content.split(/\r?\n/);
|
|
8258
|
+
const out = [];
|
|
8259
|
+
const heads = [];
|
|
8260
|
+
for (let i = 0; i < lines.length; i++) {
|
|
8261
|
+
const line = lines[i];
|
|
8262
|
+
const m = HEADING_RE.exec(line);
|
|
8263
|
+
if (m) heads.push({ line: i + 1, depth: m[1].length, heading: m[2].trim() });
|
|
8264
|
+
}
|
|
8265
|
+
const leadInEndLine = heads.length > 0 ? heads[0].line - 1 : lines.length;
|
|
8266
|
+
const leadInBody = lines.slice(0, leadInEndLine).join("\n").trim();
|
|
8267
|
+
if (leadInBody.length > 0) {
|
|
8268
|
+
out.push({
|
|
8269
|
+
relPath,
|
|
8270
|
+
heading: "",
|
|
8271
|
+
slug: `${relPath}#`,
|
|
8272
|
+
depth: 0,
|
|
8273
|
+
words: tokenize(leadInBody),
|
|
8274
|
+
preview: makePreview(leadInBody),
|
|
8275
|
+
startLine: 1,
|
|
8276
|
+
endLine: leadInEndLine
|
|
8277
|
+
});
|
|
8278
|
+
}
|
|
8279
|
+
for (let i = 0; i < heads.length; i++) {
|
|
8280
|
+
const h = heads[i];
|
|
8281
|
+
const startLine = h.line;
|
|
8282
|
+
const endLine = i + 1 < heads.length ? heads[i + 1].line - 1 : lines.length;
|
|
8283
|
+
const body = lines.slice(startLine - 1, endLine).join("\n");
|
|
8284
|
+
out.push({
|
|
8285
|
+
relPath,
|
|
8286
|
+
heading: h.heading,
|
|
8287
|
+
slug: `${relPath}#${slugify(h.heading)}`,
|
|
8288
|
+
depth: h.depth,
|
|
8289
|
+
words: tokenize(body),
|
|
8290
|
+
preview: makePreview(body),
|
|
8291
|
+
startLine,
|
|
8292
|
+
endLine
|
|
8293
|
+
});
|
|
8294
|
+
}
|
|
8295
|
+
return out;
|
|
8296
|
+
}
|
|
8297
|
+
function makePreview(body) {
|
|
8298
|
+
const trimmed = body.replace(/^#{1,6}\s+.+$\r?\n?/m, "").trim();
|
|
8299
|
+
if (trimmed.length <= PREVIEW_CHARS) return trimmed;
|
|
8300
|
+
return trimmed.slice(0, PREVIEW_CHARS) + "\u2026";
|
|
8301
|
+
}
|
|
8302
|
+
function slugify(text2) {
|
|
8303
|
+
return text2.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
8304
|
+
}
|
|
8305
|
+
function extractWikiLinks(text2) {
|
|
8306
|
+
const seen = /* @__PURE__ */ new Set();
|
|
8307
|
+
let m;
|
|
8308
|
+
WIKI_LINK_RE.lastIndex = 0;
|
|
8309
|
+
while ((m = WIKI_LINK_RE.exec(text2)) !== null) {
|
|
8310
|
+
const target = m[1].trim();
|
|
8311
|
+
if (target.length > 0) seen.add(target);
|
|
8312
|
+
}
|
|
8313
|
+
return [...seen].sort();
|
|
8314
|
+
}
|
|
8315
|
+
function byteLength3(s) {
|
|
8316
|
+
return new TextEncoder().encode(s).byteLength;
|
|
8317
|
+
}
|
|
8318
|
+
|
|
8319
|
+
// src/knowledge/scope.ts
|
|
8320
|
+
init_esm_shims();
|
|
8321
|
+
var SAFE_PATH_RE = /^[a-zA-Z0-9_\-./]+$/;
|
|
8322
|
+
function parseFolderRef(raw) {
|
|
8323
|
+
if (typeof raw !== "string" || raw.length === 0) {
|
|
8324
|
+
throw new Error(`invalid knowledge folder ref: empty`);
|
|
8325
|
+
}
|
|
8326
|
+
if (raw.startsWith("/")) {
|
|
8327
|
+
throw new Error(`invalid knowledge folder ref: absolute paths not allowed ("${raw}")`);
|
|
8328
|
+
}
|
|
8329
|
+
const trimmed = raw.replace(/\/+$/g, "");
|
|
8330
|
+
if (trimmed.length === 0) {
|
|
8331
|
+
throw new Error(`invalid knowledge folder ref: "${raw}"`);
|
|
8332
|
+
}
|
|
8333
|
+
if (!SAFE_PATH_RE.test(trimmed)) {
|
|
8334
|
+
throw new Error(`invalid knowledge folder ref: unsafe characters in "${raw}"`);
|
|
8335
|
+
}
|
|
8336
|
+
if (trimmed.split("/").some((seg) => seg === ".." || seg === "." || seg === "")) {
|
|
8337
|
+
throw new Error(`invalid knowledge folder ref: traversal in "${raw}"`);
|
|
8338
|
+
}
|
|
8339
|
+
const segs = trimmed.split("/");
|
|
8340
|
+
const base = segs[0];
|
|
8341
|
+
const subPath = segs.slice(1).join("/");
|
|
8342
|
+
return { path: trimmed, base, subPath };
|
|
8343
|
+
}
|
|
8344
|
+
function relPathInScope(folder, relPath) {
|
|
8345
|
+
if (folder.subPath === "") return true;
|
|
8346
|
+
return relPath === folder.subPath || relPath.startsWith(`${folder.subPath}/`);
|
|
8347
|
+
}
|
|
8348
|
+
function parseKnowledgeRef(raw) {
|
|
8349
|
+
if (typeof raw !== "string" || raw.length === 0) {
|
|
8350
|
+
throw new Error("invalid knowledge ref: empty");
|
|
8351
|
+
}
|
|
8352
|
+
if (raw.startsWith("ext:")) {
|
|
8353
|
+
const name = raw.slice("ext:".length);
|
|
8354
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(name) || name.length === 0) {
|
|
8355
|
+
throw new Error(`invalid knowledge ref: external name "${name}" has unsafe characters`);
|
|
8356
|
+
}
|
|
8357
|
+
return { kind: "ext", target: name };
|
|
8358
|
+
}
|
|
8359
|
+
if (raw.startsWith("/")) {
|
|
8360
|
+
throw new Error(`invalid knowledge ref: absolute paths not allowed ("${raw}")`);
|
|
8361
|
+
}
|
|
8362
|
+
const hashAt = raw.indexOf("#");
|
|
8363
|
+
const filePath = hashAt === -1 ? raw : raw.slice(0, hashAt);
|
|
8364
|
+
const section = hashAt === -1 ? void 0 : raw.slice(hashAt + 1);
|
|
8365
|
+
if (!SAFE_PATH_RE.test(filePath)) {
|
|
8366
|
+
throw new Error(`invalid knowledge ref: unsafe characters in "${filePath}"`);
|
|
8367
|
+
}
|
|
8368
|
+
if (filePath.split("/").some((seg) => seg === ".." || seg === "." || seg === "")) {
|
|
8369
|
+
throw new Error(`invalid knowledge ref: traversal in "${filePath}"`);
|
|
8370
|
+
}
|
|
8371
|
+
if (section !== void 0) {
|
|
8372
|
+
if (section.length > 0 && !/^[a-zA-Z0-9_-]+$/.test(section)) {
|
|
8373
|
+
throw new Error(`invalid knowledge ref: unsafe characters in section "${section}"`);
|
|
8374
|
+
}
|
|
8375
|
+
return { kind: "section", target: filePath, section };
|
|
8376
|
+
}
|
|
8377
|
+
return { kind: "file", target: filePath };
|
|
8378
|
+
}
|
|
8379
|
+
function refInScope(folders, filePath) {
|
|
8380
|
+
return folders.some((f) => {
|
|
8381
|
+
if (filePath === f.base || filePath.startsWith(`${f.base}/`)) {
|
|
8382
|
+
const relInBase = filePath === f.base ? "" : filePath.slice(f.base.length + 1);
|
|
8383
|
+
return relPathInScope(f, relInBase);
|
|
8384
|
+
}
|
|
8385
|
+
return false;
|
|
8386
|
+
});
|
|
8387
|
+
}
|
|
8388
|
+
|
|
8250
8389
|
// src/tools/searchKnowledge.ts
|
|
8251
8390
|
var DEFAULT_MAX_RESULTS = 5;
|
|
8252
8391
|
var inputSchema18 = z26.object({
|
|
@@ -8331,17 +8470,24 @@ function truncatePreview(s) {
|
|
|
8331
8470
|
async function loadIndex(adapter, base, cache) {
|
|
8332
8471
|
const cached2 = cache.get(base);
|
|
8333
8472
|
if (cached2 !== void 0) return cached2;
|
|
8334
|
-
let raw;
|
|
8473
|
+
let raw = null;
|
|
8335
8474
|
try {
|
|
8336
8475
|
raw = await adapter.readFile(`${base}/_index.json`);
|
|
8337
8476
|
} catch {
|
|
8338
|
-
|
|
8477
|
+
raw = null;
|
|
8478
|
+
}
|
|
8479
|
+
if (raw !== null) {
|
|
8480
|
+
try {
|
|
8481
|
+
const parsed = JSON.parse(raw);
|
|
8482
|
+
cache.set(base, parsed);
|
|
8483
|
+
return parsed;
|
|
8484
|
+
} catch {
|
|
8485
|
+
}
|
|
8339
8486
|
}
|
|
8340
|
-
if (raw === null) return null;
|
|
8341
8487
|
try {
|
|
8342
|
-
const
|
|
8343
|
-
cache.set(base,
|
|
8344
|
-
return
|
|
8488
|
+
const built = await buildKnowledgeIndex({ adapter, base });
|
|
8489
|
+
cache.set(base, built);
|
|
8490
|
+
return built;
|
|
8345
8491
|
} catch {
|
|
8346
8492
|
return null;
|
|
8347
8493
|
}
|
|
@@ -8500,7 +8646,7 @@ function createReadKnowledgeTool(opts) {
|
|
|
8500
8646
|
const idx = await loadIndex2(opts.adapter, base, indexCache);
|
|
8501
8647
|
if (idx === null) {
|
|
8502
8648
|
return {
|
|
8503
|
-
content: `
|
|
8649
|
+
content: `ERR_KNOWLEDGE_REF_NOT_FOUND: base "${base}" has no readable files`,
|
|
8504
8650
|
isError: true
|
|
8505
8651
|
};
|
|
8506
8652
|
}
|
|
@@ -8606,17 +8752,24 @@ ${payload}`,
|
|
|
8606
8752
|
async function loadIndex2(adapter, base, cache) {
|
|
8607
8753
|
const cached2 = cache.get(base);
|
|
8608
8754
|
if (cached2 !== void 0) return cached2;
|
|
8609
|
-
let raw;
|
|
8755
|
+
let raw = null;
|
|
8610
8756
|
try {
|
|
8611
8757
|
raw = await adapter.readFile(`${base}/_index.json`);
|
|
8612
8758
|
} catch {
|
|
8613
|
-
|
|
8759
|
+
raw = null;
|
|
8760
|
+
}
|
|
8761
|
+
if (raw !== null) {
|
|
8762
|
+
try {
|
|
8763
|
+
const idx = JSON.parse(raw);
|
|
8764
|
+
cache.set(base, idx);
|
|
8765
|
+
return idx;
|
|
8766
|
+
} catch {
|
|
8767
|
+
}
|
|
8614
8768
|
}
|
|
8615
|
-
if (raw === null) return null;
|
|
8616
8769
|
try {
|
|
8617
|
-
const
|
|
8618
|
-
cache.set(base,
|
|
8619
|
-
return
|
|
8770
|
+
const built = await buildKnowledgeIndex({ adapter, base });
|
|
8771
|
+
cache.set(base, built);
|
|
8772
|
+
return built;
|
|
8620
8773
|
} catch {
|
|
8621
8774
|
return null;
|
|
8622
8775
|
}
|
|
@@ -11147,153 +11300,6 @@ function buildToolRegistry(options) {
|
|
|
11147
11300
|
// src/index.ts
|
|
11148
11301
|
init_contract();
|
|
11149
11302
|
init_fetchData();
|
|
11150
|
-
|
|
11151
|
-
// src/knowledge/indexer.ts
|
|
11152
|
-
init_esm_shims();
|
|
11153
|
-
var HEADING_RE = /^(#{1,6})[ \t]+(.+?)\s*$/;
|
|
11154
|
-
var WIKI_LINK_RE = /\[\[([^\]|#]+)(?:[#|][^\]]*)?\]\]/g;
|
|
11155
|
-
var FORMAT_BY_EXT = {
|
|
11156
|
-
md: "md",
|
|
11157
|
-
markdown: "md",
|
|
11158
|
-
txt: "txt",
|
|
11159
|
-
json: "json",
|
|
11160
|
-
csv: "csv",
|
|
11161
|
-
html: "html",
|
|
11162
|
-
htm: "html",
|
|
11163
|
-
pdf: "pdf",
|
|
11164
|
-
docx: "docx"
|
|
11165
|
-
};
|
|
11166
|
-
var PREVIEW_CHARS = 200;
|
|
11167
|
-
async function buildKnowledgeIndex(options) {
|
|
11168
|
-
const { adapter, base } = options;
|
|
11169
|
-
const safeBase = base.replace(/^\/+|\/+$/g, "");
|
|
11170
|
-
if (safeBase.length === 0 || safeBase.includes("..")) {
|
|
11171
|
-
throw new Error(`buildKnowledgeIndex: invalid base "${base}"`);
|
|
11172
|
-
}
|
|
11173
|
-
const files = await listFilesRecursive(adapter, safeBase);
|
|
11174
|
-
const sections = [];
|
|
11175
|
-
const filesMeta = {};
|
|
11176
|
-
for (const fileRel of files) {
|
|
11177
|
-
if (fileRel === "_index.json") continue;
|
|
11178
|
-
const fullPath = `${safeBase}/${fileRel}`;
|
|
11179
|
-
const ext = (fileRel.split(".").pop() ?? "").toLowerCase();
|
|
11180
|
-
const format = FORMAT_BY_EXT[ext];
|
|
11181
|
-
if (format === void 0) continue;
|
|
11182
|
-
const raw = await adapter.readFile(fullPath);
|
|
11183
|
-
if (raw === null) continue;
|
|
11184
|
-
const sizeBytes = byteLength3(raw);
|
|
11185
|
-
const meta = { format, size: sizeBytes };
|
|
11186
|
-
if (format === "md" || format === "txt") {
|
|
11187
|
-
const fileSections = splitSections(raw, fileRel);
|
|
11188
|
-
sections.push(...fileSections);
|
|
11189
|
-
const wikiLinks = extractWikiLinks(raw);
|
|
11190
|
-
if (wikiLinks.length > 0) meta.wikiLinks = wikiLinks;
|
|
11191
|
-
}
|
|
11192
|
-
filesMeta[fileRel] = meta;
|
|
11193
|
-
}
|
|
11194
|
-
return {
|
|
11195
|
-
schema: "v1",
|
|
11196
|
-
base: safeBase,
|
|
11197
|
-
builtAt: options.nowIso ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
11198
|
-
fileCount: Object.keys(filesMeta).length,
|
|
11199
|
-
sections,
|
|
11200
|
-
files: filesMeta
|
|
11201
|
-
};
|
|
11202
|
-
}
|
|
11203
|
-
async function writeKnowledgeIndex(options) {
|
|
11204
|
-
const index = await buildKnowledgeIndex(options);
|
|
11205
|
-
await options.adapter.writeFile(`${index.base}/_index.json`, JSON.stringify(index, null, 2));
|
|
11206
|
-
return index;
|
|
11207
|
-
}
|
|
11208
|
-
async function listFilesRecursive(adapter, dir) {
|
|
11209
|
-
const out = [];
|
|
11210
|
-
const stack = [""];
|
|
11211
|
-
while (stack.length > 0) {
|
|
11212
|
-
const sub = stack.pop();
|
|
11213
|
-
const fullDir = sub === "" ? dir : `${dir}/${sub}`;
|
|
11214
|
-
let entries = [];
|
|
11215
|
-
try {
|
|
11216
|
-
entries = await adapter.listDir(fullDir);
|
|
11217
|
-
} catch {
|
|
11218
|
-
continue;
|
|
11219
|
-
}
|
|
11220
|
-
for (const name of entries) {
|
|
11221
|
-
const childRel = sub === "" ? name : `${sub}/${name}`;
|
|
11222
|
-
const childFull = `${dir}/${childRel}`;
|
|
11223
|
-
const isDir = await adapter.isDirectory(childFull).catch(() => false);
|
|
11224
|
-
if (isDir) {
|
|
11225
|
-
stack.push(childRel);
|
|
11226
|
-
} else {
|
|
11227
|
-
out.push(childRel);
|
|
11228
|
-
}
|
|
11229
|
-
}
|
|
11230
|
-
}
|
|
11231
|
-
return out.sort();
|
|
11232
|
-
}
|
|
11233
|
-
function splitSections(content, relPath) {
|
|
11234
|
-
const lines = content.split(/\r?\n/);
|
|
11235
|
-
const out = [];
|
|
11236
|
-
const heads = [];
|
|
11237
|
-
for (let i = 0; i < lines.length; i++) {
|
|
11238
|
-
const line = lines[i];
|
|
11239
|
-
const m = HEADING_RE.exec(line);
|
|
11240
|
-
if (m) heads.push({ line: i + 1, depth: m[1].length, heading: m[2].trim() });
|
|
11241
|
-
}
|
|
11242
|
-
const leadInEndLine = heads.length > 0 ? heads[0].line - 1 : lines.length;
|
|
11243
|
-
const leadInBody = lines.slice(0, leadInEndLine).join("\n").trim();
|
|
11244
|
-
if (leadInBody.length > 0) {
|
|
11245
|
-
out.push({
|
|
11246
|
-
relPath,
|
|
11247
|
-
heading: "",
|
|
11248
|
-
slug: `${relPath}#`,
|
|
11249
|
-
depth: 0,
|
|
11250
|
-
words: tokenize(leadInBody),
|
|
11251
|
-
preview: makePreview(leadInBody),
|
|
11252
|
-
startLine: 1,
|
|
11253
|
-
endLine: leadInEndLine
|
|
11254
|
-
});
|
|
11255
|
-
}
|
|
11256
|
-
for (let i = 0; i < heads.length; i++) {
|
|
11257
|
-
const h = heads[i];
|
|
11258
|
-
const startLine = h.line;
|
|
11259
|
-
const endLine = i + 1 < heads.length ? heads[i + 1].line - 1 : lines.length;
|
|
11260
|
-
const body = lines.slice(startLine - 1, endLine).join("\n");
|
|
11261
|
-
out.push({
|
|
11262
|
-
relPath,
|
|
11263
|
-
heading: h.heading,
|
|
11264
|
-
slug: `${relPath}#${slugify(h.heading)}`,
|
|
11265
|
-
depth: h.depth,
|
|
11266
|
-
words: tokenize(body),
|
|
11267
|
-
preview: makePreview(body),
|
|
11268
|
-
startLine,
|
|
11269
|
-
endLine
|
|
11270
|
-
});
|
|
11271
|
-
}
|
|
11272
|
-
return out;
|
|
11273
|
-
}
|
|
11274
|
-
function makePreview(body) {
|
|
11275
|
-
const trimmed = body.replace(/^#{1,6}\s+.+$\r?\n?/m, "").trim();
|
|
11276
|
-
if (trimmed.length <= PREVIEW_CHARS) return trimmed;
|
|
11277
|
-
return trimmed.slice(0, PREVIEW_CHARS) + "\u2026";
|
|
11278
|
-
}
|
|
11279
|
-
function slugify(text2) {
|
|
11280
|
-
return text2.toLowerCase().trim().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
11281
|
-
}
|
|
11282
|
-
function extractWikiLinks(text2) {
|
|
11283
|
-
const seen = /* @__PURE__ */ new Set();
|
|
11284
|
-
let m;
|
|
11285
|
-
WIKI_LINK_RE.lastIndex = 0;
|
|
11286
|
-
while ((m = WIKI_LINK_RE.exec(text2)) !== null) {
|
|
11287
|
-
const target = m[1].trim();
|
|
11288
|
-
if (target.length > 0) seen.add(target);
|
|
11289
|
-
}
|
|
11290
|
-
return [...seen].sort();
|
|
11291
|
-
}
|
|
11292
|
-
function byteLength3(s) {
|
|
11293
|
-
return new TextEncoder().encode(s).byteLength;
|
|
11294
|
-
}
|
|
11295
|
-
|
|
11296
|
-
// src/index.ts
|
|
11297
11303
|
init_orchestrate();
|
|
11298
11304
|
init_planParser();
|
|
11299
11305
|
init_retry();
|