@autorag/librarian 2.5.2 → 2.5.3
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 +7 -6
- package/dist/agent/agent.d.ts +9 -14
- package/dist/agent/index.d.ts +1 -2
- package/dist/agent/search-single-datasource-tool.d.ts +14 -8
- package/dist/cli/index.js +2130 -1057
- package/dist/core.js +1711 -665
- package/dist/datasource/errors.d.ts +1 -1
- package/dist/datasource/index.d.ts +3 -2
- package/dist/datasource/skills/discrawl/skill.d.ts +1 -1
- package/dist/datasource/skills/discrawl/types.d.ts +2 -2
- package/dist/datasource/skills/github-gist/connector.d.ts +38 -0
- package/dist/datasource/skills/github-gist/index.d.ts +3 -0
- package/dist/datasource/skills/github-gist/semantic.d.ts +102 -0
- package/dist/datasource/skills/github-gist/skill.d.ts +39 -0
- package/dist/datasource/skills/lark/client.d.ts +23 -0
- package/dist/datasource/skills/lark/index.d.ts +2 -0
- package/dist/datasource/skills/lark/skill.d.ts +36 -0
- package/dist/datasource/skills/lazykatok/client.d.ts +28 -0
- package/dist/datasource/skills/lazykatok/index.d.ts +12 -0
- package/dist/datasource/skills/{katok → lazykatok}/methods.d.ts +12 -12
- package/dist/datasource/skills/lazykatok/paths.d.ts +40 -0
- package/dist/datasource/skills/{katok → lazykatok}/skill.d.ts +10 -10
- package/dist/datasource/skills/lazykatok/types.d.ts +134 -0
- package/dist/datasource/skills/mailcrawl/client.d.ts +2 -0
- package/dist/datasource/skills/mailcrawl/types.d.ts +12 -0
- package/dist/datasource/types.d.ts +4 -4
- package/dist/embedding-runtime/manifest.d.ts +8 -0
- package/dist/embedding-runtime/types.d.ts +4 -0
- package/dist/index.js +1719 -671
- package/dist/process/terminate-tree.d.ts +2 -0
- package/dist/retrieval/types.d.ts +1 -1
- package/licenses/embedding-assets.json +20 -4
- package/package.json +1 -1
- package/skills/autorag-doctor/SKILL.md +4 -3
- package/skills/autorag-lite-setup/SKILL.md +2 -2
- package/skills/autorag-setup/SKILL.md +9 -6
- package/dist/agent/search-datasource-tool.d.ts +0 -30
- package/dist/datasource/skills/katok/client.d.ts +0 -21
- package/dist/datasource/skills/katok/index.d.ts +0 -12
- package/dist/datasource/skills/katok/paths.d.ts +0 -40
- package/dist/datasource/skills/katok/types.d.ts +0 -123
package/dist/index.js
CHANGED
|
@@ -3826,14 +3826,22 @@ var init_manifest = __esm(() => {
|
|
|
3826
3826
|
revision: "370f27d7550e0def9b39c1f16d3fbaa13aa67728",
|
|
3827
3827
|
sha256: "06507c7b42688469c4e7298b0a1e16deff06caf291cf0a5b278c308249c3e439",
|
|
3828
3828
|
license: "Apache-2.0",
|
|
3829
|
-
noticeReference: "Qwen3 model card and Apache-2.0 license"
|
|
3829
|
+
noticeReference: "Qwen3 model card and Apache-2.0 license",
|
|
3830
|
+
intendedUse: "Local loopback embedding for AutoRAG MinSync and native-datasource semantic retrieval. Not a generative model.",
|
|
3831
|
+
unsuitableUse: "Chat or generation, remote embedding of corpus text, shipping weights in the npm package, any GGUF other than the pinned SHA-256.",
|
|
3832
|
+
upstreamCardUrl: "https://huggingface.co/Qwen/Qwen3-Embedding-0.6B",
|
|
3833
|
+
modelCard: "docs/model-cards/qwen3-embedding-0.6b.md"
|
|
3830
3834
|
},
|
|
3831
3835
|
embeddinggemma: {
|
|
3832
3836
|
url: "https://huggingface.co/ggml-org/embeddinggemma-300M-GGUF/resolve/0f741b5a6585bd53aeb15cd1372c56f2a0f65e12/embeddinggemma-300M-Q8_0.gguf",
|
|
3833
3837
|
revision: "0f741b5a6585bd53aeb15cd1372c56f2a0f65e12",
|
|
3834
3838
|
sha256: "b5ce9d77a3fc4b3b39ccb5643c36777911cc4eb46a66962eadfa3f5f60490d63",
|
|
3835
3839
|
license: "Gemma Terms of Use",
|
|
3836
|
-
noticeReference: "Google EmbeddingGemma model card and Gemma Terms of Use"
|
|
3840
|
+
noticeReference: "Google EmbeddingGemma model card and Gemma Terms of Use",
|
|
3841
|
+
intendedUse: "Local loopback embedding for AutoRAG MinSync and native-datasource semantic retrieval. Not a generative model.",
|
|
3842
|
+
unsuitableUse: "Chat or generation, remote embedding of corpus text, shipping weights in the npm package, any GGUF other than the pinned SHA-256, uses restricted by the Gemma Prohibited Use Policy.",
|
|
3843
|
+
upstreamCardUrl: "https://ai.google.dev/gemma/docs/embeddinggemma/model_card",
|
|
3844
|
+
modelCard: "docs/model-cards/embeddinggemma-300m.md"
|
|
3837
3845
|
}
|
|
3838
3846
|
};
|
|
3839
3847
|
});
|
|
@@ -9243,68 +9251,8 @@ var init_search_all_tool = __esm(() => {
|
|
|
9243
9251
|
});
|
|
9244
9252
|
});
|
|
9245
9253
|
|
|
9246
|
-
// src/agent/search-datasource-tool.ts
|
|
9247
|
-
import { Type as Type12 } from "typebox";
|
|
9248
|
-
function createSearchDatasourceDocumentsTool(provider) {
|
|
9249
|
-
return {
|
|
9250
|
-
name: SEARCH_DATASOURCE_DOCUMENTS_TOOL_NAME,
|
|
9251
|
-
label: "Search Datasource Documents",
|
|
9252
|
-
description: "Search configured external datasource skills such as cloud drives and KakaoTalk chats, fanning out to every datasource CLI. When the question targets one connection, prefer its dedicated search_datasource_<name> tool, which spawns only that connection's CLIs. Load the matching datasource skill first; authority is server-configured and tool arguments can only provide query, topK, and an optional narrowing scope.",
|
|
9253
|
-
parameters: searchDatasourceSchema,
|
|
9254
|
-
async execute(_toolCallId, params) {
|
|
9255
|
-
const query = params.query.trim();
|
|
9256
|
-
if (query.length === 0) {
|
|
9257
|
-
return {
|
|
9258
|
-
content: [{ type: "text", text: "Datasource query was empty; no datasource documents searched." }],
|
|
9259
|
-
details: { method: "datasource", resultCount: 0, sources: [], diagnostics: [] }
|
|
9260
|
-
};
|
|
9261
|
-
}
|
|
9262
|
-
const { results, diagnostics } = await provider.searchDatasourceDocuments(query, {
|
|
9263
|
-
topK: params.topK,
|
|
9264
|
-
scope: params.scope
|
|
9265
|
-
});
|
|
9266
|
-
return {
|
|
9267
|
-
content: [{ type: "text", text: formatDatasourceResults(results, diagnostics) }],
|
|
9268
|
-
details: {
|
|
9269
|
-
method: "datasource",
|
|
9270
|
-
resultCount: results.length,
|
|
9271
|
-
sources: [...new Set(results.map((result) => result.source))],
|
|
9272
|
-
diagnostics,
|
|
9273
|
-
results: toRetrievalTraceResults(results)
|
|
9274
|
-
}
|
|
9275
|
-
};
|
|
9276
|
-
}
|
|
9277
|
-
};
|
|
9278
|
-
}
|
|
9279
|
-
function formatDatasourceResults(results, diagnostics) {
|
|
9280
|
-
const diagnosticSummary = diagnostics.length > 0 ? `
|
|
9281
|
-
|
|
9282
|
-
Diagnostics: ${diagnostics.map((d) => `${d.source ?? "datasource"}:${d.code}`).join(", ")}` : "";
|
|
9283
|
-
if (results.length === 0)
|
|
9284
|
-
return `No datasource results.${diagnosticSummary}`;
|
|
9285
|
-
const rows = results.map((result, index) => {
|
|
9286
|
-
const line = result.content.replace(/\s+/gu, " ").slice(0, 500);
|
|
9287
|
-
return `[${index + 1}] ${result.source} score=${result.score.toFixed(4)}
|
|
9288
|
-
${line}`;
|
|
9289
|
-
});
|
|
9290
|
-
return `Datasource results:
|
|
9291
|
-
|
|
9292
|
-
${rows.join(`
|
|
9293
|
-
|
|
9294
|
-
`)}${diagnosticSummary}`;
|
|
9295
|
-
}
|
|
9296
|
-
var SEARCH_DATASOURCE_DOCUMENTS_TOOL_NAME = "search_datasource_documents", searchDatasourceSchema;
|
|
9297
|
-
var init_search_datasource_tool = __esm(() => {
|
|
9298
|
-
init_search_documents();
|
|
9299
|
-
searchDatasourceSchema = Type12.Object({
|
|
9300
|
-
query: Type12.String({ description: "Query to search across configured external datasource skills." }),
|
|
9301
|
-
topK: Type12.Optional(Type12.Integer({ description: "Maximum number of datasource chunks to return. Defaults to 50." })),
|
|
9302
|
-
scope: Type12.Optional(Type12.String({ description: "Optional opaque datasource scope, e.g. /kakao/account or /kakao/account/**." }))
|
|
9303
|
-
});
|
|
9304
|
-
});
|
|
9305
|
-
|
|
9306
9254
|
// src/agent/search-minsync-tool.ts
|
|
9307
|
-
import { Type as
|
|
9255
|
+
import { Type as Type12 } from "typebox";
|
|
9308
9256
|
function createSearchMinSyncDocumentsTool(getMethod, resolveScope = (scope) => scope) {
|
|
9309
9257
|
return {
|
|
9310
9258
|
name: SEARCH_MINSYNC_DOCUMENTS_TOOL_NAME,
|
|
@@ -9375,12 +9323,12 @@ ${rows.join(`
|
|
|
9375
9323
|
var SEARCH_MINSYNC_DOCUMENTS_TOOL_NAME = "semantic_search_local_docs", searchMinSyncSchema;
|
|
9376
9324
|
var init_search_minsync_tool = __esm(() => {
|
|
9377
9325
|
init_search_documents();
|
|
9378
|
-
searchMinSyncSchema =
|
|
9379
|
-
query:
|
|
9326
|
+
searchMinSyncSchema = Type12.Object({
|
|
9327
|
+
query: Type12.String({
|
|
9380
9328
|
description: "Semantic query to search parsed document mirrors with MinSync vector retrieval."
|
|
9381
9329
|
}),
|
|
9382
|
-
topK:
|
|
9383
|
-
scope:
|
|
9330
|
+
topK: Type12.Optional(Type12.Integer({ description: "Maximum number of MinSync semantic chunks to return. Defaults to 50." })),
|
|
9331
|
+
scope: Type12.Optional(Type12.String({ description: "Optional opaque virtual-path scope, e.g. /docs or /docs/**." }))
|
|
9384
9332
|
});
|
|
9385
9333
|
});
|
|
9386
9334
|
|
|
@@ -9398,7 +9346,7 @@ function datasourceSearchToolName(datasourceId) {
|
|
|
9398
9346
|
}
|
|
9399
9347
|
|
|
9400
9348
|
// src/agent/search-single-datasource-tool.ts
|
|
9401
|
-
import { Type as
|
|
9349
|
+
import { Type as Type13 } from "typebox";
|
|
9402
9350
|
function createSingleDatasourceSearchTools(provider, specs) {
|
|
9403
9351
|
return specs.map((spec) => createTool(provider, spec));
|
|
9404
9352
|
}
|
|
@@ -9407,7 +9355,7 @@ function createTool(provider, spec) {
|
|
|
9407
9355
|
return {
|
|
9408
9356
|
name: singleDatasourceToolName(spec.datasourceId),
|
|
9409
9357
|
label: `Search ${spec.datasourceId}`,
|
|
9410
|
-
description: `Search only the "${spec.datasourceId}" datasource connection: ${spec.description} ` + `
|
|
9358
|
+
description: `Search only the "${spec.datasourceId}" datasource connection: ${spec.description} ` + `This tool spawns only this connection's CLIs and returns only this connection's hits.${scopeLine} ` + `Authority is server-configured; tool arguments can only provide query, topK, and an optional narrowing scope.`,
|
|
9411
9359
|
parameters: searchSingleDatasourceSchema,
|
|
9412
9360
|
async execute(_toolCallId, params) {
|
|
9413
9361
|
const query = params.query.trim();
|
|
@@ -9441,15 +9389,31 @@ function createTool(provider, spec) {
|
|
|
9441
9389
|
}
|
|
9442
9390
|
};
|
|
9443
9391
|
}
|
|
9392
|
+
function formatDatasourceResults(results, diagnostics) {
|
|
9393
|
+
const diagnosticSummary = diagnostics.length > 0 ? `
|
|
9394
|
+
|
|
9395
|
+
Diagnostics: ${diagnostics.map((d) => `${d.source ?? "datasource"}:${d.code}`).join(", ")}` : "";
|
|
9396
|
+
if (results.length === 0)
|
|
9397
|
+
return `No datasource results.${diagnosticSummary}`;
|
|
9398
|
+
const rows = results.map((result, index) => {
|
|
9399
|
+
const line = result.content.replace(/\s+/gu, " ").slice(0, 500);
|
|
9400
|
+
return `[${index + 1}] ${result.source} score=${result.score.toFixed(4)}
|
|
9401
|
+
${line}`;
|
|
9402
|
+
});
|
|
9403
|
+
return `Datasource results:
|
|
9404
|
+
|
|
9405
|
+
${rows.join(`
|
|
9406
|
+
|
|
9407
|
+
`)}${diagnosticSummary}`;
|
|
9408
|
+
}
|
|
9444
9409
|
var singleDatasourceToolName, searchSingleDatasourceSchema;
|
|
9445
9410
|
var init_search_single_datasource_tool = __esm(() => {
|
|
9446
|
-
init_search_datasource_tool();
|
|
9447
9411
|
init_search_documents();
|
|
9448
9412
|
singleDatasourceToolName = datasourceSearchToolName;
|
|
9449
|
-
searchSingleDatasourceSchema =
|
|
9450
|
-
query:
|
|
9451
|
-
topK:
|
|
9452
|
-
scope:
|
|
9413
|
+
searchSingleDatasourceSchema = Type13.Object({
|
|
9414
|
+
query: Type13.String({ description: "Query to search within this datasource connection." }),
|
|
9415
|
+
topK: Type13.Optional(Type13.Integer({ description: "Maximum number of chunks to return. Defaults to 50." })),
|
|
9416
|
+
scope: Type13.Optional(Type13.String({ description: "Optional scope narrowing inside this datasource, e.g. one instance root." }))
|
|
9453
9417
|
});
|
|
9454
9418
|
});
|
|
9455
9419
|
|
|
@@ -9467,7 +9431,6 @@ function buildSystemPrompt(config) {
|
|
|
9467
9431
|
toolLine(config, "jikji_find", "local discovery through Jikji answer packs"),
|
|
9468
9432
|
toolLine(config, "search_all_documents", "fan out across every configured retrieval method and merge results"),
|
|
9469
9433
|
toolLine(config, "semantic_search_local_docs", "semantic MinSync search over parsed document mirrors"),
|
|
9470
|
-
toolLine(config, "search_datasource_documents", "search authorized external datasources; scope may only narrow access"),
|
|
9471
9434
|
toolLine(config, "load_datasource_skill", "load instructions for an authorized datasource"),
|
|
9472
9435
|
toolLine(config, "scan_duplicate_documents", "read-only dupey scan of configured local document roots"),
|
|
9473
9436
|
toolLine(config, "web_search", "search the public internet for current information beyond the local corpus and knowledge cutoff"),
|
|
@@ -9475,13 +9438,12 @@ function buildSystemPrompt(config) {
|
|
|
9475
9438
|
toolLine(config, "check_memory", "inspect advisory retrieval hints from prior feedback"),
|
|
9476
9439
|
toolLine(config, "recommend_peer_targets", "recommend local peer personas to ask about a topic without contacting them"),
|
|
9477
9440
|
toolLine(config, "emit_autorag_results", "return the final structured answer and number-to-source mapping"),
|
|
9478
|
-
...config.toolNames.filter((name) => name.startsWith("search_datasource_")
|
|
9441
|
+
...config.toolNames.filter((name) => name.startsWith("search_datasource_")).map((name) => `- **${name}**: search only the ${name.slice("search_datasource_".length).replace(/_/g, "-")} datasource connection, spawning no other datasource CLIs`),
|
|
9479
9442
|
...config.toolNames.filter((name) => ![
|
|
9480
9443
|
"bash",
|
|
9481
9444
|
"jikji_find",
|
|
9482
9445
|
"search_all_documents",
|
|
9483
9446
|
"semantic_search_local_docs",
|
|
9484
|
-
"search_datasource_documents",
|
|
9485
9447
|
"load_datasource_skill",
|
|
9486
9448
|
"scan_duplicate_documents",
|
|
9487
9449
|
"web_search",
|
|
@@ -9514,7 +9476,7 @@ ${FENCING_GUARD_LINE}
|
|
|
9514
9476
|
` : "";
|
|
9515
9477
|
const webResearch = toolAvailable(config, "web_search") || toolAvailable(config, "web_fetch") ? `## Web Research
|
|
9516
9478
|
|
|
9517
|
-
\`web_search\` searches the public internet for current information beyond the local corpus and the model's knowledge cutoff; prefer primary sources (official docs, papers) and corroborate key claims with multiple sources. \`web_fetch\` reads a specific http(s) URL as markdown/text — pages found via web_search, official docs, papers. web_fetch only accepts http(s) URLs: never local file paths (use bash) or datasource virtual ids such as /kakao/... (use
|
|
9479
|
+
\`web_search\` searches the public internet for current information beyond the local corpus and the model's knowledge cutoff; prefer primary sources (official docs, papers) and corroborate key claims with multiple sources. \`web_fetch\` reads a specific http(s) URL as markdown/text — pages found via web_search, official docs, papers. web_fetch only accepts http(s) URLs: never local file paths (use bash) or datasource virtual ids such as /kakao/... (use that connection's dedicated search_datasource_<id> tool). Keep result URLs for traceability. Web queries leave the machine: never include private corpus content or secrets in web_search queries or fetched URLs.
|
|
9518
9480
|
` : "";
|
|
9519
9481
|
return `You are AutoRAG, a ${modelId} librarian agent for document collections, cloud drives, images, and messenger history.
|
|
9520
9482
|
|
|
@@ -9543,7 +9505,7 @@ ${noSearchTools}
|
|
|
9543
9505
|
- Use MinSync lexical mode for exact terminology, MinSync vector search for semantic similarity, and \`search_all_documents\` when hybrid ranking over the same MinSync chunks can help.
|
|
9544
9506
|
- Use \`bash\` to read already-retrieved local files with cat/head/sed. find/grep/rg must be small and bounded: one already-known directory from retrieval, a tight pattern, and a cap (head, maxdepth, or file types). Never recursively scan a whole search root (Downloads, Documents, Desktop, or /); those calls miss the bash timeout and stall the search loop.
|
|
9545
9507
|
- If retrieval is empty, retry a simpler query or synonyms through retrieval tools first. Do not widen filesystem discovery to compensate.
|
|
9546
|
-
- Local retrieval sources are absolute filesystem paths and may be read with \`bash\` after verifying the returned path. Datasource retrieval sources use slash-prefixed virtual identifiers such as /kakao/..., /mailcrawl/..., /slack/..., /discord/..., and /github/...; they are not OS paths and must never be passed to \`cd\`, \`cat\`, or other filesystem tools. Search
|
|
9508
|
+
- Local retrieval sources are absolute filesystem paths and may be read with \`bash\` after verifying the returned path. Datasource retrieval sources use slash-prefixed virtual identifiers such as /kakao/..., /mailcrawl/..., /slack/..., /discord/..., and /github/...; they are not OS paths and must never be passed to \`cd\`, \`cat\`, or other filesystem tools. Search them through the connection's dedicated \`search_datasource_<id>\` tool and the loaded datasource skill/native CLI; every authorized connection has its own tool, and \`search_all_documents\` still spans all of them at once.
|
|
9547
9509
|
- When exploring local files and folders, actively use \`jikji_find\` as your primary discovery tool. Do not manually traverse folders with exploratory bash commands; reserve \`bash\` for targeted reading of identified files (cat, head, sed).
|
|
9548
9510
|
- When search results or evidence contain conflicting information, treat the freshest and most recent information as authoritative and correct.
|
|
9549
9511
|
- Cross-check important claims against the original source and preserve real source paths.
|
|
@@ -11586,7 +11548,7 @@ var init_render = __esm(() => {
|
|
|
11586
11548
|
});
|
|
11587
11549
|
|
|
11588
11550
|
// src/agent/web-fetch-tool.ts
|
|
11589
|
-
import { Type as
|
|
11551
|
+
import { Type as Type14 } from "typebox";
|
|
11590
11552
|
function truncateHead(output, maxBytes, maxLines) {
|
|
11591
11553
|
const lines = output.split(`
|
|
11592
11554
|
`);
|
|
@@ -11618,7 +11580,7 @@ function createWebFetchTool(options = {}) {
|
|
|
11618
11580
|
content: [
|
|
11619
11581
|
{
|
|
11620
11582
|
type: "text",
|
|
11621
|
-
text: `web_fetch only reads http(s) URLs; received "${url}". Local files belong to bash and datasource virtual ids to
|
|
11583
|
+
text: `web_fetch only reads http(s) URLs; received "${url}". Local files belong to bash and datasource virtual ids to their dedicated datasource search tools.`
|
|
11622
11584
|
}
|
|
11623
11585
|
],
|
|
11624
11586
|
details: {
|
|
@@ -11683,9 +11645,9 @@ var WEB_FETCH_TOOL_NAME = "web_fetch", FETCH_DEFAULT_MAX_LINES = 300, FETCH_MAX_
|
|
|
11683
11645
|
var init_web_fetch_tool = __esm(() => {
|
|
11684
11646
|
init_render();
|
|
11685
11647
|
FETCH_MAX_OUTPUT_BYTES = 50 * 1024;
|
|
11686
|
-
webFetchSchema =
|
|
11687
|
-
url:
|
|
11688
|
-
raw:
|
|
11648
|
+
webFetchSchema = Type14.Object({
|
|
11649
|
+
url: Type14.String({ description: "The http(s) URL to fetch and read." }),
|
|
11650
|
+
raw: Type14.Optional(Type14.Boolean({ description: "Return the raw response body without markdown rendering or formatting." }))
|
|
11689
11651
|
});
|
|
11690
11652
|
});
|
|
11691
11653
|
|
|
@@ -15205,7 +15167,7 @@ var init_search = __esm(() => {
|
|
|
15205
15167
|
});
|
|
15206
15168
|
|
|
15207
15169
|
// src/agent/web-search-tool.ts
|
|
15208
|
-
import { Type as
|
|
15170
|
+
import { Type as Type15 } from "typebox";
|
|
15209
15171
|
function createWebSearchTool(options = {}) {
|
|
15210
15172
|
return {
|
|
15211
15173
|
name: WEB_SEARCH_TOOL_NAME,
|
|
@@ -15275,15 +15237,15 @@ function createWebSearchTool(options = {}) {
|
|
|
15275
15237
|
var WEB_SEARCH_TOOL_NAME = "web_search", webSearchSchema;
|
|
15276
15238
|
var init_web_search_tool = __esm(() => {
|
|
15277
15239
|
init_search();
|
|
15278
|
-
webSearchSchema =
|
|
15279
|
-
query:
|
|
15240
|
+
webSearchSchema = Type15.Object({
|
|
15241
|
+
query: Type15.String({
|
|
15280
15242
|
description: 'Search query. Supports Google-style directives: site:/-site:, after:/before: (YYYY-MM-DD), inurl:, intitle:, filetype:, "exact phrase", -term, OR.'
|
|
15281
15243
|
}),
|
|
15282
|
-
recency:
|
|
15244
|
+
recency: Type15.Optional(Type15.Union([Type15.Literal("day"), Type15.Literal("week"), Type15.Literal("month"), Type15.Literal("year")], {
|
|
15283
15245
|
description: "Optional recency window for results (pure time filter)."
|
|
15284
15246
|
})),
|
|
15285
|
-
limit:
|
|
15286
|
-
num_search_results:
|
|
15247
|
+
limit: Type15.Optional(Type15.Integer({ description: "Maximum number of results to return." })),
|
|
15248
|
+
num_search_results: Type15.Optional(Type15.Integer({ description: "Alias for limit (result count hint)." }))
|
|
15287
15249
|
});
|
|
15288
15250
|
});
|
|
15289
15251
|
|
|
@@ -15411,7 +15373,6 @@ class AutoRAGAgent {
|
|
|
15411
15373
|
this.memory.load();
|
|
15412
15374
|
this.runLogger = new AutoRAGRunLogger(join22(dirname12(memPath), "logs", "runs.jsonl"));
|
|
15413
15375
|
const checkMemoryTool = createCheckMemoryTool(this.memory);
|
|
15414
|
-
const searchDatasourceTool = createSearchDatasourceDocumentsTool(this);
|
|
15415
15376
|
const singleDatasourceTools = createSingleDatasourceSearchTools(this, this.singleDatasourceToolSpecs());
|
|
15416
15377
|
this.searchToolNames = new Set([...SEARCH_TOOLS, ...singleDatasourceTools.map((tool) => tool.name)]);
|
|
15417
15378
|
const searchMinSyncTool = createSearchMinSyncDocumentsTool(() => this.remoteFilteredRetrievalMethod(this.minSyncMethod), (scope) => this.resolveRetrievalScope(scope));
|
|
@@ -15431,7 +15392,6 @@ class AutoRAGAgent {
|
|
|
15431
15392
|
const reservedNames = new Set([
|
|
15432
15393
|
BASH_TOOL_NAME,
|
|
15433
15394
|
"check_memory",
|
|
15434
|
-
SEARCH_DATASOURCE_DOCUMENTS_TOOL_NAME,
|
|
15435
15395
|
...singleDatasourceTools.map((tool) => tool.name),
|
|
15436
15396
|
LOAD_DATASOURCE_SKILL_TOOL_NAME,
|
|
15437
15397
|
EMIT_AUTORAG_RESULTS_TOOL_NAME,
|
|
@@ -15459,7 +15419,6 @@ class AutoRAGAgent {
|
|
|
15459
15419
|
checkMemoryTool,
|
|
15460
15420
|
searchMinSyncTool,
|
|
15461
15421
|
searchAllTool,
|
|
15462
|
-
searchDatasourceTool,
|
|
15463
15422
|
...singleDatasourceTools,
|
|
15464
15423
|
loadDatasourceSkillTool,
|
|
15465
15424
|
...webSearchTool !== undefined ? [webSearchTool] : [],
|
|
@@ -16628,30 +16587,6 @@ ${initialRetrievalContext ?? "Pending; continue only with a brief progress state
|
|
|
16628
16587
|
async searchAllDocuments(query, options = {}) {
|
|
16629
16588
|
return this.retrieveWithDiagnostics(query, { topK: options.topK, scope: options.scope });
|
|
16630
16589
|
}
|
|
16631
|
-
async searchDatasourceDocuments(query, options = {}) {
|
|
16632
|
-
const retrievalOptions = {
|
|
16633
|
-
...this.activeRetrievalOptions,
|
|
16634
|
-
topK: options.topK,
|
|
16635
|
-
scope: options.scope
|
|
16636
|
-
};
|
|
16637
|
-
const ctx = this.datasourceAccessContext(retrievalOptions);
|
|
16638
|
-
const methods = this.methodRegistry.list().filter((method) => {
|
|
16639
|
-
const descriptor = method.describe();
|
|
16640
|
-
return descriptor.datasourceId !== undefined && ctx.isAccessible(descriptor);
|
|
16641
|
-
});
|
|
16642
|
-
if (methods.length === 0)
|
|
16643
|
-
return { results: [], diagnostics: [] };
|
|
16644
|
-
const { results: byMethod, diagnostics } = await this.retriever.retrieveWithDiagnostics(methods, query, retrievalOptions);
|
|
16645
|
-
const filteredByMethod = this.datasourceFilter.filter(byMethod, methods, ctx, options.scope);
|
|
16646
|
-
for (const results of filteredByMethod.values()) {
|
|
16647
|
-
for (const result of results)
|
|
16648
|
-
retrievalOptions.observedSources?.add(result.source);
|
|
16649
|
-
}
|
|
16650
|
-
return {
|
|
16651
|
-
results: this.rerankWithMemory(query, this.merger.merge(filteredByMethod, { topK: options.topK ?? MERGED_EVIDENCE_CEILING, dedup: true })),
|
|
16652
|
-
diagnostics
|
|
16653
|
-
};
|
|
16654
|
-
}
|
|
16655
16590
|
async searchSingleDatasourceDocuments(datasourceId, query, options = {}) {
|
|
16656
16591
|
const retrievalOptions = {
|
|
16657
16592
|
...this.activeRetrievalOptions,
|
|
@@ -16888,7 +16823,6 @@ var init_agent = __esm(() => {
|
|
|
16888
16823
|
init_local_model();
|
|
16889
16824
|
init_peer_target_tool();
|
|
16890
16825
|
init_search_all_tool();
|
|
16891
|
-
init_search_datasource_tool();
|
|
16892
16826
|
init_search_documents();
|
|
16893
16827
|
init_search_minsync_tool();
|
|
16894
16828
|
init_search_single_datasource_tool();
|
|
@@ -16899,7 +16833,6 @@ var init_agent = __esm(() => {
|
|
|
16899
16833
|
SEARCH_TOOLS = [
|
|
16900
16834
|
SEARCH_MINSYNC_DOCUMENTS_TOOL_NAME,
|
|
16901
16835
|
SEARCH_ALL_DOCUMENTS_TOOL_NAME,
|
|
16902
|
-
SEARCH_DATASOURCE_DOCUMENTS_TOOL_NAME,
|
|
16903
16836
|
JIKJI_FIND_TOOL_NAME
|
|
16904
16837
|
];
|
|
16905
16838
|
RemoteSessionRejectedError = class RemoteSessionRejectedError extends Error {
|
|
@@ -17577,7 +17510,7 @@ class ClawGallerySkill {
|
|
|
17577
17510
|
"- Never use `lexical` unless a sparse V-SPLADE index exists; it must not fall back to dense vectors.",
|
|
17578
17511
|
"- `hybrid` is the default and asks ClawGallery to RRF-fuse keyword results with every available dense and sparse vector channel.",
|
|
17579
17512
|
"",
|
|
17580
|
-
`Use the dedicated \`${datasourceSearchToolName(CLAWGALLERY_DATASOURCE_ID)}\` tool with a natural-language query.
|
|
17513
|
+
`Use the dedicated \`${datasourceSearchToolName(CLAWGALLERY_DATASOURCE_ID)}\` tool with a natural-language query. Prefer hybrid/default search unless you know which index capability is available. If an explicit vector mode is needed, inspect \`clawgallery vdr status --json\` first when capability details are available.`,
|
|
17581
17514
|
"",
|
|
17582
17515
|
"With only V-SPLADE synced, use lexical or hybrid. With only dense VDR synced, use embedding or hybrid. When both are synced, use hybrid so dense VDR and sparse V-SPLADE results can coexist and be RRF-combined.",
|
|
17583
17516
|
"",
|
|
@@ -18426,7 +18359,7 @@ class ConnectorDatasourceSkill {
|
|
|
18426
18359
|
`Indexing is server-managed and refreshed ${cadence}. You do not trigger indexing; just search.`,
|
|
18427
18360
|
"",
|
|
18428
18361
|
"## How to search",
|
|
18429
|
-
`Call the dedicated \`${datasourceSearchToolName(skillName)}\` tool with a natural-language \`query\`. Optionally pass \`topK\` and a narrowing \`scope\`.
|
|
18362
|
+
`Call the dedicated \`${datasourceSearchToolName(skillName)}\` tool with a natural-language \`query\`. Optionally pass \`topK\` and a narrowing \`scope\`. Available authorized scopes:`,
|
|
18430
18363
|
instanceScopes.length > 0 ? instanceScopes : "- (no authorized instances)",
|
|
18431
18364
|
"",
|
|
18432
18365
|
"`scope` can only narrow within already-authorized scopes; it can never widen access.",
|
|
@@ -18565,7 +18498,7 @@ function createCloudDriveSkillDefinition(skillName, provider) {
|
|
|
18565
18498
|
"Configure and authenticate the remote with `rclone config`; AutoRAG never receives or stores provider credentials.",
|
|
18566
18499
|
"Google Drive is Tier-1 supported. OneDrive and other rclone remotes use the same manifest contract. iCloud Drive is experimental and requires periodic Apple ID reauthentication.",
|
|
18567
18500
|
"Indexing is incremental: `rclone lsjson` inventories metadata, then only added or changed indexable files are mirrored. Search uses the last completed snapshot while a failed sync is retried.",
|
|
18568
|
-
`This connection is independently addressable. Load \`datasource-${skillName}\`, then call \`${datasourceSearchToolName(skillName)}\` with an optional narrowing scope under \`/${skillName}/<instance
|
|
18501
|
+
`This connection is independently addressable. Load \`datasource-${skillName}\`, then call \`${datasourceSearchToolName(skillName)}\` with an optional narrowing scope under \`/${skillName}/<instance>/**\`.`
|
|
18569
18502
|
],
|
|
18570
18503
|
nativeCliNote: "The underlying remote can be browsed directly with the `rclone` CLI through `bash` (e.g. `rclone lsl <remote>:<path>` or `rclone cat <remote>:<path>/<file>`); the dedicated tool searches the mirrored, parsed snapshot."
|
|
18571
18504
|
};
|
|
@@ -18609,6 +18542,40 @@ var init_cloud_drive = __esm(() => {
|
|
|
18609
18542
|
init_skill2();
|
|
18610
18543
|
});
|
|
18611
18544
|
|
|
18545
|
+
// src/process/terminate-tree.ts
|
|
18546
|
+
import { spawn as spawn9 } from "node:child_process";
|
|
18547
|
+
function terminateProcessTree(child, signal = "SIGKILL") {
|
|
18548
|
+
const pid = child.pid;
|
|
18549
|
+
if (pid === undefined)
|
|
18550
|
+
return false;
|
|
18551
|
+
if (process.platform === "win32") {
|
|
18552
|
+
const killer = spawn9("taskkill", ["/pid", String(pid), "/t", "/f"], { stdio: "ignore", windowsHide: true });
|
|
18553
|
+
killer.on("error", () => killDirectChild(child, signal));
|
|
18554
|
+
killer.on("close", (code) => {
|
|
18555
|
+
if (code !== 0)
|
|
18556
|
+
killDirectChild(child, signal);
|
|
18557
|
+
});
|
|
18558
|
+
return true;
|
|
18559
|
+
}
|
|
18560
|
+
try {
|
|
18561
|
+
process.kill(-pid, signal);
|
|
18562
|
+
return true;
|
|
18563
|
+
} catch {
|
|
18564
|
+
return killDirectChild(child, signal);
|
|
18565
|
+
}
|
|
18566
|
+
}
|
|
18567
|
+
function killDirectChild(child, signal) {
|
|
18568
|
+
if (child.exitCode !== null || child.signalCode !== null)
|
|
18569
|
+
return false;
|
|
18570
|
+
try {
|
|
18571
|
+
return child.kill(signal);
|
|
18572
|
+
} catch {
|
|
18573
|
+
return false;
|
|
18574
|
+
}
|
|
18575
|
+
}
|
|
18576
|
+
var TREE_KILL_GRACE_MS = 500;
|
|
18577
|
+
var init_terminate_tree = () => {};
|
|
18578
|
+
|
|
18612
18579
|
// src/datasource/skills/discrawl/types.ts
|
|
18613
18580
|
var ENGLISH_ONLY_EMBEDDING_MODELS, DEFAULT_DISCRAWL_EMBEDDING_MODEL = "embeddinggemma", DEFAULT_DISCRAWL_BINARY = "discrawl", DEFAULT_DISCRAWL_TIMEOUT_MS = 30000, DEFAULT_DISCRAWL_MAX_BUFFER_BYTES = 1048576, DEFAULT_DISCRAWL_MODE = "hybrid";
|
|
18614
18581
|
var init_types4 = __esm(() => {
|
|
@@ -18625,7 +18592,7 @@ var init_types4 = __esm(() => {
|
|
|
18625
18592
|
});
|
|
18626
18593
|
|
|
18627
18594
|
// src/datasource/skills/discrawl/client.ts
|
|
18628
|
-
import { spawn as
|
|
18595
|
+
import { spawn as spawn10 } from "node:child_process";
|
|
18629
18596
|
import { mkdirSync as mkdirSync14, readFileSync as readFileSync15, writeFileSync as writeFileSync13 } from "node:fs";
|
|
18630
18597
|
import { dirname as dirname15 } from "node:path";
|
|
18631
18598
|
|
|
@@ -18762,27 +18729,52 @@ function managedConfigPath(workspace) {
|
|
|
18762
18729
|
return `${workspace}/.autorag/datasources/discrawl/config.toml`;
|
|
18763
18730
|
}
|
|
18764
18731
|
function spawnDiscrawl(request) {
|
|
18765
|
-
return new Promise((
|
|
18732
|
+
return new Promise((resolveResult) => {
|
|
18766
18733
|
const { options, args, env, signal } = request;
|
|
18767
18734
|
const portable = portableSpawnCommand(options.binaryPath ?? DEFAULT_DISCRAWL_BINARY, args);
|
|
18768
|
-
const child =
|
|
18735
|
+
const child = spawn10(portable.command, [...portable.args], {
|
|
18769
18736
|
env,
|
|
18770
18737
|
...request.cwd === undefined ? {} : { cwd: request.cwd },
|
|
18771
18738
|
detached: process.platform !== "win32",
|
|
18739
|
+
windowsHide: true,
|
|
18772
18740
|
stdio: ["ignore", "pipe", "pipe"]
|
|
18773
18741
|
});
|
|
18774
18742
|
let stdout = { text: "", bytes: 0, capped: false };
|
|
18775
18743
|
let stderr = { text: "", bytes: 0, capped: false };
|
|
18776
18744
|
let settled = false;
|
|
18777
18745
|
let finalReason;
|
|
18746
|
+
let pipeGuard;
|
|
18778
18747
|
const maxBuffer = options.maxBufferBytes ?? DEFAULT_DISCRAWL_MAX_BUFFER_BYTES;
|
|
18748
|
+
const settleWith = (result) => {
|
|
18749
|
+
if (settled)
|
|
18750
|
+
return;
|
|
18751
|
+
settled = true;
|
|
18752
|
+
clearTimeout(timeout);
|
|
18753
|
+
if (pipeGuard !== undefined)
|
|
18754
|
+
clearTimeout(pipeGuard);
|
|
18755
|
+
signal?.removeEventListener("abort", abortHandler);
|
|
18756
|
+
resolveResult(result);
|
|
18757
|
+
};
|
|
18758
|
+
const finish = (code) => {
|
|
18759
|
+
if (finalReason !== undefined) {
|
|
18760
|
+
settleWith({ ok: false, reason: finalReason, stdout: stdout.text, stderr: stderr.text, code });
|
|
18761
|
+
return;
|
|
18762
|
+
}
|
|
18763
|
+
settleWith({
|
|
18764
|
+
ok: code === 0,
|
|
18765
|
+
reason: code === 0 ? undefined : "nonzero-exit",
|
|
18766
|
+
stdout: stdout.text,
|
|
18767
|
+
stderr: stderr.text,
|
|
18768
|
+
code
|
|
18769
|
+
});
|
|
18770
|
+
};
|
|
18779
18771
|
const timeout = setTimeout(() => {
|
|
18780
18772
|
finalReason = "timeout";
|
|
18781
|
-
|
|
18773
|
+
terminateProcessTree(child, "SIGKILL");
|
|
18782
18774
|
}, options.timeoutMs ?? DEFAULT_DISCRAWL_TIMEOUT_MS);
|
|
18783
18775
|
const abortHandler = () => {
|
|
18784
18776
|
finalReason = "aborted";
|
|
18785
|
-
|
|
18777
|
+
terminateProcessTree(child, "SIGKILL");
|
|
18786
18778
|
};
|
|
18787
18779
|
if (signal?.aborted)
|
|
18788
18780
|
abortHandler();
|
|
@@ -18793,43 +18785,27 @@ function spawnDiscrawl(request) {
|
|
|
18793
18785
|
stdout = appendBounded2(stdout, chunk, maxBuffer);
|
|
18794
18786
|
if (stdout.capped) {
|
|
18795
18787
|
finalReason = "stdout-too-large";
|
|
18796
|
-
|
|
18788
|
+
terminateProcessTree(child, "SIGKILL");
|
|
18797
18789
|
}
|
|
18798
18790
|
});
|
|
18799
18791
|
child.stderr.on("data", (chunk) => {
|
|
18800
18792
|
stderr = appendBounded2(stderr, chunk, maxBuffer);
|
|
18801
18793
|
if (stderr.capped) {
|
|
18802
18794
|
finalReason = "stderr-too-large";
|
|
18803
|
-
|
|
18795
|
+
terminateProcessTree(child, "SIGKILL");
|
|
18804
18796
|
}
|
|
18805
18797
|
});
|
|
18806
|
-
child.on("
|
|
18798
|
+
child.on("exit", () => {
|
|
18807
18799
|
if (settled)
|
|
18808
18800
|
return;
|
|
18809
|
-
|
|
18810
|
-
|
|
18811
|
-
signal?.removeEventListener("abort", abortHandler);
|
|
18812
|
-
const reason = error.code === "ENOENT" ? "binary-missing" : "spawn-error";
|
|
18813
|
-
resolve({ ok: false, reason, stdout: stdout.text, stderr: describeSpawnFailure(reason), code: null });
|
|
18801
|
+
terminateProcessTree(child, "SIGKILL");
|
|
18802
|
+
pipeGuard = setTimeout(() => finish(child.exitCode), TREE_KILL_GRACE_MS);
|
|
18814
18803
|
});
|
|
18815
|
-
child.on("
|
|
18816
|
-
|
|
18817
|
-
|
|
18818
|
-
settled = true;
|
|
18819
|
-
clearTimeout(timeout);
|
|
18820
|
-
signal?.removeEventListener("abort", abortHandler);
|
|
18821
|
-
if (finalReason !== undefined) {
|
|
18822
|
-
resolve({ ok: false, reason: finalReason, stdout: stdout.text, stderr: stderr.text, code });
|
|
18823
|
-
return;
|
|
18824
|
-
}
|
|
18825
|
-
resolve({
|
|
18826
|
-
ok: code === 0,
|
|
18827
|
-
reason: code === 0 ? undefined : "nonzero-exit",
|
|
18828
|
-
stdout: stdout.text,
|
|
18829
|
-
stderr: stderr.text,
|
|
18830
|
-
code
|
|
18831
|
-
});
|
|
18804
|
+
child.on("error", (error) => {
|
|
18805
|
+
const reason = error.code === "ENOENT" ? "binary-missing" : "spawn-error";
|
|
18806
|
+
settleWith({ ok: false, reason, stdout: stdout.text, stderr: describeSpawnFailure(reason), code: null });
|
|
18832
18807
|
});
|
|
18808
|
+
child.on("close", (code) => finish(code));
|
|
18833
18809
|
});
|
|
18834
18810
|
}
|
|
18835
18811
|
function nativeGatewayBaseUrl(baseUrl) {
|
|
@@ -18893,17 +18869,6 @@ function findUserTokenKey(env) {
|
|
|
18893
18869
|
}
|
|
18894
18870
|
return;
|
|
18895
18871
|
}
|
|
18896
|
-
function terminate3(child) {
|
|
18897
|
-
if (child.killed)
|
|
18898
|
-
return;
|
|
18899
|
-
if (process.platform !== "win32" && child.pid !== undefined) {
|
|
18900
|
-
try {
|
|
18901
|
-
process.kill(-child.pid, "SIGKILL");
|
|
18902
|
-
return;
|
|
18903
|
-
} catch {}
|
|
18904
|
-
}
|
|
18905
|
-
child.kill("SIGKILL");
|
|
18906
|
-
}
|
|
18907
18872
|
function describeSpawnFailure(reason) {
|
|
18908
18873
|
return reason === "binary-missing" ? "the discrawl binary could not be found" : "the discrawl binary could not be started";
|
|
18909
18874
|
}
|
|
@@ -19123,6 +19088,7 @@ function ok2(data, result) {
|
|
|
19123
19088
|
var USER_TOKEN_KEYS, SAFE_INHERITED_ENV_KEYS, SAFE_DISCRAWL_ENV_PREFIX = "DISCRAWL_";
|
|
19124
19089
|
var init_client4 = __esm(() => {
|
|
19125
19090
|
init_portable_spawn();
|
|
19091
|
+
init_terminate_tree();
|
|
19126
19092
|
init_types4();
|
|
19127
19093
|
USER_TOKEN_KEYS = new Set([
|
|
19128
19094
|
"discord_user_token",
|
|
@@ -19435,7 +19401,7 @@ class DiscrawlSkill {
|
|
|
19435
19401
|
`Indexing is server-managed and refreshed ${cadence}. Sync is incremental (cursor-based) and embeddings are queued per changed message. You do not trigger indexing; just search.`,
|
|
19436
19402
|
"",
|
|
19437
19403
|
"## How to search",
|
|
19438
|
-
`Call the dedicated \`${datasourceSearchToolName(DISCORD_DATASOURCE_ID2)}\` tool with a natural-language \`query\`. Optionally pass \`topK\` and a narrowing \`scope\`.
|
|
19404
|
+
`Call the dedicated \`${datasourceSearchToolName(DISCORD_DATASOURCE_ID2)}\` tool with a natural-language \`query\`. Optionally pass \`topK\` and a narrowing \`scope\`. Available authorized scopes:`,
|
|
19439
19405
|
instanceScopes.length > 0 ? instanceScopes : "- (no authorized instances)",
|
|
19440
19406
|
"",
|
|
19441
19407
|
"`scope` can only narrow within already-authorized scopes; it can never widen access.",
|
|
@@ -19674,47 +19640,1232 @@ var init_github = __esm(() => {
|
|
|
19674
19640
|
init_skill4();
|
|
19675
19641
|
});
|
|
19676
19642
|
|
|
19677
|
-
// src/datasource/skills/
|
|
19678
|
-
|
|
19679
|
-
|
|
19680
|
-
|
|
19681
|
-
|
|
19682
|
-
|
|
19643
|
+
// src/datasource/skills/github-gist/connector.ts
|
|
19644
|
+
import { execFile as execFile3 } from "node:child_process";
|
|
19645
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync15, readFileSync as readFileSync16, writeFileSync as writeFileSync14 } from "node:fs";
|
|
19646
|
+
import { dirname as dirname16 } from "node:path";
|
|
19647
|
+
async function defaultGhTokenRunner() {
|
|
19648
|
+
return new Promise((resolve) => {
|
|
19649
|
+
execFile3("gh", ["auth", "token"], { timeout: GH_TOKEN_TIMEOUT_MS }, (error, stdout) => {
|
|
19650
|
+
if (error) {
|
|
19651
|
+
resolve(undefined);
|
|
19652
|
+
return;
|
|
19653
|
+
}
|
|
19654
|
+
const token = stdout.trim();
|
|
19655
|
+
resolve(token.length > 0 ? token : undefined);
|
|
19656
|
+
});
|
|
19657
|
+
});
|
|
19658
|
+
}
|
|
19683
19659
|
|
|
19684
|
-
class
|
|
19660
|
+
class GitHubGistConnector {
|
|
19685
19661
|
options;
|
|
19686
19662
|
constructor(options = {}) {
|
|
19687
19663
|
this.options = options;
|
|
19688
19664
|
}
|
|
19689
|
-
async
|
|
19690
|
-
const
|
|
19691
|
-
if (
|
|
19692
|
-
return
|
|
19693
|
-
|
|
19694
|
-
|
|
19695
|
-
|
|
19696
|
-
|
|
19697
|
-
|
|
19665
|
+
async fetch(signal) {
|
|
19666
|
+
const token = await this.resolveAuth();
|
|
19667
|
+
if (token === undefined) {
|
|
19668
|
+
return {
|
|
19669
|
+
ok: false,
|
|
19670
|
+
reason: "not-configured",
|
|
19671
|
+
message: "no GitHub token: set GITHUB_TOKEN (or connector.tokenEnv) or authenticate the gh CLI"
|
|
19672
|
+
};
|
|
19673
|
+
}
|
|
19674
|
+
const baseUrl = this.options.baseUrl ?? DEFAULT_BASE_URL4;
|
|
19675
|
+
const request = {
|
|
19676
|
+
headers: {
|
|
19677
|
+
Accept: "application/vnd.github+json",
|
|
19678
|
+
"X-GitHub-Api-Version": "2022-11-28",
|
|
19679
|
+
"User-Agent": "autorag-datasource",
|
|
19680
|
+
Authorization: `Bearer ${token}`
|
|
19681
|
+
},
|
|
19682
|
+
timeoutMs: this.options.timeoutMs,
|
|
19683
|
+
fetchImpl: this.options.fetchImpl,
|
|
19684
|
+
signal
|
|
19685
|
+
};
|
|
19686
|
+
const maxPages = this.options.maxPages ?? DEFAULT_MAX_PAGES2;
|
|
19687
|
+
const maxGists = this.options.maxGists ?? DEFAULT_MAX_GISTS;
|
|
19688
|
+
const listed = new Map;
|
|
19689
|
+
for (let page = 1;page <= maxPages && listed.size < maxGists; page += 1) {
|
|
19690
|
+
const url = `${baseUrl}/gists?per_page=100&page=${page}`;
|
|
19691
|
+
const result = await httpJson(url, request);
|
|
19692
|
+
if (!result.ok) {
|
|
19693
|
+
if (result.reason === "auth")
|
|
19694
|
+
return { ok: false, reason: "auth", message: "github: unauthorized" };
|
|
19695
|
+
if (result.reason === "rate-limited" || result.reason === "permission") {
|
|
19696
|
+
return { ok: false, reason: "rate-limited", message: "github: rate limited or forbidden" };
|
|
19697
|
+
}
|
|
19698
|
+
return { ok: false, reason: "api-error", message: `github: gist list failed: ${result.message}` };
|
|
19699
|
+
}
|
|
19700
|
+
const items = asArray(result.json);
|
|
19701
|
+
if (items.length === 0)
|
|
19702
|
+
break;
|
|
19703
|
+
for (const raw of items) {
|
|
19704
|
+
if (listed.size >= maxGists)
|
|
19705
|
+
break;
|
|
19706
|
+
const item = asRecord(raw);
|
|
19707
|
+
const id = asString(item?.id);
|
|
19708
|
+
const updatedAt = asString(item?.updated_at);
|
|
19709
|
+
if (id === undefined || updatedAt === undefined)
|
|
19710
|
+
continue;
|
|
19711
|
+
listed.set(id, { updatedAt });
|
|
19712
|
+
}
|
|
19713
|
+
if (items.length < 100)
|
|
19714
|
+
break;
|
|
19715
|
+
}
|
|
19716
|
+
const previous = this.loadState();
|
|
19717
|
+
const changedIds = [];
|
|
19718
|
+
for (const [id, entry] of listed) {
|
|
19719
|
+
if (previous.gists[id] !== entry.updatedAt)
|
|
19720
|
+
changedIds.push(id);
|
|
19721
|
+
}
|
|
19722
|
+
const deletedDocIds = Object.keys(previous.gists).filter((id) => !listed.has(id));
|
|
19723
|
+
const documents = [];
|
|
19724
|
+
const warnings = [];
|
|
19725
|
+
const failedIds = new Set;
|
|
19726
|
+
for (const id of changedIds) {
|
|
19727
|
+
const result = await httpJson(`${baseUrl}/gists/${encodeURIComponent(id)}`, request);
|
|
19728
|
+
if (!result.ok) {
|
|
19729
|
+
warnings.push(`gist ${id} fetch failed: ${result.message}`);
|
|
19730
|
+
failedIds.add(id);
|
|
19731
|
+
continue;
|
|
19732
|
+
}
|
|
19733
|
+
const document = toDocument(asRecord(result.json));
|
|
19734
|
+
if (document !== undefined)
|
|
19735
|
+
documents.push(document);
|
|
19736
|
+
}
|
|
19737
|
+
this.saveState({
|
|
19738
|
+
version: STATE_VERSION,
|
|
19739
|
+
gists: Object.fromEntries([...listed].filter(([id]) => !failedIds.has(id)).map(([id, e]) => [id, e.updatedAt]))
|
|
19740
|
+
});
|
|
19741
|
+
const changed = changedIds.length > 0 || deletedDocIds.length > 0;
|
|
19742
|
+
return {
|
|
19743
|
+
ok: true,
|
|
19744
|
+
documents,
|
|
19745
|
+
changed,
|
|
19746
|
+
deletedDocIds,
|
|
19747
|
+
...warnings.length > 0 ? { warnings } : {}
|
|
19748
|
+
};
|
|
19698
19749
|
}
|
|
19699
|
-
async
|
|
19700
|
-
const
|
|
19701
|
-
if (
|
|
19702
|
-
return
|
|
19703
|
-
|
|
19704
|
-
|
|
19705
|
-
|
|
19706
|
-
|
|
19707
|
-
|
|
19750
|
+
async resolveAuth() {
|
|
19751
|
+
const direct = resolveToken(this.options.token, this.options.tokenEnv ?? DEFAULT_TOKEN_ENV2);
|
|
19752
|
+
if (direct !== undefined)
|
|
19753
|
+
return direct;
|
|
19754
|
+
if (this.options.ghCliFallback === false)
|
|
19755
|
+
return;
|
|
19756
|
+
const runner = this.options.ghTokenRunner ?? defaultGhTokenRunner;
|
|
19757
|
+
try {
|
|
19758
|
+
return await runner();
|
|
19759
|
+
} catch {
|
|
19760
|
+
return;
|
|
19761
|
+
}
|
|
19708
19762
|
}
|
|
19709
|
-
|
|
19710
|
-
const
|
|
19763
|
+
loadState() {
|
|
19764
|
+
const statePath = this.options.statePath;
|
|
19765
|
+
if (statePath === undefined || !existsSync20(statePath))
|
|
19766
|
+
return { version: STATE_VERSION, gists: {} };
|
|
19767
|
+
try {
|
|
19768
|
+
const parsed = JSON.parse(readFileSync16(statePath, "utf8"));
|
|
19769
|
+
if (parsed.version !== STATE_VERSION || typeof parsed.gists !== "object" || parsed.gists === null) {
|
|
19770
|
+
return { version: STATE_VERSION, gists: {} };
|
|
19771
|
+
}
|
|
19772
|
+
return parsed;
|
|
19773
|
+
} catch {
|
|
19774
|
+
return { version: STATE_VERSION, gists: {} };
|
|
19775
|
+
}
|
|
19776
|
+
}
|
|
19777
|
+
saveState(state) {
|
|
19778
|
+
const statePath = this.options.statePath;
|
|
19779
|
+
if (statePath === undefined)
|
|
19780
|
+
return;
|
|
19781
|
+
try {
|
|
19782
|
+
mkdirSync15(dirname16(statePath), { recursive: true });
|
|
19783
|
+
writeFileSync14(statePath, `${JSON.stringify(state)}
|
|
19784
|
+
`, "utf8");
|
|
19785
|
+
} catch {}
|
|
19786
|
+
}
|
|
19787
|
+
}
|
|
19788
|
+
function toDocument(gist) {
|
|
19789
|
+
if (gist === undefined)
|
|
19790
|
+
return;
|
|
19791
|
+
const id = asString(gist.id);
|
|
19792
|
+
if (id === undefined)
|
|
19793
|
+
return;
|
|
19794
|
+
const description = asString(gist.description) ?? "";
|
|
19795
|
+
const filesRecord = asRecord(gist.files) ?? {};
|
|
19796
|
+
const fileNames = Object.keys(filesRecord);
|
|
19797
|
+
const sections = [];
|
|
19798
|
+
for (const name of fileNames) {
|
|
19799
|
+
const file = asRecord(filesRecord[name]);
|
|
19800
|
+
const filename = asString(file?.filename) ?? name;
|
|
19801
|
+
const content = asString(file?.content) ?? "";
|
|
19802
|
+
sections.push(`## ${filename}
|
|
19803
|
+
${content}`);
|
|
19804
|
+
}
|
|
19805
|
+
const title = description.length > 0 ? description : fileNames[0] ?? id;
|
|
19806
|
+
const content = [description, ...sections].filter((part) => part.length > 0).join(`
|
|
19807
|
+
|
|
19808
|
+
`);
|
|
19809
|
+
return {
|
|
19810
|
+
docId: id,
|
|
19811
|
+
hierarchy: ["gists"],
|
|
19812
|
+
title,
|
|
19813
|
+
content: content.length > 0 ? content : title,
|
|
19814
|
+
publishedAt: parseEpochMs(gist.updated_at),
|
|
19815
|
+
metadata: {
|
|
19816
|
+
gistId: id,
|
|
19817
|
+
public: gist.public === true,
|
|
19818
|
+
files: fileNames,
|
|
19819
|
+
...asString(gist.html_url) !== undefined ? { htmlUrl: asString(gist.html_url) } : {}
|
|
19820
|
+
}
|
|
19821
|
+
};
|
|
19822
|
+
}
|
|
19823
|
+
var DEFAULT_BASE_URL4 = "https://api.github.com", DEFAULT_TOKEN_ENV2 = "GITHUB_TOKEN", DEFAULT_MAX_PAGES2 = 10, DEFAULT_MAX_GISTS = 500, GH_TOKEN_TIMEOUT_MS = 5000, STATE_VERSION = 1;
|
|
19824
|
+
var init_connector3 = () => {};
|
|
19825
|
+
|
|
19826
|
+
// src/datasource/skills/github-gist/semantic.ts
|
|
19827
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
19828
|
+
import { existsSync as existsSync21, mkdirSync as mkdirSync16, readFileSync as readFileSync17, writeFileSync as writeFileSync15 } from "node:fs";
|
|
19829
|
+
import { dirname as dirname17 } from "node:path";
|
|
19830
|
+
function contentHash(chunk) {
|
|
19831
|
+
return createHash7("sha256").update(`${chunk.title ?? ""}
|
|
19832
|
+
${chunk.content}`).digest("hex");
|
|
19833
|
+
}
|
|
19834
|
+
function sameIdentity(a, b) {
|
|
19835
|
+
return a.provider === b.provider && a.model === b.model && a.dimension === b.dimension;
|
|
19836
|
+
}
|
|
19837
|
+
function cosine(a, b) {
|
|
19838
|
+
let dot = 0;
|
|
19839
|
+
let normA = 0;
|
|
19840
|
+
let normB = 0;
|
|
19841
|
+
const length = Math.min(a.length, b.length);
|
|
19842
|
+
for (let i = 0;i < length; i += 1) {
|
|
19843
|
+
const x = a[i] ?? 0;
|
|
19844
|
+
const y = b[i] ?? 0;
|
|
19845
|
+
dot += x * y;
|
|
19846
|
+
normA += x * x;
|
|
19847
|
+
normB += y * y;
|
|
19848
|
+
}
|
|
19849
|
+
if (normA === 0 || normB === 0)
|
|
19850
|
+
return 0;
|
|
19851
|
+
return dot / (Math.sqrt(normA) * Math.sqrt(normB));
|
|
19852
|
+
}
|
|
19853
|
+
|
|
19854
|
+
class GistSemanticIndex {
|
|
19855
|
+
statePath;
|
|
19856
|
+
identity;
|
|
19857
|
+
entries = {};
|
|
19858
|
+
loaded = false;
|
|
19859
|
+
constructor(options = {}) {
|
|
19860
|
+
this.statePath = options.statePath;
|
|
19861
|
+
}
|
|
19862
|
+
async sync(chunks, embedder) {
|
|
19863
|
+
this.ensureLoaded();
|
|
19864
|
+
let identity;
|
|
19865
|
+
try {
|
|
19866
|
+
identity = await embedder.identity();
|
|
19867
|
+
} catch (error) {
|
|
19868
|
+
return { ok: false, message: error instanceof Error ? error.message : String(error) };
|
|
19869
|
+
}
|
|
19870
|
+
if (this.identity === undefined || !sameIdentity(this.identity, identity)) {
|
|
19871
|
+
this.entries = {};
|
|
19872
|
+
this.identity = identity;
|
|
19873
|
+
}
|
|
19874
|
+
const currentIds = new Set(chunks.map((chunk) => chunk.chunkId));
|
|
19875
|
+
for (const chunkId of Object.keys(this.entries)) {
|
|
19876
|
+
if (!currentIds.has(chunkId))
|
|
19877
|
+
delete this.entries[chunkId];
|
|
19878
|
+
}
|
|
19879
|
+
const pending = chunks.filter((chunk) => {
|
|
19880
|
+
const entry = this.entries[chunk.chunkId];
|
|
19881
|
+
return entry === undefined || entry.hash !== contentHash(chunk);
|
|
19882
|
+
});
|
|
19883
|
+
if (pending.length === 0) {
|
|
19884
|
+
this.persist();
|
|
19885
|
+
return { ok: true, embedded: 0 };
|
|
19886
|
+
}
|
|
19887
|
+
let vectors;
|
|
19888
|
+
try {
|
|
19889
|
+
vectors = await embedder.embed(pending.map((chunk) => `${chunk.title ?? ""}
|
|
19890
|
+
${chunk.content}`));
|
|
19891
|
+
} catch (error) {
|
|
19892
|
+
return { ok: false, message: error instanceof Error ? error.message : String(error) };
|
|
19893
|
+
}
|
|
19894
|
+
if (vectors.length !== pending.length) {
|
|
19895
|
+
return { ok: false, message: `embedder returned ${vectors.length} vectors for ${pending.length} chunks` };
|
|
19896
|
+
}
|
|
19897
|
+
for (const [index, chunk] of pending.entries()) {
|
|
19898
|
+
const vector = vectors[index] ?? [];
|
|
19899
|
+
this.entries[chunk.chunkId] = { hash: contentHash(chunk), vector };
|
|
19900
|
+
}
|
|
19901
|
+
this.persist();
|
|
19902
|
+
return { ok: true, embedded: pending.length };
|
|
19903
|
+
}
|
|
19904
|
+
searchByVector(queryVector, topK) {
|
|
19905
|
+
this.ensureLoaded();
|
|
19906
|
+
const scored = [];
|
|
19907
|
+
for (const [chunkId, entry] of Object.entries(this.entries)) {
|
|
19908
|
+
const score = cosine(queryVector, entry.vector);
|
|
19909
|
+
if (score > 0)
|
|
19910
|
+
scored.push({ chunkId, score });
|
|
19911
|
+
}
|
|
19912
|
+
scored.sort((a, b) => b.score - a.score || a.chunkId.localeCompare(b.chunkId));
|
|
19913
|
+
return scored.slice(0, topK);
|
|
19914
|
+
}
|
|
19915
|
+
ensureLoaded() {
|
|
19916
|
+
if (this.loaded)
|
|
19917
|
+
return;
|
|
19918
|
+
this.loaded = true;
|
|
19919
|
+
if (this.statePath === undefined || !existsSync21(this.statePath))
|
|
19920
|
+
return;
|
|
19921
|
+
try {
|
|
19922
|
+
const parsed = JSON.parse(readFileSync17(this.statePath, "utf8"));
|
|
19923
|
+
if (parsed.version !== VECTORS_VERSION || typeof parsed.entries !== "object" || parsed.entries === null)
|
|
19924
|
+
return;
|
|
19925
|
+
if (typeof parsed.identity?.dimension !== "number")
|
|
19926
|
+
return;
|
|
19927
|
+
this.identity = parsed.identity;
|
|
19928
|
+
this.entries = { ...parsed.entries };
|
|
19929
|
+
} catch {}
|
|
19930
|
+
}
|
|
19931
|
+
persist() {
|
|
19932
|
+
if (this.statePath === undefined)
|
|
19933
|
+
return;
|
|
19934
|
+
if (this.identity === undefined)
|
|
19935
|
+
return;
|
|
19936
|
+
try {
|
|
19937
|
+
mkdirSync16(dirname17(this.statePath), { recursive: true });
|
|
19938
|
+
const payload = {
|
|
19939
|
+
version: VECTORS_VERSION,
|
|
19940
|
+
identity: this.identity,
|
|
19941
|
+
entries: this.entries
|
|
19942
|
+
};
|
|
19943
|
+
writeFileSync15(this.statePath, `${JSON.stringify(payload)}
|
|
19944
|
+
`, "utf8");
|
|
19945
|
+
} catch {}
|
|
19946
|
+
}
|
|
19947
|
+
}
|
|
19948
|
+
|
|
19949
|
+
class GitHubGistSemanticMethod {
|
|
19950
|
+
options;
|
|
19951
|
+
constructor(options) {
|
|
19952
|
+
this.options = options;
|
|
19953
|
+
}
|
|
19954
|
+
describe() {
|
|
19955
|
+
const { skillName, skillType, tags } = this.options;
|
|
19956
|
+
return {
|
|
19957
|
+
name: `${skillName}-semantic`,
|
|
19958
|
+
type: "vector",
|
|
19959
|
+
description: `Semantic retrieval over embedded ${skillType} chunks`,
|
|
19960
|
+
status: "active",
|
|
19961
|
+
capabilities: ["semantic", "scoped", "path-opaque-sources"],
|
|
19962
|
+
datasourceId: skillName,
|
|
19963
|
+
tags: [...tags]
|
|
19964
|
+
};
|
|
19965
|
+
}
|
|
19966
|
+
async retrieve(query, options) {
|
|
19967
|
+
const trimmed = query.trim();
|
|
19968
|
+
if (trimmed.length === 0)
|
|
19969
|
+
return [];
|
|
19970
|
+
const topK = options.topK ?? DEFAULT_TOP_K3;
|
|
19971
|
+
let queryVector;
|
|
19972
|
+
try {
|
|
19973
|
+
queryVector = (await this.options.embedder.embed([trimmed]))[0];
|
|
19974
|
+
} catch {
|
|
19975
|
+
return [];
|
|
19976
|
+
}
|
|
19977
|
+
if (queryVector === undefined)
|
|
19978
|
+
return [];
|
|
19979
|
+
const hits = this.options.index.searchByVector(queryVector, Math.max(topK * 3, topK));
|
|
19980
|
+
if (hits.length === 0)
|
|
19981
|
+
return [];
|
|
19982
|
+
const byChunkId = new Map(this.options.store.chunks().map((chunk) => [chunk.chunkId, chunk]));
|
|
19983
|
+
const { skillName, instanceId } = this.options;
|
|
19984
|
+
const mapped = [];
|
|
19985
|
+
for (const { chunkId, score } of hits) {
|
|
19986
|
+
const chunk = byChunkId.get(chunkId);
|
|
19987
|
+
if (chunk === undefined)
|
|
19988
|
+
continue;
|
|
19989
|
+
const source = datasourceSourcePath(skillName, instanceId, chunk.chunkId);
|
|
19990
|
+
if (!this.matchesScope(source, options.scope, options.allowedScopes))
|
|
19991
|
+
continue;
|
|
19992
|
+
mapped.push({
|
|
19993
|
+
id: `${skillName}:${instanceId}:${chunk.chunkId}`,
|
|
19994
|
+
content: chunk.content,
|
|
19995
|
+
source,
|
|
19996
|
+
score,
|
|
19997
|
+
metadata: {
|
|
19998
|
+
...chunk.metadata,
|
|
19999
|
+
method: `${skillName}-semantic`,
|
|
20000
|
+
datasourceId: skillName,
|
|
20001
|
+
instanceId,
|
|
20002
|
+
chunkId: chunk.chunkId,
|
|
20003
|
+
...chunk.title !== undefined ? { title: chunk.title } : {},
|
|
20004
|
+
...chunk.hierarchy.length > 0 ? { hierarchy: chunk.hierarchy.join("/") } : {},
|
|
20005
|
+
...chunk.publishedAt !== undefined ? { publishedAt: chunk.publishedAt } : {}
|
|
20006
|
+
}
|
|
20007
|
+
});
|
|
20008
|
+
if (mapped.length >= topK)
|
|
20009
|
+
break;
|
|
20010
|
+
}
|
|
20011
|
+
return mapped;
|
|
20012
|
+
}
|
|
20013
|
+
matchesScope(source, scope, allowedScopes) {
|
|
20014
|
+
if (!matchesDatasourceScope(source, scope))
|
|
20015
|
+
return false;
|
|
20016
|
+
if (allowedScopes === undefined || allowedScopes.length === 0)
|
|
20017
|
+
return true;
|
|
20018
|
+
return allowedScopes.some((entry) => matchesDatasourceScope(source, entry));
|
|
20019
|
+
}
|
|
20020
|
+
}
|
|
20021
|
+
function createGatewayGistEmbedder(options = {}) {
|
|
20022
|
+
let ensured;
|
|
20023
|
+
async function ensure() {
|
|
20024
|
+
if (ensured !== undefined)
|
|
20025
|
+
return ensured;
|
|
20026
|
+
let runtime = options.runtime;
|
|
20027
|
+
if (runtime === undefined) {
|
|
20028
|
+
const module = await Promise.resolve().then(() => (init_embedding_runtime(), {}));
|
|
20029
|
+
runtime = { ensureRuntime };
|
|
20030
|
+
}
|
|
20031
|
+
const result = await runtime.ensureRuntime({ profileId: options.profileId, cachedOnly: true });
|
|
20032
|
+
ensured = {
|
|
20033
|
+
baseUrl: result.baseUrl,
|
|
20034
|
+
identity: {
|
|
20035
|
+
provider: result.identity.provider,
|
|
20036
|
+
model: result.identity.model,
|
|
20037
|
+
dimension: result.identity.dimension
|
|
20038
|
+
}
|
|
20039
|
+
};
|
|
20040
|
+
return ensured;
|
|
20041
|
+
}
|
|
20042
|
+
return {
|
|
20043
|
+
identity: async () => (await ensure()).identity,
|
|
20044
|
+
async embed(texts) {
|
|
20045
|
+
if (texts.length === 0)
|
|
20046
|
+
return [];
|
|
20047
|
+
const { baseUrl, identity } = await ensure();
|
|
20048
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
20049
|
+
const embeddings = [];
|
|
20050
|
+
for (let offset = 0;offset < texts.length; offset += GIST_EMBED_BATCH_SIZE) {
|
|
20051
|
+
const batch = texts.slice(offset, offset + GIST_EMBED_BATCH_SIZE);
|
|
20052
|
+
const response = await fetchImpl(`${baseUrl}/v1/embeddings`, {
|
|
20053
|
+
method: "POST",
|
|
20054
|
+
headers: { "Content-Type": "application/json" },
|
|
20055
|
+
body: JSON.stringify({ model: identity.model, input: [...batch] })
|
|
20056
|
+
});
|
|
20057
|
+
if (!response.ok)
|
|
20058
|
+
throw new Error(`gateway /v1/embeddings returned HTTP ${response.status}`);
|
|
20059
|
+
const json = await response.json();
|
|
20060
|
+
const rows = [...json.data ?? []].sort((a, b) => (a.index ?? 0) - (b.index ?? 0));
|
|
20061
|
+
const batchEmbeddings = rows.map((row) => row.embedding ?? []);
|
|
20062
|
+
if (batchEmbeddings.length !== batch.length || batchEmbeddings.some((row) => row.length !== identity.dimension)) {
|
|
20063
|
+
throw new Error("gateway /v1/embeddings returned an invalid embedding batch");
|
|
20064
|
+
}
|
|
20065
|
+
embeddings.push(...batchEmbeddings);
|
|
20066
|
+
}
|
|
20067
|
+
return embeddings;
|
|
20068
|
+
}
|
|
20069
|
+
};
|
|
20070
|
+
}
|
|
20071
|
+
var VECTORS_VERSION = 1, DEFAULT_TOP_K3 = 20, GIST_EMBED_BATCH_SIZE = 32;
|
|
20072
|
+
var init_semantic = __esm(() => {
|
|
20073
|
+
init_scope2();
|
|
20074
|
+
});
|
|
20075
|
+
|
|
20076
|
+
// src/datasource/skills/github-gist/skill.ts
|
|
20077
|
+
import { join as join25 } from "node:path";
|
|
20078
|
+
function gistDatasourceDir(workspaceRoot, skillName, instanceId) {
|
|
20079
|
+
return join25(workspaceRoot, ".autorag", "datasources", sanitizeIdSegment(skillName), sanitizeIdSegment(instanceId));
|
|
20080
|
+
}
|
|
20081
|
+
var GITHUB_GIST_SKILL_DEFINITION, DEFAULT_INSTANCE_ID3 = "default", GitHubGistSkill;
|
|
20082
|
+
var init_skill5 = __esm(() => {
|
|
20083
|
+
init_connector();
|
|
20084
|
+
init_connector_skill();
|
|
20085
|
+
init_connector3();
|
|
20086
|
+
init_semantic();
|
|
20087
|
+
GITHUB_GIST_SKILL_DEFINITION = {
|
|
20088
|
+
skillName: "github-gist",
|
|
20089
|
+
skillType: "github-gist",
|
|
20090
|
+
description: "GitHub Gist datasource (authenticated account)",
|
|
20091
|
+
capabilities: ["gists", "api", "polling", "incremental", "lexical", "semantic"],
|
|
20092
|
+
defaultTags: ["github", "gists"],
|
|
20093
|
+
contentType: "gist",
|
|
20094
|
+
manifestDescription: "Search the authenticated GitHub account's indexed gists — code snippets, notes, and design memos. Use for questions about content the user saved as a gist.",
|
|
20095
|
+
manifestNotes: [
|
|
20096
|
+
"Gist visibility is bounded by the configured token scopes; secret gists are included when the token allows.",
|
|
20097
|
+
"Semantic retrieval embeds chunks through the local loopback embedding gateway; gist content never leaves the machine for embeddings."
|
|
20098
|
+
]
|
|
20099
|
+
};
|
|
20100
|
+
GitHubGistSkill = class GitHubGistSkill extends ConnectorDatasourceSkill {
|
|
20101
|
+
semanticIndex;
|
|
20102
|
+
semanticEmbedder;
|
|
20103
|
+
semanticMethod;
|
|
20104
|
+
constructor(options = {}) {
|
|
20105
|
+
const { connector, connectorOptions, semantic, ...rest } = options;
|
|
20106
|
+
const instanceId = options.instanceId ?? DEFAULT_INSTANCE_ID3;
|
|
20107
|
+
const statePath = connectorOptions?.statePath ?? (options.workspaceRoot === undefined ? undefined : join25(gistDatasourceDir(options.workspaceRoot, GITHUB_GIST_SKILL_DEFINITION.skillName, instanceId), "state.json"));
|
|
20108
|
+
super(GITHUB_GIST_SKILL_DEFINITION, {
|
|
20109
|
+
...rest,
|
|
20110
|
+
connector: connector ?? new GitHubGistConnector({
|
|
20111
|
+
...connectorOptions ?? {},
|
|
20112
|
+
...statePath !== undefined && connectorOptions?.statePath === undefined ? { statePath } : {}
|
|
20113
|
+
})
|
|
20114
|
+
});
|
|
20115
|
+
if (semantic?.enabled !== false) {
|
|
20116
|
+
this.semanticIndex = new GistSemanticIndex({
|
|
20117
|
+
statePath: semantic?.statePath ?? (options.workspaceRoot === undefined ? undefined : join25(gistDatasourceDir(options.workspaceRoot, GITHUB_GIST_SKILL_DEFINITION.skillName, instanceId), "vectors.json"))
|
|
20118
|
+
});
|
|
20119
|
+
this.semanticEmbedder = semantic?.embedder ?? createGatewayGistEmbedder(semantic?.embedderOptions ?? {});
|
|
20120
|
+
this.semanticMethod = new GitHubGistSemanticMethod({
|
|
20121
|
+
skillName: this.describe().name,
|
|
20122
|
+
skillType: GITHUB_GIST_SKILL_DEFINITION.skillType,
|
|
20123
|
+
instanceId: this.instanceId,
|
|
20124
|
+
tags: this.describe().tags,
|
|
20125
|
+
store: this.store,
|
|
20126
|
+
index: this.semanticIndex,
|
|
20127
|
+
embedder: this.semanticEmbedder
|
|
20128
|
+
});
|
|
20129
|
+
}
|
|
20130
|
+
}
|
|
20131
|
+
async index() {
|
|
20132
|
+
const result = await super.index();
|
|
20133
|
+
if (!result.ok || this.semanticIndex === undefined || this.semanticEmbedder === undefined)
|
|
20134
|
+
return result;
|
|
20135
|
+
const sync = await this.semanticIndex.sync(this.store.chunks(), this.semanticEmbedder);
|
|
20136
|
+
if (sync.ok)
|
|
20137
|
+
return result;
|
|
20138
|
+
return {
|
|
20139
|
+
...result,
|
|
20140
|
+
diagnostics: [
|
|
20141
|
+
...result.diagnostics,
|
|
20142
|
+
{
|
|
20143
|
+
code: "datasource-index-failed",
|
|
20144
|
+
severity: "warning",
|
|
20145
|
+
message: boundDiagnosticText2(`semantic-unavailable: ${sync.message}`),
|
|
20146
|
+
instanceId: this.instanceId,
|
|
20147
|
+
source: this.describe().name
|
|
20148
|
+
}
|
|
20149
|
+
]
|
|
20150
|
+
};
|
|
20151
|
+
}
|
|
20152
|
+
retrievalMethods() {
|
|
20153
|
+
const methods = super.retrievalMethods();
|
|
20154
|
+
return this.semanticMethod === undefined ? methods : [...methods, this.semanticMethod];
|
|
20155
|
+
}
|
|
20156
|
+
};
|
|
20157
|
+
});
|
|
20158
|
+
|
|
20159
|
+
// src/datasource/skills/github-gist/index.ts
|
|
20160
|
+
var init_github_gist = __esm(() => {
|
|
20161
|
+
init_connector3();
|
|
20162
|
+
init_semantic();
|
|
20163
|
+
init_skill5();
|
|
20164
|
+
});
|
|
20165
|
+
|
|
20166
|
+
// src/datasource/crawler-client.ts
|
|
20167
|
+
import { spawn as spawn11 } from "node:child_process";
|
|
20168
|
+
|
|
20169
|
+
class CrawlerCliClient {
|
|
20170
|
+
profile;
|
|
20171
|
+
options;
|
|
20172
|
+
constructor(profile, options = {}) {
|
|
20173
|
+
this.profile = profile;
|
|
20174
|
+
this.options = options;
|
|
20175
|
+
}
|
|
20176
|
+
async sync(signal) {
|
|
20177
|
+
const result = await this.run(this.profile.syncArgs(this.options), signal);
|
|
20178
|
+
if (!result.ok)
|
|
20179
|
+
return toFailure2(result);
|
|
20180
|
+
const count = this.profile.parseSyncCount(result.stdout);
|
|
20181
|
+
if (count === undefined)
|
|
20182
|
+
return toFailure2(result, "invalid-output");
|
|
20183
|
+
return { ok: true, count, stdout: result.stdout, stderr: result.stderr, code: result.code ?? 0 };
|
|
20184
|
+
}
|
|
20185
|
+
async search(query, options = {}) {
|
|
20186
|
+
const topK = options.topK ?? 20;
|
|
20187
|
+
const result = await this.run(this.profile.searchArgs(this.options, query, topK), options.signal);
|
|
20188
|
+
if (!result.ok)
|
|
20189
|
+
return toFailure2(result);
|
|
20190
|
+
const hits = this.profile.parseHits(result.stdout);
|
|
20191
|
+
if (hits === undefined)
|
|
20192
|
+
return toFailure2(result, "invalid-output");
|
|
20193
|
+
return { ok: true, hits, stdout: result.stdout, stderr: result.stderr, code: result.code ?? 0 };
|
|
20194
|
+
}
|
|
20195
|
+
async run(args, signal) {
|
|
20196
|
+
const env = controlledEnv3(this.profile.allowedEnvPrefixes, this.options.env);
|
|
20197
|
+
env.CRAWLKIT_NO_UPDATE_CHECK = "1";
|
|
20198
|
+
return spawnCrawler(this.options.binaryPath ?? this.profile.binaryName, args, env, signal, this.options, this.options.workspacePath);
|
|
20199
|
+
}
|
|
20200
|
+
}
|
|
20201
|
+
function spawnCrawler(command, args, env, signal, options, cwd) {
|
|
20202
|
+
return new Promise((resolve) => {
|
|
20203
|
+
const portable = portableSpawnCommand(command, args);
|
|
20204
|
+
const child = spawn11(portable.command, [...portable.args], {
|
|
20205
|
+
env,
|
|
20206
|
+
...cwd === undefined ? {} : { cwd },
|
|
20207
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
20208
|
+
});
|
|
20209
|
+
let stdout = { text: "", bytes: 0, capped: false };
|
|
20210
|
+
let stderr = { text: "", bytes: 0, capped: false };
|
|
20211
|
+
let settled = false;
|
|
20212
|
+
let finalReason;
|
|
20213
|
+
const maxBuffer = options.maxBufferBytes ?? DEFAULT_MAX_BUFFER_BYTES3;
|
|
20214
|
+
const timeout = setTimeout(() => {
|
|
20215
|
+
finalReason = "timeout";
|
|
20216
|
+
terminate3(child);
|
|
20217
|
+
}, options.timeoutMs ?? DEFAULT_TIMEOUT_MS8);
|
|
20218
|
+
const abortHandler = () => {
|
|
20219
|
+
finalReason = "aborted";
|
|
20220
|
+
terminate3(child);
|
|
20221
|
+
};
|
|
20222
|
+
if (signal?.aborted)
|
|
20223
|
+
abortHandler();
|
|
20224
|
+
signal?.addEventListener("abort", abortHandler, { once: true });
|
|
20225
|
+
child.stdout.setEncoding("utf8");
|
|
20226
|
+
child.stderr.setEncoding("utf8");
|
|
20227
|
+
child.stdout.on("data", (chunk) => {
|
|
20228
|
+
stdout = appendBounded3(stdout, chunk, maxBuffer);
|
|
20229
|
+
if (stdout.capped) {
|
|
20230
|
+
finalReason = "stdout-too-large";
|
|
20231
|
+
terminate3(child);
|
|
20232
|
+
}
|
|
20233
|
+
});
|
|
20234
|
+
child.stderr.on("data", (chunk) => {
|
|
20235
|
+
stderr = appendBounded3(stderr, chunk, maxBuffer);
|
|
20236
|
+
if (stderr.capped) {
|
|
20237
|
+
finalReason = "stderr-too-large";
|
|
20238
|
+
terminate3(child);
|
|
20239
|
+
}
|
|
20240
|
+
});
|
|
20241
|
+
child.on("error", (error) => {
|
|
20242
|
+
if (settled)
|
|
20243
|
+
return;
|
|
20244
|
+
settled = true;
|
|
20245
|
+
clearTimeout(timeout);
|
|
20246
|
+
signal?.removeEventListener("abort", abortHandler);
|
|
20247
|
+
resolve({
|
|
20248
|
+
ok: false,
|
|
20249
|
+
reason: error.code === "ENOENT" ? "binary-missing" : "spawn-error",
|
|
20250
|
+
stdout: stdout.text,
|
|
20251
|
+
stderr: "",
|
|
20252
|
+
code: null
|
|
20253
|
+
});
|
|
20254
|
+
});
|
|
20255
|
+
child.on("close", (code) => {
|
|
20256
|
+
if (settled)
|
|
20257
|
+
return;
|
|
20258
|
+
settled = true;
|
|
20259
|
+
clearTimeout(timeout);
|
|
20260
|
+
signal?.removeEventListener("abort", abortHandler);
|
|
20261
|
+
resolve({
|
|
20262
|
+
ok: code === 0 && finalReason === undefined,
|
|
20263
|
+
...finalReason !== undefined ? { reason: finalReason } : code === 0 ? {} : { reason: "nonzero-exit" },
|
|
20264
|
+
stdout: stdout.text,
|
|
20265
|
+
stderr: stderr.text,
|
|
20266
|
+
code
|
|
20267
|
+
});
|
|
20268
|
+
});
|
|
20269
|
+
});
|
|
20270
|
+
}
|
|
20271
|
+
function controlledEnv3(allowedPrefixes, configured) {
|
|
20272
|
+
const env = {};
|
|
20273
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
20274
|
+
if (value !== undefined && isAllowedEnvKey(key, allowedPrefixes))
|
|
20275
|
+
env[key] = value;
|
|
20276
|
+
}
|
|
20277
|
+
for (const [key, value] of Object.entries(configured ?? {})) {
|
|
20278
|
+
if (value === undefined)
|
|
20279
|
+
delete env[key];
|
|
20280
|
+
else if (isAllowedEnvKey(key, allowedPrefixes))
|
|
20281
|
+
env[key] = value;
|
|
20282
|
+
}
|
|
20283
|
+
return env;
|
|
20284
|
+
}
|
|
20285
|
+
function isAllowedEnvKey(key, allowedPrefixes) {
|
|
20286
|
+
return SAFE_ENV_KEYS.has(key) || process.platform === "win32" && [...SAFE_ENV_KEYS].some((safeKey) => safeKey.toUpperCase() === key.toUpperCase()) || key.startsWith("CRAWLKIT_") || allowedPrefixes.some((prefix) => key.startsWith(prefix));
|
|
20287
|
+
}
|
|
20288
|
+
function appendBounded3(state, chunk, maxBytes) {
|
|
20289
|
+
const nextBytes = state.bytes + Buffer.byteLength(chunk);
|
|
20290
|
+
if (nextBytes <= maxBytes)
|
|
20291
|
+
return { text: state.text + chunk, bytes: nextBytes, capped: false };
|
|
20292
|
+
const remaining = Math.max(maxBytes - state.bytes, 0);
|
|
20293
|
+
return { text: state.text + chunk.slice(0, remaining), bytes: maxBytes, capped: true };
|
|
20294
|
+
}
|
|
20295
|
+
function terminate3(child) {
|
|
20296
|
+
if (!child.killed)
|
|
20297
|
+
child.kill("SIGTERM");
|
|
20298
|
+
}
|
|
20299
|
+
function toFailure2(result, reason) {
|
|
20300
|
+
return {
|
|
20301
|
+
ok: false,
|
|
20302
|
+
reason: reason ?? result.reason ?? "nonzero-exit",
|
|
20303
|
+
stdout: result.stdout,
|
|
20304
|
+
stderr: boundDiagnosticText4(result),
|
|
20305
|
+
code: result.code
|
|
20306
|
+
};
|
|
20307
|
+
}
|
|
20308
|
+
function boundDiagnosticText4(result) {
|
|
20309
|
+
if (result.stderr.length > 0)
|
|
20310
|
+
return result.stderr.trim().slice(0, 4000);
|
|
20311
|
+
if (result.stdout.length > 0)
|
|
20312
|
+
return result.stdout.trim().slice(0, 4000);
|
|
20313
|
+
return "";
|
|
20314
|
+
}
|
|
20315
|
+
var DEFAULT_TIMEOUT_MS8 = 60000, DEFAULT_MAX_BUFFER_BYTES3 = 1048576, SAFE_ENV_KEYS;
|
|
20316
|
+
var init_crawler_client = __esm(() => {
|
|
20317
|
+
init_portable_spawn();
|
|
20318
|
+
SAFE_ENV_KEYS = new Set([
|
|
20319
|
+
"HOME",
|
|
20320
|
+
"LANG",
|
|
20321
|
+
"LC_ALL",
|
|
20322
|
+
"PATH",
|
|
20323
|
+
"TMPDIR",
|
|
20324
|
+
"TMP",
|
|
20325
|
+
"TEMP",
|
|
20326
|
+
"NO_COLOR",
|
|
20327
|
+
"APPDATA",
|
|
20328
|
+
"ComSpec",
|
|
20329
|
+
"LOCALAPPDATA",
|
|
20330
|
+
"PATHEXT",
|
|
20331
|
+
"SystemDrive",
|
|
20332
|
+
"SystemRoot",
|
|
20333
|
+
"USERPROFILE",
|
|
20334
|
+
"WINDIR"
|
|
20335
|
+
]);
|
|
20336
|
+
});
|
|
20337
|
+
|
|
20338
|
+
// src/datasource/skills/lark/client.ts
|
|
20339
|
+
class LarkClient {
|
|
20340
|
+
version;
|
|
20341
|
+
auth;
|
|
20342
|
+
messages;
|
|
20343
|
+
docs;
|
|
20344
|
+
sleep;
|
|
20345
|
+
constructor(options = {}) {
|
|
20346
|
+
const cli = {
|
|
20347
|
+
binaryPath: options.binaryPath ?? "lark-cli",
|
|
20348
|
+
...options.env !== undefined ? { env: options.env } : {},
|
|
20349
|
+
...options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}
|
|
20350
|
+
};
|
|
20351
|
+
const chatIds = (options.chatIds ?? []).filter(isSafeId);
|
|
20352
|
+
this.version = new CrawlerCliClient(VERSION_PROFILE, cli);
|
|
20353
|
+
this.auth = new CrawlerCliClient(AUTH_PROFILE, cli);
|
|
20354
|
+
this.messages = new CrawlerCliClient(messageProfile(chatIds), cli);
|
|
20355
|
+
this.docs = new CrawlerCliClient(DOC_PROFILE, cli);
|
|
20356
|
+
this.sleep = options.sleep ?? delay2;
|
|
20357
|
+
}
|
|
20358
|
+
probeVersion() {
|
|
20359
|
+
return this.version.sync();
|
|
20360
|
+
}
|
|
20361
|
+
probeAuth() {
|
|
20362
|
+
return this.auth.sync();
|
|
20363
|
+
}
|
|
20364
|
+
searchMessages(query, topK) {
|
|
20365
|
+
return this.retry(() => this.messages.search(query, topK === undefined ? {} : { topK }));
|
|
20366
|
+
}
|
|
20367
|
+
searchDocs(query, topK) {
|
|
20368
|
+
return this.retry(() => this.docs.search(query, topK === undefined ? {} : { topK }));
|
|
20369
|
+
}
|
|
20370
|
+
async retry(run) {
|
|
20371
|
+
let failure;
|
|
20372
|
+
for (let attempt = 0;attempt < MAX_ATTEMPTS; attempt += 1) {
|
|
20373
|
+
const result = await run();
|
|
20374
|
+
if (result.ok)
|
|
20375
|
+
return result;
|
|
20376
|
+
failure = result;
|
|
20377
|
+
if (!isRateLimited(result) || attempt === MAX_ATTEMPTS - 1)
|
|
20378
|
+
return result;
|
|
20379
|
+
await this.sleep(200 * 2 ** attempt);
|
|
20380
|
+
}
|
|
20381
|
+
return failure ?? { ok: false, reason: "spawn-error", stdout: "", stderr: "", code: null };
|
|
20382
|
+
}
|
|
20383
|
+
}
|
|
20384
|
+
function messageProfile(chatIds) {
|
|
20385
|
+
return {
|
|
20386
|
+
binaryName: "lark-cli",
|
|
20387
|
+
allowedEnvPrefixes: [],
|
|
20388
|
+
syncArgs: () => [],
|
|
20389
|
+
searchArgs: (_options, query, topK) => {
|
|
20390
|
+
const args = [
|
|
20391
|
+
"im",
|
|
20392
|
+
"+messages-search",
|
|
20393
|
+
"--query",
|
|
20394
|
+
query,
|
|
20395
|
+
"--format",
|
|
20396
|
+
"json",
|
|
20397
|
+
"--page-size",
|
|
20398
|
+
String(clampPageSize(topK, MESSAGE_PAGE_MAX))
|
|
20399
|
+
];
|
|
20400
|
+
if (chatIds.length > 0)
|
|
20401
|
+
args.push("--chat-id", chatIds.join(","));
|
|
20402
|
+
return args;
|
|
20403
|
+
},
|
|
20404
|
+
parseSyncCount: () => 0,
|
|
20405
|
+
parseHits: parseMessages
|
|
20406
|
+
};
|
|
20407
|
+
}
|
|
20408
|
+
function parseMessages(stdout) {
|
|
20409
|
+
const data = envelopeData(stdout);
|
|
20410
|
+
if (data === undefined)
|
|
20411
|
+
return;
|
|
20412
|
+
const rows = data.messages;
|
|
20413
|
+
if (!Array.isArray(rows))
|
|
20414
|
+
return;
|
|
20415
|
+
const hits = [];
|
|
20416
|
+
for (const row of rows) {
|
|
20417
|
+
if (!isRecord12(row))
|
|
20418
|
+
return;
|
|
20419
|
+
const id = scalarString(row.message_id);
|
|
20420
|
+
const content = scalarString(row.content);
|
|
20421
|
+
if (id === undefined || content === undefined || !isSafeId(id))
|
|
20422
|
+
continue;
|
|
20423
|
+
const chatId = scalarString(row.chat_id);
|
|
20424
|
+
const observedAt = scalarString(row.create_time);
|
|
20425
|
+
hits.push({
|
|
20426
|
+
id,
|
|
20427
|
+
content,
|
|
20428
|
+
score: 1 / (hits.length + 1),
|
|
20429
|
+
...scalarString(row.chat_name) !== undefined ? { title: scalarString(row.chat_name) } : {},
|
|
20430
|
+
metadata: {
|
|
20431
|
+
...chatId !== undefined ? { chatId } : {},
|
|
20432
|
+
...scalarString(row.chat_type) !== undefined ? { chatType: scalarString(row.chat_type) } : {},
|
|
20433
|
+
...scalarString(row.chat_name) !== undefined ? { chatName: scalarString(row.chat_name) } : {},
|
|
20434
|
+
...observedAt !== undefined ? { observedAt } : {},
|
|
20435
|
+
coverage: "server-side-unverified"
|
|
20436
|
+
}
|
|
20437
|
+
});
|
|
20438
|
+
}
|
|
20439
|
+
return hits;
|
|
20440
|
+
}
|
|
20441
|
+
function parseDocs(stdout) {
|
|
20442
|
+
const data = envelopeData(stdout);
|
|
20443
|
+
if (data === undefined)
|
|
20444
|
+
return;
|
|
20445
|
+
const rows = data.results;
|
|
20446
|
+
if (!Array.isArray(rows))
|
|
20447
|
+
return;
|
|
20448
|
+
const hits = [];
|
|
20449
|
+
for (const row of rows) {
|
|
20450
|
+
if (!isRecord12(row))
|
|
20451
|
+
return;
|
|
20452
|
+
const meta = isRecord12(row.result_meta) ? row.result_meta : {};
|
|
20453
|
+
const token = firstString(meta, ["token", "docs_token"]) ?? firstString(row, ["token", "docs_token"]) ?? tokenFromUrl(firstString(meta, ["url"]));
|
|
20454
|
+
const content = stripHighlight(firstString(row, ["summary_highlighted", "title_highlighted", "summary", "title"]) ?? "");
|
|
20455
|
+
if (token === undefined || !isSafeId(token) || content.length === 0)
|
|
20456
|
+
continue;
|
|
20457
|
+
const permalink = firstString(meta, ["url"]);
|
|
20458
|
+
const observedAt = firstString(meta, ["update_time_iso", "update_time"]) ?? scalarString(meta.update_time);
|
|
20459
|
+
hits.push({
|
|
20460
|
+
id: token,
|
|
20461
|
+
content,
|
|
20462
|
+
score: 1 / (hits.length + 1),
|
|
20463
|
+
...firstString(row, ["title", "title_highlighted"]) !== undefined ? { title: stripHighlight(firstString(row, ["title", "title_highlighted"]) ?? "") } : {},
|
|
20464
|
+
metadata: {
|
|
20465
|
+
...permalink !== undefined ? { permalink } : {},
|
|
20466
|
+
...observedAt !== undefined ? { observedAt } : {},
|
|
20467
|
+
coverage: "server-side-unverified"
|
|
20468
|
+
}
|
|
20469
|
+
});
|
|
20470
|
+
}
|
|
20471
|
+
return hits;
|
|
20472
|
+
}
|
|
20473
|
+
function envelopeData(stdout) {
|
|
20474
|
+
const trimmed = stdout.trim();
|
|
20475
|
+
if (trimmed.length === 0)
|
|
20476
|
+
return;
|
|
20477
|
+
let parsed;
|
|
20478
|
+
try {
|
|
20479
|
+
parsed = JSON.parse(trimmed);
|
|
20480
|
+
} catch {
|
|
20481
|
+
return;
|
|
20482
|
+
}
|
|
20483
|
+
if (!isRecord12(parsed) || parsed.ok !== true || !isRecord12(parsed.data))
|
|
20484
|
+
return;
|
|
20485
|
+
return parsed.data;
|
|
20486
|
+
}
|
|
20487
|
+
function firstString(record, keys) {
|
|
20488
|
+
for (const key of keys) {
|
|
20489
|
+
const value = scalarString(record[key]);
|
|
20490
|
+
if (value !== undefined)
|
|
20491
|
+
return value;
|
|
20492
|
+
}
|
|
20493
|
+
return;
|
|
20494
|
+
}
|
|
20495
|
+
function scalarString(value) {
|
|
20496
|
+
if (typeof value === "string" && value.length > 0)
|
|
20497
|
+
return value;
|
|
20498
|
+
if (typeof value === "number" && Number.isFinite(value))
|
|
20499
|
+
return String(value);
|
|
20500
|
+
return;
|
|
20501
|
+
}
|
|
20502
|
+
function tokenFromUrl(url) {
|
|
20503
|
+
if (url === undefined)
|
|
20504
|
+
return;
|
|
20505
|
+
const path = url.split("?")[0]?.split("#")[0] ?? "";
|
|
20506
|
+
const parts = path.split("/").filter((part) => part.length > 0);
|
|
20507
|
+
const segment = parts[parts.length - 1];
|
|
20508
|
+
return segment !== undefined && isSafeId(segment) ? segment : undefined;
|
|
20509
|
+
}
|
|
20510
|
+
function stripHighlight(value) {
|
|
20511
|
+
return value.replaceAll("<h>", "").replaceAll("</h>", "").replaceAll("<hb>", "").replaceAll("</hb>", "").trim();
|
|
20512
|
+
}
|
|
20513
|
+
function isSafeId(value) {
|
|
20514
|
+
return value.length > 0 && value !== "." && value !== ".." && !value.includes("#") && !value.includes("/");
|
|
20515
|
+
}
|
|
20516
|
+
function isRecord12(value) {
|
|
20517
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20518
|
+
}
|
|
20519
|
+
function isRateLimited(failure) {
|
|
20520
|
+
return failure.stderr.includes(RATE_LIMIT_CODE) || failure.stdout.includes(RATE_LIMIT_CODE);
|
|
20521
|
+
}
|
|
20522
|
+
function clampPageSize(topK, max) {
|
|
20523
|
+
if (!Number.isFinite(topK))
|
|
20524
|
+
return Math.min(20, max);
|
|
20525
|
+
const truncated = Math.trunc(topK);
|
|
20526
|
+
if (truncated < 1)
|
|
20527
|
+
return 1;
|
|
20528
|
+
if (truncated > max)
|
|
20529
|
+
return max;
|
|
20530
|
+
return truncated;
|
|
20531
|
+
}
|
|
20532
|
+
function delay2(ms) {
|
|
20533
|
+
return new Promise((resolve) => {
|
|
20534
|
+
setTimeout(resolve, ms);
|
|
20535
|
+
});
|
|
20536
|
+
}
|
|
20537
|
+
var MESSAGE_PAGE_MAX = 50, DOC_PAGE_MAX = 20, RATE_LIMIT_CODE = "99991400", MAX_ATTEMPTS = 7, VERSION_PROFILE, AUTH_PROFILE, DOC_PROFILE;
|
|
20538
|
+
var init_client5 = __esm(() => {
|
|
20539
|
+
init_crawler_client();
|
|
20540
|
+
VERSION_PROFILE = {
|
|
20541
|
+
binaryName: "lark-cli",
|
|
20542
|
+
allowedEnvPrefixes: [],
|
|
20543
|
+
syncArgs: () => ["--version"],
|
|
20544
|
+
searchArgs: () => [],
|
|
20545
|
+
parseSyncCount: () => 0,
|
|
20546
|
+
parseHits: () => []
|
|
20547
|
+
};
|
|
20548
|
+
AUTH_PROFILE = {
|
|
20549
|
+
binaryName: "lark-cli",
|
|
20550
|
+
allowedEnvPrefixes: [],
|
|
20551
|
+
syncArgs: () => ["auth", "status", "--json"],
|
|
20552
|
+
searchArgs: () => [],
|
|
20553
|
+
parseSyncCount: () => 0,
|
|
20554
|
+
parseHits: () => []
|
|
20555
|
+
};
|
|
20556
|
+
DOC_PROFILE = {
|
|
20557
|
+
binaryName: "lark-cli",
|
|
20558
|
+
allowedEnvPrefixes: [],
|
|
20559
|
+
syncArgs: () => [],
|
|
20560
|
+
searchArgs: (_options, query, topK) => [
|
|
20561
|
+
"drive",
|
|
20562
|
+
"+search",
|
|
20563
|
+
"--query",
|
|
20564
|
+
query,
|
|
20565
|
+
"--format",
|
|
20566
|
+
"json",
|
|
20567
|
+
"--page-size",
|
|
20568
|
+
String(clampPageSize(topK, DOC_PAGE_MAX))
|
|
20569
|
+
],
|
|
20570
|
+
parseSyncCount: () => 0,
|
|
20571
|
+
parseHits: parseDocs
|
|
20572
|
+
};
|
|
20573
|
+
});
|
|
20574
|
+
|
|
20575
|
+
// src/datasource/skills/lark/skill.ts
|
|
20576
|
+
class LarkSkill {
|
|
20577
|
+
client;
|
|
20578
|
+
datasourceId;
|
|
20579
|
+
instanceId;
|
|
20580
|
+
instances;
|
|
20581
|
+
tags;
|
|
20582
|
+
chatIds;
|
|
20583
|
+
embedderBaseUrl;
|
|
20584
|
+
lastIndexedAt;
|
|
20585
|
+
lastError;
|
|
20586
|
+
constructor(options = {}) {
|
|
20587
|
+
this.datasourceId = options.datasourceId ?? "lark";
|
|
20588
|
+
this.instanceId = isSafeId(options.instanceId ?? "default") ? options.instanceId ?? "default" : "default";
|
|
20589
|
+
this.instances = options.instances !== undefined && options.instances.length > 0 ? options.instances : [this.instanceId];
|
|
20590
|
+
this.tags = options.tags ?? DEFAULT_TAGS2;
|
|
20591
|
+
this.chatIds = options.chatIds ?? [];
|
|
20592
|
+
this.embedderBaseUrl = options.embedderBaseUrl;
|
|
20593
|
+
this.client = options.client ?? new LarkClient({
|
|
20594
|
+
...options.binaryPath !== undefined ? { binaryPath: options.binaryPath } : {},
|
|
20595
|
+
...options.env !== undefined ? { env: options.env } : {},
|
|
20596
|
+
...options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {},
|
|
20597
|
+
...options.chatIds !== undefined ? { chatIds: options.chatIds } : {},
|
|
20598
|
+
...options.sleep !== undefined ? { sleep: options.sleep } : {}
|
|
20599
|
+
});
|
|
20600
|
+
}
|
|
20601
|
+
describe() {
|
|
20602
|
+
return {
|
|
20603
|
+
name: this.datasourceId,
|
|
20604
|
+
id: this.datasourceId,
|
|
20605
|
+
type: "lark-remote",
|
|
20606
|
+
description: "Lark/Feishu remote search via lark-cli. Credentials stay in the CLI keychain.",
|
|
20607
|
+
capabilities: ["external-cli", "remote-search", "scoped"],
|
|
20608
|
+
tags: this.tags,
|
|
20609
|
+
status: "active",
|
|
20610
|
+
requiresExternalCli: true,
|
|
20611
|
+
datasourceId: this.datasourceId,
|
|
20612
|
+
instanceId: this.instanceId,
|
|
20613
|
+
instances: this.instances
|
|
20614
|
+
};
|
|
20615
|
+
}
|
|
20616
|
+
polling() {
|
|
20617
|
+
return {
|
|
20618
|
+
mode: "none",
|
|
20619
|
+
...this.lastIndexedAt !== undefined ? { lastIndexedAt: this.lastIndexedAt } : {},
|
|
20620
|
+
...this.lastError !== undefined ? { lastError: this.lastError } : {}
|
|
20621
|
+
};
|
|
20622
|
+
}
|
|
20623
|
+
async index() {
|
|
20624
|
+
try {
|
|
20625
|
+
if (isRemoteEmbedder(this.embedderBaseUrl)) {
|
|
20626
|
+
return this.fail("datasource-embedding-egress-rejected", "remote embedding egress is not allowed for lark");
|
|
20627
|
+
}
|
|
20628
|
+
const diagnostics = [this.note(REMOTE_NOTE, "datasource-empty", "info")];
|
|
20629
|
+
const version = await this.client.probeVersion();
|
|
20630
|
+
if (!version.ok) {
|
|
20631
|
+
const message = probeMessage("--version", version);
|
|
20632
|
+
this.lastError = message;
|
|
20633
|
+
diagnostics.push(this.note(message, "datasource-unavailable", "warning"));
|
|
20634
|
+
return this.ok(diagnostics);
|
|
20635
|
+
}
|
|
20636
|
+
const auth = await this.client.probeAuth();
|
|
20637
|
+
if (!auth.ok) {
|
|
20638
|
+
const message = probeMessage("auth status", auth);
|
|
20639
|
+
this.lastError = message;
|
|
20640
|
+
diagnostics.push(this.note(message, "datasource-auth-error", "warning"));
|
|
20641
|
+
return this.ok(diagnostics);
|
|
20642
|
+
}
|
|
20643
|
+
this.lastError = undefined;
|
|
20644
|
+
this.lastIndexedAt = Date.now();
|
|
20645
|
+
return this.ok(diagnostics);
|
|
20646
|
+
} catch (error) {
|
|
20647
|
+
const message = error instanceof Error ? error.message : "lark index failed";
|
|
20648
|
+
return this.fail("datasource-unavailable", message);
|
|
20649
|
+
}
|
|
20650
|
+
}
|
|
20651
|
+
retrievalMethods() {
|
|
20652
|
+
return [new LarkRemoteMethod(this, "messages"), new LarkRemoteMethod(this, "docs")];
|
|
20653
|
+
}
|
|
20654
|
+
describeSources() {
|
|
20655
|
+
return this.instances.map((instanceId) => ({
|
|
20656
|
+
source: normalizeVirtualPath2(`/${this.datasourceId}/${instanceId}`),
|
|
20657
|
+
datasourceId: this.datasourceId,
|
|
20658
|
+
skill: this.datasourceId,
|
|
20659
|
+
instanceId,
|
|
20660
|
+
contentType: "lark",
|
|
20661
|
+
metadata: { datasourceId: this.datasourceId, instanceId, tags: this.tags }
|
|
20662
|
+
}));
|
|
20663
|
+
}
|
|
20664
|
+
skillManifest() {
|
|
20665
|
+
const scopes = this.instances.map((instanceId) => `- \`${normalizeVirtualPath2(`/${this.datasourceId}/${instanceId}`)}\``).join(`
|
|
20666
|
+
`);
|
|
20667
|
+
const chats = this.chatIds.length === 0 ? "Message search covers every chat the logged-in identity can already see." : `Message search is limited to configured chat ids: ${this.chatIds.join(", ")}.`;
|
|
20668
|
+
return {
|
|
20669
|
+
name: `datasource-${this.datasourceId}`,
|
|
20670
|
+
description: "Search the signed-in Lark or Feishu tenant for messages and cloud documents. The tenant keeps the index; AutoRAG does not copy it.",
|
|
20671
|
+
content: [
|
|
20672
|
+
"# Lark / Feishu (lark-cli remote search)",
|
|
20673
|
+
"",
|
|
20674
|
+
"Search live Lark/Feishu messages and cloud documents through the official `lark-cli`. AutoRAG does not open the desktop client's private databases, does not keep a local archive, and never sees app secrets or user tokens. Those stay in the CLI keychain.",
|
|
20675
|
+
"",
|
|
20676
|
+
"## When to use",
|
|
20677
|
+
"Questions about Lark/Feishu chats or docs (docx, wiki, drive, sheets, bitable) the signed-in user can already open.",
|
|
20678
|
+
"",
|
|
20679
|
+
"## How to search",
|
|
20680
|
+
`Call the dedicated \`${datasourceSearchToolName(this.datasourceId)}\` tool with a query and optional narrowing scope. Available authorized scopes:`,
|
|
20681
|
+
scopes,
|
|
20682
|
+
"",
|
|
20683
|
+
"`scope` can only narrow within already-authorized scopes; it can never widen access. A scope under `messages` searches chats. A scope under `docs` searches documents.",
|
|
20684
|
+
"",
|
|
20685
|
+
chats,
|
|
20686
|
+
"",
|
|
20687
|
+
"Server ranking is not BM25, vector, or hybrid. Coverage of old messages, retention, and chat types is whatever the tenant indexed for this token, and that coverage is not guaranteed. A hit is a live pointer: later edits or recalls change the text. Document search rejects a query longer than 30 Unicode characters.",
|
|
20688
|
+
"",
|
|
20689
|
+
"## Read a hit",
|
|
20690
|
+
"Search snippets are not the whole record. Read them with the CLI, not with `bash` on the `/lark/...` identity:",
|
|
20691
|
+
"- `lark-cli im +messages-mget --message-ids <message_id> --format json`",
|
|
20692
|
+
"- `lark-cli docs +fetch --doc <token> --doc-format markdown`",
|
|
20693
|
+
"",
|
|
20694
|
+
"## Native CLI",
|
|
20695
|
+
"The external `lark-cli` owns login and credentials. When the dedicated tool cannot express a filter, call it through `bash`:",
|
|
20696
|
+
'- `lark-cli im +messages-search --query "<query>" --format json`',
|
|
20697
|
+
'- `lark-cli drive +search --query "<query>" --format json`',
|
|
20698
|
+
"Login is `lark-cli auth login` with explicit scopes (`search:message` for chats, `search:docs:read` for documents), then `lark-cli auth status`. `auth login --recommend` does not grant those scopes by itself.",
|
|
20699
|
+
`Never pass datasource virtual paths (\`/${this.datasourceId}/...\`) to bash; they are not OS paths.`
|
|
20700
|
+
].join(`
|
|
20701
|
+
`)
|
|
20702
|
+
};
|
|
20703
|
+
}
|
|
20704
|
+
async search(surface, query, options) {
|
|
20705
|
+
const trimmed = query.trim();
|
|
20706
|
+
if (trimmed.length === 0)
|
|
20707
|
+
return [];
|
|
20708
|
+
if (!surfaceSelected(options.scope, this.datasourceId, this.instanceId, surface))
|
|
20709
|
+
return [];
|
|
20710
|
+
const result = surface === "messages" ? await this.client.searchMessages(trimmed, options.topK) : await this.client.searchDocs(trimmed, options.topK);
|
|
20711
|
+
if (!result.ok)
|
|
20712
|
+
throw datasourceCliError(this.datasourceId, "search", result);
|
|
20713
|
+
const hits = [];
|
|
20714
|
+
for (const hit of result.hits) {
|
|
20715
|
+
if (!isSafeId(hit.id))
|
|
20716
|
+
continue;
|
|
20717
|
+
const source = normalizeVirtualPath2(`/${this.datasourceId}/${this.instanceId}/${surface}/${hit.id}`);
|
|
20718
|
+
if (source.includes("#"))
|
|
20719
|
+
continue;
|
|
20720
|
+
hits.push({
|
|
20721
|
+
id: hit.id,
|
|
20722
|
+
content: hit.content,
|
|
20723
|
+
source,
|
|
20724
|
+
score: hit.score,
|
|
20725
|
+
metadata: {
|
|
20726
|
+
...hit.metadata ?? {},
|
|
20727
|
+
datasourceId: this.datasourceId,
|
|
20728
|
+
instanceId: this.instanceId,
|
|
20729
|
+
surface
|
|
20730
|
+
}
|
|
20731
|
+
});
|
|
20732
|
+
}
|
|
20733
|
+
return hits;
|
|
20734
|
+
}
|
|
20735
|
+
methodTags(surface) {
|
|
20736
|
+
if (this.tags === DEFAULT_TAGS2)
|
|
20737
|
+
return [surface === "messages" ? CHAT_TAG : DOCS_TAG];
|
|
20738
|
+
return this.tags;
|
|
20739
|
+
}
|
|
20740
|
+
ok(diagnostics) {
|
|
20741
|
+
return {
|
|
20742
|
+
ok: true,
|
|
20743
|
+
instanceId: this.instanceId,
|
|
20744
|
+
skill: this.datasourceId,
|
|
20745
|
+
chunkCount: 0,
|
|
20746
|
+
indexedAt: this.lastIndexedAt ?? Date.now(),
|
|
20747
|
+
diagnostics
|
|
20748
|
+
};
|
|
20749
|
+
}
|
|
20750
|
+
fail(code, message) {
|
|
20751
|
+
return {
|
|
20752
|
+
ok: false,
|
|
20753
|
+
instanceId: this.instanceId,
|
|
20754
|
+
skill: this.datasourceId,
|
|
20755
|
+
indexedAt: Date.now(),
|
|
20756
|
+
diagnostics: [this.note(message, code, "error")],
|
|
20757
|
+
error: message,
|
|
20758
|
+
code,
|
|
20759
|
+
message
|
|
20760
|
+
};
|
|
20761
|
+
}
|
|
20762
|
+
note(message, code, severity) {
|
|
20763
|
+
return { code, severity, message, instanceId: this.instanceId, source: this.datasourceId };
|
|
20764
|
+
}
|
|
20765
|
+
}
|
|
20766
|
+
|
|
20767
|
+
class LarkRemoteMethod {
|
|
20768
|
+
skill;
|
|
20769
|
+
surface;
|
|
20770
|
+
constructor(skill, surface) {
|
|
20771
|
+
this.skill = skill;
|
|
20772
|
+
this.surface = surface;
|
|
20773
|
+
}
|
|
20774
|
+
describe() {
|
|
20775
|
+
const descriptor = this.skill.describe();
|
|
20776
|
+
return {
|
|
20777
|
+
name: `${descriptor.datasourceId ?? "lark"}-${this.surface}`,
|
|
20778
|
+
type: "remote",
|
|
20779
|
+
description: this.surface === "messages" ? "Server-side Lark/Feishu message search via lark-cli" : "Server-side Lark/Feishu document search via lark-cli",
|
|
20780
|
+
status: "active",
|
|
20781
|
+
capabilities: ["remote-search", "scoped", "external-cli", "path-opaque-sources"],
|
|
20782
|
+
datasourceId: descriptor.datasourceId,
|
|
20783
|
+
tags: this.skill.methodTags(this.surface)
|
|
20784
|
+
};
|
|
20785
|
+
}
|
|
20786
|
+
retrieve(query, options) {
|
|
20787
|
+
return this.skill.search(this.surface, query, options);
|
|
20788
|
+
}
|
|
20789
|
+
}
|
|
20790
|
+
function surfaceSelected(scope, datasourceId, instanceId, surface) {
|
|
20791
|
+
if (scope === undefined || scope.trim().length === 0)
|
|
20792
|
+
return true;
|
|
20793
|
+
const root = normalizeVirtualPath2(`/${datasourceId}/${instanceId}/${surface}`);
|
|
20794
|
+
const normalized = normalizeVirtualPath2(scope);
|
|
20795
|
+
if (normalized === root || normalized.startsWith(`${root}/`))
|
|
20796
|
+
return true;
|
|
20797
|
+
return matchesDatasourceScope(root, normalized);
|
|
20798
|
+
}
|
|
20799
|
+
function probeMessage(command, failure) {
|
|
20800
|
+
const stderr = failure.stderr.trim();
|
|
20801
|
+
const exit = failure.code === null || failure.code === undefined ? "no exit code" : `exit code ${failure.code}`;
|
|
20802
|
+
return `lark-cli ${command} failed (${failure.reason}, ${exit})${stderr.length > 0 ? `: ${stderr}` : ""}`;
|
|
20803
|
+
}
|
|
20804
|
+
function isRemoteEmbedder(value) {
|
|
20805
|
+
if (value === undefined)
|
|
20806
|
+
return false;
|
|
20807
|
+
const trimmed = value.trim().toLowerCase();
|
|
20808
|
+
return trimmed.startsWith("https://") || trimmed.startsWith("http://");
|
|
20809
|
+
}
|
|
20810
|
+
var CHAT_TAG = "lark:chat", DOCS_TAG = "lark:docs", DEFAULT_TAGS2, REMOTE_NOTE = "remote-search datasource: no local mirror";
|
|
20811
|
+
var init_skill6 = __esm(() => {
|
|
20812
|
+
init_errors2();
|
|
20813
|
+
init_scope2();
|
|
20814
|
+
init_client5();
|
|
20815
|
+
DEFAULT_TAGS2 = [CHAT_TAG, DOCS_TAG];
|
|
20816
|
+
});
|
|
20817
|
+
|
|
20818
|
+
// src/datasource/skills/lark/index.ts
|
|
20819
|
+
var init_lark = __esm(() => {
|
|
20820
|
+
init_client5();
|
|
20821
|
+
init_skill6();
|
|
20822
|
+
});
|
|
20823
|
+
|
|
20824
|
+
// src/datasource/skills/lazykatok/types.ts
|
|
20825
|
+
var DEFAULT_LAZYKATOK_BINARY = "lazykatok", DEFAULT_LAZYKATOK_TIMEOUT_MS = 60000, DEFAULT_LAZYKATOK_SOURCE = "macos", DEFAULT_LAZYKATOK_MAX_BUFFER_BYTES;
|
|
20826
|
+
var init_types5 = __esm(() => {
|
|
20827
|
+
DEFAULT_LAZYKATOK_MAX_BUFFER_BYTES = 16 * 1048576;
|
|
20828
|
+
});
|
|
20829
|
+
|
|
20830
|
+
// src/datasource/skills/lazykatok/client.ts
|
|
20831
|
+
import { spawn as spawn12 } from "node:child_process";
|
|
20832
|
+
import { existsSync as existsSync22 } from "node:fs";
|
|
20833
|
+
import { delimiter as delimiter4, join as join26 } from "node:path";
|
|
20834
|
+
|
|
20835
|
+
class LazykatokClient {
|
|
20836
|
+
options;
|
|
20837
|
+
constructor(options = {}) {
|
|
20838
|
+
this.options = options;
|
|
20839
|
+
}
|
|
20840
|
+
async doctor(signal) {
|
|
20841
|
+
const result = await this.run(["doctor", "--json"], signal);
|
|
19711
20842
|
if (!result.ok)
|
|
19712
|
-
return
|
|
20843
|
+
return toFailure3(result);
|
|
20844
|
+
const parsed = parseJsonObject2(result.stdout);
|
|
20845
|
+
if (parsed === undefined)
|
|
20846
|
+
return toFailure3(result, "invalid-json");
|
|
20847
|
+
const data = normalizeDoctor2(parsed);
|
|
20848
|
+
return data === undefined ? toFailure3(result, "invalid-shape") : ok3(data, result);
|
|
20849
|
+
}
|
|
20850
|
+
async sync(signal) {
|
|
20851
|
+
const result = await this.run(syncArgs(this.options, process.platform), signal);
|
|
20852
|
+
if (!result.ok)
|
|
20853
|
+
return toFailure3(result);
|
|
20854
|
+
const parsed = parseJsonObject2(result.stdout);
|
|
20855
|
+
if (parsed === undefined)
|
|
20856
|
+
return toFailure3(result, "invalid-json");
|
|
20857
|
+
const data = normalizeSync2(parsed);
|
|
20858
|
+
return data === undefined ? toFailure3(result, "invalid-shape") : ok3(data, result);
|
|
20859
|
+
}
|
|
20860
|
+
async index(signal) {
|
|
20861
|
+
const result = await this.run(["index", "--json"], signal);
|
|
20862
|
+
if (!result.ok)
|
|
20863
|
+
return toFailure3(result);
|
|
19713
20864
|
const parsed = parseJsonObject2(result.stdout);
|
|
19714
20865
|
if (parsed === undefined)
|
|
19715
|
-
return
|
|
20866
|
+
return toFailure3(result, "invalid-json");
|
|
19716
20867
|
const data = normalizeIndex(parsed);
|
|
19717
|
-
return data === undefined ?
|
|
20868
|
+
return data === undefined ? toFailure3(result, "invalid-shape") : ok3(data, result);
|
|
19718
20869
|
}
|
|
19719
20870
|
async search(mode, query, options) {
|
|
19720
20871
|
const args = ["search", mode, query, "--json"];
|
|
@@ -19722,74 +20873,100 @@ class KatokClient {
|
|
|
19722
20873
|
args.push("--limit", String(options.topK));
|
|
19723
20874
|
const result = await this.run(args, options?.signal);
|
|
19724
20875
|
if (!result.ok)
|
|
19725
|
-
return
|
|
20876
|
+
return toFailure3(result);
|
|
19726
20877
|
const parsed = parseJsonValue(result.stdout);
|
|
19727
20878
|
if (parsed === undefined)
|
|
19728
|
-
return
|
|
20879
|
+
return toFailure3(result, "invalid-json");
|
|
19729
20880
|
const hits = normalizeHits2(parsed);
|
|
19730
|
-
return hits === undefined ?
|
|
20881
|
+
return hits === undefined ? toFailure3(result, "invalid-shape") : searchOk2(hits, result);
|
|
19731
20882
|
}
|
|
19732
20883
|
async chunkGet(chunkId, signal) {
|
|
19733
20884
|
const result = await this.run(["chunk", "get", chunkId, "--json"], signal);
|
|
19734
20885
|
if (!result.ok)
|
|
19735
|
-
return
|
|
20886
|
+
return toFailure3(result);
|
|
19736
20887
|
const parsed = parseJsonObject2(result.stdout);
|
|
19737
20888
|
if (parsed === undefined)
|
|
19738
|
-
return
|
|
20889
|
+
return toFailure3(result, "invalid-json");
|
|
19739
20890
|
const data = normalizeChunk(parsed);
|
|
19740
|
-
return data === undefined ?
|
|
20891
|
+
return data === undefined ? toFailure3(result, "invalid-shape") : ok3(data, result);
|
|
19741
20892
|
}
|
|
19742
20893
|
async context(chunkId, signal) {
|
|
19743
|
-
const result = await this.run(["context", chunkId, "--json"], signal);
|
|
20894
|
+
const result = await this.run(["chunk", "context", chunkId, "--json"], signal);
|
|
19744
20895
|
if (!result.ok)
|
|
19745
|
-
return
|
|
20896
|
+
return toFailure3(result);
|
|
19746
20897
|
const parsed = parseJsonObject2(result.stdout);
|
|
19747
20898
|
if (parsed === undefined)
|
|
19748
|
-
return
|
|
20899
|
+
return toFailure3(result, "invalid-json");
|
|
19749
20900
|
const data = normalizeContext(parsed);
|
|
19750
|
-
return data === undefined ?
|
|
20901
|
+
return data === undefined ? toFailure3(result, "invalid-shape") : ok3(data, result);
|
|
19751
20902
|
}
|
|
19752
20903
|
async parent(chunkId, signal) {
|
|
19753
|
-
const result = await this.run(["parent", chunkId, "--json"], signal);
|
|
20904
|
+
const result = await this.run(["chunk", "parent", chunkId, "--json"], signal);
|
|
19754
20905
|
if (!result.ok)
|
|
19755
|
-
return
|
|
19756
|
-
const parsed =
|
|
20906
|
+
return toFailure3(result);
|
|
20907
|
+
const parsed = parseJsonValue(result.stdout);
|
|
19757
20908
|
if (parsed === undefined)
|
|
19758
|
-
return
|
|
19759
|
-
const data =
|
|
19760
|
-
return data === undefined ?
|
|
20909
|
+
return toFailure3(result, "invalid-json");
|
|
20910
|
+
const data = normalizeParentWindows(parsed);
|
|
20911
|
+
return data === undefined ? toFailure3(result, "invalid-shape") : ok3(data, result);
|
|
19761
20912
|
}
|
|
19762
20913
|
async run(args, signal) {
|
|
19763
|
-
const env =
|
|
19764
|
-
return
|
|
20914
|
+
const env = controlledEnv4(this.options.env);
|
|
20915
|
+
return spawnLazykatok({
|
|
19765
20916
|
options: this.options,
|
|
19766
|
-
args: [...
|
|
20917
|
+
args: [...commonArgs2(this.options), ...args],
|
|
19767
20918
|
env,
|
|
19768
20919
|
signal
|
|
19769
20920
|
});
|
|
19770
20921
|
}
|
|
19771
20922
|
}
|
|
19772
|
-
function
|
|
20923
|
+
function spawnLazykatok(request) {
|
|
19773
20924
|
return new Promise((resolve) => {
|
|
19774
20925
|
const { options, args, env, signal } = request;
|
|
19775
|
-
const portable = portableSpawnCommand(commandFor2(options
|
|
19776
|
-
const child =
|
|
20926
|
+
const portable = portableSpawnCommand(commandFor2(options, env), args);
|
|
20927
|
+
const child = spawn12(portable.command, [...portable.args], {
|
|
19777
20928
|
env,
|
|
19778
20929
|
...request.cwd === undefined ? {} : { cwd: request.cwd },
|
|
20930
|
+
detached: process.platform !== "win32",
|
|
20931
|
+
windowsHide: true,
|
|
19779
20932
|
stdio: ["ignore", "pipe", "pipe"]
|
|
19780
20933
|
});
|
|
19781
20934
|
let stdout = { text: "", bytes: 0, capped: false };
|
|
19782
20935
|
let stderr = { text: "", bytes: 0, capped: false };
|
|
19783
20936
|
let settled = false;
|
|
19784
20937
|
let finalReason;
|
|
19785
|
-
|
|
20938
|
+
let pipeGuard;
|
|
20939
|
+
const maxBuffer = options.maxBufferBytes ?? DEFAULT_LAZYKATOK_MAX_BUFFER_BYTES;
|
|
20940
|
+
const settleWith = (result) => {
|
|
20941
|
+
if (settled)
|
|
20942
|
+
return;
|
|
20943
|
+
settled = true;
|
|
20944
|
+
clearTimeout(timeout);
|
|
20945
|
+
if (pipeGuard !== undefined)
|
|
20946
|
+
clearTimeout(pipeGuard);
|
|
20947
|
+
signal?.removeEventListener("abort", abortHandler);
|
|
20948
|
+
resolve(result);
|
|
20949
|
+
};
|
|
20950
|
+
const finish = (code) => {
|
|
20951
|
+
if (finalReason !== undefined) {
|
|
20952
|
+
settleWith({ ok: false, reason: finalReason, stdout: stdout.text, stderr: stderr.text, code });
|
|
20953
|
+
return;
|
|
20954
|
+
}
|
|
20955
|
+
settleWith({
|
|
20956
|
+
ok: code === 0,
|
|
20957
|
+
reason: code === 0 ? undefined : "nonzero-exit",
|
|
20958
|
+
stdout: stdout.text,
|
|
20959
|
+
stderr: stderr.text,
|
|
20960
|
+
code
|
|
20961
|
+
});
|
|
20962
|
+
};
|
|
19786
20963
|
const timeout = setTimeout(() => {
|
|
19787
20964
|
finalReason = "timeout";
|
|
19788
|
-
|
|
19789
|
-
}, options.timeoutMs ??
|
|
20965
|
+
terminateProcessTree(child, "SIGKILL");
|
|
20966
|
+
}, options.timeoutMs ?? DEFAULT_LAZYKATOK_TIMEOUT_MS);
|
|
19790
20967
|
const abortHandler = () => {
|
|
19791
20968
|
finalReason = "aborted";
|
|
19792
|
-
|
|
20969
|
+
terminateProcessTree(child, "SIGKILL");
|
|
19793
20970
|
};
|
|
19794
20971
|
if (signal?.aborted)
|
|
19795
20972
|
abortHandler();
|
|
@@ -19797,50 +20974,55 @@ function spawnKatok(request) {
|
|
|
19797
20974
|
child.stdout.setEncoding("utf8");
|
|
19798
20975
|
child.stderr.setEncoding("utf8");
|
|
19799
20976
|
child.stdout.on("data", (chunk) => {
|
|
19800
|
-
stdout =
|
|
20977
|
+
stdout = appendBounded4(stdout, chunk, maxBuffer);
|
|
19801
20978
|
if (stdout.capped) {
|
|
19802
20979
|
finalReason = "stdout-too-large";
|
|
19803
|
-
|
|
20980
|
+
terminateProcessTree(child, "SIGKILL");
|
|
19804
20981
|
}
|
|
19805
20982
|
});
|
|
19806
20983
|
child.stderr.on("data", (chunk) => {
|
|
19807
|
-
stderr =
|
|
20984
|
+
stderr = appendBounded4(stderr, chunk, maxBuffer);
|
|
19808
20985
|
if (stderr.capped) {
|
|
19809
20986
|
finalReason = "stderr-too-large";
|
|
19810
|
-
|
|
20987
|
+
terminateProcessTree(child, "SIGKILL");
|
|
19811
20988
|
}
|
|
19812
20989
|
});
|
|
19813
20990
|
child.on("error", (error) => {
|
|
19814
|
-
if (settled)
|
|
19815
|
-
return;
|
|
19816
|
-
settled = true;
|
|
19817
|
-
clearTimeout(timeout);
|
|
19818
|
-
signal?.removeEventListener("abort", abortHandler);
|
|
19819
20991
|
const reason = error.code === "ENOENT" ? "binary-missing" : "spawn-error";
|
|
19820
|
-
|
|
20992
|
+
settleWith({ ok: false, reason, stdout: stdout.text, stderr: describeSpawnFailure2(reason), code: null });
|
|
19821
20993
|
});
|
|
19822
|
-
child.on("
|
|
20994
|
+
child.on("exit", () => {
|
|
19823
20995
|
if (settled)
|
|
19824
20996
|
return;
|
|
19825
|
-
|
|
19826
|
-
|
|
19827
|
-
|
|
19828
|
-
|
|
19829
|
-
|
|
19830
|
-
return;
|
|
19831
|
-
}
|
|
19832
|
-
resolve({
|
|
19833
|
-
ok: code === 0,
|
|
19834
|
-
reason: code === 0 ? undefined : "nonzero-exit",
|
|
19835
|
-
stdout: stdout.text,
|
|
19836
|
-
stderr: stderr.text,
|
|
19837
|
-
code
|
|
19838
|
-
});
|
|
20997
|
+
terminateProcessTree(child, "SIGKILL");
|
|
20998
|
+
pipeGuard = setTimeout(() => finish(child.exitCode), TREE_KILL_GRACE_MS);
|
|
20999
|
+
});
|
|
21000
|
+
child.on("close", (code) => {
|
|
21001
|
+
finish(code);
|
|
19839
21002
|
});
|
|
19840
21003
|
});
|
|
19841
21004
|
}
|
|
19842
|
-
function commandFor2(
|
|
19843
|
-
|
|
21005
|
+
function commandFor2(options, env) {
|
|
21006
|
+
if (options.binaryPath !== undefined)
|
|
21007
|
+
return options.binaryPath;
|
|
21008
|
+
return lookupInPath2(DEFAULT_LAZYKATOK_BINARY, env) ?? DEFAULT_LAZYKATOK_BINARY;
|
|
21009
|
+
}
|
|
21010
|
+
function lookupInPath2(executable, env) {
|
|
21011
|
+
const pathEnv = env.PATH;
|
|
21012
|
+
if (typeof pathEnv !== "string" || pathEnv.length === 0)
|
|
21013
|
+
return;
|
|
21014
|
+
for (const dir of pathEnv.split(delimiter4)) {
|
|
21015
|
+
if (dir.length === 0)
|
|
21016
|
+
continue;
|
|
21017
|
+
const candidate = join26(dir, executable);
|
|
21018
|
+
if (existsSync22(candidate))
|
|
21019
|
+
return candidate;
|
|
21020
|
+
}
|
|
21021
|
+
return;
|
|
21022
|
+
}
|
|
21023
|
+
function syncArgs(options, platform = process.platform) {
|
|
21024
|
+
const source = options.source ?? (platform === "darwin" ? DEFAULT_LAZYKATOK_SOURCE : undefined);
|
|
21025
|
+
return ["sync", ...source === undefined ? [] : ["--source", source], "--json"];
|
|
19844
21026
|
}
|
|
19845
21027
|
function commonArgs2(options) {
|
|
19846
21028
|
const args = [];
|
|
@@ -19850,42 +21032,31 @@ function commonArgs2(options) {
|
|
|
19850
21032
|
args.push("--config", options.configPath);
|
|
19851
21033
|
return args;
|
|
19852
21034
|
}
|
|
19853
|
-
function
|
|
21035
|
+
function controlledEnv4(configuredEnv) {
|
|
19854
21036
|
const env = {};
|
|
19855
21037
|
for (const [key, value] of Object.entries(process.env)) {
|
|
19856
|
-
if (value !== undefined &&
|
|
21038
|
+
if (value !== undefined && isAllowedLazykatokEnvKey(key))
|
|
19857
21039
|
env[key] = value;
|
|
19858
21040
|
}
|
|
19859
21041
|
for (const [key, value] of Object.entries(configuredEnv ?? {})) {
|
|
19860
21042
|
if (value === undefined) {
|
|
19861
21043
|
delete env[key];
|
|
19862
|
-
} else if (
|
|
21044
|
+
} else if (isAllowedLazykatokEnvKey(key)) {
|
|
19863
21045
|
env[key] = value;
|
|
19864
21046
|
}
|
|
19865
21047
|
}
|
|
19866
21048
|
return env;
|
|
19867
21049
|
}
|
|
19868
|
-
function
|
|
19869
|
-
return SAFE_INHERITED_ENV_KEYS2.has(key) || key.startsWith(
|
|
21050
|
+
function isAllowedLazykatokEnvKey(key) {
|
|
21051
|
+
return SAFE_INHERITED_ENV_KEYS2.has(key) || SAFE_CLI_ENV_PREFIXES.some((prefix) => key.startsWith(prefix));
|
|
19870
21052
|
}
|
|
19871
21053
|
function searchOk2(hits, result) {
|
|
19872
21054
|
return { ok: true, hits, data: { hits }, stdout: result.stdout, stderr: result.stderr, code: result.code ?? 0 };
|
|
19873
21055
|
}
|
|
19874
|
-
function terminate4(child) {
|
|
19875
|
-
if (child.killed)
|
|
19876
|
-
return;
|
|
19877
|
-
if (process.platform !== "win32" && child.pid !== undefined) {
|
|
19878
|
-
try {
|
|
19879
|
-
process.kill(-child.pid, "SIGKILL");
|
|
19880
|
-
return;
|
|
19881
|
-
} catch {}
|
|
19882
|
-
}
|
|
19883
|
-
child.kill("SIGKILL");
|
|
19884
|
-
}
|
|
19885
21056
|
function describeSpawnFailure2(reason) {
|
|
19886
|
-
return reason === "binary-missing" ? "the
|
|
21057
|
+
return reason === "binary-missing" ? "the lazykatok binary could not be found" : "the lazykatok binary could not be started";
|
|
19887
21058
|
}
|
|
19888
|
-
function
|
|
21059
|
+
function appendBounded4(state, chunk, maxBytes) {
|
|
19889
21060
|
const chunkBytes = Buffer.byteLength(chunk);
|
|
19890
21061
|
const nextBytes = state.bytes + chunkBytes;
|
|
19891
21062
|
if (nextBytes <= maxBytes)
|
|
@@ -19925,25 +21096,25 @@ function asBoolean(value) {
|
|
|
19925
21096
|
}
|
|
19926
21097
|
function normalizeDoctor2(raw) {
|
|
19927
21098
|
const version = asString3(raw.version);
|
|
19928
|
-
const ready = asBoolean(raw.ready);
|
|
21099
|
+
const ready = asBoolean(raw.ready) ?? (asRecord3(raw.freshness) === undefined ? undefined : true);
|
|
19929
21100
|
if (ready === undefined)
|
|
19930
21101
|
return;
|
|
19931
21102
|
const metadata = stripKnown(raw, new Set(["version", "ready"]));
|
|
19932
21103
|
return { ...version !== undefined ? { version } : {}, ready, metadata };
|
|
19933
21104
|
}
|
|
19934
21105
|
function normalizeSync2(raw) {
|
|
19935
|
-
const synced = asBoolean(raw.synced);
|
|
19936
|
-
if (synced === undefined)
|
|
21106
|
+
const synced = asBoolean(raw.synced) ?? (asNumber3(raw.total_messages) === undefined ? undefined : true);
|
|
21107
|
+
if (synced === undefined || raw.ok === false)
|
|
19937
21108
|
return;
|
|
19938
|
-
const messageCount = asNumber3(raw.messageCount);
|
|
21109
|
+
const messageCount = asNumber3(raw.messageCount) ?? asNumber3(raw.total_messages);
|
|
19939
21110
|
const metadata = stripKnown(raw, new Set(["synced", "messageCount"]));
|
|
19940
21111
|
return { synced, ...messageCount !== undefined ? { messageCount } : {}, metadata };
|
|
19941
21112
|
}
|
|
19942
21113
|
function normalizeIndex(raw) {
|
|
19943
|
-
const chunkCount = asNumber3(raw.chunkCount);
|
|
21114
|
+
const chunkCount = asNumber3(raw.chunkCount) ?? asNumber3(raw.candidate_chunks);
|
|
19944
21115
|
if (chunkCount === undefined)
|
|
19945
21116
|
return;
|
|
19946
|
-
const metadata = stripKnown(raw, new Set(["chunkCount"]));
|
|
21117
|
+
const metadata = stripKnown(raw, new Set(["chunkCount", "candidate_chunks", "documents"]));
|
|
19947
21118
|
return { chunkCount, metadata };
|
|
19948
21119
|
}
|
|
19949
21120
|
function normalizeHits2(raw) {
|
|
@@ -19962,6 +21133,18 @@ function normalizeHits2(raw) {
|
|
|
19962
21133
|
}
|
|
19963
21134
|
return normalized;
|
|
19964
21135
|
}
|
|
21136
|
+
function chatIdentityMetadata(record) {
|
|
21137
|
+
const chatName = asString3(record.chat_name);
|
|
21138
|
+
const senderNickname = asString3(record.sender_nickname);
|
|
21139
|
+
const startedAt = asString3(record.started_at);
|
|
21140
|
+
const endedAt = asString3(record.ended_at);
|
|
21141
|
+
return {
|
|
21142
|
+
...chatName !== undefined ? { chatName } : {},
|
|
21143
|
+
...senderNickname !== undefined ? { senderNickname } : {},
|
|
21144
|
+
...startedAt !== undefined ? { startedAt } : {},
|
|
21145
|
+
...endedAt !== undefined ? { endedAt } : {}
|
|
21146
|
+
};
|
|
21147
|
+
}
|
|
19965
21148
|
function normalizeHit(record) {
|
|
19966
21149
|
const chunkId = asString3(record.chunkId) ?? asString3(record.chunk_id);
|
|
19967
21150
|
const score = asNumber3(record.score);
|
|
@@ -19969,47 +21152,55 @@ function normalizeHit(record) {
|
|
|
19969
21152
|
if (chunkId === undefined || chunkId.length === 0 || score === undefined || content === undefined)
|
|
19970
21153
|
return;
|
|
19971
21154
|
const metadata = stripKnown(record, new Set(["chunkId", "chunk_id", "score", "content", "snippet"]));
|
|
19972
|
-
|
|
19973
|
-
const senderNickname = asString3(record.sender_nickname);
|
|
19974
|
-
const startedAt = asString3(record.started_at);
|
|
19975
|
-
const endedAt = asString3(record.ended_at);
|
|
19976
|
-
return {
|
|
19977
|
-
chunkId,
|
|
19978
|
-
score,
|
|
19979
|
-
content,
|
|
19980
|
-
metadata: {
|
|
19981
|
-
...metadata,
|
|
19982
|
-
...chatName !== undefined ? { chatName } : {},
|
|
19983
|
-
...senderNickname !== undefined ? { senderNickname } : {},
|
|
19984
|
-
...startedAt !== undefined ? { startedAt } : {},
|
|
19985
|
-
...endedAt !== undefined ? { endedAt } : {}
|
|
19986
|
-
}
|
|
19987
|
-
};
|
|
21155
|
+
return { chunkId, score, content, metadata: { ...metadata, ...chatIdentityMetadata(record) } };
|
|
19988
21156
|
}
|
|
19989
21157
|
function normalizeChunk(raw) {
|
|
19990
|
-
const chunkId = asString3(raw.chunkId);
|
|
19991
|
-
const content = asString3(raw.content);
|
|
21158
|
+
const chunkId = asString3(raw.chunkId) ?? asString3(raw.chunk_id) ?? asString3(raw.parent_id);
|
|
21159
|
+
const content = asString3(raw.content) ?? asString3(raw.text);
|
|
19992
21160
|
if (chunkId === undefined || chunkId.length === 0 || content === undefined)
|
|
19993
21161
|
return;
|
|
19994
|
-
const metadata = stripKnown(raw, new Set(["chunkId", "content"]));
|
|
19995
|
-
return { chunkId, content, metadata };
|
|
21162
|
+
const metadata = stripKnown(raw, new Set(["chunkId", "chunk_id", "parent_id", "content", "text"]));
|
|
21163
|
+
return { chunkId, content, metadata: { ...metadata, ...chatIdentityMetadata(raw) } };
|
|
19996
21164
|
}
|
|
19997
21165
|
function normalizeContext(raw) {
|
|
19998
|
-
const
|
|
19999
|
-
if (
|
|
21166
|
+
const legacyChunks = raw.chunks;
|
|
21167
|
+
if (Array.isArray(legacyChunks)) {
|
|
21168
|
+
const chunks = normalizeChunkList(legacyChunks);
|
|
21169
|
+
return chunks === undefined ? undefined : { chunks, metadata: stripKnown(raw, new Set(["chunks"])) };
|
|
21170
|
+
}
|
|
21171
|
+
const target = asRecord3(raw.chunk);
|
|
21172
|
+
if (target === undefined)
|
|
21173
|
+
return;
|
|
21174
|
+
const chunk = normalizeChunk(target);
|
|
21175
|
+
if (chunk === undefined)
|
|
21176
|
+
return;
|
|
21177
|
+
const before = normalizeChunkList(raw.previous) ?? [];
|
|
21178
|
+
const after = normalizeChunkList(raw.next) ?? [];
|
|
21179
|
+
return {
|
|
21180
|
+
chunks: [...before, chunk, ...after],
|
|
21181
|
+
metadata: stripKnown(raw, new Set(["chunk"]))
|
|
21182
|
+
};
|
|
21183
|
+
}
|
|
21184
|
+
function normalizeChunkList(value) {
|
|
21185
|
+
if (!Array.isArray(value))
|
|
20000
21186
|
return;
|
|
20001
21187
|
const chunks = [];
|
|
20002
|
-
for (const entry of
|
|
21188
|
+
for (const entry of value) {
|
|
20003
21189
|
const record = asRecord3(entry);
|
|
20004
21190
|
if (record === undefined)
|
|
20005
|
-
|
|
21191
|
+
continue;
|
|
20006
21192
|
const chunk = normalizeChunk(record);
|
|
20007
|
-
if (chunk
|
|
20008
|
-
|
|
20009
|
-
chunks.push(chunk);
|
|
21193
|
+
if (chunk !== undefined)
|
|
21194
|
+
chunks.push(chunk);
|
|
20010
21195
|
}
|
|
20011
|
-
|
|
20012
|
-
|
|
21196
|
+
return chunks;
|
|
21197
|
+
}
|
|
21198
|
+
function normalizeParentWindows(raw) {
|
|
21199
|
+
const windows = normalizeChunkList(raw);
|
|
21200
|
+
if (windows !== undefined)
|
|
21201
|
+
return windows;
|
|
21202
|
+
const nested = asRecord3(raw)?.parent_windows;
|
|
21203
|
+
return normalizeChunkList(nested);
|
|
20013
21204
|
}
|
|
20014
21205
|
function stripKnown(raw, known) {
|
|
20015
21206
|
const metadata = {};
|
|
@@ -20019,16 +21210,16 @@ function stripKnown(raw, known) {
|
|
|
20019
21210
|
}
|
|
20020
21211
|
return metadata;
|
|
20021
21212
|
}
|
|
20022
|
-
function
|
|
21213
|
+
function toFailure3(result, reason) {
|
|
20023
21214
|
return {
|
|
20024
21215
|
ok: false,
|
|
20025
21216
|
reason: reason ?? result.reason ?? "nonzero-exit",
|
|
20026
21217
|
stdout: result.stdout,
|
|
20027
|
-
stderr:
|
|
21218
|
+
stderr: boundDiagnosticText5(result.stderr),
|
|
20028
21219
|
code: result.code
|
|
20029
21220
|
};
|
|
20030
21221
|
}
|
|
20031
|
-
function
|
|
21222
|
+
function boundDiagnosticText5(value) {
|
|
20032
21223
|
if (value.length === 0)
|
|
20033
21224
|
return "";
|
|
20034
21225
|
return value.trim().slice(0, 4000);
|
|
@@ -20036,22 +21227,24 @@ function boundDiagnosticText4(value) {
|
|
|
20036
21227
|
function ok3(data, result) {
|
|
20037
21228
|
return { ok: true, data, stdout: result.stdout, stderr: result.stderr, code: result.code ?? 0 };
|
|
20038
21229
|
}
|
|
20039
|
-
var SAFE_INHERITED_ENV_KEYS2,
|
|
20040
|
-
var
|
|
21230
|
+
var SAFE_INHERITED_ENV_KEYS2, SAFE_CLI_ENV_PREFIXES;
|
|
21231
|
+
var init_client6 = __esm(() => {
|
|
20041
21232
|
init_portable_spawn();
|
|
21233
|
+
init_terminate_tree();
|
|
20042
21234
|
init_types5();
|
|
20043
21235
|
SAFE_INHERITED_ENV_KEYS2 = new Set(["HOME", "LANG", "LC_ALL", "PATH", "TMPDIR", "TMP", "TEMP"]);
|
|
21236
|
+
SAFE_CLI_ENV_PREFIXES = ["KATOK_", "LAZYKATOK_"];
|
|
20044
21237
|
});
|
|
20045
21238
|
|
|
20046
|
-
// src/datasource/skills/
|
|
20047
|
-
function
|
|
20048
|
-
return `/${
|
|
21239
|
+
// src/datasource/skills/lazykatok/paths.ts
|
|
21240
|
+
function lazykatokSourcePath(instanceId, chunkId) {
|
|
21241
|
+
return `/${LAZYKATOK_SOURCE_KIND}/${instanceId}/chunks/${chunkId}`;
|
|
20049
21242
|
}
|
|
20050
|
-
var
|
|
21243
|
+
var LAZYKATOK_SOURCE_KIND = "kakao";
|
|
20051
21244
|
var init_paths4 = () => {};
|
|
20052
21245
|
|
|
20053
|
-
// src/datasource/skills/
|
|
20054
|
-
class
|
|
21246
|
+
// src/datasource/skills/lazykatok/methods.ts
|
|
21247
|
+
class LazykatokBm25Method {
|
|
20055
21248
|
client;
|
|
20056
21249
|
instanceId;
|
|
20057
21250
|
tags;
|
|
@@ -20064,7 +21257,7 @@ class KatokBm25Method {
|
|
|
20064
21257
|
return {
|
|
20065
21258
|
name: "kakao-bm25",
|
|
20066
21259
|
type: "bm25",
|
|
20067
|
-
description: "BM25 lexical retrieval over KakaoTalk chat chunks via the external
|
|
21260
|
+
description: "BM25 lexical retrieval over KakaoTalk chat chunks via the external lazykatok CLI",
|
|
20068
21261
|
status: "active",
|
|
20069
21262
|
capabilities: ["lexical", "keyword-mode", "external-cli", "path-opaque-sources"],
|
|
20070
21263
|
datasourceId: KAKAO_DATASOURCE_ID,
|
|
@@ -20072,11 +21265,11 @@ class KatokBm25Method {
|
|
|
20072
21265
|
};
|
|
20073
21266
|
}
|
|
20074
21267
|
retrieve(query, options) {
|
|
20075
|
-
return
|
|
21268
|
+
return retrieveLazykatok(this.client, "keyword", "kakao-bm25", this.instanceId, query, options);
|
|
20076
21269
|
}
|
|
20077
21270
|
}
|
|
20078
21271
|
|
|
20079
|
-
class
|
|
21272
|
+
class LazykatokSemanticMethod {
|
|
20080
21273
|
client;
|
|
20081
21274
|
instanceId;
|
|
20082
21275
|
tags;
|
|
@@ -20089,7 +21282,7 @@ class KatokSemanticMethod {
|
|
|
20089
21282
|
return {
|
|
20090
21283
|
name: "kakao-semantic",
|
|
20091
21284
|
type: "vector",
|
|
20092
|
-
description: "Semantic vector retrieval over KakaoTalk chat chunks via the external
|
|
21285
|
+
description: "Semantic vector retrieval over KakaoTalk chat chunks via the external lazykatok CLI",
|
|
20093
21286
|
status: "active",
|
|
20094
21287
|
capabilities: ["semantic", "vector-mode", "external-cli", "path-opaque-sources"],
|
|
20095
21288
|
datasourceId: KAKAO_DATASOURCE_ID,
|
|
@@ -20097,29 +21290,29 @@ class KatokSemanticMethod {
|
|
|
20097
21290
|
};
|
|
20098
21291
|
}
|
|
20099
21292
|
retrieve(query, options) {
|
|
20100
|
-
return
|
|
21293
|
+
return retrieveLazykatok(this.client, "semantic", "kakao-semantic", this.instanceId, query, options);
|
|
20101
21294
|
}
|
|
20102
21295
|
}
|
|
20103
|
-
async function
|
|
21296
|
+
async function retrieveLazykatok(client, mode, methodName, instanceId, query, options) {
|
|
20104
21297
|
const trimmed = query.trim();
|
|
20105
21298
|
if (trimmed.length === 0)
|
|
20106
21299
|
return [];
|
|
20107
|
-
const topK = options.topK ??
|
|
21300
|
+
const topK = options.topK ?? DEFAULT_TOP_K4;
|
|
20108
21301
|
const searchOptions = { topK, signal: options.signal };
|
|
20109
21302
|
const result = await client.search(mode, trimmed, searchOptions);
|
|
20110
21303
|
if (!result.ok)
|
|
20111
21304
|
throw datasourceCliError(KAKAO_DATASOURCE_ID, `search --mode ${mode}`, result);
|
|
20112
21305
|
const mapped = [];
|
|
20113
21306
|
for (const hit of result.hits) {
|
|
20114
|
-
const source =
|
|
21307
|
+
const source = lazykatokSource(instanceId, hit);
|
|
20115
21308
|
mapped.push(toRetrievalResult2(hit, source, methodName, instanceId, mode));
|
|
20116
21309
|
if (mapped.length >= topK)
|
|
20117
21310
|
break;
|
|
20118
21311
|
}
|
|
20119
21312
|
return mapped;
|
|
20120
21313
|
}
|
|
20121
|
-
function
|
|
20122
|
-
return
|
|
21314
|
+
function lazykatokSource(instanceId, hit) {
|
|
21315
|
+
return lazykatokSourcePath(instanceId, hit.chunkId);
|
|
20123
21316
|
}
|
|
20124
21317
|
function toRetrievalResult2(hit, source, methodName, instanceId, mode) {
|
|
20125
21318
|
return {
|
|
@@ -20137,15 +21330,15 @@ function toRetrievalResult2(hit, source, methodName, instanceId, mode) {
|
|
|
20137
21330
|
}
|
|
20138
21331
|
};
|
|
20139
21332
|
}
|
|
20140
|
-
var KAKAO_DATASOURCE_ID = "kakao", DEFAULT_KAKAO_TAGS,
|
|
21333
|
+
var KAKAO_DATASOURCE_ID = "kakao", DEFAULT_KAKAO_TAGS, DEFAULT_TOP_K4 = 20;
|
|
20141
21334
|
var init_methods3 = __esm(() => {
|
|
20142
21335
|
init_errors2();
|
|
20143
21336
|
init_paths4();
|
|
20144
21337
|
DEFAULT_KAKAO_TAGS = ["kakaotalk", "personal", "pii"];
|
|
20145
21338
|
});
|
|
20146
21339
|
|
|
20147
|
-
// src/datasource/skills/
|
|
20148
|
-
class
|
|
21340
|
+
// src/datasource/skills/lazykatok/skill.ts
|
|
21341
|
+
class LazykatokSkill {
|
|
20149
21342
|
client;
|
|
20150
21343
|
instanceId;
|
|
20151
21344
|
instances;
|
|
@@ -20154,7 +21347,7 @@ class KatokSkill {
|
|
|
20154
21347
|
lastIndexedAt;
|
|
20155
21348
|
constructor(options) {
|
|
20156
21349
|
this.client = options.client;
|
|
20157
|
-
this.instanceId = options.instanceId ??
|
|
21350
|
+
this.instanceId = options.instanceId ?? DEFAULT_INSTANCE_ID4;
|
|
20158
21351
|
this.instances = options.instances !== undefined && options.instances.length > 0 ? options.instances : [this.instanceId];
|
|
20159
21352
|
this.pollingIntervalMs = options.pollingIntervalMs ?? DEFAULT_POLLING_INTERVAL_MS3;
|
|
20160
21353
|
this.tags = options.tags ?? DEFAULT_KAKAO_TAGS2;
|
|
@@ -20165,7 +21358,7 @@ class KatokSkill {
|
|
|
20165
21358
|
name: KAKAO_DATASOURCE_ID2,
|
|
20166
21359
|
id: KAKAO_DATASOURCE_ID2,
|
|
20167
21360
|
type: KAKAO_SKILL_TYPE,
|
|
20168
|
-
description: "KakaoTalk datasource via the external
|
|
21361
|
+
description: "KakaoTalk datasource via the external lazykatok CLI",
|
|
20169
21362
|
capabilities: ["chat", "external-cli", "polling", "bm25", "semantic"],
|
|
20170
21363
|
tags: this.tags,
|
|
20171
21364
|
status: "active",
|
|
@@ -20215,8 +21408,8 @@ class KatokSkill {
|
|
|
20215
21408
|
}
|
|
20216
21409
|
retrievalMethods() {
|
|
20217
21410
|
return [
|
|
20218
|
-
new
|
|
20219
|
-
new
|
|
21411
|
+
new LazykatokBm25Method({ client: this.client, instanceId: this.instanceId, tags: this.tags }),
|
|
21412
|
+
new LazykatokSemanticMethod({ client: this.client, instanceId: this.instanceId, tags: this.tags })
|
|
20220
21413
|
];
|
|
20221
21414
|
}
|
|
20222
21415
|
describeSources() {
|
|
@@ -20243,7 +21436,7 @@ class KatokSkill {
|
|
|
20243
21436
|
content: [
|
|
20244
21437
|
`# KakaoTalk datasource (${KAKAO_SKILL_TYPE})`,
|
|
20245
21438
|
"",
|
|
20246
|
-
"This skill searches KakaoTalk chats that are indexed through the external `
|
|
21439
|
+
"This skill searches KakaoTalk chats that are indexed through the external `lazykatok` CLI. AutoRAG never reads KakaoTalk databases directly.",
|
|
20247
21440
|
"",
|
|
20248
21441
|
"## When to use",
|
|
20249
21442
|
"Use this skill when the question is about KakaoTalk conversations, chat participants, or content shared inside chats.",
|
|
@@ -20252,16 +21445,16 @@ class KatokSkill {
|
|
|
20252
21445
|
`Indexing is server-managed and refreshed ${cadence}. You do not trigger indexing; just search.`,
|
|
20253
21446
|
"",
|
|
20254
21447
|
"## How to search",
|
|
20255
|
-
`Call the dedicated \`${datasourceSearchToolName(KAKAO_DATASOURCE_ID2)}\` tool with a natural-language \`query\` and \`topK\`.
|
|
21448
|
+
`Call the dedicated \`${datasourceSearchToolName(KAKAO_DATASOURCE_ID2)}\` tool with a natural-language \`query\` and \`topK\`. This datasource does not support per-source scope narrowing. Authorized datasource:`,
|
|
20256
21449
|
instanceSources.length > 0 ? instanceSources : "- (no configured instances)",
|
|
20257
21450
|
"",
|
|
20258
|
-
"Access is controlled by the trusted datasource tag; chat/channel filtering is owned by
|
|
21451
|
+
"Access is controlled by the trusted datasource tag; chat/channel filtering is owned by lazykatok.",
|
|
20259
21452
|
"",
|
|
20260
21453
|
"## Native CLI",
|
|
20261
|
-
"The external `
|
|
20262
|
-
'- `
|
|
20263
|
-
"- `
|
|
20264
|
-
"- `
|
|
21454
|
+
"The external `lazykatok` CLI owns the archive, index, and credentials. When the dedicated tool cannot express what you need, call lazykatok directly through `bash`:",
|
|
21455
|
+
'- `lazykatok search bm25 "<query>" --json --limit 20` — lexical search (`semantic` mode also available)',
|
|
21456
|
+
"- `lazykatok chunk get <chunkId> --json` — fetch one chunk by id (chunk ids appear in result metadata)",
|
|
21457
|
+
"- `lazykatok chunk context <chunkId> --json` — surrounding messages of a chunk",
|
|
20265
21458
|
"Never pass datasource virtual paths (`/kakao/...`) to bash; they are not OS paths.",
|
|
20266
21459
|
"",
|
|
20267
21460
|
"## Output rules",
|
|
@@ -20291,8 +21484,8 @@ class KatokSkill {
|
|
|
20291
21484
|
};
|
|
20292
21485
|
}
|
|
20293
21486
|
}
|
|
20294
|
-
var KAKAO_DATASOURCE_ID2 = "kakao", KAKAO_SKILL_TYPE = "kakaotalk",
|
|
20295
|
-
var
|
|
21487
|
+
var KAKAO_DATASOURCE_ID2 = "kakao", KAKAO_SKILL_TYPE = "kakaotalk", DEFAULT_INSTANCE_ID4 = "default", DEFAULT_POLLING_INTERVAL_MS3, DEFAULT_KAKAO_TAGS2;
|
|
21488
|
+
var init_skill7 = __esm(() => {
|
|
20296
21489
|
init_skip();
|
|
20297
21490
|
init_scope2();
|
|
20298
21491
|
init_methods3();
|
|
@@ -20300,17 +21493,17 @@ var init_skill5 = __esm(() => {
|
|
|
20300
21493
|
DEFAULT_KAKAO_TAGS2 = ["kakaotalk", "personal", "pii"];
|
|
20301
21494
|
});
|
|
20302
21495
|
|
|
20303
|
-
// src/datasource/skills/
|
|
20304
|
-
var
|
|
20305
|
-
|
|
21496
|
+
// src/datasource/skills/lazykatok/index.ts
|
|
21497
|
+
var init_lazykatok = __esm(() => {
|
|
21498
|
+
init_client6();
|
|
20306
21499
|
init_methods3();
|
|
20307
|
-
|
|
21500
|
+
init_skill7();
|
|
20308
21501
|
init_types5();
|
|
20309
21502
|
});
|
|
20310
21503
|
|
|
20311
21504
|
// src/datasource/skills/mail-export/connector.ts
|
|
20312
21505
|
import { readdir as readdir2, readFile as readFile7, stat as stat5 } from "node:fs/promises";
|
|
20313
|
-
import { basename as basename10, dirname as
|
|
21506
|
+
import { basename as basename10, dirname as dirname18, extname as extname9, join as join27 } from "node:path";
|
|
20314
21507
|
import { simpleParser as simpleParser2 } from "mailparser";
|
|
20315
21508
|
|
|
20316
21509
|
class MailExportConnector {
|
|
@@ -20336,7 +21529,7 @@ class MailExportConnector {
|
|
|
20336
21529
|
continue;
|
|
20337
21530
|
const extension = extname9(entry.name).toLowerCase();
|
|
20338
21531
|
if (extension === ".eml" || extension === ".mbox") {
|
|
20339
|
-
files.push(
|
|
21532
|
+
files.push(join27(entry.parentPath, entry.name));
|
|
20340
21533
|
}
|
|
20341
21534
|
}
|
|
20342
21535
|
} else if (info.isFile()) {
|
|
@@ -20371,7 +21564,7 @@ class MailExportConnector {
|
|
|
20371
21564
|
continue;
|
|
20372
21565
|
}
|
|
20373
21566
|
const stem = basename10(file, extname9(file));
|
|
20374
|
-
const mailboxDir = basename10(
|
|
21567
|
+
const mailboxDir = basename10(dirname18(file));
|
|
20375
21568
|
const hierarchy = ["mailboxes", mailboxDir, stem];
|
|
20376
21569
|
const extension = extname9(file).toLowerCase();
|
|
20377
21570
|
const rawMessages = extension === ".mbox" ? splitMbox(bytes.toString("utf8")) : [bytes.toString("utf8")];
|
|
@@ -20441,16 +21634,16 @@ function splitMbox(text) {
|
|
|
20441
21634
|
return messages.filter((message) => message.trim().length > 0);
|
|
20442
21635
|
}
|
|
20443
21636
|
var DEFAULT_MAX_DOCUMENTS3 = 500, DEFAULT_MAX_BYTES_PER_FILE2, MAX_BODY_CHARS = 50000, MBOX_SEPARATOR;
|
|
20444
|
-
var
|
|
21637
|
+
var init_connector4 = __esm(() => {
|
|
20445
21638
|
DEFAULT_MAX_BYTES_PER_FILE2 = 50 * 1024 * 1024;
|
|
20446
21639
|
MBOX_SEPARATOR = /^From .*\d{4}$/mu;
|
|
20447
21640
|
});
|
|
20448
21641
|
|
|
20449
21642
|
// src/datasource/skills/mail-export/skill.ts
|
|
20450
21643
|
var MAIL_EXPORT_SKILL_DEFINITION, MailExportSkill;
|
|
20451
|
-
var
|
|
21644
|
+
var init_skill8 = __esm(() => {
|
|
20452
21645
|
init_connector_skill();
|
|
20453
|
-
|
|
21646
|
+
init_connector4();
|
|
20454
21647
|
MAIL_EXPORT_SKILL_DEFINITION = {
|
|
20455
21648
|
skillName: "mail-export",
|
|
20456
21649
|
skillType: "mail-export",
|
|
@@ -20476,26 +21669,26 @@ var init_skill6 = __esm(() => {
|
|
|
20476
21669
|
|
|
20477
21670
|
// src/datasource/skills/mail-export/index.ts
|
|
20478
21671
|
var init_mail_export = __esm(() => {
|
|
20479
|
-
|
|
20480
|
-
|
|
21672
|
+
init_connector4();
|
|
21673
|
+
init_skill8();
|
|
20481
21674
|
});
|
|
20482
21675
|
|
|
20483
21676
|
// src/datasource/skills/mailcrawl/config.ts
|
|
20484
|
-
import { chmodSync, mkdirSync as
|
|
21677
|
+
import { chmodSync, mkdirSync as mkdirSync17 } from "node:fs";
|
|
20485
21678
|
function validateMailcrawlInstanceId(instanceId) {
|
|
20486
21679
|
if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/u.test(instanceId)) {
|
|
20487
21680
|
throw new Error("mailcrawl instanceId must be a safe single path segment");
|
|
20488
21681
|
}
|
|
20489
21682
|
}
|
|
20490
21683
|
function ensurePrivateMailcrawlDataDir(path) {
|
|
20491
|
-
|
|
21684
|
+
mkdirSync17(path, { recursive: true, mode: 448 });
|
|
20492
21685
|
if (process.platform !== "win32")
|
|
20493
21686
|
chmodSync(path, 448);
|
|
20494
21687
|
}
|
|
20495
21688
|
var init_config = () => {};
|
|
20496
21689
|
|
|
20497
21690
|
// src/datasource/skills/mailcrawl/client.ts
|
|
20498
|
-
import { spawn as
|
|
21691
|
+
import { spawn as spawn13 } from "node:child_process";
|
|
20499
21692
|
|
|
20500
21693
|
class MailcrawlClient {
|
|
20501
21694
|
options;
|
|
@@ -20515,7 +21708,7 @@ class MailcrawlClient {
|
|
|
20515
21708
|
...this.options.fixture === undefined ? [] : ["--fixture", this.options.fixture],
|
|
20516
21709
|
...this.options.himalayaConfig === undefined ? [] : ["--himalaya-config", this.options.himalayaConfig]
|
|
20517
21710
|
];
|
|
20518
|
-
const result = await this.run(args, signal);
|
|
21711
|
+
const result = await this.run(args, signal, this.indexTimeoutMs());
|
|
20519
21712
|
if (!result.ok)
|
|
20520
21713
|
return failure2(result);
|
|
20521
21714
|
const parsed = parseObject2(result.stdout);
|
|
@@ -20547,7 +21740,7 @@ class MailcrawlClient {
|
|
|
20547
21740
|
"--json",
|
|
20548
21741
|
query.trim()
|
|
20549
21742
|
];
|
|
20550
|
-
const result = await this.run(args, options?.signal);
|
|
21743
|
+
const result = await this.run(args, options?.signal, this.options.timeoutMs ?? DEFAULT_SEARCH_TIMEOUT_MS2);
|
|
20551
21744
|
if (!result.ok)
|
|
20552
21745
|
return failure2(result);
|
|
20553
21746
|
const parsed = parseJson3(result.stdout);
|
|
@@ -20568,7 +21761,10 @@ class MailcrawlClient {
|
|
|
20568
21761
|
code: result.code ?? 0
|
|
20569
21762
|
};
|
|
20570
21763
|
}
|
|
20571
|
-
|
|
21764
|
+
indexTimeoutMs() {
|
|
21765
|
+
return this.options.indexTimeoutMs ?? this.options.timeoutMs ?? DEFAULT_INDEX_TIMEOUT_MS;
|
|
21766
|
+
}
|
|
21767
|
+
async run(args, signal, timeoutMs) {
|
|
20572
21768
|
const violation = findRemoteEmbeddingViolation({ ...process.env, ...this.options.env ?? {} });
|
|
20573
21769
|
if (violation !== undefined) {
|
|
20574
21770
|
return { ok: false, reason: "remote-embedding-rejected", stdout: "", stderr: "", code: null };
|
|
@@ -20578,21 +21774,21 @@ class MailcrawlClient {
|
|
|
20578
21774
|
ensurePrivateMailcrawlDataDir(dataDir);
|
|
20579
21775
|
const env = {};
|
|
20580
21776
|
for (const [key, value] of Object.entries(process.env)) {
|
|
20581
|
-
if (value !== undefined && (
|
|
21777
|
+
if (value !== undefined && (SAFE_ENV_KEYS2.has(key) || SAFE_MAILCRAWL_ENV_KEYS.has(key)))
|
|
20582
21778
|
env[key] = value;
|
|
20583
21779
|
}
|
|
20584
21780
|
for (const [key, value] of Object.entries(this.options.env ?? {})) {
|
|
20585
21781
|
if (value === undefined)
|
|
20586
21782
|
delete env[key];
|
|
20587
|
-
else if (
|
|
21783
|
+
else if (SAFE_ENV_KEYS2.has(key) || SAFE_MAILCRAWL_ENV_KEYS.has(key))
|
|
20588
21784
|
env[key] = value;
|
|
20589
21785
|
}
|
|
20590
21786
|
if (dataDir !== undefined)
|
|
20591
21787
|
env.MAILCRAWL_DATA_DIR = dataDir;
|
|
20592
|
-
return spawnMailcrawl(this.options.binaryPath ?? DEFAULT_BINARY4, args, env, this.options, signal);
|
|
21788
|
+
return spawnMailcrawl(this.options.binaryPath ?? DEFAULT_BINARY4, args, env, this.options, signal, timeoutMs);
|
|
20593
21789
|
}
|
|
20594
21790
|
async index(signal) {
|
|
20595
|
-
const result = await this.run(["index", "--json"], signal);
|
|
21791
|
+
const result = await this.run(["index", "--json"], signal, this.indexTimeoutMs());
|
|
20596
21792
|
if (!result.ok)
|
|
20597
21793
|
return failure2(result);
|
|
20598
21794
|
const parsed = parseObject2(result.stdout);
|
|
@@ -20602,27 +21798,30 @@ class MailcrawlClient {
|
|
|
20602
21798
|
return ok4({
|
|
20603
21799
|
embedded: number(parsed, "embedded"),
|
|
20604
21800
|
reused: number(parsed, "reused"),
|
|
20605
|
-
generation: string(parsed, "generation")
|
|
21801
|
+
generation: string(parsed, "generation"),
|
|
21802
|
+
archiveRevision: string(parsed, "archiveRevision"),
|
|
21803
|
+
rebuilt: typeof parsed.rebuilt === "boolean" ? parsed.rebuilt : undefined,
|
|
21804
|
+
embedder: string(parsed, "embedder")
|
|
20606
21805
|
}, result);
|
|
20607
21806
|
}
|
|
20608
21807
|
}
|
|
20609
|
-
function spawnMailcrawl(binary, args, env, options, signal) {
|
|
21808
|
+
function spawnMailcrawl(binary, args, env, options, signal, timeoutMs) {
|
|
20610
21809
|
return new Promise((resolveResult) => {
|
|
20611
21810
|
const portable = portableSpawnCommand(binary, args);
|
|
20612
|
-
const child =
|
|
21811
|
+
const child = spawn13(portable.command, portable.args, {
|
|
20613
21812
|
env,
|
|
20614
21813
|
detached: process.platform !== "win32",
|
|
20615
21814
|
stdio: ["ignore", "pipe", "pipe"]
|
|
20616
21815
|
});
|
|
20617
21816
|
let stdout = { text: "", bytes: 0, exceeded: false }, stderr = { text: "", bytes: 0, exceeded: false }, settled = false, reason;
|
|
20618
|
-
const max = options.maxBufferBytes ??
|
|
21817
|
+
const max = options.maxBufferBytes ?? DEFAULT_MAX_BUFFER_BYTES4;
|
|
20619
21818
|
const timer = setTimeout(() => {
|
|
20620
21819
|
reason = "timeout";
|
|
20621
|
-
|
|
20622
|
-
},
|
|
21820
|
+
terminate4(child);
|
|
21821
|
+
}, timeoutMs);
|
|
20623
21822
|
const abort = () => {
|
|
20624
21823
|
reason = "aborted";
|
|
20625
|
-
|
|
21824
|
+
terminate4(child);
|
|
20626
21825
|
};
|
|
20627
21826
|
if (signal?.aborted)
|
|
20628
21827
|
abort();
|
|
@@ -20633,14 +21832,14 @@ function spawnMailcrawl(binary, args, env, options, signal) {
|
|
|
20633
21832
|
stdout = appendOutput(stdout, chunk, max);
|
|
20634
21833
|
if (stdout.exceeded && reason === undefined) {
|
|
20635
21834
|
reason = "stdout-too-large";
|
|
20636
|
-
|
|
21835
|
+
terminate4(child);
|
|
20637
21836
|
}
|
|
20638
21837
|
});
|
|
20639
21838
|
child.stderr.on("data", (chunk) => {
|
|
20640
21839
|
stderr = appendOutput(stderr, chunk, max);
|
|
20641
21840
|
if (stderr.exceeded && reason === undefined) {
|
|
20642
21841
|
reason = "stderr-too-large";
|
|
20643
|
-
|
|
21842
|
+
terminate4(child);
|
|
20644
21843
|
}
|
|
20645
21844
|
});
|
|
20646
21845
|
child.on("error", (error) => {
|
|
@@ -20673,7 +21872,7 @@ function spawnMailcrawl(binary, args, env, options, signal) {
|
|
|
20673
21872
|
});
|
|
20674
21873
|
});
|
|
20675
21874
|
}
|
|
20676
|
-
function
|
|
21875
|
+
function terminate4(child) {
|
|
20677
21876
|
if (child.killed)
|
|
20678
21877
|
return;
|
|
20679
21878
|
if (process.platform !== "win32" && child.pid !== undefined) {
|
|
@@ -20748,11 +21947,11 @@ function failure2(result) {
|
|
|
20748
21947
|
ok: false,
|
|
20749
21948
|
reason: result.reason ?? "nonzero-exit",
|
|
20750
21949
|
stdout: result.stdout,
|
|
20751
|
-
stderr:
|
|
21950
|
+
stderr: boundDiagnosticText6(result.stderr),
|
|
20752
21951
|
code: result.code
|
|
20753
21952
|
};
|
|
20754
21953
|
}
|
|
20755
|
-
function
|
|
21954
|
+
function boundDiagnosticText6(value) {
|
|
20756
21955
|
if (value.length === 0)
|
|
20757
21956
|
return "";
|
|
20758
21957
|
return value.trim().slice(0, 4000);
|
|
@@ -20780,10 +21979,22 @@ function findRemoteEmbeddingViolation(env) {
|
|
|
20780
21979
|
const lower = key.toLowerCase();
|
|
20781
21980
|
if (REMOTE_EMBEDDING_ENV_KEYS.has(lower))
|
|
20782
21981
|
return key;
|
|
20783
|
-
if (lower === "mailcrawl_embedder"
|
|
20784
|
-
|
|
21982
|
+
if (lower === "mailcrawl_embedder" || lower === "mailcrawl_embed_url") {
|
|
21983
|
+
if (isRemoteHttpEndpoint(value))
|
|
21984
|
+
return key;
|
|
21985
|
+
}
|
|
21986
|
+
}
|
|
21987
|
+
return;
|
|
21988
|
+
}
|
|
21989
|
+
function isRemoteHttpEndpoint(value) {
|
|
21990
|
+
const trimmed = value.trim();
|
|
21991
|
+
if (!/^https?:\/\//iu.test(trimmed))
|
|
21992
|
+
return false;
|
|
21993
|
+
try {
|
|
21994
|
+
return !LOOPBACK_HOSTS2.has(new URL(trimmed).hostname);
|
|
21995
|
+
} catch {
|
|
21996
|
+
return true;
|
|
20785
21997
|
}
|
|
20786
|
-
return;
|
|
20787
21998
|
}
|
|
20788
21999
|
function truncateUtf8(value, maxBytes) {
|
|
20789
22000
|
if (Buffer.byteLength(value) <= maxBytes)
|
|
@@ -20797,14 +22008,26 @@ function truncateUtf8(value, maxBytes) {
|
|
|
20797
22008
|
}
|
|
20798
22009
|
return "";
|
|
20799
22010
|
}
|
|
20800
|
-
var DEFAULT_BINARY4 = "mailcrawl",
|
|
20801
|
-
var
|
|
22011
|
+
var DEFAULT_BINARY4 = "mailcrawl", DEFAULT_SEARCH_TIMEOUT_MS2 = 60000, DEFAULT_INDEX_TIMEOUT_MS = 1800000, DEFAULT_MAX_BUFFER_BYTES4 = 1048576, LOOPBACK_HOSTS2, SAFE_ENV_KEYS2, SAFE_MAILCRAWL_ENV_KEYS, REMOTE_EMBEDDING_ENV_KEYS;
|
|
22012
|
+
var init_client7 = __esm(() => {
|
|
20802
22013
|
init_portable_spawn();
|
|
20803
22014
|
init_config();
|
|
20804
|
-
|
|
22015
|
+
LOOPBACK_HOSTS2 = new Set(["127.0.0.1", "localhost", "[::1]", "::1"]);
|
|
22016
|
+
SAFE_ENV_KEYS2 = new Set(["HOME", "LANG", "LC_ALL", "PATH", "TMPDIR", "TMP", "TEMP", "NO_COLOR"]);
|
|
20805
22017
|
SAFE_MAILCRAWL_ENV_KEYS = new Set([
|
|
20806
22018
|
"MAILCRAWL_DATA_DIR",
|
|
20807
22019
|
"MAILCRAWL_EMBEDDER",
|
|
22020
|
+
"MAILCRAWL_EMBEDDER_PROVIDER",
|
|
22021
|
+
"MAILCRAWL_EMBED_URL",
|
|
22022
|
+
"MAILCRAWL_EMBED_MODEL",
|
|
22023
|
+
"MAILCRAWL_EMBED_DIM",
|
|
22024
|
+
"MAILCRAWL_EMBED_TIMEOUT",
|
|
22025
|
+
"MAILCRAWL_EMBED_BATCH_SIZE",
|
|
22026
|
+
"MAILCRAWL_QUERY_PREFIX",
|
|
22027
|
+
"MAILCRAWL_PASSAGE_PREFIX",
|
|
22028
|
+
"MAILCRAWL_NATIVE_MODEL",
|
|
22029
|
+
"MAILCRAWL_NATIVE_DEVICE",
|
|
22030
|
+
"MAILCRAWL_NATIVE_DTYPE",
|
|
20808
22031
|
"MAILCRAWL_KIWI_MODEL",
|
|
20809
22032
|
"MAILCRAWL_JA_HELPER",
|
|
20810
22033
|
"MAILCRAWL_ZH_HELPER"
|
|
@@ -20999,7 +22222,7 @@ Use this skill for authorized local email retrieval. AutoRAG invokes the externa
|
|
|
20999
22222
|
Indexing is server-managed and incremental; do not trigger sync yourself.
|
|
21000
22223
|
|
|
21001
22224
|
## Search
|
|
21002
|
-
Call the dedicated \`${datasourceSearchToolName("mailcrawl")}\` tool with a natural-language query.
|
|
22225
|
+
Call the dedicated \`${datasourceSearchToolName("mailcrawl")}\` tool with a natural-language query. Available scopes:
|
|
21003
22226
|
${scopes}
|
|
21004
22227
|
|
|
21005
22228
|
The selectable retrieval modes are BM25, semantic, and hybrid. Scope arguments can only narrow trusted access. Source identifiers remain opaque and hierarchical.
|
|
@@ -21032,9 +22255,9 @@ Never pass datasource virtual paths (\`/mailcrawl/...\`) to bash; they are not O
|
|
|
21032
22255
|
}
|
|
21033
22256
|
}
|
|
21034
22257
|
var TAGS;
|
|
21035
|
-
var
|
|
22258
|
+
var init_skill9 = __esm(() => {
|
|
21036
22259
|
init_scope2();
|
|
21037
|
-
|
|
22260
|
+
init_client7();
|
|
21038
22261
|
init_config();
|
|
21039
22262
|
init_methods4();
|
|
21040
22263
|
TAGS = ["mailcrawl", "email", "pii"];
|
|
@@ -21042,181 +22265,9 @@ var init_skill7 = __esm(() => {
|
|
|
21042
22265
|
|
|
21043
22266
|
// src/datasource/skills/mailcrawl/index.ts
|
|
21044
22267
|
var init_mailcrawl = __esm(() => {
|
|
21045
|
-
|
|
22268
|
+
init_client7();
|
|
21046
22269
|
init_methods4();
|
|
21047
|
-
|
|
21048
|
-
});
|
|
21049
|
-
|
|
21050
|
-
// src/datasource/crawler-client.ts
|
|
21051
|
-
import { spawn as spawn12 } from "node:child_process";
|
|
21052
|
-
|
|
21053
|
-
class CrawlerCliClient {
|
|
21054
|
-
profile;
|
|
21055
|
-
options;
|
|
21056
|
-
constructor(profile, options = {}) {
|
|
21057
|
-
this.profile = profile;
|
|
21058
|
-
this.options = options;
|
|
21059
|
-
}
|
|
21060
|
-
async sync(signal) {
|
|
21061
|
-
const result = await this.run(this.profile.syncArgs(this.options), signal);
|
|
21062
|
-
if (!result.ok)
|
|
21063
|
-
return toFailure3(result);
|
|
21064
|
-
const count = this.profile.parseSyncCount(result.stdout);
|
|
21065
|
-
if (count === undefined)
|
|
21066
|
-
return toFailure3(result, "invalid-output");
|
|
21067
|
-
return { ok: true, count, stdout: result.stdout, stderr: result.stderr, code: result.code ?? 0 };
|
|
21068
|
-
}
|
|
21069
|
-
async search(query, options = {}) {
|
|
21070
|
-
const topK = options.topK ?? 20;
|
|
21071
|
-
const result = await this.run(this.profile.searchArgs(this.options, query, topK), options.signal);
|
|
21072
|
-
if (!result.ok)
|
|
21073
|
-
return toFailure3(result);
|
|
21074
|
-
const hits = this.profile.parseHits(result.stdout);
|
|
21075
|
-
if (hits === undefined)
|
|
21076
|
-
return toFailure3(result, "invalid-output");
|
|
21077
|
-
return { ok: true, hits, stdout: result.stdout, stderr: result.stderr, code: result.code ?? 0 };
|
|
21078
|
-
}
|
|
21079
|
-
async run(args, signal) {
|
|
21080
|
-
const env = controlledEnv4(this.profile.allowedEnvPrefixes, this.options.env);
|
|
21081
|
-
env.CRAWLKIT_NO_UPDATE_CHECK = "1";
|
|
21082
|
-
return spawnCrawler(this.options.binaryPath ?? this.profile.binaryName, args, env, signal, this.options, this.options.workspacePath);
|
|
21083
|
-
}
|
|
21084
|
-
}
|
|
21085
|
-
function spawnCrawler(command, args, env, signal, options, cwd) {
|
|
21086
|
-
return new Promise((resolve) => {
|
|
21087
|
-
const portable = portableSpawnCommand(command, args);
|
|
21088
|
-
const child = spawn12(portable.command, [...portable.args], {
|
|
21089
|
-
env,
|
|
21090
|
-
...cwd === undefined ? {} : { cwd },
|
|
21091
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
21092
|
-
});
|
|
21093
|
-
let stdout = { text: "", bytes: 0, capped: false };
|
|
21094
|
-
let stderr = { text: "", bytes: 0, capped: false };
|
|
21095
|
-
let settled = false;
|
|
21096
|
-
let finalReason;
|
|
21097
|
-
const maxBuffer = options.maxBufferBytes ?? DEFAULT_MAX_BUFFER_BYTES4;
|
|
21098
|
-
const timeout = setTimeout(() => {
|
|
21099
|
-
finalReason = "timeout";
|
|
21100
|
-
terminate6(child);
|
|
21101
|
-
}, options.timeoutMs ?? DEFAULT_TIMEOUT_MS9);
|
|
21102
|
-
const abortHandler = () => {
|
|
21103
|
-
finalReason = "aborted";
|
|
21104
|
-
terminate6(child);
|
|
21105
|
-
};
|
|
21106
|
-
if (signal?.aborted)
|
|
21107
|
-
abortHandler();
|
|
21108
|
-
signal?.addEventListener("abort", abortHandler, { once: true });
|
|
21109
|
-
child.stdout.setEncoding("utf8");
|
|
21110
|
-
child.stderr.setEncoding("utf8");
|
|
21111
|
-
child.stdout.on("data", (chunk) => {
|
|
21112
|
-
stdout = appendBounded4(stdout, chunk, maxBuffer);
|
|
21113
|
-
if (stdout.capped) {
|
|
21114
|
-
finalReason = "stdout-too-large";
|
|
21115
|
-
terminate6(child);
|
|
21116
|
-
}
|
|
21117
|
-
});
|
|
21118
|
-
child.stderr.on("data", (chunk) => {
|
|
21119
|
-
stderr = appendBounded4(stderr, chunk, maxBuffer);
|
|
21120
|
-
if (stderr.capped) {
|
|
21121
|
-
finalReason = "stderr-too-large";
|
|
21122
|
-
terminate6(child);
|
|
21123
|
-
}
|
|
21124
|
-
});
|
|
21125
|
-
child.on("error", (error) => {
|
|
21126
|
-
if (settled)
|
|
21127
|
-
return;
|
|
21128
|
-
settled = true;
|
|
21129
|
-
clearTimeout(timeout);
|
|
21130
|
-
signal?.removeEventListener("abort", abortHandler);
|
|
21131
|
-
resolve({
|
|
21132
|
-
ok: false,
|
|
21133
|
-
reason: error.code === "ENOENT" ? "binary-missing" : "spawn-error",
|
|
21134
|
-
stdout: stdout.text,
|
|
21135
|
-
stderr: "",
|
|
21136
|
-
code: null
|
|
21137
|
-
});
|
|
21138
|
-
});
|
|
21139
|
-
child.on("close", (code) => {
|
|
21140
|
-
if (settled)
|
|
21141
|
-
return;
|
|
21142
|
-
settled = true;
|
|
21143
|
-
clearTimeout(timeout);
|
|
21144
|
-
signal?.removeEventListener("abort", abortHandler);
|
|
21145
|
-
resolve({
|
|
21146
|
-
ok: code === 0 && finalReason === undefined,
|
|
21147
|
-
...finalReason !== undefined ? { reason: finalReason } : code === 0 ? {} : { reason: "nonzero-exit" },
|
|
21148
|
-
stdout: stdout.text,
|
|
21149
|
-
stderr: stderr.text,
|
|
21150
|
-
code
|
|
21151
|
-
});
|
|
21152
|
-
});
|
|
21153
|
-
});
|
|
21154
|
-
}
|
|
21155
|
-
function controlledEnv4(allowedPrefixes, configured) {
|
|
21156
|
-
const env = {};
|
|
21157
|
-
for (const [key, value] of Object.entries(process.env)) {
|
|
21158
|
-
if (value !== undefined && isAllowedEnvKey(key, allowedPrefixes))
|
|
21159
|
-
env[key] = value;
|
|
21160
|
-
}
|
|
21161
|
-
for (const [key, value] of Object.entries(configured ?? {})) {
|
|
21162
|
-
if (value === undefined)
|
|
21163
|
-
delete env[key];
|
|
21164
|
-
else if (isAllowedEnvKey(key, allowedPrefixes))
|
|
21165
|
-
env[key] = value;
|
|
21166
|
-
}
|
|
21167
|
-
return env;
|
|
21168
|
-
}
|
|
21169
|
-
function isAllowedEnvKey(key, allowedPrefixes) {
|
|
21170
|
-
return SAFE_ENV_KEYS2.has(key) || process.platform === "win32" && [...SAFE_ENV_KEYS2].some((safeKey) => safeKey.toUpperCase() === key.toUpperCase()) || key.startsWith("CRAWLKIT_") || allowedPrefixes.some((prefix) => key.startsWith(prefix));
|
|
21171
|
-
}
|
|
21172
|
-
function appendBounded4(state, chunk, maxBytes) {
|
|
21173
|
-
const nextBytes = state.bytes + Buffer.byteLength(chunk);
|
|
21174
|
-
if (nextBytes <= maxBytes)
|
|
21175
|
-
return { text: state.text + chunk, bytes: nextBytes, capped: false };
|
|
21176
|
-
const remaining = Math.max(maxBytes - state.bytes, 0);
|
|
21177
|
-
return { text: state.text + chunk.slice(0, remaining), bytes: maxBytes, capped: true };
|
|
21178
|
-
}
|
|
21179
|
-
function terminate6(child) {
|
|
21180
|
-
if (!child.killed)
|
|
21181
|
-
child.kill("SIGTERM");
|
|
21182
|
-
}
|
|
21183
|
-
function toFailure3(result, reason) {
|
|
21184
|
-
return {
|
|
21185
|
-
ok: false,
|
|
21186
|
-
reason: reason ?? result.reason ?? "nonzero-exit",
|
|
21187
|
-
stdout: result.stdout,
|
|
21188
|
-
stderr: boundDiagnosticText6(result),
|
|
21189
|
-
code: result.code
|
|
21190
|
-
};
|
|
21191
|
-
}
|
|
21192
|
-
function boundDiagnosticText6(result) {
|
|
21193
|
-
if (result.stderr.length > 0)
|
|
21194
|
-
return result.stderr.trim().slice(0, 4000);
|
|
21195
|
-
if (result.stdout.length > 0)
|
|
21196
|
-
return result.stdout.trim().slice(0, 4000);
|
|
21197
|
-
return "";
|
|
21198
|
-
}
|
|
21199
|
-
var DEFAULT_TIMEOUT_MS9 = 60000, DEFAULT_MAX_BUFFER_BYTES4 = 1048576, SAFE_ENV_KEYS2;
|
|
21200
|
-
var init_crawler_client = __esm(() => {
|
|
21201
|
-
init_portable_spawn();
|
|
21202
|
-
SAFE_ENV_KEYS2 = new Set([
|
|
21203
|
-
"HOME",
|
|
21204
|
-
"LANG",
|
|
21205
|
-
"LC_ALL",
|
|
21206
|
-
"PATH",
|
|
21207
|
-
"TMPDIR",
|
|
21208
|
-
"TMP",
|
|
21209
|
-
"TEMP",
|
|
21210
|
-
"NO_COLOR",
|
|
21211
|
-
"APPDATA",
|
|
21212
|
-
"ComSpec",
|
|
21213
|
-
"LOCALAPPDATA",
|
|
21214
|
-
"PATHEXT",
|
|
21215
|
-
"SystemDrive",
|
|
21216
|
-
"SystemRoot",
|
|
21217
|
-
"USERPROFILE",
|
|
21218
|
-
"WINDIR"
|
|
21219
|
-
]);
|
|
22270
|
+
init_skill9();
|
|
21220
22271
|
});
|
|
21221
22272
|
|
|
21222
22273
|
// src/datasource/crawler-skill.ts
|
|
@@ -21237,7 +22288,7 @@ class CrawlerDatasourceSkill {
|
|
|
21237
22288
|
description: `${definition.description} (${options.datasourceId})`
|
|
21238
22289
|
};
|
|
21239
22290
|
this.client = options.client;
|
|
21240
|
-
this.instanceId = options.instanceId ??
|
|
22291
|
+
this.instanceId = options.instanceId ?? DEFAULT_INSTANCE_ID5;
|
|
21241
22292
|
this.instances = options.instances !== undefined && options.instances.length > 0 ? options.instances : [this.instanceId];
|
|
21242
22293
|
this.pollingIntervalMs = options.pollingIntervalMs ?? DEFAULT_POLLING_INTERVAL_MS4;
|
|
21243
22294
|
this.tags = options.tags ?? definition.defaultTags;
|
|
@@ -21324,7 +22375,7 @@ class CrawlerDatasourceSkill {
|
|
|
21324
22375
|
this.definition.manifestDescription,
|
|
21325
22376
|
"",
|
|
21326
22377
|
"## How to search",
|
|
21327
|
-
`Call the dedicated \`${datasourceSearchToolName(this.definition.datasourceId)}\` tool with a query and optional narrowing scope.
|
|
22378
|
+
`Call the dedicated \`${datasourceSearchToolName(this.definition.datasourceId)}\` tool with a query and optional narrowing scope. Available authorized scopes:`,
|
|
21328
22379
|
scopes,
|
|
21329
22380
|
"",
|
|
21330
22381
|
"`scope` can only narrow within already-authorized scopes; it can never widen access.",
|
|
@@ -21431,7 +22482,7 @@ function matchesScope2(source, scope, allowedScopes) {
|
|
|
21431
22482
|
function failureCode2(reason) {
|
|
21432
22483
|
return reason === "binary-missing" || reason === "spawn-error" || reason === "timeout" || reason === "aborted" ? "datasource-unavailable" : "datasource-index-failed";
|
|
21433
22484
|
}
|
|
21434
|
-
var
|
|
22485
|
+
var DEFAULT_INSTANCE_ID5 = "default", DEFAULT_POLLING_INTERVAL_MS4;
|
|
21435
22486
|
var init_crawler_skill = __esm(() => {
|
|
21436
22487
|
init_errors2();
|
|
21437
22488
|
init_scope2();
|
|
@@ -21453,7 +22504,7 @@ function parseCount(stdout) {
|
|
|
21453
22504
|
return;
|
|
21454
22505
|
if (Array.isArray(parsed))
|
|
21455
22506
|
return parsed.length;
|
|
21456
|
-
if (!
|
|
22507
|
+
if (!isRecord13(parsed))
|
|
21457
22508
|
return;
|
|
21458
22509
|
for (const key of ["pages", "page_count", "pageCount", "synced", "count"]) {
|
|
21459
22510
|
const value = parsed[key];
|
|
@@ -21468,12 +22519,12 @@ function parseHits(stdout) {
|
|
|
21468
22519
|
return parseTabSeparatedHits(trimmed);
|
|
21469
22520
|
}
|
|
21470
22521
|
const parsed = parseJson4(stdout);
|
|
21471
|
-
const rows = Array.isArray(parsed) ? parsed :
|
|
22522
|
+
const rows = Array.isArray(parsed) ? parsed : isRecord13(parsed) && Array.isArray(parsed.results) ? parsed.results : undefined;
|
|
21472
22523
|
if (rows === undefined)
|
|
21473
22524
|
return;
|
|
21474
22525
|
const hits = [];
|
|
21475
22526
|
for (const [index, row] of rows.entries()) {
|
|
21476
|
-
if (!
|
|
22527
|
+
if (!isRecord13(row))
|
|
21477
22528
|
return;
|
|
21478
22529
|
const id = stringValue2(row, ["page_id", "id"]);
|
|
21479
22530
|
const content = stringValue2(row, ["snippet", "text", "content"]);
|
|
@@ -21537,7 +22588,7 @@ function parseJson4(stdout) {
|
|
|
21537
22588
|
return;
|
|
21538
22589
|
}
|
|
21539
22590
|
}
|
|
21540
|
-
function
|
|
22591
|
+
function isRecord13(value) {
|
|
21541
22592
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21542
22593
|
}
|
|
21543
22594
|
function stringValue2(record, keys) {
|
|
@@ -21586,46 +22637,16 @@ var init_notion = __esm(() => {
|
|
|
21586
22637
|
};
|
|
21587
22638
|
});
|
|
21588
22639
|
|
|
21589
|
-
// src/process/terminate-tree.ts
|
|
21590
|
-
import { spawn as spawn13 } from "node:child_process";
|
|
21591
|
-
function terminateProcessTree(child, signal = "SIGTERM") {
|
|
21592
|
-
const pid = child.pid;
|
|
21593
|
-
if (pid === undefined)
|
|
21594
|
-
return false;
|
|
21595
|
-
if (process.platform === "win32") {
|
|
21596
|
-
const killer = spawn13("taskkill", ["/pid", String(pid), "/t", "/f"], { stdio: "ignore", windowsHide: true });
|
|
21597
|
-
killer.on("error", () => killDirectChild(child, signal));
|
|
21598
|
-
return true;
|
|
21599
|
-
}
|
|
21600
|
-
try {
|
|
21601
|
-
process.kill(-pid, signal);
|
|
21602
|
-
return true;
|
|
21603
|
-
} catch {
|
|
21604
|
-
return killDirectChild(child, signal);
|
|
21605
|
-
}
|
|
21606
|
-
}
|
|
21607
|
-
function killDirectChild(child, signal) {
|
|
21608
|
-
if (child.exitCode !== null || child.signalCode !== null)
|
|
21609
|
-
return false;
|
|
21610
|
-
try {
|
|
21611
|
-
return child.kill(signal);
|
|
21612
|
-
} catch {
|
|
21613
|
-
return false;
|
|
21614
|
-
}
|
|
21615
|
-
}
|
|
21616
|
-
var TREE_KILL_GRACE_MS = 500;
|
|
21617
|
-
var init_terminate_tree = () => {};
|
|
21618
|
-
|
|
21619
22640
|
// src/datasource/skills/obsidian/paths.ts
|
|
21620
|
-
import { join as
|
|
22641
|
+
import { join as join28 } from "node:path";
|
|
21621
22642
|
function obsidianDatasourceRoot(workspaceRoot, instanceId) {
|
|
21622
|
-
return
|
|
22643
|
+
return join28(workspaceRoot, AUTORAG_DIRNAME, DATASOURCES_DIRNAME, OBSIDIAN_DATASOURCE_DIRNAME, instanceId);
|
|
21623
22644
|
}
|
|
21624
22645
|
function obsidianQmdConfigDir(workspaceRoot, instanceId) {
|
|
21625
|
-
return
|
|
22646
|
+
return join28(obsidianDatasourceRoot(workspaceRoot, instanceId), "config");
|
|
21626
22647
|
}
|
|
21627
22648
|
function obsidianQmdCacheDir(workspaceRoot, instanceId) {
|
|
21628
|
-
return
|
|
22649
|
+
return join28(obsidianDatasourceRoot(workspaceRoot, instanceId), "cache");
|
|
21629
22650
|
}
|
|
21630
22651
|
function stripEdgeDashes(value) {
|
|
21631
22652
|
let start = 0;
|
|
@@ -21648,7 +22669,7 @@ var DEFAULT_QMD_BINARY = "qmd", DEFAULT_QMD_TIMEOUT_MS = 60000, DEFAULT_QMD_MAX_
|
|
|
21648
22669
|
|
|
21649
22670
|
// src/datasource/skills/obsidian/client.ts
|
|
21650
22671
|
import { spawn as spawn14 } from "node:child_process";
|
|
21651
|
-
import { mkdirSync as
|
|
22672
|
+
import { mkdirSync as mkdirSync18, writeFileSync as writeFileSync16 } from "node:fs";
|
|
21652
22673
|
import { isAbsolute as isAbsolute6, resolve as resolve12 } from "node:path";
|
|
21653
22674
|
|
|
21654
22675
|
class QmdClient {
|
|
@@ -21668,10 +22689,10 @@ class QmdClient {
|
|
|
21668
22689
|
const cacheDir = obsidianQmdCacheDir(workspaceRoot, instanceId);
|
|
21669
22690
|
try {
|
|
21670
22691
|
if (this.options.configPath === undefined) {
|
|
21671
|
-
|
|
21672
|
-
|
|
22692
|
+
mkdirSync18(configDir, { recursive: true });
|
|
22693
|
+
writeFileSync16(resolve12(configDir, "index.yml"), renderIndexYaml(collectionName, vaultPath), "utf8");
|
|
21673
22694
|
}
|
|
21674
|
-
|
|
22695
|
+
mkdirSync18(cacheDir, { recursive: true });
|
|
21675
22696
|
} catch (error) {
|
|
21676
22697
|
return failure3("spawn-error", error instanceof Error ? error.message : "failed to write qmd config");
|
|
21677
22698
|
}
|
|
@@ -21894,7 +22915,7 @@ ${stderr}`;
|
|
|
21894
22915
|
}
|
|
21895
22916
|
try {
|
|
21896
22917
|
const parsed = JSON.parse(stdout);
|
|
21897
|
-
if (
|
|
22918
|
+
if (isRecord14(parsed)) {
|
|
21898
22919
|
return {
|
|
21899
22920
|
indexed: numberField(parsed, "indexed") ?? numberField(parsed, "new") ?? 0,
|
|
21900
22921
|
updated: numberField(parsed, "updated") ?? 0,
|
|
@@ -21923,7 +22944,7 @@ function parseSearchHits(stdout) {
|
|
|
21923
22944
|
function extractHitRows(parsed) {
|
|
21924
22945
|
if (Array.isArray(parsed))
|
|
21925
22946
|
return parsed;
|
|
21926
|
-
if (!
|
|
22947
|
+
if (!isRecord14(parsed))
|
|
21927
22948
|
return;
|
|
21928
22949
|
for (const key of ["results", "hits", "documents", "items"]) {
|
|
21929
22950
|
const value = parsed[key];
|
|
@@ -21935,7 +22956,7 @@ function extractHitRows(parsed) {
|
|
|
21935
22956
|
return;
|
|
21936
22957
|
}
|
|
21937
22958
|
function normalizeHit3(raw) {
|
|
21938
|
-
if (!
|
|
22959
|
+
if (!isRecord14(raw))
|
|
21939
22960
|
return;
|
|
21940
22961
|
const score = numberField(raw, "score") ?? numberField(raw, "relevance") ?? 0;
|
|
21941
22962
|
const docid = stringField(raw, "docid") ?? stringField(raw, "id");
|
|
@@ -21981,11 +23002,11 @@ function numberField(record, key) {
|
|
|
21981
23002
|
const value = record[key];
|
|
21982
23003
|
return typeof value === "number" && Number.isFinite(value) ? value : undefined;
|
|
21983
23004
|
}
|
|
21984
|
-
function
|
|
23005
|
+
function isRecord14(value) {
|
|
21985
23006
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21986
23007
|
}
|
|
21987
23008
|
var SAFE_INHERITED_ENV_KEYS3, SAFE_QMD_ENV_PREFIX = "QMD_";
|
|
21988
|
-
var
|
|
23009
|
+
var init_client8 = __esm(() => {
|
|
21989
23010
|
init_portable_spawn();
|
|
21990
23011
|
init_terminate_tree();
|
|
21991
23012
|
init_paths5();
|
|
@@ -22064,7 +23085,7 @@ async function retrieveObsidian(client, mode, methodName, instanceId, query, opt
|
|
|
22064
23085
|
const trimmed = query.trim();
|
|
22065
23086
|
if (trimmed.length === 0)
|
|
22066
23087
|
return [];
|
|
22067
|
-
const topK = options.topK ??
|
|
23088
|
+
const topK = options.topK ?? DEFAULT_TOP_K5;
|
|
22068
23089
|
const searchOptions = { topK, signal: options.signal };
|
|
22069
23090
|
const result = await client.search(mode, trimmed, searchOptions);
|
|
22070
23091
|
if (!result.ok)
|
|
@@ -22106,7 +23127,7 @@ function toRetrievalResult3(hit, source, methodName, instanceId, mode) {
|
|
|
22106
23127
|
}
|
|
22107
23128
|
};
|
|
22108
23129
|
}
|
|
22109
|
-
var OBSIDIAN_DATASOURCE_ID = "obsidian", DEFAULT_OBSIDIAN_TAGS,
|
|
23130
|
+
var OBSIDIAN_DATASOURCE_ID = "obsidian", DEFAULT_OBSIDIAN_TAGS, DEFAULT_TOP_K5 = 20;
|
|
22110
23131
|
var init_methods5 = __esm(() => {
|
|
22111
23132
|
init_errors2();
|
|
22112
23133
|
init_scope2();
|
|
@@ -22124,7 +23145,7 @@ class ObsidianSkill {
|
|
|
22124
23145
|
lastIndexedAt;
|
|
22125
23146
|
lastError;
|
|
22126
23147
|
constructor(options = {}) {
|
|
22127
|
-
this.instanceId = options.instanceId ??
|
|
23148
|
+
this.instanceId = options.instanceId ?? DEFAULT_INSTANCE_ID6;
|
|
22128
23149
|
this.instances = options.instances !== undefined && options.instances.length > 0 ? options.instances : [this.instanceId];
|
|
22129
23150
|
this.pollingIntervalMs = options.pollingIntervalMs ?? DEFAULT_POLLING_INTERVAL_MS5;
|
|
22130
23151
|
this.tags = options.tags ?? DEFAULT_OBSIDIAN_TAGS2;
|
|
@@ -22246,7 +23267,7 @@ class ObsidianSkill {
|
|
|
22246
23267
|
`Indexing is server-managed and refreshed ${cadence} via \`qmd update\` (+ \`qmd embed\` for semantic). You do not trigger indexing; just search.`,
|
|
22247
23268
|
"",
|
|
22248
23269
|
"## How to search",
|
|
22249
|
-
`Call the dedicated \`${datasourceSearchToolName(OBSIDIAN_DATASOURCE_ID2)}\` tool with a natural-language \`query\`. Optionally pass \`topK\` and a narrowing \`scope\`.
|
|
23270
|
+
`Call the dedicated \`${datasourceSearchToolName(OBSIDIAN_DATASOURCE_ID2)}\` tool with a natural-language \`query\`. Optionally pass \`topK\` and a narrowing \`scope\`. Available authorized scopes:`,
|
|
22250
23271
|
instanceScopes.length > 0 ? instanceScopes : "- (no authorized instances)",
|
|
22251
23272
|
"",
|
|
22252
23273
|
"`scope` can only narrow within already-authorized scopes; it can never widen access.",
|
|
@@ -22293,10 +23314,10 @@ function boundDiagnostic(value) {
|
|
|
22293
23314
|
const trimmed = value.trim();
|
|
22294
23315
|
return trimmed.length > 500 ? `${trimmed.slice(0, 500)}...` : trimmed;
|
|
22295
23316
|
}
|
|
22296
|
-
var OBSIDIAN_DATASOURCE_ID2 = "obsidian", OBSIDIAN_SKILL_TYPE = "obsidian-vault",
|
|
22297
|
-
var
|
|
23317
|
+
var OBSIDIAN_DATASOURCE_ID2 = "obsidian", OBSIDIAN_SKILL_TYPE = "obsidian-vault", DEFAULT_INSTANCE_ID6 = "default", DEFAULT_POLLING_INTERVAL_MS5, DEFAULT_OBSIDIAN_TAGS2;
|
|
23318
|
+
var init_skill10 = __esm(() => {
|
|
22298
23319
|
init_scope2();
|
|
22299
|
-
|
|
23320
|
+
init_client8();
|
|
22300
23321
|
init_methods5();
|
|
22301
23322
|
init_paths5();
|
|
22302
23323
|
DEFAULT_POLLING_INTERVAL_MS5 = 15 * 60 * 1000;
|
|
@@ -22305,10 +23326,10 @@ var init_skill8 = __esm(() => {
|
|
|
22305
23326
|
|
|
22306
23327
|
// src/datasource/skills/obsidian/index.ts
|
|
22307
23328
|
var init_obsidian = __esm(() => {
|
|
22308
|
-
|
|
23329
|
+
init_client8();
|
|
22309
23330
|
init_methods5();
|
|
22310
23331
|
init_paths5();
|
|
22311
|
-
|
|
23332
|
+
init_skill10();
|
|
22312
23333
|
});
|
|
22313
23334
|
|
|
22314
23335
|
// src/datasource/skills/rss/connector.ts
|
|
@@ -22458,13 +23479,13 @@ function present(item) {
|
|
|
22458
23479
|
return item !== undefined;
|
|
22459
23480
|
}
|
|
22460
23481
|
var DEFAULT_MAX_DOCUMENTS4 = 500, DEFAULT_MAX_ITEMS_PER_FEED = 100, DEFAULT_FEED_TIMEOUT_MS = 30000, MAX_CONTENT_CHARS2 = 20000, ACCEPT_HEADER = "application/rss+xml, application/atom+xml, application/xml, text/xml";
|
|
22461
|
-
var
|
|
23482
|
+
var init_connector5 = () => {};
|
|
22462
23483
|
|
|
22463
23484
|
// src/datasource/skills/rss/skill.ts
|
|
22464
23485
|
var RSS_SKILL_DEFINITION, DEFAULT_DEDUPE_WINDOW_MS, RssSkill;
|
|
22465
|
-
var
|
|
23486
|
+
var init_skill11 = __esm(() => {
|
|
22466
23487
|
init_connector_skill();
|
|
22467
|
-
|
|
23488
|
+
init_connector5();
|
|
22468
23489
|
RSS_SKILL_DEFINITION = {
|
|
22469
23490
|
skillName: "rss",
|
|
22470
23491
|
skillType: "rss-feeds",
|
|
@@ -22490,8 +23511,8 @@ var init_skill9 = __esm(() => {
|
|
|
22490
23511
|
|
|
22491
23512
|
// src/datasource/skills/rss/index.ts
|
|
22492
23513
|
var init_rss = __esm(() => {
|
|
22493
|
-
|
|
22494
|
-
|
|
23514
|
+
init_connector5();
|
|
23515
|
+
init_skill11();
|
|
22495
23516
|
});
|
|
22496
23517
|
|
|
22497
23518
|
// src/datasource/skills/slack/index.ts
|
|
@@ -22508,7 +23529,7 @@ function parseCount2(stdout) {
|
|
|
22508
23529
|
return;
|
|
22509
23530
|
if (Array.isArray(parsed))
|
|
22510
23531
|
return parsed.length;
|
|
22511
|
-
if (!
|
|
23532
|
+
if (!isRecord15(parsed))
|
|
22512
23533
|
return;
|
|
22513
23534
|
for (const key of ["messages", "message_count", "messageCount", "synced", "count"]) {
|
|
22514
23535
|
const value = parsed[key];
|
|
@@ -22521,12 +23542,12 @@ function parseHits2(stdout) {
|
|
|
22521
23542
|
const parsed = parseJson5(stdout);
|
|
22522
23543
|
if (parsed === null)
|
|
22523
23544
|
return [];
|
|
22524
|
-
const rows = Array.isArray(parsed) ? parsed :
|
|
23545
|
+
const rows = Array.isArray(parsed) ? parsed : isRecord15(parsed) && Array.isArray(parsed.messages) ? parsed.messages : undefined;
|
|
22525
23546
|
if (rows === undefined)
|
|
22526
23547
|
return;
|
|
22527
23548
|
const hits = [];
|
|
22528
23549
|
for (const [index, row] of rows.entries()) {
|
|
22529
|
-
if (!
|
|
23550
|
+
if (!isRecord15(row))
|
|
22530
23551
|
return;
|
|
22531
23552
|
const workspaceId = stringValue3(row, ["workspace_id"]);
|
|
22532
23553
|
const workspaceName = stringValue3(row, ["workspace_name"]);
|
|
@@ -22581,7 +23602,7 @@ function parseJson5(stdout) {
|
|
|
22581
23602
|
return;
|
|
22582
23603
|
}
|
|
22583
23604
|
}
|
|
22584
|
-
function
|
|
23605
|
+
function isRecord15(value) {
|
|
22585
23606
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22586
23607
|
}
|
|
22587
23608
|
function stringValue3(record, keys) {
|
|
@@ -22645,7 +23666,7 @@ var init_slack = __esm(() => {
|
|
|
22645
23666
|
|
|
22646
23667
|
// src/datasource/skills/spotlight/connector.ts
|
|
22647
23668
|
import { spawn as spawn15 } from "node:child_process";
|
|
22648
|
-
import { createHash as
|
|
23669
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
22649
23670
|
import { readFile as fsReadFile, stat as stat6 } from "node:fs/promises";
|
|
22650
23671
|
import { basename as basename11, extname as extname10 } from "node:path";
|
|
22651
23672
|
|
|
@@ -22668,7 +23689,7 @@ class SpotlightConnector {
|
|
|
22668
23689
|
if (queries.length === 0) {
|
|
22669
23690
|
return { ok: false, reason: "not-configured", message: "no spotlight queries configured" };
|
|
22670
23691
|
}
|
|
22671
|
-
const timeoutMs = this.options.timeoutMs ??
|
|
23692
|
+
const timeoutMs = this.options.timeoutMs ?? DEFAULT_TIMEOUT_MS9;
|
|
22672
23693
|
const status = await this.run("mdutil", ["-s", "/"], timeoutMs);
|
|
22673
23694
|
if (status.ok && /indexing disabled/iu.test(status.stdout)) {
|
|
22674
23695
|
return {
|
|
@@ -22729,7 +23750,7 @@ class SpotlightConnector {
|
|
|
22729
23750
|
if (content.length === 0)
|
|
22730
23751
|
continue;
|
|
22731
23752
|
documents.push({
|
|
22732
|
-
docId:
|
|
23753
|
+
docId: createHash8("sha256").update(path).digest("hex").slice(0, 16),
|
|
22733
23754
|
hierarchy: ["files"],
|
|
22734
23755
|
title: basename11(path),
|
|
22735
23756
|
content,
|
|
@@ -22762,7 +23783,7 @@ class SpotlightConnector {
|
|
|
22762
23783
|
return { ok: true, documents, ...warnings.length > 0 ? { warnings } : {} };
|
|
22763
23784
|
}
|
|
22764
23785
|
}
|
|
22765
|
-
var DEFAULT_MAX_RESULTS_PER_QUERY = 100, DEFAULT_MAX_DOCUMENTS5 = 300, DEFAULT_MAX_BYTES_PER_FILE3,
|
|
23786
|
+
var DEFAULT_MAX_RESULTS_PER_QUERY = 100, DEFAULT_MAX_DOCUMENTS5 = 300, DEFAULT_MAX_BYTES_PER_FILE3, DEFAULT_TIMEOUT_MS9 = 15000, MAX_CONTENT_CHARS3 = 1e5, MAX_BUFFER_BYTES, FDA_GUIDANCE = "grant Full Disk Access to the terminal or app running AutoRAG (System Settings -> Privacy & Security -> Full Disk Access), then restart it", spawnRunner = (command, args, timeoutMs) => new Promise((resolve) => {
|
|
22766
23787
|
const child = spawn15(command, [...args], { stdio: ["ignore", "pipe", "pipe"] });
|
|
22767
23788
|
let stdout = "";
|
|
22768
23789
|
let stderr = "";
|
|
@@ -22795,16 +23816,16 @@ var DEFAULT_MAX_RESULTS_PER_QUERY = 100, DEFAULT_MAX_DOCUMENTS5 = 300, DEFAULT_M
|
|
|
22795
23816
|
finish({ ok: code === 0, stdout, stderr, code });
|
|
22796
23817
|
});
|
|
22797
23818
|
});
|
|
22798
|
-
var
|
|
23819
|
+
var init_connector6 = __esm(() => {
|
|
22799
23820
|
DEFAULT_MAX_BYTES_PER_FILE3 = 256 * 1024;
|
|
22800
23821
|
MAX_BUFFER_BYTES = 4 * 1024 * 1024;
|
|
22801
23822
|
});
|
|
22802
23823
|
|
|
22803
23824
|
// src/datasource/skills/spotlight/skill.ts
|
|
22804
23825
|
var SPOTLIGHT_SKILL_DEFINITION, SpotlightSkill;
|
|
22805
|
-
var
|
|
23826
|
+
var init_skill12 = __esm(() => {
|
|
22806
23827
|
init_connector_skill();
|
|
22807
|
-
|
|
23828
|
+
init_connector6();
|
|
22808
23829
|
SPOTLIGHT_SKILL_DEFINITION = {
|
|
22809
23830
|
skillName: "spotlight",
|
|
22810
23831
|
skillType: "spotlight-search",
|
|
@@ -22841,8 +23862,8 @@ var init_skill10 = __esm(() => {
|
|
|
22841
23862
|
|
|
22842
23863
|
// src/datasource/skills/spotlight/index.ts
|
|
22843
23864
|
var init_spotlight = __esm(() => {
|
|
22844
|
-
|
|
22845
|
-
|
|
23865
|
+
init_connector6();
|
|
23866
|
+
init_skill12();
|
|
22846
23867
|
});
|
|
22847
23868
|
|
|
22848
23869
|
// src/datasource/skills/telecrawl/index.ts
|
|
@@ -22859,7 +23880,7 @@ function parseCount3(stdout) {
|
|
|
22859
23880
|
return;
|
|
22860
23881
|
if (Array.isArray(parsed))
|
|
22861
23882
|
return parsed.length;
|
|
22862
|
-
if (!
|
|
23883
|
+
if (!isRecord16(parsed))
|
|
22863
23884
|
return;
|
|
22864
23885
|
for (const key of ["messages", "message_count", "messageCount", "imported", "count"]) {
|
|
22865
23886
|
const value = parsed[key];
|
|
@@ -22872,12 +23893,12 @@ function parseHits3(stdout) {
|
|
|
22872
23893
|
const parsed = parseJson6(stdout);
|
|
22873
23894
|
if (parsed === null)
|
|
22874
23895
|
return [];
|
|
22875
|
-
const rows = Array.isArray(parsed) ? parsed :
|
|
23896
|
+
const rows = Array.isArray(parsed) ? parsed : isRecord16(parsed) && Array.isArray(parsed.messages) ? parsed.messages : undefined;
|
|
22876
23897
|
if (rows === undefined)
|
|
22877
23898
|
return;
|
|
22878
23899
|
const hits = [];
|
|
22879
23900
|
for (const [index, row] of rows.entries()) {
|
|
22880
|
-
if (!
|
|
23901
|
+
if (!isRecord16(row))
|
|
22881
23902
|
return;
|
|
22882
23903
|
const id = stringValue4(row, ["message_id", "event_id", "id"]);
|
|
22883
23904
|
const content = stringValue4(row, ["snippet", "text", "content"]);
|
|
@@ -22916,7 +23937,7 @@ function parseJson6(stdout) {
|
|
|
22916
23937
|
return;
|
|
22917
23938
|
}
|
|
22918
23939
|
}
|
|
22919
|
-
function
|
|
23940
|
+
function isRecord16(value) {
|
|
22920
23941
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22921
23942
|
}
|
|
22922
23943
|
function stringValue4(record, keys) {
|
|
@@ -22979,7 +24000,7 @@ function parseCount4(stdout) {
|
|
|
22979
24000
|
return;
|
|
22980
24001
|
if (Array.isArray(parsed))
|
|
22981
24002
|
return parsed.length;
|
|
22982
|
-
if (!
|
|
24003
|
+
if (!isRecord17(parsed))
|
|
22983
24004
|
return;
|
|
22984
24005
|
for (const key of ["messages", "message_count", "messageCount", "imported", "count"]) {
|
|
22985
24006
|
const value = parsed[key];
|
|
@@ -22992,12 +24013,12 @@ function parseHits4(stdout) {
|
|
|
22992
24013
|
const parsed = parseJson7(stdout);
|
|
22993
24014
|
if (parsed === null)
|
|
22994
24015
|
return [];
|
|
22995
|
-
const rows = Array.isArray(parsed) ? parsed :
|
|
24016
|
+
const rows = Array.isArray(parsed) ? parsed : isRecord17(parsed) && Array.isArray(parsed.messages) ? parsed.messages : undefined;
|
|
22996
24017
|
if (rows === undefined)
|
|
22997
24018
|
return;
|
|
22998
24019
|
const hits = [];
|
|
22999
24020
|
for (const [index, row] of rows.entries()) {
|
|
23000
|
-
if (!
|
|
24021
|
+
if (!isRecord17(row))
|
|
23001
24022
|
return;
|
|
23002
24023
|
const id = stringValue5(row, ["message_id", "event_id", "id"]);
|
|
23003
24024
|
const content = stringValue5(row, ["snippet", "text", "content"]);
|
|
@@ -23034,7 +24055,7 @@ function parseJson7(stdout) {
|
|
|
23034
24055
|
return;
|
|
23035
24056
|
}
|
|
23036
24057
|
}
|
|
23037
|
-
function
|
|
24058
|
+
function isRecord17(value) {
|
|
23038
24059
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
23039
24060
|
}
|
|
23040
24061
|
function stringValue5(record, keys) {
|
|
@@ -23092,6 +24113,16 @@ var init_wacrawl = __esm(() => {
|
|
|
23092
24113
|
});
|
|
23093
24114
|
|
|
23094
24115
|
// src/datasource/skills/factory.ts
|
|
24116
|
+
function larkConnectorOptions(connector) {
|
|
24117
|
+
if (connector === undefined)
|
|
24118
|
+
return {};
|
|
24119
|
+
const binaryPath = connector.binaryPath;
|
|
24120
|
+
const embedderBaseUrl = connector.embedderBaseUrl;
|
|
24121
|
+
return {
|
|
24122
|
+
...typeof binaryPath === "string" ? { binaryPath } : {},
|
|
24123
|
+
...typeof embedderBaseUrl === "string" ? { embedderBaseUrl } : {}
|
|
24124
|
+
};
|
|
24125
|
+
}
|
|
23095
24126
|
function common(config, workspaceRoot) {
|
|
23096
24127
|
return {
|
|
23097
24128
|
...config.instanceId !== undefined ? { instanceId: config.instanceId } : {},
|
|
@@ -23125,13 +24156,14 @@ function buildDatasourceSkills(config, workspaceRoot, embeddingRuntime) {
|
|
|
23125
24156
|
unknown.push(name);
|
|
23126
24157
|
continue;
|
|
23127
24158
|
}
|
|
23128
|
-
const
|
|
24159
|
+
const larkOwnsChannels = templateName === "lark";
|
|
24160
|
+
const hasChannelFilter = !larkOwnsChannels && ((entry.channels?.ids?.length ?? 0) > 0 || (entry.channels?.names?.length ?? 0) > 0);
|
|
23129
24161
|
let aliased = skill;
|
|
23130
24162
|
if (name !== templateName || hasChannelFilter) {
|
|
23131
24163
|
aliased = new AliasedDatasourceSkill(skill, {
|
|
23132
24164
|
alias: name,
|
|
23133
|
-
|
|
23134
|
-
|
|
24165
|
+
...!larkOwnsChannels && entry.channels?.ids !== undefined ? { channelIds: entry.channels.ids } : {},
|
|
24166
|
+
...!larkOwnsChannels && entry.channels?.names !== undefined ? { channelNames: entry.channels.names } : {}
|
|
23135
24167
|
});
|
|
23136
24168
|
}
|
|
23137
24169
|
skills.push(typeof entry.description === "string" && entry.description.trim().length > 0 ? new DescribedDatasourceSkill(aliased, entry.description.trim()) : aliased);
|
|
@@ -23145,7 +24177,9 @@ var init_factory = __esm(() => {
|
|
|
23145
24177
|
init_cloud_drive();
|
|
23146
24178
|
init_discrawl();
|
|
23147
24179
|
init_github();
|
|
23148
|
-
|
|
24180
|
+
init_github_gist();
|
|
24181
|
+
init_lark();
|
|
24182
|
+
init_lazykatok();
|
|
23149
24183
|
init_mail_export();
|
|
23150
24184
|
init_mailcrawl();
|
|
23151
24185
|
init_notion();
|
|
@@ -23240,8 +24274,15 @@ var init_factory = __esm(() => {
|
|
|
23240
24274
|
...workspaceRoot === undefined ? {} : { workspacePath: workspaceRoot }
|
|
23241
24275
|
}
|
|
23242
24276
|
}),
|
|
23243
|
-
|
|
23244
|
-
|
|
24277
|
+
lark: (config, _workspaceRoot, registrationName) => new LarkSkill({
|
|
24278
|
+
datasourceId: registrationName,
|
|
24279
|
+
...config.instanceId !== undefined ? { instanceId: config.instanceId } : {},
|
|
24280
|
+
...config.tags !== undefined ? { tags: config.tags } : {},
|
|
24281
|
+
...config.channels?.ids !== undefined ? { chatIds: config.channels.ids } : {},
|
|
24282
|
+
...larkConnectorOptions(config.connector)
|
|
24283
|
+
}),
|
|
24284
|
+
kakao: (config, _workspaceRoot, _registrationName) => new LazykatokSkill({
|
|
24285
|
+
client: new LazykatokClient({
|
|
23245
24286
|
...config.connector
|
|
23246
24287
|
}),
|
|
23247
24288
|
...config.instanceId !== undefined ? { instanceId: config.instanceId } : {},
|
|
@@ -23253,6 +24294,11 @@ var init_factory = __esm(() => {
|
|
|
23253
24294
|
skillName: registrationName,
|
|
23254
24295
|
connectorOptions: config.connector
|
|
23255
24296
|
}),
|
|
24297
|
+
"github-gist": (config, workspaceRoot, registrationName) => new GitHubGistSkill({
|
|
24298
|
+
...common(config, workspaceRoot),
|
|
24299
|
+
skillName: registrationName,
|
|
24300
|
+
connectorOptions: config.connector
|
|
24301
|
+
}),
|
|
23256
24302
|
"cloud-drive": (config, workspaceRoot, registrationName) => new CloudDriveSkill({
|
|
23257
24303
|
...common(config, workspaceRoot),
|
|
23258
24304
|
skillName: registrationName,
|
|
@@ -23298,8 +24344,8 @@ var init_factory = __esm(() => {
|
|
|
23298
24344
|
|
|
23299
24345
|
// src/cli/config.ts
|
|
23300
24346
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
23301
|
-
import { existsSync as
|
|
23302
|
-
import { basename as basename12, dirname as
|
|
24347
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync19, readFileSync as readFileSync18, renameSync as renameSync8, unlinkSync as unlinkSync4, writeFileSync as writeFileSync17 } from "node:fs";
|
|
24348
|
+
import { basename as basename12, dirname as dirname19, isAbsolute as isAbsolute7, join as join29, resolve as resolve13 } from "node:path";
|
|
23303
24349
|
import { findEnvKeys, getEnvApiKey, getModel, getProviders } from "@earendil-works/pi-ai/compat";
|
|
23304
24350
|
function resolveConfigPath(input) {
|
|
23305
24351
|
const flags = input.flags;
|
|
@@ -23314,15 +24360,15 @@ function resolveConfigPath(input) {
|
|
|
23314
24360
|
return { configPath: envConfig, explicit: true };
|
|
23315
24361
|
}
|
|
23316
24362
|
return {
|
|
23317
|
-
configPath:
|
|
24363
|
+
configPath: join29(resolveAutoRAGHome(env), DEFAULT_CONFIG_FILENAME),
|
|
23318
24364
|
explicit: false,
|
|
23319
|
-
legacyPath:
|
|
24365
|
+
legacyPath: join29(cwd, LEGACY_CONFIG_FILENAME)
|
|
23320
24366
|
};
|
|
23321
24367
|
}
|
|
23322
24368
|
function readConfigFile(configPath, explicit) {
|
|
23323
24369
|
let exists;
|
|
23324
24370
|
try {
|
|
23325
|
-
exists =
|
|
24371
|
+
exists = existsSync23(configPath);
|
|
23326
24372
|
} catch {
|
|
23327
24373
|
exists = false;
|
|
23328
24374
|
}
|
|
@@ -23334,7 +24380,7 @@ function readConfigFile(configPath, explicit) {
|
|
|
23334
24380
|
}
|
|
23335
24381
|
let text;
|
|
23336
24382
|
try {
|
|
23337
|
-
text =
|
|
24383
|
+
text = readFileSync18(configPath, "utf8");
|
|
23338
24384
|
} catch (err) {
|
|
23339
24385
|
throw new ConfigError(`Failed to read config file: ${err.message}`);
|
|
23340
24386
|
}
|
|
@@ -23372,9 +24418,9 @@ function acquireConfigWriteLock(configPath) {
|
|
|
23372
24418
|
});
|
|
23373
24419
|
}
|
|
23374
24420
|
function replaceFileAtomically(path, contents, assertCommitAllowed) {
|
|
23375
|
-
const temporaryPath =
|
|
24421
|
+
const temporaryPath = join29(dirname19(path), `.${basename12(path)}.${process.pid}.${randomUUID7()}.tmp`);
|
|
23376
24422
|
try {
|
|
23377
|
-
|
|
24423
|
+
writeFileSync17(temporaryPath, contents, { encoding: "utf8", flag: "wx", flush: true, mode: 384 });
|
|
23378
24424
|
assertCommitAllowed?.();
|
|
23379
24425
|
renameSync8(temporaryPath, path);
|
|
23380
24426
|
} finally {
|
|
@@ -23382,15 +24428,15 @@ function replaceFileAtomically(path, contents, assertCommitAllowed) {
|
|
|
23382
24428
|
}
|
|
23383
24429
|
}
|
|
23384
24430
|
function migrateLegacyConfig(configPath, legacyPath) {
|
|
23385
|
-
if (
|
|
24431
|
+
if (existsSync23(configPath) || !existsSync23(legacyPath))
|
|
23386
24432
|
return;
|
|
23387
24433
|
const legacy = readConfigFile(legacyPath, true);
|
|
23388
|
-
const legacyBytes =
|
|
23389
|
-
const migrated = normalizeLegacyConfigPaths(legacy ?? {},
|
|
24434
|
+
const legacyBytes = readFileSync18(legacyPath);
|
|
24435
|
+
const migrated = normalizeLegacyConfigPaths(legacy ?? {}, dirname19(legacyPath));
|
|
23390
24436
|
const migratedPathsUnchanged = legacy?.workspacePath === migrated.workspacePath && legacy?.memoryPath === migrated.memoryPath && JSON.stringify(legacy?.searchPaths) === JSON.stringify(migrated.searchPaths);
|
|
23391
24437
|
const migratedBytes = migratedPathsUnchanged ? legacyBytes : `${JSON.stringify(migrated, null, 2)}
|
|
23392
24438
|
`;
|
|
23393
|
-
|
|
24439
|
+
mkdirSync19(dirname19(configPath), { recursive: true });
|
|
23394
24440
|
const lock = acquireConfigWriteLock(configPath);
|
|
23395
24441
|
try {
|
|
23396
24442
|
const winner = readConfigFile(configPath, false);
|
|
@@ -23420,7 +24466,7 @@ function resolveConfigFileReadOnly(configPath, explicit, legacyPath) {
|
|
|
23420
24466
|
const legacy = readConfigFile(legacyPath, false);
|
|
23421
24467
|
if (legacy === undefined)
|
|
23422
24468
|
return {};
|
|
23423
|
-
return normalizeLegacyConfigPaths(legacy,
|
|
24469
|
+
return normalizeLegacyConfigPaths(legacy, dirname19(legacyPath));
|
|
23424
24470
|
}
|
|
23425
24471
|
function resolveSearchPaths(searchPaths, origin) {
|
|
23426
24472
|
return searchPaths.map((searchPath) => resolvePersistedPath(searchPath, origin));
|
|
@@ -23865,10 +24911,10 @@ function resolveConfig(input) {
|
|
|
23865
24911
|
const file = readOnly ? resolveConfigFileReadOnly(configPath, explicit, legacyPath) : !explicit && legacyPath ? migrateLegacyConfig(configPath, legacyPath) ?? readConfigFile(configPath, explicit) ?? {} : readConfigFile(configPath, explicit) ?? {};
|
|
23866
24912
|
const defaultSearchPaths = ["."];
|
|
23867
24913
|
const defaultWorkspacePath = cwd;
|
|
23868
|
-
const defaultMemoryPath =
|
|
24914
|
+
const defaultMemoryPath = join29(resolveAutoRAGHome(env), "memory.json");
|
|
23869
24915
|
const flagSearchPaths = parseCsv(flagString(flags, "search-paths"));
|
|
23870
24916
|
const envSearchPaths = parseCsv(envString(env, "AUTORAG_SEARCH_PATHS"));
|
|
23871
|
-
const configOrigin =
|
|
24917
|
+
const configOrigin = dirname19(resolve13(configPath));
|
|
23872
24918
|
const fileWorkspacePath = typeof file.workspacePath === "string" ? resolvePersistedPath(file.workspacePath, configOrigin) : undefined;
|
|
23873
24919
|
const fileSearchPaths = file.searchPaths ? resolveSearchPaths(file.searchPaths, fileWorkspacePath ?? configOrigin) : undefined;
|
|
23874
24920
|
const searchPaths = flagSearchPaths ?? envSearchPaths ?? fileSearchPaths ?? defaultSearchPaths;
|
|
@@ -24225,7 +25271,7 @@ function writeConfigObject(path, config) {
|
|
|
24225
25271
|
if (config === null || typeof config !== "object" || Array.isArray(config)) {
|
|
24226
25272
|
throw new ConfigError("Config file must be a JSON object");
|
|
24227
25273
|
}
|
|
24228
|
-
|
|
25274
|
+
mkdirSync19(dirname19(path), { recursive: true });
|
|
24229
25275
|
const contents = `${JSON.stringify(config, null, 2)}
|
|
24230
25276
|
`;
|
|
24231
25277
|
const lock = acquireConfigWriteLock(path);
|
|
@@ -24238,7 +25284,7 @@ function writeConfigObject(path, config) {
|
|
|
24238
25284
|
function writeDefaultConfig(path, partial, opts = {}) {
|
|
24239
25285
|
const cwd = resolve13(opts.cwd ?? process.cwd());
|
|
24240
25286
|
const workspacePath = resolvePersistedPath(partial.workspacePath ?? ".", cwd);
|
|
24241
|
-
const memoryPath = partial.memoryPath === undefined ?
|
|
25287
|
+
const memoryPath = partial.memoryPath === undefined ? join29(resolveAutoRAGHome(opts.env), "memory.json") : resolvePersistedPath(partial.memoryPath, workspacePath);
|
|
24242
25288
|
const full = {
|
|
24243
25289
|
searchPaths: resolveSearchPaths(partial.searchPaths ?? ["."], cwd),
|
|
24244
25290
|
workspacePath,
|
|
@@ -24261,19 +25307,19 @@ function writeDefaultConfig(path, partial, opts = {}) {
|
|
|
24261
25307
|
full.p2p = normalizeP2pConfig(partial.p2p);
|
|
24262
25308
|
else
|
|
24263
25309
|
full.p2p = { enabled: false };
|
|
24264
|
-
|
|
25310
|
+
mkdirSync19(dirname19(path), { recursive: true });
|
|
24265
25311
|
const contents = `${JSON.stringify(full, null, 2)}
|
|
24266
25312
|
`;
|
|
24267
25313
|
const lock = acquireConfigWriteLock(path);
|
|
24268
25314
|
try {
|
|
24269
|
-
if (!opts.force &&
|
|
25315
|
+
if (!opts.force && existsSync23(path)) {
|
|
24270
25316
|
throw new ConfigError(`Config file already exists: ${path}`);
|
|
24271
25317
|
}
|
|
24272
25318
|
if (opts.force || opts.atomicCreate)
|
|
24273
25319
|
replaceFileAtomically(path, contents, lock.assertOwned);
|
|
24274
25320
|
else {
|
|
24275
25321
|
lock.assertOwned();
|
|
24276
|
-
|
|
25322
|
+
writeFileSync17(path, contents, { encoding: "utf8", flag: "wx", flush: true, mode: 384 });
|
|
24277
25323
|
}
|
|
24278
25324
|
} catch (error) {
|
|
24279
25325
|
if (!opts.force && isEexistError(error)) {
|
|
@@ -24449,7 +25495,6 @@ init_dupey_tool();
|
|
|
24449
25495
|
init_emit_results_tool();
|
|
24450
25496
|
init_jikji_find_tool();
|
|
24451
25497
|
init_search_all_tool();
|
|
24452
|
-
init_search_datasource_tool();
|
|
24453
25498
|
init_search_minsync_tool();
|
|
24454
25499
|
init_search_single_datasource_tool();
|
|
24455
25500
|
init_system_prompt();
|
|
@@ -24638,7 +25683,8 @@ init_cloud_drive();
|
|
|
24638
25683
|
init_discrawl();
|
|
24639
25684
|
init_factory();
|
|
24640
25685
|
init_github();
|
|
24641
|
-
|
|
25686
|
+
init_lark();
|
|
25687
|
+
init_lazykatok();
|
|
24642
25688
|
init_mail_export();
|
|
24643
25689
|
init_mailcrawl();
|
|
24644
25690
|
init_notion();
|
|
@@ -24707,10 +25753,12 @@ export {
|
|
|
24707
25753
|
JIKJI_CRATE_NAME,
|
|
24708
25754
|
JIKJI_INSTALL_TIMEOUT_MS,
|
|
24709
25755
|
JikjiClient,
|
|
24710
|
-
|
|
24711
|
-
|
|
24712
|
-
|
|
24713
|
-
|
|
25756
|
+
LarkClient,
|
|
25757
|
+
LarkSkill,
|
|
25758
|
+
LazykatokBm25Method,
|
|
25759
|
+
LazykatokClient,
|
|
25760
|
+
LazykatokSemanticMethod,
|
|
25761
|
+
LazykatokSkill,
|
|
24714
25762
|
LocalEmbedderError,
|
|
24715
25763
|
MAILCRAWL_MODES,
|
|
24716
25764
|
MINSYNC_CONFIG_DIR,
|