@agent-native/core 0.53.0 → 0.54.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/action.d.ts +40 -1
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js +69 -2
- package/dist/action.js.map +1 -1
- package/dist/agent/index.d.ts +1 -0
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +1 -0
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/observational-memory/index.d.ts +6 -6
- package/dist/agent/observational-memory/index.js +6 -6
- package/dist/agent/observational-memory/index.js.map +1 -1
- package/dist/agent/observational-memory/read.d.ts +7 -9
- package/dist/agent/observational-memory/read.d.ts.map +1 -1
- package/dist/agent/observational-memory/read.js +7 -9
- package/dist/agent/observational-memory/read.js.map +1 -1
- package/dist/agent/processors.d.ts +146 -0
- package/dist/agent/processors.d.ts.map +1 -0
- package/dist/agent/processors.js +122 -0
- package/dist/agent/processors.js.map +1 -0
- package/dist/agent/production-agent.d.ts +10 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +101 -0
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-loop-with-resume.d.ts.map +1 -1
- package/dist/agent/run-loop-with-resume.js +4 -5
- package/dist/agent/run-loop-with-resume.js.map +1 -1
- package/dist/agent/tool-call-journal.d.ts +6 -8
- package/dist/agent/tool-call-journal.d.ts.map +1 -1
- package/dist/agent/tool-call-journal.js +6 -8
- package/dist/agent/tool-call-journal.js.map +1 -1
- package/dist/agent/types.d.ts +11 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/cli/gateway-helpers.d.ts +15 -0
- package/dist/cli/gateway-helpers.d.ts.map +1 -0
- package/dist/cli/gateway-helpers.js +51 -0
- package/dist/cli/gateway-helpers.js.map +1 -0
- package/dist/cli/plan-local.d.ts.map +1 -1
- package/dist/cli/plan-local.js +129 -4
- package/dist/cli/plan-local.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +38 -3
- package/dist/cli/skills.js.map +1 -1
- package/dist/cli/workspace-dev.d.ts.map +1 -1
- package/dist/cli/workspace-dev.js +9 -27
- package/dist/cli/workspace-dev.js.map +1 -1
- package/dist/coding-tools/run-code.d.ts.map +1 -1
- package/dist/coding-tools/run-code.js +18 -2
- package/dist/coding-tools/run-code.js.map +1 -1
- package/dist/extensions/fetch-tool.d.ts.map +1 -1
- package/dist/extensions/fetch-tool.js +80 -15
- package/dist/extensions/fetch-tool.js.map +1 -1
- package/dist/extensions/web-content.d.ts +61 -0
- package/dist/extensions/web-content.d.ts.map +1 -0
- package/dist/extensions/web-content.js +468 -0
- package/dist/extensions/web-content.js.map +1 -0
- package/dist/extensions/web-search-tool.js +3 -3
- package/dist/extensions/web-search-tool.js.map +1 -1
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +4 -1
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/provider-api/corpus-jobs.d.ts +80 -0
- package/dist/provider-api/corpus-jobs.d.ts.map +1 -1
- package/dist/provider-api/corpus-jobs.js +219 -22
- package/dist/provider-api/corpus-jobs.js.map +1 -1
- package/dist/provider-api/index.d.ts +24 -32
- package/dist/provider-api/index.d.ts.map +1 -1
- package/dist/provider-api/index.js +28 -1
- package/dist/provider-api/index.js.map +1 -1
- package/dist/server/agent-chat-plugin.js +1 -1
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/better-auth-instance.d.ts +7 -0
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js +90 -0
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/deep-link.d.ts +7 -0
- package/dist/server/deep-link.d.ts.map +1 -1
- package/dist/server/deep-link.js +13 -2
- package/dist/server/deep-link.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/templates/default/.agents/skills/actions/SKILL.md +52 -1
- package/dist/templates/default/.agents/skills/security/SKILL.md +22 -0
- package/dist/templates/workspace-core/.agents/skills/actions/SKILL.md +52 -1
- package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +6 -4
- package/dist/templates/workspace-core/.agents/skills/observability/SKILL.md +11 -0
- package/dist/templates/workspace-core/.agents/skills/security/SKILL.md +22 -0
- package/docs/content/actions.md +50 -0
- package/docs/content/durable-resume.md +49 -0
- package/docs/content/external-agents.md +2 -2
- package/docs/content/human-approval.md +101 -0
- package/docs/content/observability.md +21 -0
- package/docs/content/observational-memory.md +63 -0
- package/docs/content/plan-plugin.md +5 -0
- package/docs/content/pr-visual-recap.md +4 -3
- package/docs/content/processors.md +99 -0
- package/docs/content/template-plan.md +78 -14
- package/package.json +6 -1
- package/src/templates/default/.agents/skills/actions/SKILL.md +52 -1
- package/src/templates/default/.agents/skills/security/SKILL.md +22 -0
- package/src/templates/workspace-core/.agents/skills/actions/SKILL.md +52 -1
- package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +6 -4
- package/src/templates/workspace-core/.agents/skills/observability/SKILL.md +11 -0
- package/src/templates/workspace-core/.agents/skills/security/SKILL.md +22 -0
|
@@ -142,5 +142,85 @@ export declare function createProviderCorpusJobAction(options: CreateProviderCor
|
|
|
142
142
|
deleted?: undefined;
|
|
143
143
|
jobId?: undefined;
|
|
144
144
|
}>;
|
|
145
|
+
export declare function createProviderCorpusJobReadAction(options: Pick<CreateProviderCorpusJobActionOptions, "appId">): import("../action.js").ActionDefinition<{
|
|
146
|
+
operation?: "status" | "list" | "results" | undefined;
|
|
147
|
+
jobId?: string | undefined;
|
|
148
|
+
offset?: unknown;
|
|
149
|
+
limit?: unknown;
|
|
150
|
+
}, {
|
|
151
|
+
job: {
|
|
152
|
+
id: string;
|
|
153
|
+
name: string;
|
|
154
|
+
mode: string;
|
|
155
|
+
status: ProviderCorpusJobStatus;
|
|
156
|
+
provider: string;
|
|
157
|
+
createdAt: string;
|
|
158
|
+
updatedAt: string;
|
|
159
|
+
};
|
|
160
|
+
coverage: {
|
|
161
|
+
pagesProcessed: number;
|
|
162
|
+
batchesProcessed: number;
|
|
163
|
+
itemsProcessed: number;
|
|
164
|
+
matchedItems: number;
|
|
165
|
+
totalHits: number;
|
|
166
|
+
storedHits: number;
|
|
167
|
+
truncatedHits: boolean;
|
|
168
|
+
};
|
|
169
|
+
checkpoint: Record<string, unknown>;
|
|
170
|
+
error: string | null;
|
|
171
|
+
nextResumeAt: string | null;
|
|
172
|
+
} | {
|
|
173
|
+
jobs: {
|
|
174
|
+
job: {
|
|
175
|
+
id: string;
|
|
176
|
+
name: string;
|
|
177
|
+
mode: string;
|
|
178
|
+
status: ProviderCorpusJobStatus;
|
|
179
|
+
provider: string;
|
|
180
|
+
createdAt: string;
|
|
181
|
+
updatedAt: string;
|
|
182
|
+
};
|
|
183
|
+
coverage: {
|
|
184
|
+
pagesProcessed: number;
|
|
185
|
+
batchesProcessed: number;
|
|
186
|
+
itemsProcessed: number;
|
|
187
|
+
matchedItems: number;
|
|
188
|
+
totalHits: number;
|
|
189
|
+
storedHits: number;
|
|
190
|
+
truncatedHits: boolean;
|
|
191
|
+
};
|
|
192
|
+
checkpoint: Record<string, unknown>;
|
|
193
|
+
error: string | null;
|
|
194
|
+
nextResumeAt: string | null;
|
|
195
|
+
}[];
|
|
196
|
+
total: number;
|
|
197
|
+
} | {
|
|
198
|
+
hits: Record<string, unknown>[];
|
|
199
|
+
offset: number;
|
|
200
|
+
limit: number;
|
|
201
|
+
job: {
|
|
202
|
+
id: string;
|
|
203
|
+
name: string;
|
|
204
|
+
mode: string;
|
|
205
|
+
status: ProviderCorpusJobStatus;
|
|
206
|
+
provider: string;
|
|
207
|
+
createdAt: string;
|
|
208
|
+
updatedAt: string;
|
|
209
|
+
};
|
|
210
|
+
coverage: {
|
|
211
|
+
pagesProcessed: number;
|
|
212
|
+
batchesProcessed: number;
|
|
213
|
+
itemsProcessed: number;
|
|
214
|
+
matchedItems: number;
|
|
215
|
+
totalHits: number;
|
|
216
|
+
storedHits: number;
|
|
217
|
+
truncatedHits: boolean;
|
|
218
|
+
};
|
|
219
|
+
checkpoint: Record<string, unknown>;
|
|
220
|
+
error: string | null;
|
|
221
|
+
nextResumeAt: string | null;
|
|
222
|
+
jobs?: undefined;
|
|
223
|
+
total?: undefined;
|
|
224
|
+
}>;
|
|
145
225
|
export {};
|
|
146
226
|
//# sourceMappingURL=corpus-jobs.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"corpus-jobs.d.ts","sourceRoot":"","sources":["../../src/provider-api/corpus-jobs.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAqB,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAE5E,OAAO,EASL,KAAK,uBAAuB,EAC7B,MAAM,wBAAwB,CAAC;AAEhC,KAAK,qBAAqB,GAAG;IAC3B,cAAc,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAChE,CAAC;AAEF,MAAM,WAAW,oCAAoC;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,qBAAqB,CAAC;CACzC;
|
|
1
|
+
{"version":3,"file":"corpus-jobs.d.ts","sourceRoot":"","sources":["../../src/provider-api/corpus-jobs.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAqB,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAE5E,OAAO,EASL,KAAK,uBAAuB,EAC7B,MAAM,wBAAwB,CAAC;AAEhC,KAAK,qBAAqB,GAAG;IAC3B,cAAc,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAChE,CAAC;AAEF,MAAM,WAAW,oCAAoC;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,qBAAqB,CAAC;CACzC;AA0PD,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,oCAAoC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAa9C;AAED,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,IAAI,CAAC,oCAAoC,EAAE,OAAO,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAY7D"}
|
|
@@ -178,6 +178,18 @@ const ProviderCorpusJobSchema = z.object({
|
|
|
178
178
|
.optional()
|
|
179
179
|
.describe("Results/list limit."),
|
|
180
180
|
});
|
|
181
|
+
const ProviderCorpusJobReadSchema = z.object({
|
|
182
|
+
operation: z.enum(["list", "status", "results"]).default("list"),
|
|
183
|
+
jobId: z.string().optional().describe("Existing job id for status/results."),
|
|
184
|
+
offset: z.coerce.number().int().min(0).optional().describe("Results offset."),
|
|
185
|
+
limit: z.coerce
|
|
186
|
+
.number()
|
|
187
|
+
.int()
|
|
188
|
+
.min(1)
|
|
189
|
+
.max(1_000)
|
|
190
|
+
.optional()
|
|
191
|
+
.describe("Results/list limit."),
|
|
192
|
+
});
|
|
181
193
|
const DEFAULT_PAGE_BUDGET = 25;
|
|
182
194
|
const DEFAULT_BATCH_BUDGET = 25;
|
|
183
195
|
const DEFAULT_RUNTIME_MS = 90_000;
|
|
@@ -196,6 +208,17 @@ export function createProviderCorpusJobAction(options) {
|
|
|
196
208
|
run: async (args) => runProviderCorpusJobAction(args, options),
|
|
197
209
|
});
|
|
198
210
|
}
|
|
211
|
+
export function createProviderCorpusJobReadAction(options) {
|
|
212
|
+
return defineAction({
|
|
213
|
+
description: "Read provider corpus job status and stored results for the current user. " +
|
|
214
|
+
"This read-only companion is for UI polling and status surfaces; it cannot start or continue provider requests.",
|
|
215
|
+
schema: ProviderCorpusJobReadSchema,
|
|
216
|
+
http: { method: "GET" },
|
|
217
|
+
readOnly: true,
|
|
218
|
+
agentTool: false,
|
|
219
|
+
run: async (args) => runProviderCorpusJobReadAction(args, options),
|
|
220
|
+
});
|
|
221
|
+
}
|
|
199
222
|
async function runProviderCorpusJobAction(args, options) {
|
|
200
223
|
const ctx = getCredentialContext();
|
|
201
224
|
if (!ctx)
|
|
@@ -256,6 +279,45 @@ async function runProviderCorpusJobAction(args, options) {
|
|
|
256
279
|
}
|
|
257
280
|
throw new Error(`Unsupported provider corpus operation ${args.operation}.`);
|
|
258
281
|
}
|
|
282
|
+
async function runProviderCorpusJobReadAction(args, options) {
|
|
283
|
+
const ctx = getCredentialContext();
|
|
284
|
+
if (!ctx)
|
|
285
|
+
throw new Error("No authenticated context for provider corpus jobs.");
|
|
286
|
+
if (args.operation === "list") {
|
|
287
|
+
const jobs = await listProviderCorpusJobs({
|
|
288
|
+
appId: options.appId,
|
|
289
|
+
ownerEmail: ctx.userEmail,
|
|
290
|
+
limit: args.limit,
|
|
291
|
+
});
|
|
292
|
+
return { jobs: jobs.map(jobStatus), total: jobs.length };
|
|
293
|
+
}
|
|
294
|
+
const jobId = args.jobId?.trim();
|
|
295
|
+
if (!jobId)
|
|
296
|
+
throw new Error(`${args.operation} requires jobId.`);
|
|
297
|
+
const job = await getProviderCorpusJob({
|
|
298
|
+
id: jobId,
|
|
299
|
+
appId: options.appId,
|
|
300
|
+
ownerEmail: ctx.userEmail,
|
|
301
|
+
});
|
|
302
|
+
if (!job) {
|
|
303
|
+
throw new Error(`Provider corpus job ${jobId} not found or belongs to another owner/app.`);
|
|
304
|
+
}
|
|
305
|
+
if (args.operation === "status")
|
|
306
|
+
return jobStatus(job);
|
|
307
|
+
const hits = await getProviderCorpusJobHits({
|
|
308
|
+
jobId,
|
|
309
|
+
appId: options.appId,
|
|
310
|
+
ownerEmail: ctx.userEmail,
|
|
311
|
+
offset: args.offset,
|
|
312
|
+
limit: args.limit,
|
|
313
|
+
});
|
|
314
|
+
return {
|
|
315
|
+
...jobStatus(job),
|
|
316
|
+
hits,
|
|
317
|
+
offset: args.offset ?? 0,
|
|
318
|
+
limit: args.limit ?? 100,
|
|
319
|
+
};
|
|
320
|
+
}
|
|
259
321
|
async function startJob(args, appId, ownerEmail) {
|
|
260
322
|
if (!args.mode)
|
|
261
323
|
throw new Error("start requires mode.");
|
|
@@ -697,7 +759,11 @@ function searchItems(items, search, options) {
|
|
|
697
759
|
kind: match.kind,
|
|
698
760
|
query: match.query,
|
|
699
761
|
match: match.match,
|
|
700
|
-
snippet:
|
|
762
|
+
snippet: match.snippet ??
|
|
763
|
+
makeSnippet(field.text, match.index, search.contextChars, match.endIndex),
|
|
764
|
+
...(match.matchedTerms?.length
|
|
765
|
+
? { matchedTerms: match.matchedTerms }
|
|
766
|
+
: {}),
|
|
701
767
|
...(Object.keys(metadata).length ? { metadata } : {}),
|
|
702
768
|
});
|
|
703
769
|
}
|
|
@@ -1072,21 +1138,54 @@ function findItemWideTermMatch(fields, search) {
|
|
|
1072
1138
|
if (!terms.length || search.matchMode === "anyTerm")
|
|
1073
1139
|
return null;
|
|
1074
1140
|
const caseSensitive = Boolean(search.caseSensitive);
|
|
1141
|
+
const fieldWindows = fields
|
|
1142
|
+
.map((field) => {
|
|
1143
|
+
const hits = bestTermClusterInText(field.text, terms, caseSensitive).map((hit) => ({ ...hit, field }));
|
|
1144
|
+
if (hits.length !== terms.length)
|
|
1145
|
+
return null;
|
|
1146
|
+
const start = Math.min(...hits.map((hit) => hit.index));
|
|
1147
|
+
const end = Math.max(...hits.map((hit) => hit.end));
|
|
1148
|
+
return {
|
|
1149
|
+
field,
|
|
1150
|
+
hits,
|
|
1151
|
+
start,
|
|
1152
|
+
end,
|
|
1153
|
+
length: end - start,
|
|
1154
|
+
};
|
|
1155
|
+
})
|
|
1156
|
+
.filter((result) => Boolean(result))
|
|
1157
|
+
.sort((a, b) => a.length - b.length || a.start - b.start);
|
|
1158
|
+
const bestFieldWindow = fieldWindows[0];
|
|
1159
|
+
if (bestFieldWindow) {
|
|
1160
|
+
const context = boundedNumber(search.contextChars, 180, 20, 1_000);
|
|
1161
|
+
const snippet = bestFieldWindow.length > context * 4
|
|
1162
|
+
? makeCombinedTermSnippet(bestFieldWindow.hits, search.contextChars)
|
|
1163
|
+
: undefined;
|
|
1164
|
+
return {
|
|
1165
|
+
field: bestFieldWindow.field,
|
|
1166
|
+
match: {
|
|
1167
|
+
kind: "allTerms",
|
|
1168
|
+
query: terms.join(" "),
|
|
1169
|
+
index: bestFieldWindow.start,
|
|
1170
|
+
endIndex: bestFieldWindow.end,
|
|
1171
|
+
match: bestFieldWindow.field.text.slice(bestFieldWindow.start, bestFieldWindow.end),
|
|
1172
|
+
matchedTerms: terms,
|
|
1173
|
+
snippet,
|
|
1174
|
+
},
|
|
1175
|
+
};
|
|
1176
|
+
}
|
|
1075
1177
|
const termHits = terms.map((term) => {
|
|
1076
|
-
const needle = caseSensitive ? term : term.toLowerCase();
|
|
1077
1178
|
for (const field of fields) {
|
|
1078
|
-
const
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
return { term, field, index };
|
|
1179
|
+
const hit = firstTermHitInField(field, term, caseSensitive);
|
|
1180
|
+
if (hit)
|
|
1181
|
+
return hit;
|
|
1082
1182
|
}
|
|
1083
|
-
return
|
|
1183
|
+
return null;
|
|
1084
1184
|
});
|
|
1085
|
-
if (termHits.some((hit) => !hit
|
|
1185
|
+
if (termHits.some((hit) => !hit))
|
|
1086
1186
|
return null;
|
|
1087
|
-
const
|
|
1088
|
-
|
|
1089
|
-
.sort((a, b) => a.index - b.index)[0];
|
|
1187
|
+
const hits = termHits.filter(isTermHit);
|
|
1188
|
+
const first = hits.sort((a, b) => a.index - b.index)[0];
|
|
1090
1189
|
if (!first)
|
|
1091
1190
|
return null;
|
|
1092
1191
|
return {
|
|
@@ -1095,7 +1194,10 @@ function findItemWideTermMatch(fields, search) {
|
|
|
1095
1194
|
kind: "allTerms",
|
|
1096
1195
|
query: terms.join(" "),
|
|
1097
1196
|
index: first.index,
|
|
1098
|
-
|
|
1197
|
+
endIndex: first.end,
|
|
1198
|
+
match: first.match,
|
|
1199
|
+
matchedTerms: terms,
|
|
1200
|
+
snippet: makeCombinedTermSnippet(hits, search.contextChars),
|
|
1099
1201
|
},
|
|
1100
1202
|
};
|
|
1101
1203
|
}
|
|
@@ -1150,22 +1252,29 @@ function findSearchMatches(text, search, includeTerms) {
|
|
|
1150
1252
|
addSubstring(query, query, "query");
|
|
1151
1253
|
const terms = includeTerms ? normalizedTerms(search) : [];
|
|
1152
1254
|
if (terms.length) {
|
|
1153
|
-
const hits = terms
|
|
1154
|
-
.map((term) => {
|
|
1155
|
-
const needle = caseSensitive ? term : term.toLowerCase();
|
|
1156
|
-
return { term, index: haystack.indexOf(needle) };
|
|
1157
|
-
})
|
|
1158
|
-
.filter((hit) => hit.index >= 0);
|
|
1159
1255
|
const mode = search.matchMode === "anyTerm" ? "anyTerm" : "allTerms";
|
|
1256
|
+
const hits = mode === "allTerms"
|
|
1257
|
+
? bestTermClusterInText(source, terms, caseSensitive)
|
|
1258
|
+
: terms
|
|
1259
|
+
.map((term) => firstTermHitInText(source, haystack, caseSensitive ? term : term.toLowerCase(), term))
|
|
1260
|
+
.filter(isInlineTermHit)
|
|
1261
|
+
.sort((a, b) => a.index - b.index);
|
|
1160
1262
|
if ((mode === "allTerms" && hits.length === terms.length) ||
|
|
1161
1263
|
(mode === "anyTerm" && hits.length > 0)) {
|
|
1162
|
-
const first = hits
|
|
1264
|
+
const first = hits[0];
|
|
1163
1265
|
if (first) {
|
|
1266
|
+
const endIndex = mode === "allTerms"
|
|
1267
|
+
? Math.max(...hits.map((hit) => hit.end))
|
|
1268
|
+
: first.end;
|
|
1164
1269
|
matches.push({
|
|
1165
1270
|
kind: mode,
|
|
1166
1271
|
query: terms.join(" "),
|
|
1167
1272
|
index: first.index,
|
|
1168
|
-
|
|
1273
|
+
endIndex,
|
|
1274
|
+
match: mode === "allTerms"
|
|
1275
|
+
? source.slice(first.index, endIndex)
|
|
1276
|
+
: first.match,
|
|
1277
|
+
matchedTerms: mode === "allTerms" ? terms : hits.map((hit) => hit.term),
|
|
1169
1278
|
});
|
|
1170
1279
|
}
|
|
1171
1280
|
}
|
|
@@ -1179,14 +1288,102 @@ function normalizeRegexFlags(flags, caseSensitive) {
|
|
|
1179
1288
|
const withCase = caseSensitive || /i/.test(allowed) ? allowed : `${allowed}i`;
|
|
1180
1289
|
return `${withCase}g`;
|
|
1181
1290
|
}
|
|
1182
|
-
function makeSnippet(text, index, contextChars) {
|
|
1291
|
+
function makeSnippet(text, index, contextChars, endIndex = index) {
|
|
1183
1292
|
const context = boundedNumber(contextChars, 180, 20, 1_000);
|
|
1184
1293
|
const start = Math.max(0, index - context);
|
|
1185
|
-
const end = Math.min(text.length, index + context);
|
|
1294
|
+
const end = Math.min(text.length, Math.max(index, endIndex) + context);
|
|
1186
1295
|
const prefix = start > 0 ? "..." : "";
|
|
1187
1296
|
const suffix = end < text.length ? "..." : "";
|
|
1188
1297
|
return `${prefix}${text.slice(start, end)}${suffix}`
|
|
1189
1298
|
.replace(/\s+/g, " ")
|
|
1190
1299
|
.trim();
|
|
1191
1300
|
}
|
|
1301
|
+
function firstTermHitInText(source, haystack, needle, term) {
|
|
1302
|
+
const index = haystack.indexOf(needle);
|
|
1303
|
+
return index >= 0
|
|
1304
|
+
? {
|
|
1305
|
+
term,
|
|
1306
|
+
index,
|
|
1307
|
+
end: index + term.length,
|
|
1308
|
+
match: source.slice(index, index + term.length),
|
|
1309
|
+
}
|
|
1310
|
+
: null;
|
|
1311
|
+
}
|
|
1312
|
+
function firstTermHitInField(field, term, caseSensitive) {
|
|
1313
|
+
const source = field.text;
|
|
1314
|
+
const haystack = caseSensitive ? source : source.toLowerCase();
|
|
1315
|
+
const needle = caseSensitive ? term : term.toLowerCase();
|
|
1316
|
+
const hit = firstTermHitInText(source, haystack, needle, term);
|
|
1317
|
+
return hit ? { ...hit, term, field } : null;
|
|
1318
|
+
}
|
|
1319
|
+
function isInlineTermHit(hit) {
|
|
1320
|
+
return Boolean(hit);
|
|
1321
|
+
}
|
|
1322
|
+
function isTermHit(hit) {
|
|
1323
|
+
return Boolean(hit);
|
|
1324
|
+
}
|
|
1325
|
+
function bestTermClusterInText(source, terms, caseSensitive) {
|
|
1326
|
+
const haystack = caseSensitive ? source : source.toLowerCase();
|
|
1327
|
+
const allHits = terms.map((term) => {
|
|
1328
|
+
const needle = caseSensitive ? term : term.toLowerCase();
|
|
1329
|
+
const hits = [];
|
|
1330
|
+
let from = 0;
|
|
1331
|
+
while (from <= haystack.length) {
|
|
1332
|
+
const index = haystack.indexOf(needle, from);
|
|
1333
|
+
if (index < 0)
|
|
1334
|
+
break;
|
|
1335
|
+
hits.push({
|
|
1336
|
+
term,
|
|
1337
|
+
index,
|
|
1338
|
+
end: index + term.length,
|
|
1339
|
+
match: source.slice(index, index + term.length),
|
|
1340
|
+
});
|
|
1341
|
+
from = index + Math.max(1, needle.length);
|
|
1342
|
+
if (hits.length >= 100)
|
|
1343
|
+
break;
|
|
1344
|
+
}
|
|
1345
|
+
return hits;
|
|
1346
|
+
});
|
|
1347
|
+
if (allHits.some((hits) => hits.length === 0))
|
|
1348
|
+
return [];
|
|
1349
|
+
const flattened = allHits
|
|
1350
|
+
.flat()
|
|
1351
|
+
.sort((a, b) => a.index - b.index || a.end - b.end);
|
|
1352
|
+
let best = null;
|
|
1353
|
+
let bestLength = Infinity;
|
|
1354
|
+
for (let start = 0; start < flattened.length; start++) {
|
|
1355
|
+
const selected = new Map();
|
|
1356
|
+
for (let end = start; end < flattened.length; end++) {
|
|
1357
|
+
const hit = flattened[end];
|
|
1358
|
+
selected.set(hit.term, hit);
|
|
1359
|
+
if (selected.size !== terms.length)
|
|
1360
|
+
continue;
|
|
1361
|
+
const cluster = terms
|
|
1362
|
+
.map((term) => selected.get(term))
|
|
1363
|
+
.filter(isInlineTermHit)
|
|
1364
|
+
.sort((a, b) => a.index - b.index);
|
|
1365
|
+
const length = Math.max(...cluster.map((item) => item.end)) -
|
|
1366
|
+
Math.min(...cluster.map((item) => item.index));
|
|
1367
|
+
if (length < bestLength) {
|
|
1368
|
+
best = cluster;
|
|
1369
|
+
bestLength = length;
|
|
1370
|
+
}
|
|
1371
|
+
break;
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
return best ?? [];
|
|
1375
|
+
}
|
|
1376
|
+
function makeCombinedTermSnippet(hits, contextChars) {
|
|
1377
|
+
const context = boundedNumber(contextChars, 180, 20, 1_000);
|
|
1378
|
+
const shownHits = hits.slice(0, 5);
|
|
1379
|
+
const perHitContext = Math.max(20, Math.min(120, Math.floor(context / Math.max(1, Math.min(3, hits.length)))));
|
|
1380
|
+
const parts = shownHits.map((hit) => {
|
|
1381
|
+
const snippet = makeSnippet(hit.field.text, hit.index, perHitContext, hit.end);
|
|
1382
|
+
return `${hit.field.path}: ${snippet}`;
|
|
1383
|
+
});
|
|
1384
|
+
if (hits.length > shownHits.length) {
|
|
1385
|
+
parts.push(`... +${hits.length - shownHits.length} more terms`);
|
|
1386
|
+
}
|
|
1387
|
+
return parts.join(" | ");
|
|
1388
|
+
}
|
|
1192
1389
|
//# sourceMappingURL=corpus-jobs.js.map
|