homegraph 1.5.3 → 1.5.4
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/CHANGELOG.md +26 -1
- package/README.md +51 -5
- package/dist/addons/dynamic-import.d.ts +18 -0
- package/dist/addons/dynamic-import.d.ts.map +1 -0
- package/dist/addons/dynamic-import.js +25 -0
- package/dist/addons/dynamic-import.js.map +1 -0
- package/dist/addons/init-template.d.ts +15 -0
- package/dist/addons/init-template.d.ts.map +1 -0
- package/dist/addons/init-template.js +290 -0
- package/dist/addons/init-template.js.map +1 -0
- package/dist/addons/loader.d.ts +18 -0
- package/dist/addons/loader.d.ts.map +1 -0
- package/dist/addons/loader.js +88 -0
- package/dist/addons/loader.js.map +1 -0
- package/dist/addons/manager.d.ts +106 -0
- package/dist/addons/manager.d.ts.map +1 -0
- package/dist/addons/manager.js +437 -0
- package/dist/addons/manager.js.map +1 -0
- package/dist/addons/paths.d.ts +22 -0
- package/dist/addons/paths.d.ts.map +1 -0
- package/dist/addons/paths.js +65 -0
- package/dist/addons/paths.js.map +1 -0
- package/dist/addons/registry.d.ts +38 -0
- package/dist/addons/registry.d.ts.map +1 -0
- package/dist/addons/registry.js +160 -0
- package/dist/addons/registry.js.map +1 -0
- package/dist/addons/semver.d.ts +21 -0
- package/dist/addons/semver.d.ts.map +1 -0
- package/dist/addons/semver.js +79 -0
- package/dist/addons/semver.js.map +1 -0
- package/dist/addons/types.d.ts +51 -0
- package/dist/addons/types.d.ts.map +1 -0
- package/dist/addons/types.js +14 -0
- package/dist/addons/types.js.map +1 -0
- package/dist/addons/validate.d.ts +38 -0
- package/dist/addons/validate.d.ts.map +1 -0
- package/dist/addons/validate.js +165 -0
- package/dist/addons/validate.js.map +1 -0
- package/dist/arkui/migrate-snapshot.d.ts.map +1 -1
- package/dist/arkui/migrate-snapshot.js +58 -34
- package/dist/arkui/migrate-snapshot.js.map +1 -1
- package/dist/bin/addon-commands.d.ts +27 -0
- package/dist/bin/addon-commands.d.ts.map +1 -0
- package/dist/bin/addon-commands.js +254 -0
- package/dist/bin/addon-commands.js.map +1 -0
- package/dist/bin/homegraph.js +6 -1
- package/dist/bin/homegraph.js.map +1 -1
- package/dist/bin/node-version-check.d.ts +1 -1
- package/dist/bin/node-version-check.js +1 -1
- package/dist/db/sqlite-adapter.d.ts +2 -3
- package/dist/db/sqlite-adapter.d.ts.map +1 -1
- package/dist/db/sqlite-adapter.js +2 -3
- package/dist/db/sqlite-adapter.js.map +1 -1
- package/dist/extraction/languages/arkts.d.ts +14 -0
- package/dist/extraction/languages/arkts.d.ts.map +1 -1
- package/dist/extraction/languages/arkts.js +78 -32
- package/dist/extraction/languages/arkts.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/explore-repeat-guard.d.ts +123 -0
- package/dist/mcp/explore-repeat-guard.d.ts.map +1 -0
- package/dist/mcp/explore-repeat-guard.js +503 -0
- package/dist/mcp/explore-repeat-guard.js.map +1 -0
- package/dist/mcp/explore-session-state.d.ts +20 -0
- package/dist/mcp/explore-session-state.d.ts.map +1 -1
- package/dist/mcp/explore-session-state.js +31 -0
- package/dist/mcp/explore-session-state.js.map +1 -1
- package/dist/mcp/proxy.d.ts.map +1 -1
- package/dist/mcp/proxy.js +15 -4
- package/dist/mcp/proxy.js.map +1 -1
- package/dist/mcp/query-pool.d.ts.map +1 -1
- package/dist/mcp/query-pool.js +10 -13
- package/dist/mcp/query-pool.js.map +1 -1
- package/dist/mcp/server-instructions.d.ts +5 -7
- package/dist/mcp/server-instructions.d.ts.map +1 -1
- package/dist/mcp/server-instructions.js +36 -101
- package/dist/mcp/server-instructions.js.map +1 -1
- package/dist/mcp/tools.d.ts +33 -2
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +1403 -266
- package/dist/mcp/tools.js.map +1 -1
- package/dist/resolution/callback-synthesizer.d.ts.map +1 -1
- package/dist/resolution/callback-synthesizer.js +166 -0
- package/dist/resolution/callback-synthesizer.js.map +1 -1
- package/dist/search/query-utils.d.ts +47 -7
- package/dist/search/query-utils.d.ts.map +1 -1
- package/dist/search/query-utils.js +335 -109
- package/dist/search/query-utils.js.map +1 -1
- package/dist/spec/build/scan.js +1 -1
- package/dist/spec/build/scan.js.map +1 -1
- package/dist/spec/build/scope-resolver.d.ts +24 -5
- package/dist/spec/build/scope-resolver.d.ts.map +1 -1
- package/dist/spec/build/scope-resolver.js +76 -10
- package/dist/spec/build/scope-resolver.js.map +1 -1
- package/dist/spec/config.d.ts +8 -0
- package/dist/spec/config.d.ts.map +1 -1
- package/dist/spec/config.js +3 -0
- package/dist/spec/config.js.map +1 -1
- package/dist/spec/evolve/pipeline.d.ts.map +1 -1
- package/dist/spec/evolve/pipeline.js +2 -1
- package/dist/spec/evolve/pipeline.js.map +1 -1
- package/dist/spec/git/commits.d.ts +8 -3
- package/dist/spec/git/commits.d.ts.map +1 -1
- package/dist/spec/git/commits.js +12 -11
- package/dist/spec/git/commits.js.map +1 -1
- package/dist/spec/mine/addon/adapter.d.ts +45 -0
- package/dist/spec/mine/addon/adapter.d.ts.map +1 -0
- package/dist/spec/mine/addon/adapter.js +118 -0
- package/dist/spec/mine/addon/adapter.js.map +1 -0
- package/dist/spec/mine/addon/render.d.ts +20 -0
- package/dist/spec/mine/addon/render.d.ts.map +1 -0
- package/dist/spec/mine/addon/render.js +41 -0
- package/dist/spec/mine/addon/render.js.map +1 -0
- package/dist/spec/mine/addon/types.d.ts +70 -0
- package/dist/spec/mine/addon/types.d.ts.map +1 -0
- package/dist/spec/mine/addon/types.js +14 -0
- package/dist/spec/mine/addon/types.js.map +1 -0
- package/dist/spec/mine/generator.d.ts +5 -1
- package/dist/spec/mine/generator.d.ts.map +1 -1
- package/dist/spec/mine/generator.js +69 -7
- package/dist/spec/mine/generator.js.map +1 -1
- package/dist/spec/mine/pipeline.d.ts.map +1 -1
- package/dist/spec/mine/pipeline.js +5 -1
- package/dist/spec/mine/pipeline.js.map +1 -1
- package/dist/spec/mine/scanner.d.ts +1 -0
- package/dist/spec/mine/scanner.d.ts.map +1 -1
- package/dist/spec/mine/scanner.js +1 -1
- package/dist/spec/mine/scanner.js.map +1 -1
- package/dist/spec/types.d.ts +1 -1
- package/dist/spec/types.d.ts.map +1 -1
- package/package.json +6 -6
|
@@ -51,6 +51,11 @@ exports.queryAsCoNamedTypeMethodInteraction = queryAsCoNamedTypeMethodInteractio
|
|
|
51
51
|
exports.queryHasNamedMemberFocus = queryHasNamedMemberFocus;
|
|
52
52
|
exports.queryAsNamedComponentAction = queryAsNamedComponentAction;
|
|
53
53
|
exports.queryAsOutOfRepoSdkCatalog = queryAsOutOfRepoSdkCatalog;
|
|
54
|
+
exports.queryAsCodeChangeOrientation = queryAsCodeChangeOrientation;
|
|
55
|
+
exports.queryAsExternalManualOnly = queryAsExternalManualOnly;
|
|
56
|
+
exports.queryAsGreenfieldScaffold = queryAsGreenfieldScaffold;
|
|
57
|
+
exports.queryAsVcsHistoryOnly = queryAsVcsHistoryOnly;
|
|
58
|
+
exports.queryAsMediaAssetInventory = queryAsMediaAssetInventory;
|
|
54
59
|
exports.queryShouldDeferToBuiltinTools = queryShouldDeferToBuiltinTools;
|
|
55
60
|
exports.homegraphDeferGuidance = homegraphDeferGuidance;
|
|
56
61
|
exports.queryShouldPreferExploreOverSearch = queryShouldPreferExploreOverSearch;
|
|
@@ -96,6 +101,9 @@ exports.shouldBuildCallerInventory = shouldBuildCallerInventory;
|
|
|
96
101
|
exports.extractCallerSurveySymbols = extractCallerSurveySymbols;
|
|
97
102
|
exports.queryAsCrossModuleFlowSurvey = queryAsCrossModuleFlowSurvey;
|
|
98
103
|
exports.queryAsDataSourceSurvey = queryAsDataSourceSurvey;
|
|
104
|
+
exports.queryAsDataSourceDistinguishAsk = queryAsDataSourceDistinguishAsk;
|
|
105
|
+
exports.queryAsMultiTypeDependencySurvey = queryAsMultiTypeDependencySurvey;
|
|
106
|
+
exports.queryAsEventDispatchSurvey = queryAsEventDispatchSurvey;
|
|
99
107
|
exports.extractLocalDetailAnchors = extractLocalDetailAnchors;
|
|
100
108
|
exports.queryNeedsCoNamedUseBridge = queryNeedsCoNamedUseBridge;
|
|
101
109
|
exports.queryAsLocalSymbolDetail = queryAsLocalSymbolDetail;
|
|
@@ -115,6 +123,8 @@ exports.extractDomainSearchTerms = extractDomainSearchTerms;
|
|
|
115
123
|
exports.queryAsMechanismSurvey = queryAsMechanismSurvey;
|
|
116
124
|
exports.queryAsDomainFileSurvey = queryAsDomainFileSurvey;
|
|
117
125
|
exports.shouldBuildDomainFileSurvey = shouldBuildDomainFileSurvey;
|
|
126
|
+
exports.mechanismDomainPathTokens = mechanismDomainPathTokens;
|
|
127
|
+
exports.isDomainRoleSymbol = isDomainRoleSymbol;
|
|
118
128
|
exports.isImplementationEntrySymbol = isImplementationEntrySymbol;
|
|
119
129
|
exports.shouldCompactImportListing = shouldCompactImportListing;
|
|
120
130
|
exports.shouldLimitToQueryNamedFile = shouldLimitToQueryNamedFile;
|
|
@@ -208,23 +218,32 @@ function extractKitModuleNamesFromQuery(query) {
|
|
|
208
218
|
* Covers `util模块`, `util 模块`, and `@kit.Foo的bar` / `@kit.Foo bar` (export focus).
|
|
209
219
|
*/
|
|
210
220
|
function extractKitSubmoduleNamesFromQuery(query) {
|
|
221
|
+
// NL leftovers in agent rewrites ("util module API functions") — not exports.
|
|
222
|
+
const SUBMODULE_NOISE = new Set([
|
|
223
|
+
'module', 'modules', 'function', 'functions', 'feature', 'features',
|
|
224
|
+
'api', 'apis', 'capability', 'capabilities', 'export', 'exports',
|
|
225
|
+
]);
|
|
211
226
|
const names = new Set();
|
|
227
|
+
const add = (raw) => {
|
|
228
|
+
if (!raw || raw.length < 2)
|
|
229
|
+
return;
|
|
230
|
+
const s = raw.toLowerCase();
|
|
231
|
+
if (exports.STOP_WORDS.has(s) || exports.GENERIC_VERB_ANCHOR_NOISE.has(s) || SUBMODULE_NOISE.has(s))
|
|
232
|
+
return;
|
|
233
|
+
names.add(raw);
|
|
234
|
+
};
|
|
212
235
|
for (const m of query.matchAll(/([a-z][a-z0-9_]{1,24})模块/gi)) {
|
|
213
|
-
|
|
214
|
-
names.add(m[1]);
|
|
236
|
+
add(m[1]);
|
|
215
237
|
}
|
|
216
238
|
for (const m of query.matchAll(/\b([a-z][a-z0-9_]*)\s+模块\b/gi)) {
|
|
217
|
-
|
|
218
|
-
names.add(m[1]);
|
|
239
|
+
add(m[1]);
|
|
219
240
|
}
|
|
220
241
|
// `@kit.ArkTS的taskpool` / `@kit.ArkTS的 foo` — named export, not a catalog.
|
|
221
242
|
for (const m of query.matchAll(/@kit\.[A-Za-z][A-Za-z0-9]*的\s*([a-z][a-zA-Z0-9_]{2,24})\b/gi)) {
|
|
222
|
-
|
|
223
|
-
names.add(m[1]);
|
|
243
|
+
add(m[1]);
|
|
224
244
|
}
|
|
225
245
|
for (const m of query.matchAll(/@kit\.[A-Za-z][A-Za-z0-9]*[\s.]+([a-z][a-zA-Z0-9_]{2,24})\b/gi)) {
|
|
226
|
-
|
|
227
|
-
names.add(m[1]);
|
|
246
|
+
add(m[1]);
|
|
228
247
|
}
|
|
229
248
|
return [...names];
|
|
230
249
|
}
|
|
@@ -235,7 +254,9 @@ function extractKitSubmoduleNamesFromQuery(query) {
|
|
|
235
254
|
function queryAsKitModuleCapabilitySurvey(query) {
|
|
236
255
|
if (extractKitModuleNamesFromQuery(query).length === 0)
|
|
237
256
|
return false;
|
|
238
|
-
const capability = /有哪些功能|有什么功能|哪些功能|模块功能|功能有哪些|what\s+(?:are\s+the\s+)?features|module\s+features|kit\s+features/i.test(query)
|
|
257
|
+
const capability = /有哪些功能|有什么功能|哪些功能|模块功能|功能有哪些|what\s+(?:are\s+the\s+)?features|module\s+features|kit\s+features/i.test(query)
|
|
258
|
+
// Agent rewrites: "@kit.ArkTS util module API functions"
|
|
259
|
+
|| /(?:module\s+)?API\s+functions?|API\s+(?:list|catalog|surface)|what\s+(?:APIs?|functions?)\s+(?:does|are)/i.test(query);
|
|
239
260
|
if (!capability)
|
|
240
261
|
return false;
|
|
241
262
|
return /@kit\.|模块|\bkit\b/i.test(query) || extractKitSubmoduleNamesFromQuery(query).length > 0;
|
|
@@ -316,25 +337,77 @@ function queryAsNamedComponentAction(query) {
|
|
|
316
337
|
return /点击|单击|按下|按钮|悬停|hover|onClick|onTap|onHover|会发生什么|what\s+happens|when\s+(?:clicked|pressed|hovered)/i.test(query);
|
|
317
338
|
}
|
|
318
339
|
/**
|
|
319
|
-
* Out-of-repo SDK catalog (
|
|
340
|
+
* Out-of-repo SDK catalog phrasing (kit + "what features/APIs").
|
|
341
|
+
* Routed to Skip HomeGraph — graph has usages, not official feature lists.
|
|
320
342
|
*/
|
|
321
343
|
function queryAsOutOfRepoSdkCatalog(query) {
|
|
322
344
|
if (queryAsKitModuleCapabilitySurvey(query))
|
|
323
345
|
return true;
|
|
324
|
-
const catalog = /有哪些(?:功能|API|接口|方法|能力)|提供(?:哪些|什么)|模块有哪些|what\s+(?:are\s+the\s+)?(?:apis?|features|methods)|(?:api|feature)\s+(?:list|catalog)|official\s+(?:api|sdk)\s+docs|module\s+features|kit\s+features/i.test(query)
|
|
325
|
-
|
|
346
|
+
const catalog = /有哪些(?:功能|API|接口|方法|能力)|提供(?:哪些|什么)|模块有哪些|what\s+(?:are\s+the\s+)?(?:apis?|features|methods)|(?:api|feature)\s+(?:list|catalog)|official\s+(?:api|sdk)\s+docs|module\s+features|kit\s+features/i.test(query)
|
|
347
|
+
|| /(?:module\s+)?API\s+functions?|API\s+(?:list|catalog|surface)/i.test(query);
|
|
348
|
+
if (catalog && /@kit\.|\b[A-Z][A-Za-z0-9]*Kit\b/i.test(query))
|
|
349
|
+
return true;
|
|
350
|
+
// Pure SDK "which callback must I implement" with no in-repo file anchor.
|
|
351
|
+
// OHAudio-style SDK tokens may parse as Types — still catalog if no .ets/.ts file.
|
|
352
|
+
const hasFile = extractFileBasenamesFromQuery(query).length > 0;
|
|
353
|
+
const types = extractTypeNamesFromQuery(query);
|
|
354
|
+
const onlySdkishTypes = types.length > 0
|
|
355
|
+
&& types.every((t) => /^(?:OH|Napi|NAPI)/.test(t) || /(?:Kit|API)$/.test(t));
|
|
356
|
+
if (!hasFile
|
|
357
|
+
&& (types.length === 0 || onlySdkishTypes)
|
|
358
|
+
&& /(?:C\s+API|NAPI|\bOH[A-Z][A-Za-z]+\b)/i.test(query)
|
|
359
|
+
&& /需要实现哪个回调|实现哪个回调|哪个回调函数|which\s+callback\s+(?:must|should|to)\s+implement|callback\s+(?:to|must)\s+(?:implement|provide)/i.test(query)) {
|
|
360
|
+
return true;
|
|
361
|
+
}
|
|
362
|
+
return false;
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Agent is about to change an existing codebase (feature / fix / refactor).
|
|
366
|
+
* Used for explore *routing* (prefer explore / light mechanism), not Skip.
|
|
367
|
+
*/
|
|
368
|
+
function queryAsCodeChangeOrientation(query) {
|
|
369
|
+
const q = query.trim();
|
|
370
|
+
if (!q)
|
|
326
371
|
return false;
|
|
327
|
-
return
|
|
372
|
+
return (/(?:请)?(?:直接)?(?:在|给|为).{0,40}(?:工程|项目|代码|模块|页面|组件).{0,40}(?:新增|添加|增加|修改|改造|实现|修复|重构)/i.test(q)
|
|
373
|
+
|| /(?:新增|添加|增加|修改|改造|实现|修复|重构|接入|改一下|帮我改).{0,40}(?:功能|逻辑|页面|组件|入口|按钮|接口|模块)/i.test(q)
|
|
374
|
+
|| /\b(?:implement|add|introduce|wire|integrate|extend|refactor|fix|modify|update|change)\b.{0,60}\b(?:feature|page|component|module|handler|api|bug|crash|flow)\b/i.test(q)
|
|
375
|
+
|| /\b(?:fix|repair|debug)\b.{0,40}\b(?:crash|bug|error|issue|regression)\b/i.test(q)
|
|
376
|
+
|| /定位并修复|修复.*崩溃|修复.*闪退|find\s+(?:and\s+)?fix/i.test(q));
|
|
377
|
+
}
|
|
378
|
+
/** Explicit "answer from official docs / website only" — no repo graph needed. */
|
|
379
|
+
function queryAsExternalManualOnly(query) {
|
|
380
|
+
return (/(?:请)?(?:只|仅)?(?:查阅|查看|打开|去看|参考)(?:一下)?(?:官方|官网)(?:文档|手册|网站)/i.test(query)
|
|
381
|
+
|| /developer\.huawei\.com|华为开发者(?:联盟|官网)/i.test(query)
|
|
382
|
+
|| /according\s+to\s+(?:the\s+)?official\s+(?:sdk\s+)?docs?(?:\s+only)?/i.test(query)
|
|
383
|
+
|| /(?:read|see|check)\s+(?:the\s+)?official\s+(?:documentation|docs|website)\s+only/i.test(query)
|
|
384
|
+
|| /不要看代码.*(?:文档|官网)|(?:文档|官网).*(?:不要|别)看代码/i.test(query));
|
|
385
|
+
}
|
|
386
|
+
/** Scaffold / empty project from scratch — nothing useful in an existing index. */
|
|
387
|
+
function queryAsGreenfieldScaffold(query) {
|
|
388
|
+
return (/从零(?:开始)?(?:创建|新建|搭建)|创建(?:一个)?空的(?:工程|项目|应用)|新建(?:一个)?空白(?:工程|项目)/i.test(query)
|
|
389
|
+
|| /create\s+(?:a\s+)?(?:new\s+)?(?:empty\s+)?(?:harmonyos\s+|arkts\s+)?(?:project|app)\s+from\s+scratch/i.test(query)
|
|
390
|
+
|| /scaffold\s+(?:a\s+)?(?:brand\s+)?new\s+(?:empty\s+)?project/i.test(query));
|
|
391
|
+
}
|
|
392
|
+
/** Git / VCS history — not in the symbol graph. */
|
|
393
|
+
function queryAsVcsHistoryOnly(query) {
|
|
394
|
+
return (/\bgit\s+(?:log|blame|diff|show|bisect|history)\b/i.test(query)
|
|
395
|
+
|| /(?:提交历史|commit\s+history|git\s+blame|谁改过|上次提交|最近一次提交|哪次\s*commit)/i.test(query)
|
|
396
|
+
|| /(?:查看|看一下|列出).{0,12}(?:git\s+)?(?:log|blame|diff)/i.test(query));
|
|
397
|
+
}
|
|
398
|
+
/** Media / binary asset inventory by extension — Glob, not the symbol graph. */
|
|
399
|
+
function queryAsMediaAssetInventory(query) {
|
|
400
|
+
const listing = /(?:所有|全部|列出|找(?:出|到)?|盘点|有哪些|which|list|find|inventory)\b/i.test(query)
|
|
401
|
+
|| /资源文件|图片资源|音频资源|媒体资源|media\s+assets?/i.test(query);
|
|
402
|
+
if (!listing)
|
|
403
|
+
return false;
|
|
404
|
+
return (/\.(?:png|jpe?g|gif|svg|webp|bmp|ico|mp4|mp3|wav|aac|flac|ttf|otf|woff2?)\b/i.test(query)
|
|
405
|
+
|| /(?:png|jpe?g|gif|svg|webp|图片|图标|音频|视频|字体)\s*(?:文件|资源|assets?)/i.test(query));
|
|
328
406
|
}
|
|
329
407
|
function queryShouldDeferToBuiltinTools(query) {
|
|
330
408
|
const q = query.trim();
|
|
331
409
|
if (!q)
|
|
332
410
|
return null;
|
|
333
|
-
// Pre-existing catalog classifiers (@kit / *Kit + "what features/APIs").
|
|
334
|
-
// Checked before named-member heuristics — `@kit.X` can look like Type.member.
|
|
335
|
-
if (queryAsOutOfRepoSdkCatalog(q) || queryAsKitModuleCapabilitySurvey(q)) {
|
|
336
|
-
return 'sdk-catalog';
|
|
337
|
-
}
|
|
338
411
|
const hasType = extractTypeNamesFromQuery(q).length > 0;
|
|
339
412
|
const hasFile = extractFileBasenamesFromQuery(q).length > 0;
|
|
340
413
|
const hasMember = extractMemberAccessFromQuery(q).length > 0;
|
|
@@ -342,62 +415,35 @@ function queryShouldDeferToBuiltinTools(query) {
|
|
|
342
415
|
const hasCaps = /\b[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+\b/.test(q);
|
|
343
416
|
const hasField = extractFieldLikeSymbolsFromQuery(q).length > 0;
|
|
344
417
|
const hasPath = extractPathSegmentsFromQuery(q).length > 0;
|
|
345
|
-
|
|
346
|
-
//
|
|
418
|
+
const hasGraphAnchor = hasType || hasFile || hasMember || hasKit || hasCaps || hasField || hasPath;
|
|
419
|
+
// 1) Explicit external-manual-only asks.
|
|
420
|
+
if (queryAsExternalManualOnly(q))
|
|
421
|
+
return 'external-manual';
|
|
422
|
+
// 1b) Kit/SDK feature catalogs ("what APIs does X have") — not in-repo usage.
|
|
423
|
+
if (queryAsOutOfRepoSdkCatalog(q))
|
|
424
|
+
return 'sdk-catalog';
|
|
425
|
+
// 2) VCS history (independent of anchors — graph has no commits).
|
|
426
|
+
if (queryAsVcsHistoryOnly(q))
|
|
427
|
+
return 'vcs-history';
|
|
428
|
+
// 3) Media/binary asset inventories → Glob.
|
|
429
|
+
if (queryAsMediaAssetInventory(q))
|
|
430
|
+
return 'media-assets';
|
|
431
|
+
// 4) Greenfield empty scaffold (no existing code to orient on).
|
|
432
|
+
if (!hasGraphAnchor && queryAsGreenfieldScaffold(q))
|
|
433
|
+
return 'greenfield';
|
|
434
|
+
// 5) Repo-wide literal / copy / layout-string hunts → Grep.
|
|
435
|
+
// Layout chains (`.width('100%')`) can look like member access — still Skip.
|
|
436
|
+
if (queryLooksLikeLiteralOrCopyHunt(q))
|
|
437
|
+
return 'literal-hunt';
|
|
438
|
+
// 6) Topic → file list with no Type/file anchor → Glob/Grep.
|
|
347
439
|
if (!hasType
|
|
348
440
|
&& !hasFile
|
|
349
|
-
&&
|
|
350
|
-
&& !hasKit
|
|
351
|
-
&& !hasCaps
|
|
352
|
-
&& !hasField
|
|
353
|
-
&& !hasPath
|
|
354
|
-
&& queryLooksLikeLiteralOrCopyHunt(q)) {
|
|
355
|
-
return 'concept-or-existence';
|
|
356
|
-
}
|
|
357
|
-
// Structural / in-repo usage surveys must still run.
|
|
358
|
-
if (queryAsMechanismSurvey(q) || queryAsCrossModuleFlowSurvey(q))
|
|
359
|
-
return null;
|
|
360
|
-
if (shouldBuildKitModuleUsageSurvey(q) || shouldBuildApiUsageSurvey(q))
|
|
361
|
-
return null;
|
|
362
|
-
if (shouldBuildCallerInventory(q) || shouldTryLightMechanismExplore(q))
|
|
363
|
-
return null;
|
|
364
|
-
if (queryAsNamedComponentAction(q) || queryHasNamedMemberFocus(q))
|
|
365
|
-
return null;
|
|
366
|
-
if (queryAsInterpretationSurvey(q) || queryAsLocalSymbolDetail(q))
|
|
367
|
-
return null;
|
|
368
|
-
if (queryHasFocusedNamedAnchors(q))
|
|
369
|
-
return null;
|
|
370
|
-
if (queryAsDeclarationSiteSurvey(q)
|
|
371
|
-
|| queryAsConstantUsageSurvey(q)
|
|
372
|
-
|| queryAsFieldUsageSurvey(q)
|
|
373
|
-
|| queryAsModuleExportSurvey(q)
|
|
374
|
-
|| queryAsModuleDependencySurvey(q)) {
|
|
375
|
-
return null;
|
|
376
|
-
}
|
|
377
|
-
// "Which files relate to <topic>?" with no Type/file anchor → Glob/Grep.
|
|
378
|
-
if (/哪些文件|有哪些.*文件|相关的?\s*文件|涉及.*文件|which\s+files?|files?\s+(?:are\s+)?related/i.test(q)
|
|
379
|
-
&& !hasType
|
|
380
|
-
&& !hasFile) {
|
|
441
|
+
&& /哪些文件|有哪些.*文件|相关的?\s*文件|涉及.*文件|which\s+files?|files?\s+(?:are\s+)?related/i.test(q)) {
|
|
381
442
|
return 'file-listing';
|
|
382
443
|
}
|
|
383
|
-
//
|
|
384
|
-
if (
|
|
385
|
-
&&
|
|
386
|
-
&& !hasFile
|
|
387
|
-
&& !hasMember
|
|
388
|
-
&& !hasKit) {
|
|
389
|
-
return 'concept-or-existence';
|
|
390
|
-
}
|
|
391
|
-
// Hover / 悬停 without a named Type → inventory of hover handlers (not Skip).
|
|
392
|
-
if (shouldBuildHoverHandlerSurvey(q))
|
|
393
|
-
return null;
|
|
394
|
-
// Behavioral / interaction outcome with zero graph anchors → Grep (no symbol to seed).
|
|
395
|
-
// Do NOT include hover/悬停 here — those have a graph inventory path above.
|
|
396
|
-
if (!hasType
|
|
397
|
-
&& !hasFile
|
|
398
|
-
&& !hasMember
|
|
399
|
-
&& !hasKit
|
|
400
|
-
&& /会有什么|会发生什么|什么反应|what\s+happens|what\s+(?:is|are)\s+the\s+(?:reaction|response)|when\s+(?:the\s+)?user\b/i.test(q)) {
|
|
444
|
+
// 7) Pure existence / concept-compare with zero graph anchors → Grep/docs.
|
|
445
|
+
if (!hasGraphAnchor
|
|
446
|
+
&& /有使用|是否使用|有没有使用|使用了.*吗|是否存在|有没有完整|有什么不同|区别|difference|vs\.?|versus|对比|does\s+(?:this\s+)?(?:project|repo)\s+have|is\s+there\s+(?:a\s+)?complete/i.test(q)) {
|
|
401
447
|
return 'concept-or-existence';
|
|
402
448
|
}
|
|
403
449
|
return null;
|
|
@@ -406,15 +452,20 @@ function queryShouldDeferToBuiltinTools(query) {
|
|
|
406
452
|
function homegraphDeferGuidance(kind, query) {
|
|
407
453
|
const q = query.trim().slice(0, 120);
|
|
408
454
|
const reasons = {
|
|
409
|
-
'sdk-catalog': 'Official SDK / @kit feature catalogs are outside this repo index — use SDK docs.',
|
|
410
455
|
'file-listing': 'Topic → file lists need Grep/Glob (keyword paths), not the symbol graph.',
|
|
411
|
-
'
|
|
456
|
+
'literal-hunt': 'Repo-wide literal / copy / layout-string hunts with no Type/file/@kit anchor — use Grep.',
|
|
457
|
+
'concept-or-existence': 'Pure existence/concept-compare with no named in-repo Type/file/@kit/@ohos anchor — Grep/docs.',
|
|
458
|
+
'external-manual': 'Question asks for official website/docs only — open the manual; HomeGraph indexes code/API graphs, not marketing pages.',
|
|
459
|
+
'sdk-catalog': 'Kit/SDK **feature or API catalogs** ("what does util export") need SDK docs — HomeGraph indexes in-repo imports/usages, not official capability lists. Rephrase as "which files import @kit.X / export Y" if you want usages.',
|
|
460
|
+
'greenfield': 'Scaffolding an empty project from scratch needs generators/docs, not an existing code graph.',
|
|
461
|
+
'vcs-history': 'Git/commit/blame/diff history is not in the symbol graph — use git / IDE history.',
|
|
462
|
+
'media-assets': 'Media/binary asset inventories (.png/.mp4/fonts/…) need Glob, not the symbol graph.',
|
|
412
463
|
};
|
|
413
464
|
return [
|
|
414
465
|
'Skip HomeGraph for this question shape — do **not** retry any `homegraph_*` tool for it.',
|
|
415
466
|
reasons[kind],
|
|
416
467
|
`Query: "${q}${query.trim().length > 120 ? '…' : ''}"`,
|
|
417
|
-
'Next: Grep / Glob / Read / SDK docs.
|
|
468
|
+
'Next: Grep / Glob / Read / git / SDK docs / project generators as appropriate. Otherwise call `homegraph_explore` with the task or symbol names.',
|
|
418
469
|
].join('\n');
|
|
419
470
|
}
|
|
420
471
|
/**
|
|
@@ -424,8 +475,10 @@ function queryShouldPreferExploreOverSearch(query) {
|
|
|
424
475
|
const q = query.trim();
|
|
425
476
|
if (!q)
|
|
426
477
|
return false;
|
|
427
|
-
if (queryLooksLikeLiteralOrCopyHunt(query))
|
|
478
|
+
if (queryLooksLikeLiteralOrCopyHunt(query) && !queryAsCodeChangeOrientation(query))
|
|
428
479
|
return false;
|
|
480
|
+
if (queryAsCodeChangeOrientation(query))
|
|
481
|
+
return true;
|
|
429
482
|
if (/^[A-Za-z_][\w]*$/.test(q))
|
|
430
483
|
return true;
|
|
431
484
|
if (extractFileBasenamesFromQuery(query).length > 0
|
|
@@ -720,6 +773,18 @@ exports.GENERIC_VERB_ANCHOR_NOISE = new Set([
|
|
|
720
773
|
// Inventory / NL fillers agents leave in rewritten bags (not real symbols).
|
|
721
774
|
'usage', 'usages', 'use', 'uses', 'using', 'api', 'apis', 'endpoint', 'endpoints',
|
|
722
775
|
'project', 'codebase', 'repo', 'documentation', 'document', 'docs', '说明',
|
|
776
|
+
// Kit-deps rewrite leftovers: "ServiceCollaborationKit import usage dependencies"
|
|
777
|
+
// must NOT become import-inventory focus (matches every `import` line).
|
|
778
|
+
'import', 'imports', 'importing', 'dependency', 'dependencies', 'deps', 'dep',
|
|
779
|
+
'param', 'params', 'parameter', 'parameters', 'extra', 'other', 'require', 'requires',
|
|
780
|
+
'calling', 'call', 'calls', 'needed', 'install', 'installing',
|
|
781
|
+
// Kit catalog rewrites: "util module API functions"
|
|
782
|
+
'module', 'modules', 'function', 'functions', 'feature', 'features',
|
|
783
|
+
'capability', 'capabilities', 'export', 'exports',
|
|
784
|
+
// Data-source EN rewrites: "badge source system service" must NOT become
|
|
785
|
+
// import-inventory focus (matches every `*Service` / ServiceExtensionAbility).
|
|
786
|
+
'service', 'services', 'source', 'sources', 'system', 'systems',
|
|
787
|
+
'upstream', 'origin', 'origins',
|
|
723
788
|
// Shared-lib / GL thread NL leftovers (not symbols).
|
|
724
789
|
'context', 'opengl', 'gles', 'glesv3', 'egl',
|
|
725
790
|
]);
|
|
@@ -879,14 +944,21 @@ function queryAsFieldUsageSurvey(query) {
|
|
|
879
944
|
}
|
|
880
945
|
/**
|
|
881
946
|
* Native shared lib + GL/EGL thread questions (`libfoo.so` … OpenGL … 哪个线程).
|
|
882
|
-
* Light-mechanism (CMake +
|
|
947
|
+
* Light-mechanism (CMake + named Draw/Render/EGL owners), not `.so` member survey.
|
|
883
948
|
*/
|
|
884
949
|
function queryAsNativeRenderThreadSurvey(query) {
|
|
885
950
|
const hasLib = /\b\w+\.(?:so|dll|dylib)\b/i.test(query)
|
|
886
951
|
|| /\blib\w+\b/i.test(query);
|
|
887
952
|
const hasGl = /\b(?:GLES(?:v3)?|EGL|OpenGL)\b/i.test(query);
|
|
888
953
|
const hasThread = /线程|thread|UI\s*线程|主线程|JS\s*主?线程/i.test(query);
|
|
889
|
-
|
|
954
|
+
if ((hasLib || hasGl) && hasThread)
|
|
955
|
+
return true;
|
|
956
|
+
// Named Draw/Render/EGL owner + frame-sync / sub-thread (no project Type list).
|
|
957
|
+
if (/\b(?:[A-Z][A-Za-z0-9]*(?:Draw|Render)|EGL(?:Core)?|EglCore)\b/.test(query)
|
|
958
|
+
&& /帧同步|撕裂|tearing|frame\s*sync|synchron|mutex|sub-?thread|子线程/i.test(query)) {
|
|
959
|
+
return true;
|
|
960
|
+
}
|
|
961
|
+
return false;
|
|
890
962
|
}
|
|
891
963
|
/** Named `.d.ts` wrap — what calls / imports it in-repo. */
|
|
892
964
|
function queryAsDtsWrapSurvey(query) {
|
|
@@ -915,11 +987,15 @@ function queryAsAssignedFlagImpactSurvey(query) {
|
|
|
915
987
|
* Named Toggle/control kept consistent across surfaces — which module guarantees it.
|
|
916
988
|
*/
|
|
917
989
|
function queryAsNamedControlStateSyncSurvey(query) {
|
|
990
|
+
// Prefer Toggle/Switch anchors — bag-of-words rewrites often add Control/Center noise Types.
|
|
918
991
|
const types = extractTypeNamesFromQuery(query).filter((t) => !isFrameworkUiDecoratorName(t));
|
|
919
|
-
|
|
992
|
+
const controlTypes = types.filter((t) => /Toggle|Switch|开关/i.test(t));
|
|
993
|
+
const anchors = controlTypes.length > 0 ? controlTypes : types;
|
|
994
|
+
if (anchors.length < 1 || anchors.length > 3)
|
|
920
995
|
return false;
|
|
921
|
-
return (
|
|
922
|
-
|| (/Toggle|Switch
|
|
996
|
+
return (/状态一致|保持一致|多处|多端|哪个模块保证|who\s+keeps|consistent\s+state|state\s+consistenc|state\s+sync|consistenc(?:y|ies)|guarantees?\s+it|which\s+module\s+guarantees|across\s+(?:surfaces|places)/i.test(query)
|
|
997
|
+
|| (/Toggle|Switch|开关/i.test(query)
|
|
998
|
+
&& /一致|保证|模块|consistenc|consistent|guarantees?/i.test(query)));
|
|
923
999
|
}
|
|
924
1000
|
/**
|
|
925
1001
|
* Methods listed beside a Type for caller inventories
|
|
@@ -990,6 +1066,16 @@ function queryAsModuleDependencySurvey(query) {
|
|
|
990
1066
|
* Shape-only: no PascalCase Type / file / member / kit anchors.
|
|
991
1067
|
*/
|
|
992
1068
|
function queryLooksLikeLiteralOrCopyHunt(query) {
|
|
1069
|
+
// Layout/style literal chains first — `.width('100%')` looks like member access
|
|
1070
|
+
// to extractors but is Grep territory.
|
|
1071
|
+
if (/检索所有\s*\.\w+\(\s*['"][^'"]+['"]\s*\)/i.test(query)
|
|
1072
|
+
|| /\.\w+\(\s*['"][^'"]{1,40}['"]\s*\).{0,80}\.\w+\(\s*['"][^'"]{1,40}['"]\s*\)/i.test(query)) {
|
|
1073
|
+
if (extractTypeNamesFromQuery(query).length === 0
|
|
1074
|
+
&& extractFileBasenamesFromQuery(query).length === 0
|
|
1075
|
+
&& extractKitModuleNamesFromQuery(query).length === 0) {
|
|
1076
|
+
return true;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
993
1079
|
if (extractTypeNamesFromQuery(query).length > 0)
|
|
994
1080
|
return false;
|
|
995
1081
|
if (extractFileBasenamesFromQuery(query).length > 0)
|
|
@@ -1059,6 +1145,11 @@ function extractApiUsageTokens(query) {
|
|
|
1059
1145
|
if (m[1] && m[1].length >= 6)
|
|
1060
1146
|
tokens.add(m[1]);
|
|
1061
1147
|
}
|
|
1148
|
+
// "statfs这个API端点" / "使用了statfs这个API" — Chinese demonstrative after the symbol.
|
|
1149
|
+
for (const m of query.matchAll(/\b([A-Za-z_][\w]{2,})\s*这个\s*(?:API|接口|端点|方法)/gi)) {
|
|
1150
|
+
if (m[1] && !exports.GENERIC_VERB_ANCHOR_NOISE.has(m[1].toLowerCase()))
|
|
1151
|
+
tokens.add(m[1]);
|
|
1152
|
+
}
|
|
1062
1153
|
// When a PascalCase SDK/module token is present (Telephony, DrawContext), drop
|
|
1063
1154
|
// short lowercase bag noise agents add (`call`/`radio`/`usage`) — those flood
|
|
1064
1155
|
// false-positive files and tank precision.
|
|
@@ -1190,7 +1281,57 @@ function queryAsCrossModuleFlowSurvey(query) {
|
|
|
1190
1281
|
}
|
|
1191
1282
|
/** Data-source / upstream-service intent (来源于哪个服务 / which service). */
|
|
1192
1283
|
function queryAsDataSourceSurvey(query) {
|
|
1193
|
-
|
|
1284
|
+
if (/来源于|数据来源|状态来源|来自哪个|哪个系统服务|来自什么服务|data\s+source|status\s+source|state\s+source|which\s+service|来源.*服务|如何统一或区分/i.test(query)) {
|
|
1285
|
+
return true;
|
|
1286
|
+
}
|
|
1287
|
+
// Agent EN / bag-of-words rewrites of the same intent.
|
|
1288
|
+
if (/\bsystem\s+service\b/i.test(query))
|
|
1289
|
+
return true;
|
|
1290
|
+
if (/\bupstream\s+(?:service|source|data)\b/i.test(query))
|
|
1291
|
+
return true;
|
|
1292
|
+
if (/\bsource\b.{0,48}\b(?:system\s+)?service\b/i.test(query))
|
|
1293
|
+
return true;
|
|
1294
|
+
if (/\b(?:data|status|state)\b.{0,48}\bsource\b/i.test(query))
|
|
1295
|
+
return true;
|
|
1296
|
+
return false;
|
|
1297
|
+
}
|
|
1298
|
+
/** "How are sources unified/distinguished" — inventory alone is Partial, not ANSWER NOW. */
|
|
1299
|
+
function queryAsDataSourceDistinguishAsk(query) {
|
|
1300
|
+
if (/如何统一或区分|统一或区分|区分.*来源|来源.*区分|unify|distinguish|how\s+(?:are|is).{0,40}(?:unified|distinguished)/i.test(query)) {
|
|
1301
|
+
return true;
|
|
1302
|
+
}
|
|
1303
|
+
// Rewrites may drop 「如何统一或区分」but keep 状态来源 / status|state source.
|
|
1304
|
+
if (/哪个系统服务|which\s+system\s+service|来源于哪个|来自哪个系统/i.test(query)) {
|
|
1305
|
+
return false;
|
|
1306
|
+
}
|
|
1307
|
+
if (/\bsystem\s+service\b/i.test(query) && !/状态来源|status\s*source|state.{0,24}source/i.test(query)) {
|
|
1308
|
+
return false;
|
|
1309
|
+
}
|
|
1310
|
+
return /状态来源|status\s*source|state\s+change\s+source|state.{0,24}source/i.test(query);
|
|
1311
|
+
}
|
|
1312
|
+
/**
|
|
1313
|
+
* ≥3 named Types + dependency/relationship ask — inventory edges, not a fat
|
|
1314
|
+
* multi-body compact that hits the soft deadline.
|
|
1315
|
+
*/
|
|
1316
|
+
function queryAsMultiTypeDependencySurvey(query) {
|
|
1317
|
+
const types = extractTypeNamesFromQuery(query).filter((t) => t.length >= 8
|
|
1318
|
+
|| /(?:Manager|Installer|Parser|Service|Controller|Handler|Provider|Store)$/i.test(t));
|
|
1319
|
+
if (types.length < 3)
|
|
1320
|
+
return false;
|
|
1321
|
+
return /依赖|关系|互相|之间|调用关系|dependenc|relationship|how\s+(?:do|are).{0,40}relate|related/i.test(query);
|
|
1322
|
+
}
|
|
1323
|
+
/**
|
|
1324
|
+
* Event-type → handler/Manager dispatch inventory
|
|
1325
|
+
* (`FooEvent` types / which Managers handle them).
|
|
1326
|
+
*/
|
|
1327
|
+
function queryAsEventDispatchSurvey(query) {
|
|
1328
|
+
const types = extractTypeNamesFromQuery(query);
|
|
1329
|
+
const hasEventType = types.some((t) => /Event$/i.test(t));
|
|
1330
|
+
const hasEventCue = hasEventType
|
|
1331
|
+
|| /\b[A-Z][A-Za-z0-9]*Event\b|事件类型|事件枚举/i.test(query);
|
|
1332
|
+
if (!hasEventCue)
|
|
1333
|
+
return false;
|
|
1334
|
+
return /分发|分发给|哪些\s*Manager|handlers?|dispatch|routed?\s+to|handled\s+by|处理/i.test(query);
|
|
1194
1335
|
}
|
|
1195
1336
|
/**
|
|
1196
1337
|
* Local one/few-symbol behavior or contract — NOT multi-file mechanism / inventory.
|
|
@@ -1242,7 +1383,7 @@ function extractLocalDetailAnchors(query) {
|
|
|
1242
1383
|
return score(b) - score(a) || a.localeCompare(b);
|
|
1243
1384
|
});
|
|
1244
1385
|
// Drop framework decorator names when a concrete UI Type is also present
|
|
1245
|
-
// (`@CustomDialog` +
|
|
1386
|
+
// (`@CustomDialog` + `FooDialog` → keep only the concrete UI types).
|
|
1246
1387
|
const hasConcreteUi = ranked.some((n) => queryLooksLikeUiComponentType(n) && !isFrameworkUiDecoratorName(n));
|
|
1247
1388
|
const filtered = hasConcreteUi
|
|
1248
1389
|
? ranked.filter((n) => !isFrameworkUiDecoratorName(n))
|
|
@@ -1296,6 +1437,8 @@ function queryAsLocalSymbolDetail(query) {
|
|
|
1296
1437
|
return false;
|
|
1297
1438
|
if (queryAsDataSourceSurvey(query))
|
|
1298
1439
|
return false;
|
|
1440
|
+
if (queryAsEventDispatchSurvey(query))
|
|
1441
|
+
return false;
|
|
1299
1442
|
// Named UI control + event: compact body + callees (not import inventory).
|
|
1300
1443
|
if (queryAsNamedComponentAction(query))
|
|
1301
1444
|
return true;
|
|
@@ -1418,33 +1561,17 @@ function extractMechanismEntrySeeds(query) {
|
|
|
1418
1561
|
seeds.add(term);
|
|
1419
1562
|
}
|
|
1420
1563
|
}
|
|
1421
|
-
// Shared-lib + GLES/EGL thread — seed
|
|
1564
|
+
// Shared-lib + GLES/EGL thread — seed Draw/Render/EGL owners named in the query.
|
|
1422
1565
|
if (queryAsNativeRenderThreadSurvey(query)) {
|
|
1423
|
-
|
|
1424
|
-
|
|
1566
|
+
for (const t of extractTypeNamesFromQuery(query))
|
|
1567
|
+
seeds.add(t);
|
|
1568
|
+
for (const m of query.matchAll(/\b([A-Z][A-Za-z0-9]*(?:Draw|Render|Core))\b/g)) {
|
|
1569
|
+
if (m[1])
|
|
1570
|
+
seeds.add(m[1]);
|
|
1571
|
+
}
|
|
1425
1572
|
if (/\bCMakeLists\b|\.so\b|链接|link/i.test(query))
|
|
1426
1573
|
seeds.add('CMakeLists');
|
|
1427
1574
|
}
|
|
1428
|
-
// Theme pack download→parse→install — agents often omit PascalCase names.
|
|
1429
|
-
if (/主题|theme\s*pack|theme\s*package/i.test(query) && /安装|解析|下载|install|parse|download/i.test(query)) {
|
|
1430
|
-
for (const s of [
|
|
1431
|
-
'ThemePackParser', 'ThemePackageInstaller', 'SkinInstaller', 'IconsInstaller', 'FontInstaller',
|
|
1432
|
-
]) {
|
|
1433
|
-
seeds.add(s);
|
|
1434
|
-
}
|
|
1435
|
-
}
|
|
1436
|
-
// Notification subscribe/manage howto — same pattern (CJK domain, no Type named).
|
|
1437
|
-
if (/通知|notification/i.test(query) && /订阅|subscribe|管理|manage|多线程|multithread/i.test(query)) {
|
|
1438
|
-
for (const s of ['NotificationManager', 'NotificationSubscriber', 'AnsManager', 'SubscribeCallback']) {
|
|
1439
|
-
seeds.add(s);
|
|
1440
|
-
}
|
|
1441
|
-
}
|
|
1442
|
-
// XML parse howto — seed the real API, not bare `xml` (which floods every Xml* path).
|
|
1443
|
-
if (/\bxml\b|xml解析|解析xml/i.test(query) && /解析|parse|convert|实现/i.test(query)) {
|
|
1444
|
-
for (const s of ['convertxml', 'XmlParseUtil', 'ConvertXML', 'fastConvertToJSObject']) {
|
|
1445
|
-
seeds.add(s);
|
|
1446
|
-
}
|
|
1447
|
-
}
|
|
1448
1575
|
return [...seeds].filter((s) => s.length >= 3).slice(0, 12);
|
|
1449
1576
|
}
|
|
1450
1577
|
/**
|
|
@@ -1476,20 +1603,50 @@ function queryAsDomainMechanismBag(query) {
|
|
|
1476
1603
|
const distinct = domain.filter((t) => /^[A-Za-z][A-Za-z0-9._-]{2,}$/.test(t) && !exports.GENERIC_VERB_ANCHOR_NOISE.has(t.toLowerCase()));
|
|
1477
1604
|
if (distinct.length === 0)
|
|
1478
1605
|
return false;
|
|
1479
|
-
|
|
1606
|
+
// Only *verb* leftovers count as the action half. Noun noise in
|
|
1607
|
+
// GENERIC_VERB_ANCHOR_NOISE (`service` / `source` / `system` / `api` / …)
|
|
1608
|
+
// must not turn a multi-term locator bag (`item service`) into light-mechanism.
|
|
1609
|
+
const MECHANISM_BAG_NOUN_NOISE = new Set([
|
|
1610
|
+
'service', 'services', 'source', 'sources', 'system', 'systems',
|
|
1611
|
+
'upstream', 'origin', 'origins',
|
|
1612
|
+
'usage', 'usages', 'use', 'uses', 'using',
|
|
1613
|
+
'api', 'apis', 'endpoint', 'endpoints',
|
|
1614
|
+
'module', 'modules', 'function', 'functions', 'feature', 'features',
|
|
1615
|
+
'capability', 'capabilities', 'export', 'exports',
|
|
1616
|
+
'dependency', 'dependencies', 'deps', 'dep',
|
|
1617
|
+
'param', 'params', 'parameter', 'parameters',
|
|
1618
|
+
'project', 'codebase', 'repo', 'documentation', 'document', 'docs',
|
|
1619
|
+
'context', 'opengl', 'gles', 'glesv3', 'egl',
|
|
1620
|
+
'extra', 'other', 'require', 'requires', 'needed',
|
|
1621
|
+
]);
|
|
1622
|
+
const hasActionVerb = domain.some((t) => {
|
|
1623
|
+
const l = t.toLowerCase();
|
|
1624
|
+
return exports.GENERIC_VERB_ANCHOR_NOISE.has(l) && !MECHANISM_BAG_NOUN_NOISE.has(l);
|
|
1625
|
+
})
|
|
1480
1626
|
|| /\b(?:parse|implement|manage|handle|process|subscribe|convert|encode|decode)(?:s|d|ing)?\b/i.test(query);
|
|
1481
1627
|
// Remaining CJK tokens are the topic half of a rewritten how-question bag.
|
|
1482
1628
|
const hasCjkDomain = domain.some((t) => /[\u4e00-\u9fff]/.test(t));
|
|
1483
1629
|
return hasActionVerb || hasCjkDomain;
|
|
1484
1630
|
}
|
|
1485
1631
|
function shouldTryLightMechanismExplore(query) {
|
|
1632
|
+
if (queryShouldDeferToBuiltinTools(query))
|
|
1633
|
+
return false;
|
|
1486
1634
|
if (queryAsCrossModuleFlowSurvey(query))
|
|
1487
1635
|
return false;
|
|
1488
1636
|
if (queryAsInterpretationSurvey(query))
|
|
1489
1637
|
return false;
|
|
1490
|
-
// Literal / copy hunts → Grep (never light dump).
|
|
1491
|
-
if (queryLooksLikeLiteralOrCopyHunt(query))
|
|
1638
|
+
// Literal / copy hunts → Grep (never light dump), unless this is an edit/fix task.
|
|
1639
|
+
if (queryLooksLikeLiteralOrCopyHunt(query) && !queryAsCodeChangeOrientation(query))
|
|
1492
1640
|
return false;
|
|
1641
|
+
// Pre-edit orientation: task keywords → light mechanism seeds (domain / Type / file).
|
|
1642
|
+
if (queryAsCodeChangeOrientation(query)) {
|
|
1643
|
+
if (extractDomainSearchTerms(query).length >= 1
|
|
1644
|
+
|| extractTypeNamesFromQuery(query).length > 0
|
|
1645
|
+
|| extractFileBasenamesFromQuery(query).length > 0
|
|
1646
|
+
|| extractMemberAccessFromQuery(query).length > 0) {
|
|
1647
|
+
return true;
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1493
1650
|
// System-setting howto → lean capability inventory, not every `language` import.
|
|
1494
1651
|
if (queryAsInRepoSystemCapabilityHowto(query))
|
|
1495
1652
|
return false;
|
|
@@ -1499,6 +1656,12 @@ function shouldTryLightMechanismExplore(query) {
|
|
|
1499
1656
|
// Manager data/status source → inventory, not light-mechanism.
|
|
1500
1657
|
if (queryAsDataSourceSurvey(query))
|
|
1501
1658
|
return false;
|
|
1659
|
+
// Event type → Manager dispatch inventory.
|
|
1660
|
+
if (queryAsEventDispatchSurvey(query))
|
|
1661
|
+
return false;
|
|
1662
|
+
// ≥3 Types + dependency relationship → lean inventory (not light/compact dump).
|
|
1663
|
+
if (queryAsMultiTypeDependencySurvey(query))
|
|
1664
|
+
return false;
|
|
1502
1665
|
// Named UI control + event → compact (body + callees + usage sites), not light-mechanism.
|
|
1503
1666
|
if (queryAsNamedComponentAction(query))
|
|
1504
1667
|
return false;
|
|
@@ -1546,6 +1709,8 @@ function shouldTryLightMechanismExplore(query) {
|
|
|
1546
1709
|
* Skip expensive subgraph gathering — inventory sections alone answer the query.
|
|
1547
1710
|
*/
|
|
1548
1711
|
function shouldTryFastInventoryExplore(query) {
|
|
1712
|
+
if (queryShouldDeferToBuiltinTools(query))
|
|
1713
|
+
return false;
|
|
1549
1714
|
if (queryAsCrossModuleFlowSurvey(query))
|
|
1550
1715
|
return false;
|
|
1551
1716
|
if (shouldTryLightMechanismExplore(query))
|
|
@@ -1571,6 +1736,8 @@ function shouldTryFastInventoryExplore(query) {
|
|
|
1571
1736
|
|| shouldBuildDomainFileSurvey(query)
|
|
1572
1737
|
|| shouldBuildConfigSection(query)
|
|
1573
1738
|
|| queryAsDataSourceSurvey(query)
|
|
1739
|
+
|| queryAsEventDispatchSurvey(query)
|
|
1740
|
+
|| queryAsMultiTypeDependencySurvey(query)
|
|
1574
1741
|
|| shouldBuildHoverHandlerSurvey(query)
|
|
1575
1742
|
|| queryAsModuleExportSurvey(query)
|
|
1576
1743
|
|| queryAsModuleDependencySurvey(query)
|
|
@@ -1669,7 +1836,14 @@ function extractDomainSearchTerms(query) {
|
|
|
1669
1836
|
}
|
|
1670
1837
|
/** How/implementation/mechanism intent — needs entry symbols + flow, not flat file list. */
|
|
1671
1838
|
function queryAsMechanismSurvey(query) {
|
|
1672
|
-
|
|
1839
|
+
// Cross-Type drive / state-machine interaction — must not collapse into compact
|
|
1840
|
+
// hard-ANSWER-NOW on abstract base names (Machine+Engine, Session FG/BG, …).
|
|
1841
|
+
const types = extractTypeNamesFromQuery(query).filter((t) => !isFrameworkUiDecoratorName(t));
|
|
1842
|
+
if (types.length >= 2
|
|
1843
|
+
&& /驱动|触发|状态机|状态变化|重新计算|foreground|background|layout|布局/i.test(query)) {
|
|
1844
|
+
return true;
|
|
1845
|
+
}
|
|
1846
|
+
return /如何(?:实现|获取|做|处理|管理|驱动|触发)|怎样(?:实现|获取|做|驱动|触发)|怎么(?:实现|获取|做|驱动|触发)|是如何|是怎么|how\s+(?:is|does|are|to\s+(?:get|implement|work|drive|trigger))|机制|状态机|流程|架构|多线程|多进程|multithread|multi-thread|会走到哪些|步骤中会|解析和安装|下载完|下载后|状态变化如何|如何驱动|如何触发/i.test(query);
|
|
1673
1847
|
}
|
|
1674
1848
|
/**
|
|
1675
1849
|
* Broad domain survey — related files, usage existence, or concept comparison.
|
|
@@ -1712,7 +1886,57 @@ function shouldBuildDomainFileSurvey(query) {
|
|
|
1712
1886
|
return queryAsDomainFileSurvey(query) && extractDomainSearchTerms(query).length > 0;
|
|
1713
1887
|
}
|
|
1714
1888
|
/** Callable/class names that commonly anchor implementation flows. */
|
|
1715
|
-
exports.IMPLEMENTATION_ENTRY_NAME_RE = /Manager|Service|Handler|Extension|Parser|Helper|Controller|Provider|Worker|Backup|Restore|Subscription|Monitor|Coordinator|Delegate|Adapter|Factory|Processor/i;
|
|
1889
|
+
exports.IMPLEMENTATION_ENTRY_NAME_RE = /Manager|Service|Handler|Extension|Parser|Helper|Controller|Provider|Worker|Backup|Restore|Subscription|Monitor|Coordinator|Delegate|Adapter|Factory|Processor|Subscriber|Listener/i;
|
|
1890
|
+
/**
|
|
1891
|
+
* ASCII path/name stems for mechanism affinity.
|
|
1892
|
+
* Expands a few CJK domain nouns so `通知订阅` can match `/notification/` paths
|
|
1893
|
+
* without a product-specific file blacklist.
|
|
1894
|
+
*/
|
|
1895
|
+
function mechanismDomainPathTokens(query) {
|
|
1896
|
+
const out = new Set();
|
|
1897
|
+
for (const t of extractDomainSearchTerms(query)) {
|
|
1898
|
+
if (/^[\x00-\x7F]+$/.test(t) && t.length >= 4 && !exports.GENERIC_VERB_ANCHOR_NOISE.has(t.toLowerCase())) {
|
|
1899
|
+
out.add(t.toLowerCase());
|
|
1900
|
+
}
|
|
1901
|
+
}
|
|
1902
|
+
if (/通知/.test(query))
|
|
1903
|
+
out.add('notification');
|
|
1904
|
+
if (/订阅/.test(query)) {
|
|
1905
|
+
out.add('subscribe');
|
|
1906
|
+
out.add('subscriber');
|
|
1907
|
+
}
|
|
1908
|
+
if (/壁纸|wallpaper/i.test(query))
|
|
1909
|
+
out.add('wallpaper');
|
|
1910
|
+
if (/主题|theme/i.test(query)) {
|
|
1911
|
+
out.add('theme');
|
|
1912
|
+
// Prefer themeservice / themepack paths over appinstall "download/install" Managers.
|
|
1913
|
+
out.add('themeservice');
|
|
1914
|
+
out.add('themepack');
|
|
1915
|
+
}
|
|
1916
|
+
if (/备份|backup/i.test(query))
|
|
1917
|
+
out.add('backup');
|
|
1918
|
+
if (/恢复|restore/i.test(query))
|
|
1919
|
+
out.add('restore');
|
|
1920
|
+
if (/锁屏|screenlock|keyguard/i.test(query)) {
|
|
1921
|
+
out.add('screenlock');
|
|
1922
|
+
out.add('keyguard');
|
|
1923
|
+
}
|
|
1924
|
+
return [...out].slice(0, 12);
|
|
1925
|
+
}
|
|
1926
|
+
/** Class/file looks like a domain Manager/Service under matching path or name. */
|
|
1927
|
+
function isDomainRoleSymbol(name, filePath, domainTokens) {
|
|
1928
|
+
if (!exports.IMPLEMENTATION_ENTRY_NAME_RE.test(name))
|
|
1929
|
+
return false;
|
|
1930
|
+
if (domainTokens.length === 0)
|
|
1931
|
+
return /Manager|Subscriber|Listener$/i.test(name);
|
|
1932
|
+
const blob = `${name}\n${filePath}`.toLowerCase().replace(/\\/g, '/');
|
|
1933
|
+
return domainTokens.some((t) => {
|
|
1934
|
+
const tl = t.toLowerCase();
|
|
1935
|
+
if (tl.length < 4)
|
|
1936
|
+
return false;
|
|
1937
|
+
return blob.includes(tl) || blob.includes(`/${tl}/`);
|
|
1938
|
+
});
|
|
1939
|
+
}
|
|
1716
1940
|
function isImplementationEntrySymbol(name, domainTerms) {
|
|
1717
1941
|
if (!exports.IMPLEMENTATION_ENTRY_NAME_RE.test(name))
|
|
1718
1942
|
return false;
|
|
@@ -2043,6 +2267,8 @@ function isTestFile(filePath) {
|
|
|
2043
2267
|
lower.includes('/__tests__/') || lower.includes('/spec/') ||
|
|
2044
2268
|
lower.includes('/specs/') || lower.includes('/testlib/') ||
|
|
2045
2269
|
lower.includes('/testing/') ||
|
|
2270
|
+
// HarmonyOS / OpenHarmony instrumented test trees
|
|
2271
|
+
lower.includes('/ohostest/') ||
|
|
2046
2272
|
lower.startsWith('test/') || lower.startsWith('tests/') ||
|
|
2047
2273
|
lower.startsWith('spec/') || lower.startsWith('specs/') ||
|
|
2048
2274
|
// CamelCase test source-set dirs (Kotlin Multiplatform / Gradle / Xcode):
|