homegraph 1.5.3 → 1.5.5
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 +45 -1
- package/README.md +55 -6
- 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-semantics.d.ts +8 -0
- package/dist/arkui/migrate-semantics.d.ts.map +1 -1
- package/dist/arkui/migrate-semantics.js +24 -1
- package/dist/arkui/migrate-semantics.js.map +1 -1
- package/dist/arkui/migrate-snapshot.d.ts.map +1 -1
- package/dist/arkui/migrate-snapshot.js +69 -38
- 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/engine.d.ts.map +1 -1
- package/dist/mcp/engine.js +2 -14
- package/dist/mcp/engine.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 +540 -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/memory-budget.d.ts +9 -22
- package/dist/mcp/memory-budget.d.ts.map +1 -1
- package/dist/mcp/memory-budget.js +9 -59
- package/dist/mcp/memory-budget.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 +38 -99
- package/dist/mcp/server-instructions.js.map +1 -1
- package/dist/mcp/tools.d.ts +77 -5
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +2693 -320
- 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 +57 -7
- package/dist/search/query-utils.d.ts.map +1 -1
- package/dist/search/query-utils.js +392 -113
- 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/dist/upgrade/index.d.ts +23 -12
- package/dist/upgrade/index.d.ts.map +1 -1
- package/dist/upgrade/index.js +42 -48
- package/dist/upgrade/index.js.map +1 -1
- package/dist/upgrade/update-check.d.ts +4 -4
- package/dist/upgrade/update-check.d.ts.map +1 -1
- package/dist/upgrade/update-check.js +6 -5
- package/dist/upgrade/update-check.js.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;
|
|
@@ -85,6 +90,8 @@ exports.extractListedTypeMethodsFromQuery = extractListedTypeMethodsFromQuery;
|
|
|
85
90
|
exports.queryAsModuleExportSurvey = queryAsModuleExportSurvey;
|
|
86
91
|
exports.queryAsModuleDependencySurvey = queryAsModuleDependencySurvey;
|
|
87
92
|
exports.queryLooksLikeLiteralOrCopyHunt = queryLooksLikeLiteralOrCopyHunt;
|
|
93
|
+
exports.queryAsContainerCompositionSurvey = queryAsContainerCompositionSurvey;
|
|
94
|
+
exports.queryAsMemberUiConsequenceSurvey = queryAsMemberUiConsequenceSurvey;
|
|
88
95
|
exports.queryAsTypeLifecycleSurvey = queryAsTypeLifecycleSurvey;
|
|
89
96
|
exports.shouldPreferMemberUsageInventory = shouldPreferMemberUsageInventory;
|
|
90
97
|
exports.extractApiUsageTokens = extractApiUsageTokens;
|
|
@@ -96,6 +103,9 @@ exports.shouldBuildCallerInventory = shouldBuildCallerInventory;
|
|
|
96
103
|
exports.extractCallerSurveySymbols = extractCallerSurveySymbols;
|
|
97
104
|
exports.queryAsCrossModuleFlowSurvey = queryAsCrossModuleFlowSurvey;
|
|
98
105
|
exports.queryAsDataSourceSurvey = queryAsDataSourceSurvey;
|
|
106
|
+
exports.queryAsDataSourceDistinguishAsk = queryAsDataSourceDistinguishAsk;
|
|
107
|
+
exports.queryAsMultiTypeDependencySurvey = queryAsMultiTypeDependencySurvey;
|
|
108
|
+
exports.queryAsEventDispatchSurvey = queryAsEventDispatchSurvey;
|
|
99
109
|
exports.extractLocalDetailAnchors = extractLocalDetailAnchors;
|
|
100
110
|
exports.queryNeedsCoNamedUseBridge = queryNeedsCoNamedUseBridge;
|
|
101
111
|
exports.queryAsLocalSymbolDetail = queryAsLocalSymbolDetail;
|
|
@@ -115,6 +125,8 @@ exports.extractDomainSearchTerms = extractDomainSearchTerms;
|
|
|
115
125
|
exports.queryAsMechanismSurvey = queryAsMechanismSurvey;
|
|
116
126
|
exports.queryAsDomainFileSurvey = queryAsDomainFileSurvey;
|
|
117
127
|
exports.shouldBuildDomainFileSurvey = shouldBuildDomainFileSurvey;
|
|
128
|
+
exports.mechanismDomainPathTokens = mechanismDomainPathTokens;
|
|
129
|
+
exports.isDomainRoleSymbol = isDomainRoleSymbol;
|
|
118
130
|
exports.isImplementationEntrySymbol = isImplementationEntrySymbol;
|
|
119
131
|
exports.shouldCompactImportListing = shouldCompactImportListing;
|
|
120
132
|
exports.shouldLimitToQueryNamedFile = shouldLimitToQueryNamedFile;
|
|
@@ -208,23 +220,32 @@ function extractKitModuleNamesFromQuery(query) {
|
|
|
208
220
|
* Covers `util模块`, `util 模块`, and `@kit.Foo的bar` / `@kit.Foo bar` (export focus).
|
|
209
221
|
*/
|
|
210
222
|
function extractKitSubmoduleNamesFromQuery(query) {
|
|
223
|
+
// NL leftovers in agent rewrites ("util module API functions") — not exports.
|
|
224
|
+
const SUBMODULE_NOISE = new Set([
|
|
225
|
+
'module', 'modules', 'function', 'functions', 'feature', 'features',
|
|
226
|
+
'api', 'apis', 'capability', 'capabilities', 'export', 'exports',
|
|
227
|
+
]);
|
|
211
228
|
const names = new Set();
|
|
229
|
+
const add = (raw) => {
|
|
230
|
+
if (!raw || raw.length < 2)
|
|
231
|
+
return;
|
|
232
|
+
const s = raw.toLowerCase();
|
|
233
|
+
if (exports.STOP_WORDS.has(s) || exports.GENERIC_VERB_ANCHOR_NOISE.has(s) || SUBMODULE_NOISE.has(s))
|
|
234
|
+
return;
|
|
235
|
+
names.add(raw);
|
|
236
|
+
};
|
|
212
237
|
for (const m of query.matchAll(/([a-z][a-z0-9_]{1,24})模块/gi)) {
|
|
213
|
-
|
|
214
|
-
names.add(m[1]);
|
|
238
|
+
add(m[1]);
|
|
215
239
|
}
|
|
216
240
|
for (const m of query.matchAll(/\b([a-z][a-z0-9_]*)\s+模块\b/gi)) {
|
|
217
|
-
|
|
218
|
-
names.add(m[1]);
|
|
241
|
+
add(m[1]);
|
|
219
242
|
}
|
|
220
243
|
// `@kit.ArkTS的taskpool` / `@kit.ArkTS的 foo` — named export, not a catalog.
|
|
221
244
|
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]);
|
|
245
|
+
add(m[1]);
|
|
224
246
|
}
|
|
225
247
|
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]);
|
|
248
|
+
add(m[1]);
|
|
228
249
|
}
|
|
229
250
|
return [...names];
|
|
230
251
|
}
|
|
@@ -235,7 +256,9 @@ function extractKitSubmoduleNamesFromQuery(query) {
|
|
|
235
256
|
function queryAsKitModuleCapabilitySurvey(query) {
|
|
236
257
|
if (extractKitModuleNamesFromQuery(query).length === 0)
|
|
237
258
|
return false;
|
|
238
|
-
const capability = /有哪些功能|有什么功能|哪些功能|模块功能|功能有哪些|what\s+(?:are\s+the\s+)?features|module\s+features|kit\s+features/i.test(query)
|
|
259
|
+
const capability = /有哪些功能|有什么功能|哪些功能|模块功能|功能有哪些|what\s+(?:are\s+the\s+)?features|module\s+features|kit\s+features/i.test(query)
|
|
260
|
+
// Agent rewrites: "@kit.ArkTS util module API functions"
|
|
261
|
+
|| /(?:module\s+)?API\s+functions?|API\s+(?:list|catalog|surface)|what\s+(?:APIs?|functions?)\s+(?:does|are)/i.test(query);
|
|
239
262
|
if (!capability)
|
|
240
263
|
return false;
|
|
241
264
|
return /@kit\.|模块|\bkit\b/i.test(query) || extractKitSubmoduleNamesFromQuery(query).length > 0;
|
|
@@ -316,25 +339,77 @@ function queryAsNamedComponentAction(query) {
|
|
|
316
339
|
return /点击|单击|按下|按钮|悬停|hover|onClick|onTap|onHover|会发生什么|what\s+happens|when\s+(?:clicked|pressed|hovered)/i.test(query);
|
|
317
340
|
}
|
|
318
341
|
/**
|
|
319
|
-
* Out-of-repo SDK catalog (
|
|
342
|
+
* Out-of-repo SDK catalog phrasing (kit + "what features/APIs").
|
|
343
|
+
* Routed to Skip HomeGraph — graph has usages, not official feature lists.
|
|
320
344
|
*/
|
|
321
345
|
function queryAsOutOfRepoSdkCatalog(query) {
|
|
322
346
|
if (queryAsKitModuleCapabilitySurvey(query))
|
|
323
347
|
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
|
-
|
|
348
|
+
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)
|
|
349
|
+
|| /(?:module\s+)?API\s+functions?|API\s+(?:list|catalog|surface)/i.test(query);
|
|
350
|
+
if (catalog && /@kit\.|\b[A-Z][A-Za-z0-9]*Kit\b/i.test(query))
|
|
351
|
+
return true;
|
|
352
|
+
// Pure SDK "which callback must I implement" with no in-repo file anchor.
|
|
353
|
+
// OHAudio-style SDK tokens may parse as Types — still catalog if no .ets/.ts file.
|
|
354
|
+
const hasFile = extractFileBasenamesFromQuery(query).length > 0;
|
|
355
|
+
const types = extractTypeNamesFromQuery(query);
|
|
356
|
+
const onlySdkishTypes = types.length > 0
|
|
357
|
+
&& types.every((t) => /^(?:OH|Napi|NAPI)/.test(t) || /(?:Kit|API)$/.test(t));
|
|
358
|
+
if (!hasFile
|
|
359
|
+
&& (types.length === 0 || onlySdkishTypes)
|
|
360
|
+
&& /(?:C\s+API|NAPI|\bOH[A-Z][A-Za-z]+\b)/i.test(query)
|
|
361
|
+
&& /需要实现哪个回调|实现哪个回调|哪个回调函数|which\s+callback\s+(?:must|should|to)\s+implement|callback\s+(?:to|must)\s+(?:implement|provide)/i.test(query)) {
|
|
362
|
+
return true;
|
|
363
|
+
}
|
|
364
|
+
return false;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Agent is about to change an existing codebase (feature / fix / refactor).
|
|
368
|
+
* Used for explore *routing* (prefer explore / light mechanism), not Skip.
|
|
369
|
+
*/
|
|
370
|
+
function queryAsCodeChangeOrientation(query) {
|
|
371
|
+
const q = query.trim();
|
|
372
|
+
if (!q)
|
|
326
373
|
return false;
|
|
327
|
-
return
|
|
374
|
+
return (/(?:请)?(?:直接)?(?:在|给|为).{0,40}(?:工程|项目|代码|模块|页面|组件).{0,40}(?:新增|添加|增加|修改|改造|实现|修复|重构)/i.test(q)
|
|
375
|
+
|| /(?:新增|添加|增加|修改|改造|实现|修复|重构|接入|改一下|帮我改).{0,40}(?:功能|逻辑|页面|组件|入口|按钮|接口|模块)/i.test(q)
|
|
376
|
+
|| /\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)
|
|
377
|
+
|| /\b(?:fix|repair|debug)\b.{0,40}\b(?:crash|bug|error|issue|regression)\b/i.test(q)
|
|
378
|
+
|| /定位并修复|修复.*崩溃|修复.*闪退|find\s+(?:and\s+)?fix/i.test(q));
|
|
379
|
+
}
|
|
380
|
+
/** Explicit "answer from official docs / website only" — no repo graph needed. */
|
|
381
|
+
function queryAsExternalManualOnly(query) {
|
|
382
|
+
return (/(?:请)?(?:只|仅)?(?:查阅|查看|打开|去看|参考)(?:一下)?(?:官方|官网)(?:文档|手册|网站)/i.test(query)
|
|
383
|
+
|| /developer\.huawei\.com|华为开发者(?:联盟|官网)/i.test(query)
|
|
384
|
+
|| /according\s+to\s+(?:the\s+)?official\s+(?:sdk\s+)?docs?(?:\s+only)?/i.test(query)
|
|
385
|
+
|| /(?:read|see|check)\s+(?:the\s+)?official\s+(?:documentation|docs|website)\s+only/i.test(query)
|
|
386
|
+
|| /不要看代码.*(?:文档|官网)|(?:文档|官网).*(?:不要|别)看代码/i.test(query));
|
|
387
|
+
}
|
|
388
|
+
/** Scaffold / empty project from scratch — nothing useful in an existing index. */
|
|
389
|
+
function queryAsGreenfieldScaffold(query) {
|
|
390
|
+
return (/从零(?:开始)?(?:创建|新建|搭建)|创建(?:一个)?空的(?:工程|项目|应用)|新建(?:一个)?空白(?:工程|项目)/i.test(query)
|
|
391
|
+
|| /create\s+(?:a\s+)?(?:new\s+)?(?:empty\s+)?(?:harmonyos\s+|arkts\s+)?(?:project|app)\s+from\s+scratch/i.test(query)
|
|
392
|
+
|| /scaffold\s+(?:a\s+)?(?:brand\s+)?new\s+(?:empty\s+)?project/i.test(query));
|
|
393
|
+
}
|
|
394
|
+
/** Git / VCS history — not in the symbol graph. */
|
|
395
|
+
function queryAsVcsHistoryOnly(query) {
|
|
396
|
+
return (/\bgit\s+(?:log|blame|diff|show|bisect|history)\b/i.test(query)
|
|
397
|
+
|| /(?:提交历史|commit\s+history|git\s+blame|谁改过|上次提交|最近一次提交|哪次\s*commit)/i.test(query)
|
|
398
|
+
|| /(?:查看|看一下|列出).{0,12}(?:git\s+)?(?:log|blame|diff)/i.test(query));
|
|
399
|
+
}
|
|
400
|
+
/** Media / binary asset inventory by extension — Glob, not the symbol graph. */
|
|
401
|
+
function queryAsMediaAssetInventory(query) {
|
|
402
|
+
const listing = /(?:所有|全部|列出|找(?:出|到)?|盘点|有哪些|which|list|find|inventory)\b/i.test(query)
|
|
403
|
+
|| /资源文件|图片资源|音频资源|媒体资源|media\s+assets?/i.test(query);
|
|
404
|
+
if (!listing)
|
|
405
|
+
return false;
|
|
406
|
+
return (/\.(?:png|jpe?g|gif|svg|webp|bmp|ico|mp4|mp3|wav|aac|flac|ttf|otf|woff2?)\b/i.test(query)
|
|
407
|
+
|| /(?:png|jpe?g|gif|svg|webp|图片|图标|音频|视频|字体)\s*(?:文件|资源|assets?)/i.test(query));
|
|
328
408
|
}
|
|
329
409
|
function queryShouldDeferToBuiltinTools(query) {
|
|
330
410
|
const q = query.trim();
|
|
331
411
|
if (!q)
|
|
332
412
|
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
413
|
const hasType = extractTypeNamesFromQuery(q).length > 0;
|
|
339
414
|
const hasFile = extractFileBasenamesFromQuery(q).length > 0;
|
|
340
415
|
const hasMember = extractMemberAccessFromQuery(q).length > 0;
|
|
@@ -342,62 +417,39 @@ function queryShouldDeferToBuiltinTools(query) {
|
|
|
342
417
|
const hasCaps = /\b[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+\b/.test(q);
|
|
343
418
|
const hasField = extractFieldLikeSymbolsFromQuery(q).length > 0;
|
|
344
419
|
const hasPath = extractPathSegmentsFromQuery(q).length > 0;
|
|
345
|
-
|
|
346
|
-
//
|
|
420
|
+
const hasGraphAnchor = hasType || hasFile || hasMember || hasKit || hasCaps || hasField || hasPath;
|
|
421
|
+
// 1) Explicit external-manual-only asks.
|
|
422
|
+
if (queryAsExternalManualOnly(q))
|
|
423
|
+
return 'external-manual';
|
|
424
|
+
// 1b) Kit/SDK feature catalogs ("what APIs does X have") — not in-repo usage.
|
|
425
|
+
if (queryAsOutOfRepoSdkCatalog(q))
|
|
426
|
+
return 'sdk-catalog';
|
|
427
|
+
// 2) VCS history (independent of anchors — graph has no commits).
|
|
428
|
+
if (queryAsVcsHistoryOnly(q))
|
|
429
|
+
return 'vcs-history';
|
|
430
|
+
// 3) Media/binary asset inventories → Glob.
|
|
431
|
+
if (queryAsMediaAssetInventory(q))
|
|
432
|
+
return 'media-assets';
|
|
433
|
+
// 4) Greenfield empty scaffold (no existing code to orient on).
|
|
434
|
+
if (!hasGraphAnchor && queryAsGreenfieldScaffold(q))
|
|
435
|
+
return 'greenfield';
|
|
436
|
+
// 5) Repo-wide literal / copy / layout-string hunts → Grep.
|
|
437
|
+
// Layout chains (`.width('100%')`) can look like member access — still Skip.
|
|
438
|
+
if (queryLooksLikeLiteralOrCopyHunt(q))
|
|
439
|
+
return 'literal-hunt';
|
|
440
|
+
// 6) Topic → file list with no Type/file anchor → Glob/Grep.
|
|
347
441
|
if (!hasType
|
|
348
442
|
&& !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) {
|
|
443
|
+
&& /哪些文件|有哪些.*文件|相关的?\s*文件|涉及.*文件|which\s+files?|files?\s+(?:are\s+)?related/i.test(q)) {
|
|
381
444
|
return 'file-listing';
|
|
382
445
|
}
|
|
383
|
-
//
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
&& !
|
|
389
|
-
|
|
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)) {
|
|
446
|
+
// 7) Pure existence / concept-compare with zero graph anchors → Grep/docs.
|
|
447
|
+
// Module/cycle surveys already recognized by queryAsModuleDependencySurvey
|
|
448
|
+
// (e.g. `*constants` / `*common` leaf tokens + 循环依赖) must not fall through
|
|
449
|
+
// to concept-skip when extractTypeNames/path anchors are empty.
|
|
450
|
+
if (!hasGraphAnchor
|
|
451
|
+
&& !queryAsModuleDependencySurvey(q)
|
|
452
|
+
&& /有使用|是否使用|有没有使用|使用了.*吗|是否存在|有没有完整|有什么不同|区别|difference|vs\.?|versus|对比|does\s+(?:this\s+)?(?:project|repo)\s+have|is\s+there\s+(?:a\s+)?complete/i.test(q)) {
|
|
401
453
|
return 'concept-or-existence';
|
|
402
454
|
}
|
|
403
455
|
return null;
|
|
@@ -406,15 +458,20 @@ function queryShouldDeferToBuiltinTools(query) {
|
|
|
406
458
|
function homegraphDeferGuidance(kind, query) {
|
|
407
459
|
const q = query.trim().slice(0, 120);
|
|
408
460
|
const reasons = {
|
|
409
|
-
'sdk-catalog': 'Official SDK / @kit feature catalogs are outside this repo index — use SDK docs.',
|
|
410
461
|
'file-listing': 'Topic → file lists need Grep/Glob (keyword paths), not the symbol graph.',
|
|
411
|
-
'
|
|
462
|
+
'literal-hunt': 'Repo-wide literal / copy / layout-string hunts with no Type/file/@kit anchor — use Grep.',
|
|
463
|
+
'concept-or-existence': 'Pure existence/concept-compare with no named in-repo Type/file/@kit/@ohos anchor — Grep/docs.',
|
|
464
|
+
'external-manual': 'Question asks for official website/docs only — open the manual; HomeGraph indexes code/API graphs, not marketing pages.',
|
|
465
|
+
'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.',
|
|
466
|
+
'greenfield': 'Scaffolding an empty project from scratch needs generators/docs, not an existing code graph.',
|
|
467
|
+
'vcs-history': 'Git/commit/blame/diff history is not in the symbol graph — use git / IDE history.',
|
|
468
|
+
'media-assets': 'Media/binary asset inventories (.png/.mp4/fonts/…) need Glob, not the symbol graph.',
|
|
412
469
|
};
|
|
413
470
|
return [
|
|
414
471
|
'Skip HomeGraph for this question shape — do **not** retry any `homegraph_*` tool for it.',
|
|
415
472
|
reasons[kind],
|
|
416
473
|
`Query: "${q}${query.trim().length > 120 ? '…' : ''}"`,
|
|
417
|
-
'Next: Grep / Glob / Read / SDK docs.
|
|
474
|
+
'Next: Grep / Glob / Read / git / SDK docs / project generators as appropriate. Otherwise call `homegraph_explore` with the task or symbol names.',
|
|
418
475
|
].join('\n');
|
|
419
476
|
}
|
|
420
477
|
/**
|
|
@@ -424,8 +481,10 @@ function queryShouldPreferExploreOverSearch(query) {
|
|
|
424
481
|
const q = query.trim();
|
|
425
482
|
if (!q)
|
|
426
483
|
return false;
|
|
427
|
-
if (queryLooksLikeLiteralOrCopyHunt(query))
|
|
484
|
+
if (queryLooksLikeLiteralOrCopyHunt(query) && !queryAsCodeChangeOrientation(query))
|
|
428
485
|
return false;
|
|
486
|
+
if (queryAsCodeChangeOrientation(query))
|
|
487
|
+
return true;
|
|
429
488
|
if (/^[A-Za-z_][\w]*$/.test(q))
|
|
430
489
|
return true;
|
|
431
490
|
if (extractFileBasenamesFromQuery(query).length > 0
|
|
@@ -530,7 +589,11 @@ function shouldBuildKitModuleUsageSurvey(query) {
|
|
|
530
589
|
/** "需要额外安装哪些依赖" — kit survey must include oh-package, not only imports. */
|
|
531
590
|
function queryAsksKitInstallDeps(query) {
|
|
532
591
|
return (/额外安装|还需.*依赖|需要.*依赖|引入.*依赖|其他参数和依赖|other\s+(?:params?.{0,24})?deps?/i.test(query)
|
|
533
|
-
|| /install(?:ing)?\s+(?:extra\s+)?deps?|which\s+deps?|need(?:s)?\s+(?:other\s+)?deps?/i.test(query)
|
|
592
|
+
|| /install(?:ing)?\s+(?:extra\s+)?deps?|which\s+deps?|need(?:s)?\s+(?:other\s+)?deps?/i.test(query)
|
|
593
|
+
// Agent EN rewrites of 「其他参数和依赖」often drop "other/extra" and keep
|
|
594
|
+
// "parameters … dependencies" / "import usage … dependencies" beside a Kit name.
|
|
595
|
+
|| /parameters?\s+(?:and\s+)?dependenc/i.test(query)
|
|
596
|
+
|| /(?:import|usage).{0,48}(?:parameters?.{0,24})?dependenc/i.test(query));
|
|
534
597
|
}
|
|
535
598
|
/**
|
|
536
599
|
* Member-access patterns from a query — `obj.method`, `Type.method`, or `.member`.
|
|
@@ -711,7 +774,7 @@ exports.STOP_WORDS = new Set([
|
|
|
711
774
|
* they match every `parse`/`load` method and drown the distinctive token (xml).
|
|
712
775
|
*/
|
|
713
776
|
exports.GENERIC_VERB_ANCHOR_NOISE = new Set([
|
|
714
|
-
'parse', 'parsing', 'load', 'save', 'read', 'write', 'update', 'delete', 'create',
|
|
777
|
+
'parse', 'parsing', 'parser', 'parsers', 'load', 'save', 'read', 'write', 'update', 'delete', 'create',
|
|
715
778
|
'init', 'handle', 'process', 'run', 'start', 'stop', 'open', 'close', 'convert',
|
|
716
779
|
'get', 'set', 'add', 'remove', 'list', 'show', 'find',
|
|
717
780
|
// Lifetime / allocator verbs — agents ask "where new/delete" and these must not
|
|
@@ -720,6 +783,18 @@ exports.GENERIC_VERB_ANCHOR_NOISE = new Set([
|
|
|
720
783
|
// Inventory / NL fillers agents leave in rewritten bags (not real symbols).
|
|
721
784
|
'usage', 'usages', 'use', 'uses', 'using', 'api', 'apis', 'endpoint', 'endpoints',
|
|
722
785
|
'project', 'codebase', 'repo', 'documentation', 'document', 'docs', '说明',
|
|
786
|
+
// Kit-deps rewrite leftovers: "ServiceCollaborationKit import usage dependencies"
|
|
787
|
+
// must NOT become import-inventory focus (matches every `import` line).
|
|
788
|
+
'import', 'imports', 'importing', 'dependency', 'dependencies', 'deps', 'dep',
|
|
789
|
+
'param', 'params', 'parameter', 'parameters', 'extra', 'other', 'require', 'requires',
|
|
790
|
+
'calling', 'call', 'calls', 'needed', 'install', 'installing',
|
|
791
|
+
// Kit catalog rewrites: "util module API functions"
|
|
792
|
+
'module', 'modules', 'function', 'functions', 'feature', 'features',
|
|
793
|
+
'capability', 'capabilities', 'export', 'exports',
|
|
794
|
+
// Data-source EN rewrites: "badge source system service" must NOT become
|
|
795
|
+
// import-inventory focus (matches every `*Service` / ServiceExtensionAbility).
|
|
796
|
+
'service', 'services', 'source', 'sources', 'system', 'systems',
|
|
797
|
+
'upstream', 'origin', 'origins',
|
|
723
798
|
// Shared-lib / GL thread NL leftovers (not symbols).
|
|
724
799
|
'context', 'opengl', 'gles', 'glesv3', 'egl',
|
|
725
800
|
]);
|
|
@@ -879,14 +954,21 @@ function queryAsFieldUsageSurvey(query) {
|
|
|
879
954
|
}
|
|
880
955
|
/**
|
|
881
956
|
* Native shared lib + GL/EGL thread questions (`libfoo.so` … OpenGL … 哪个线程).
|
|
882
|
-
* Light-mechanism (CMake +
|
|
957
|
+
* Light-mechanism (CMake + named Draw/Render/EGL owners), not `.so` member survey.
|
|
883
958
|
*/
|
|
884
959
|
function queryAsNativeRenderThreadSurvey(query) {
|
|
885
960
|
const hasLib = /\b\w+\.(?:so|dll|dylib)\b/i.test(query)
|
|
886
961
|
|| /\blib\w+\b/i.test(query);
|
|
887
962
|
const hasGl = /\b(?:GLES(?:v3)?|EGL|OpenGL)\b/i.test(query);
|
|
888
963
|
const hasThread = /线程|thread|UI\s*线程|主线程|JS\s*主?线程/i.test(query);
|
|
889
|
-
|
|
964
|
+
if ((hasLib || hasGl) && hasThread)
|
|
965
|
+
return true;
|
|
966
|
+
// Named Draw/Render/EGL owner + frame-sync / sub-thread (no project Type list).
|
|
967
|
+
if (/\b(?:[A-Z][A-Za-z0-9]*(?:Draw|Render)|EGL(?:Core)?|EglCore)\b/.test(query)
|
|
968
|
+
&& /帧同步|撕裂|tearing|frame\s*sync|synchron|mutex|sub-?thread|子线程/i.test(query)) {
|
|
969
|
+
return true;
|
|
970
|
+
}
|
|
971
|
+
return false;
|
|
890
972
|
}
|
|
891
973
|
/** Named `.d.ts` wrap — what calls / imports it in-repo. */
|
|
892
974
|
function queryAsDtsWrapSurvey(query) {
|
|
@@ -915,11 +997,15 @@ function queryAsAssignedFlagImpactSurvey(query) {
|
|
|
915
997
|
* Named Toggle/control kept consistent across surfaces — which module guarantees it.
|
|
916
998
|
*/
|
|
917
999
|
function queryAsNamedControlStateSyncSurvey(query) {
|
|
1000
|
+
// Prefer Toggle/Switch anchors — bag-of-words rewrites often add Control/Center noise Types.
|
|
918
1001
|
const types = extractTypeNamesFromQuery(query).filter((t) => !isFrameworkUiDecoratorName(t));
|
|
919
|
-
|
|
1002
|
+
const controlTypes = types.filter((t) => /Toggle|Switch|开关/i.test(t));
|
|
1003
|
+
const anchors = controlTypes.length > 0 ? controlTypes : types;
|
|
1004
|
+
if (anchors.length < 1 || anchors.length > 3)
|
|
920
1005
|
return false;
|
|
921
|
-
return (
|
|
922
|
-
|| (/Toggle|Switch
|
|
1006
|
+
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)
|
|
1007
|
+
|| (/Toggle|Switch|开关/i.test(query)
|
|
1008
|
+
&& /一致|保证|模块|consistenc|consistent|guarantees?/i.test(query)));
|
|
923
1009
|
}
|
|
924
1010
|
/**
|
|
925
1011
|
* Methods listed beside a Type for caller inventories
|
|
@@ -990,6 +1076,16 @@ function queryAsModuleDependencySurvey(query) {
|
|
|
990
1076
|
* Shape-only: no PascalCase Type / file / member / kit anchors.
|
|
991
1077
|
*/
|
|
992
1078
|
function queryLooksLikeLiteralOrCopyHunt(query) {
|
|
1079
|
+
// Layout/style literal chains first — `.width('100%')` looks like member access
|
|
1080
|
+
// to extractors but is Grep territory.
|
|
1081
|
+
if (/检索所有\s*\.\w+\(\s*['"][^'"]+['"]\s*\)/i.test(query)
|
|
1082
|
+
|| /\.\w+\(\s*['"][^'"]{1,40}['"]\s*\).{0,80}\.\w+\(\s*['"][^'"]{1,40}['"]\s*\)/i.test(query)) {
|
|
1083
|
+
if (extractTypeNamesFromQuery(query).length === 0
|
|
1084
|
+
&& extractFileBasenamesFromQuery(query).length === 0
|
|
1085
|
+
&& extractKitModuleNamesFromQuery(query).length === 0) {
|
|
1086
|
+
return true;
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
993
1089
|
if (extractTypeNamesFromQuery(query).length > 0)
|
|
994
1090
|
return false;
|
|
995
1091
|
if (extractFileBasenamesFromQuery(query).length > 0)
|
|
@@ -1003,6 +1099,36 @@ function queryLooksLikeLiteralOrCopyHunt(query) {
|
|
|
1003
1099
|
return (/全仓|全搜|字面量|中文\s*(?:text|字符串)|绑了.*(?:text|文案)|literal\s+strings?/i.test(query)
|
|
1004
1100
|
|| /从.{0,16}包.{0,40}(?:导入|import).{0,20}\btext\b|导入的\s*text\s*对象|imported\s+text\s+objects?/i.test(query));
|
|
1005
1101
|
}
|
|
1102
|
+
/**
|
|
1103
|
+
* Container page + ViewModel/config injection — which pages share a shell
|
|
1104
|
+
* component and pass differentiated state into a shared ViewModel.
|
|
1105
|
+
*/
|
|
1106
|
+
function queryAsContainerCompositionSurvey(query) {
|
|
1107
|
+
if (queryAsMechanismSurvey(query) || queryAsCrossModuleFlowSurvey(query))
|
|
1108
|
+
return false;
|
|
1109
|
+
const types = extractTypeNamesFromQuery(query).filter((t) => !isFrameworkUiDecoratorName(t));
|
|
1110
|
+
const hasContainerAsk = (/共享|共用|share|shared/i.test(query) && /容器|container|Screen|Page|View/i.test(query))
|
|
1111
|
+
|| types.some((t) => /(?:Screen|Page|View|Container)$/i.test(t));
|
|
1112
|
+
const hasInjectAsk = /注入|inject|差异化|differentiat|配置|config|property/i.test(query);
|
|
1113
|
+
const hasViewModel = types.some((t) => /ViewModel$/i.test(t)) || /\bViewModel\b/i.test(query);
|
|
1114
|
+
return (hasContainerAsk && hasInjectAsk && (hasViewModel || types.length >= 2))
|
|
1115
|
+
|| (types.length >= 2
|
|
1116
|
+
&& types.some((t) => /(?:Screen|Page|View|Container)$/i.test(t))
|
|
1117
|
+
&& types.some((t) => /ViewModel$/i.test(t))
|
|
1118
|
+
&& hasInjectAsk);
|
|
1119
|
+
}
|
|
1120
|
+
/**
|
|
1121
|
+
* Named member + UI consequence ("how does UI mark/show when member returns true").
|
|
1122
|
+
* Definition/filter sites alone are rarely sufficient — steer to UI evidence.
|
|
1123
|
+
*/
|
|
1124
|
+
function queryAsMemberUiConsequenceSurvey(query) {
|
|
1125
|
+
if (!queryHasNamedMemberFocus(query))
|
|
1126
|
+
return false;
|
|
1127
|
+
if (queryAsCoNamedTypeMethodInteraction(query))
|
|
1128
|
+
return false;
|
|
1129
|
+
return (/UI|界面|显示|标记|展示|render|visual|样式|效果|\bmark\b/i.test(query)
|
|
1130
|
+
&& /如何|怎样|what|how/i.test(query));
|
|
1131
|
+
}
|
|
1006
1132
|
function queryAsTypeLifecycleSurvey(query) {
|
|
1007
1133
|
if (queryAsCrossModuleFlowSurvey(query))
|
|
1008
1134
|
return false;
|
|
@@ -1059,6 +1185,11 @@ function extractApiUsageTokens(query) {
|
|
|
1059
1185
|
if (m[1] && m[1].length >= 6)
|
|
1060
1186
|
tokens.add(m[1]);
|
|
1061
1187
|
}
|
|
1188
|
+
// "statfs这个API端点" / "使用了statfs这个API" — Chinese demonstrative after the symbol.
|
|
1189
|
+
for (const m of query.matchAll(/\b([A-Za-z_][\w]{2,})\s*这个\s*(?:API|接口|端点|方法)/gi)) {
|
|
1190
|
+
if (m[1] && !exports.GENERIC_VERB_ANCHOR_NOISE.has(m[1].toLowerCase()))
|
|
1191
|
+
tokens.add(m[1]);
|
|
1192
|
+
}
|
|
1062
1193
|
// When a PascalCase SDK/module token is present (Telephony, DrawContext), drop
|
|
1063
1194
|
// short lowercase bag noise agents add (`call`/`radio`/`usage`) — those flood
|
|
1064
1195
|
// false-positive files and tank precision.
|
|
@@ -1084,11 +1215,21 @@ function shouldBuildApiUsageSurvey(query) {
|
|
|
1084
1215
|
}
|
|
1085
1216
|
/** Caller / method survey intent — not every PascalCase token. */
|
|
1086
1217
|
function queryAsCallerOrMethodSurvey(query) {
|
|
1087
|
-
|
|
1218
|
+
if (/哪里调用|何处调用|谁调用|调用了|被调用|callers?\s+of|who\s+calls|called\s+by|哪些.*调用|外部.*调用|\bexternal\b/i.test(query)
|
|
1088
1219
|
|| /哪些方法|which\s+methods|methods?\s+(?:are\s+)?called|which\s+files?.{0,20}(?:call|invoke)/i.test(query)
|
|
1089
1220
|
// Agents often write "Type … methods … callers" / bare "callers" without "of".
|
|
1090
1221
|
|| /\bcallers?\b/i.test(query)
|
|
1091
|
-
|| /methods?.{0,40}\bcall/i.test(query))
|
|
1222
|
+
|| /methods?.{0,40}\bcall/i.test(query)) {
|
|
1223
|
+
return true;
|
|
1224
|
+
}
|
|
1225
|
+
// Agent EN rewrites of "Type 有哪些方法被外部调用" often become
|
|
1226
|
+
// "Type class definition methods" and lose 调用 — still route to caller inventory
|
|
1227
|
+
// when a named Type + plural methods bag is present. Singular "method" is too
|
|
1228
|
+
// broad ("Session method helper" is a symbol bag, not a caller survey).
|
|
1229
|
+
if (extractTypeNamesFromQuery(query).length > 0 && /\bmethods\b/i.test(query)) {
|
|
1230
|
+
return true;
|
|
1231
|
+
}
|
|
1232
|
+
return false;
|
|
1092
1233
|
}
|
|
1093
1234
|
/**
|
|
1094
1235
|
* Query is essentially just type name(s) (plus filler). Used for *inheritance*
|
|
@@ -1190,7 +1331,57 @@ function queryAsCrossModuleFlowSurvey(query) {
|
|
|
1190
1331
|
}
|
|
1191
1332
|
/** Data-source / upstream-service intent (来源于哪个服务 / which service). */
|
|
1192
1333
|
function queryAsDataSourceSurvey(query) {
|
|
1193
|
-
|
|
1334
|
+
if (/来源于|数据来源|状态来源|来自哪个|哪个系统服务|来自什么服务|data\s+source|status\s+source|state\s+source|which\s+service|来源.*服务|如何统一或区分/i.test(query)) {
|
|
1335
|
+
return true;
|
|
1336
|
+
}
|
|
1337
|
+
// Agent EN / bag-of-words rewrites of the same intent.
|
|
1338
|
+
if (/\bsystem\s+service\b/i.test(query))
|
|
1339
|
+
return true;
|
|
1340
|
+
if (/\bupstream\s+(?:service|source|data)\b/i.test(query))
|
|
1341
|
+
return true;
|
|
1342
|
+
if (/\bsource\b.{0,48}\b(?:system\s+)?service\b/i.test(query))
|
|
1343
|
+
return true;
|
|
1344
|
+
if (/\b(?:data|status|state)\b.{0,48}\bsource\b/i.test(query))
|
|
1345
|
+
return true;
|
|
1346
|
+
return false;
|
|
1347
|
+
}
|
|
1348
|
+
/** "How are sources unified/distinguished" — inventory alone is Partial, not ANSWER NOW. */
|
|
1349
|
+
function queryAsDataSourceDistinguishAsk(query) {
|
|
1350
|
+
if (/如何统一或区分|统一或区分|区分.*来源|来源.*区分|unify|distinguish|how\s+(?:are|is).{0,40}(?:unified|distinguished)/i.test(query)) {
|
|
1351
|
+
return true;
|
|
1352
|
+
}
|
|
1353
|
+
// Rewrites may drop 「如何统一或区分」but keep 状态来源 / status|state source.
|
|
1354
|
+
if (/哪个系统服务|which\s+system\s+service|来源于哪个|来自哪个系统/i.test(query)) {
|
|
1355
|
+
return false;
|
|
1356
|
+
}
|
|
1357
|
+
if (/\bsystem\s+service\b/i.test(query) && !/状态来源|status\s*source|state.{0,24}source/i.test(query)) {
|
|
1358
|
+
return false;
|
|
1359
|
+
}
|
|
1360
|
+
return /状态来源|status\s*source|state\s+change\s+source|state.{0,24}source/i.test(query);
|
|
1361
|
+
}
|
|
1362
|
+
/**
|
|
1363
|
+
* ≥3 named Types + dependency/relationship ask — inventory edges, not a fat
|
|
1364
|
+
* multi-body compact that hits the soft deadline.
|
|
1365
|
+
*/
|
|
1366
|
+
function queryAsMultiTypeDependencySurvey(query) {
|
|
1367
|
+
const types = extractTypeNamesFromQuery(query).filter((t) => t.length >= 8
|
|
1368
|
+
|| /(?:Manager|Installer|Parser|Service|Controller|Handler|Provider|Store)$/i.test(t));
|
|
1369
|
+
if (types.length < 3)
|
|
1370
|
+
return false;
|
|
1371
|
+
return /依赖|关系|互相|之间|调用关系|dependenc|relationship|how\s+(?:do|are).{0,40}relate|related/i.test(query);
|
|
1372
|
+
}
|
|
1373
|
+
/**
|
|
1374
|
+
* Event-type → handler/Manager dispatch inventory
|
|
1375
|
+
* (`FooEvent` types / which Managers handle them).
|
|
1376
|
+
*/
|
|
1377
|
+
function queryAsEventDispatchSurvey(query) {
|
|
1378
|
+
const types = extractTypeNamesFromQuery(query);
|
|
1379
|
+
const hasEventType = types.some((t) => /Event$/i.test(t));
|
|
1380
|
+
const hasEventCue = hasEventType
|
|
1381
|
+
|| /\b[A-Z][A-Za-z0-9]*Event\b|事件类型|事件枚举/i.test(query);
|
|
1382
|
+
if (!hasEventCue)
|
|
1383
|
+
return false;
|
|
1384
|
+
return /分发|分发给|哪些\s*Manager|handlers?|dispatch|routed?\s+to|handled\s+by|处理/i.test(query);
|
|
1194
1385
|
}
|
|
1195
1386
|
/**
|
|
1196
1387
|
* Local one/few-symbol behavior or contract — NOT multi-file mechanism / inventory.
|
|
@@ -1242,7 +1433,7 @@ function extractLocalDetailAnchors(query) {
|
|
|
1242
1433
|
return score(b) - score(a) || a.localeCompare(b);
|
|
1243
1434
|
});
|
|
1244
1435
|
// Drop framework decorator names when a concrete UI Type is also present
|
|
1245
|
-
// (`@CustomDialog` +
|
|
1436
|
+
// (`@CustomDialog` + `FooDialog` → keep only the concrete UI types).
|
|
1246
1437
|
const hasConcreteUi = ranked.some((n) => queryLooksLikeUiComponentType(n) && !isFrameworkUiDecoratorName(n));
|
|
1247
1438
|
const filtered = hasConcreteUi
|
|
1248
1439
|
? ranked.filter((n) => !isFrameworkUiDecoratorName(n))
|
|
@@ -1296,6 +1487,8 @@ function queryAsLocalSymbolDetail(query) {
|
|
|
1296
1487
|
return false;
|
|
1297
1488
|
if (queryAsDataSourceSurvey(query))
|
|
1298
1489
|
return false;
|
|
1490
|
+
if (queryAsEventDispatchSurvey(query))
|
|
1491
|
+
return false;
|
|
1299
1492
|
// Named UI control + event: compact body + callees (not import inventory).
|
|
1300
1493
|
if (queryAsNamedComponentAction(query))
|
|
1301
1494
|
return true;
|
|
@@ -1418,33 +1611,17 @@ function extractMechanismEntrySeeds(query) {
|
|
|
1418
1611
|
seeds.add(term);
|
|
1419
1612
|
}
|
|
1420
1613
|
}
|
|
1421
|
-
// Shared-lib + GLES/EGL thread — seed
|
|
1614
|
+
// Shared-lib + GLES/EGL thread — seed Draw/Render/EGL owners named in the query.
|
|
1422
1615
|
if (queryAsNativeRenderThreadSurvey(query)) {
|
|
1423
|
-
|
|
1424
|
-
|
|
1616
|
+
for (const t of extractTypeNamesFromQuery(query))
|
|
1617
|
+
seeds.add(t);
|
|
1618
|
+
for (const m of query.matchAll(/\b([A-Z][A-Za-z0-9]*(?:Draw|Render|Core))\b/g)) {
|
|
1619
|
+
if (m[1])
|
|
1620
|
+
seeds.add(m[1]);
|
|
1621
|
+
}
|
|
1425
1622
|
if (/\bCMakeLists\b|\.so\b|链接|link/i.test(query))
|
|
1426
1623
|
seeds.add('CMakeLists');
|
|
1427
1624
|
}
|
|
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
1625
|
return [...seeds].filter((s) => s.length >= 3).slice(0, 12);
|
|
1449
1626
|
}
|
|
1450
1627
|
/**
|
|
@@ -1476,20 +1653,50 @@ function queryAsDomainMechanismBag(query) {
|
|
|
1476
1653
|
const distinct = domain.filter((t) => /^[A-Za-z][A-Za-z0-9._-]{2,}$/.test(t) && !exports.GENERIC_VERB_ANCHOR_NOISE.has(t.toLowerCase()));
|
|
1477
1654
|
if (distinct.length === 0)
|
|
1478
1655
|
return false;
|
|
1479
|
-
|
|
1656
|
+
// Only *verb* leftovers count as the action half. Noun noise in
|
|
1657
|
+
// GENERIC_VERB_ANCHOR_NOISE (`service` / `source` / `system` / `api` / …)
|
|
1658
|
+
// must not turn a multi-term locator bag (`item service`) into light-mechanism.
|
|
1659
|
+
const MECHANISM_BAG_NOUN_NOISE = new Set([
|
|
1660
|
+
'service', 'services', 'source', 'sources', 'system', 'systems',
|
|
1661
|
+
'upstream', 'origin', 'origins',
|
|
1662
|
+
'usage', 'usages', 'use', 'uses', 'using',
|
|
1663
|
+
'api', 'apis', 'endpoint', 'endpoints',
|
|
1664
|
+
'module', 'modules', 'function', 'functions', 'feature', 'features',
|
|
1665
|
+
'capability', 'capabilities', 'export', 'exports',
|
|
1666
|
+
'dependency', 'dependencies', 'deps', 'dep',
|
|
1667
|
+
'param', 'params', 'parameter', 'parameters',
|
|
1668
|
+
'project', 'codebase', 'repo', 'documentation', 'document', 'docs',
|
|
1669
|
+
'context', 'opengl', 'gles', 'glesv3', 'egl',
|
|
1670
|
+
'extra', 'other', 'require', 'requires', 'needed',
|
|
1671
|
+
]);
|
|
1672
|
+
const hasActionVerb = domain.some((t) => {
|
|
1673
|
+
const l = t.toLowerCase();
|
|
1674
|
+
return exports.GENERIC_VERB_ANCHOR_NOISE.has(l) && !MECHANISM_BAG_NOUN_NOISE.has(l);
|
|
1675
|
+
})
|
|
1480
1676
|
|| /\b(?:parse|implement|manage|handle|process|subscribe|convert|encode|decode)(?:s|d|ing)?\b/i.test(query);
|
|
1481
1677
|
// Remaining CJK tokens are the topic half of a rewritten how-question bag.
|
|
1482
1678
|
const hasCjkDomain = domain.some((t) => /[\u4e00-\u9fff]/.test(t));
|
|
1483
1679
|
return hasActionVerb || hasCjkDomain;
|
|
1484
1680
|
}
|
|
1485
1681
|
function shouldTryLightMechanismExplore(query) {
|
|
1682
|
+
if (queryShouldDeferToBuiltinTools(query))
|
|
1683
|
+
return false;
|
|
1486
1684
|
if (queryAsCrossModuleFlowSurvey(query))
|
|
1487
1685
|
return false;
|
|
1488
1686
|
if (queryAsInterpretationSurvey(query))
|
|
1489
1687
|
return false;
|
|
1490
|
-
// Literal / copy hunts → Grep (never light dump).
|
|
1491
|
-
if (queryLooksLikeLiteralOrCopyHunt(query))
|
|
1688
|
+
// Literal / copy hunts → Grep (never light dump), unless this is an edit/fix task.
|
|
1689
|
+
if (queryLooksLikeLiteralOrCopyHunt(query) && !queryAsCodeChangeOrientation(query))
|
|
1492
1690
|
return false;
|
|
1691
|
+
// Pre-edit orientation: task keywords → light mechanism seeds (domain / Type / file).
|
|
1692
|
+
if (queryAsCodeChangeOrientation(query)) {
|
|
1693
|
+
if (extractDomainSearchTerms(query).length >= 1
|
|
1694
|
+
|| extractTypeNamesFromQuery(query).length > 0
|
|
1695
|
+
|| extractFileBasenamesFromQuery(query).length > 0
|
|
1696
|
+
|| extractMemberAccessFromQuery(query).length > 0) {
|
|
1697
|
+
return true;
|
|
1698
|
+
}
|
|
1699
|
+
}
|
|
1493
1700
|
// System-setting howto → lean capability inventory, not every `language` import.
|
|
1494
1701
|
if (queryAsInRepoSystemCapabilityHowto(query))
|
|
1495
1702
|
return false;
|
|
@@ -1499,6 +1706,12 @@ function shouldTryLightMechanismExplore(query) {
|
|
|
1499
1706
|
// Manager data/status source → inventory, not light-mechanism.
|
|
1500
1707
|
if (queryAsDataSourceSurvey(query))
|
|
1501
1708
|
return false;
|
|
1709
|
+
// Event type → Manager dispatch inventory.
|
|
1710
|
+
if (queryAsEventDispatchSurvey(query))
|
|
1711
|
+
return false;
|
|
1712
|
+
// ≥3 Types + dependency relationship → lean inventory (not light/compact dump).
|
|
1713
|
+
if (queryAsMultiTypeDependencySurvey(query))
|
|
1714
|
+
return false;
|
|
1502
1715
|
// Named UI control + event → compact (body + callees + usage sites), not light-mechanism.
|
|
1503
1716
|
if (queryAsNamedComponentAction(query))
|
|
1504
1717
|
return false;
|
|
@@ -1546,6 +1759,8 @@ function shouldTryLightMechanismExplore(query) {
|
|
|
1546
1759
|
* Skip expensive subgraph gathering — inventory sections alone answer the query.
|
|
1547
1760
|
*/
|
|
1548
1761
|
function shouldTryFastInventoryExplore(query) {
|
|
1762
|
+
if (queryShouldDeferToBuiltinTools(query))
|
|
1763
|
+
return false;
|
|
1549
1764
|
if (queryAsCrossModuleFlowSurvey(query))
|
|
1550
1765
|
return false;
|
|
1551
1766
|
if (shouldTryLightMechanismExplore(query))
|
|
@@ -1571,6 +1786,9 @@ function shouldTryFastInventoryExplore(query) {
|
|
|
1571
1786
|
|| shouldBuildDomainFileSurvey(query)
|
|
1572
1787
|
|| shouldBuildConfigSection(query)
|
|
1573
1788
|
|| queryAsDataSourceSurvey(query)
|
|
1789
|
+
|| queryAsEventDispatchSurvey(query)
|
|
1790
|
+
|| queryAsMultiTypeDependencySurvey(query)
|
|
1791
|
+
|| queryAsContainerCompositionSurvey(query)
|
|
1574
1792
|
|| shouldBuildHoverHandlerSurvey(query)
|
|
1575
1793
|
|| queryAsModuleExportSurvey(query)
|
|
1576
1794
|
|| queryAsModuleDependencySurvey(query)
|
|
@@ -1669,7 +1887,14 @@ function extractDomainSearchTerms(query) {
|
|
|
1669
1887
|
}
|
|
1670
1888
|
/** How/implementation/mechanism intent — needs entry symbols + flow, not flat file list. */
|
|
1671
1889
|
function queryAsMechanismSurvey(query) {
|
|
1672
|
-
|
|
1890
|
+
// Cross-Type drive / state-machine interaction — must not collapse into compact
|
|
1891
|
+
// hard-ANSWER-NOW on abstract base names (Machine+Engine, Session FG/BG, …).
|
|
1892
|
+
const types = extractTypeNamesFromQuery(query).filter((t) => !isFrameworkUiDecoratorName(t));
|
|
1893
|
+
if (types.length >= 2
|
|
1894
|
+
&& /驱动|触发|状态机|状态变化|重新计算|foreground|background|layout|布局/i.test(query)) {
|
|
1895
|
+
return true;
|
|
1896
|
+
}
|
|
1897
|
+
return /如何(?:实现|获取|做|处理|管理|驱动|触发)|怎样(?:实现|获取|做|驱动|触发)|怎么(?:实现|获取|做|驱动|触发)|是如何|是怎么|how\s+(?:is|does|are|to\s+(?:get|implement|work|drive|trigger))|机制|状态机|流程|架构|多线程|多进程|multithread|multi-thread|会走到哪些|步骤中会|解析和安装|下载完|下载后|状态变化如何|如何驱动|如何触发/i.test(query);
|
|
1673
1898
|
}
|
|
1674
1899
|
/**
|
|
1675
1900
|
* Broad domain survey — related files, usage existence, or concept comparison.
|
|
@@ -1712,7 +1937,59 @@ function shouldBuildDomainFileSurvey(query) {
|
|
|
1712
1937
|
return queryAsDomainFileSurvey(query) && extractDomainSearchTerms(query).length > 0;
|
|
1713
1938
|
}
|
|
1714
1939
|
/** 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;
|
|
1940
|
+
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;
|
|
1941
|
+
/**
|
|
1942
|
+
* ASCII path/name stems for mechanism affinity.
|
|
1943
|
+
* Expands a few CJK domain nouns so `通知订阅` can match `/notification/` paths
|
|
1944
|
+
* without a product-specific file blacklist.
|
|
1945
|
+
*/
|
|
1946
|
+
function mechanismDomainPathTokens(query) {
|
|
1947
|
+
const out = new Set();
|
|
1948
|
+
for (const t of extractDomainSearchTerms(query)) {
|
|
1949
|
+
// ≥3 so short distinctive stems (`xml`) survive agent EN rewrites; verb
|
|
1950
|
+
// noise (`parse`/`parser`) stays out via GENERIC_VERB_ANCHOR_NOISE.
|
|
1951
|
+
if (/^[\x00-\x7F]+$/.test(t) && t.length >= 3 && !exports.GENERIC_VERB_ANCHOR_NOISE.has(t.toLowerCase())) {
|
|
1952
|
+
out.add(t.toLowerCase());
|
|
1953
|
+
}
|
|
1954
|
+
}
|
|
1955
|
+
if (/通知/.test(query))
|
|
1956
|
+
out.add('notification');
|
|
1957
|
+
if (/订阅/.test(query)) {
|
|
1958
|
+
out.add('subscribe');
|
|
1959
|
+
out.add('subscriber');
|
|
1960
|
+
}
|
|
1961
|
+
if (/壁纸|wallpaper/i.test(query))
|
|
1962
|
+
out.add('wallpaper');
|
|
1963
|
+
if (/主题|theme/i.test(query)) {
|
|
1964
|
+
out.add('theme');
|
|
1965
|
+
// Prefer themeservice / themepack paths over appinstall "download/install" Managers.
|
|
1966
|
+
out.add('themeservice');
|
|
1967
|
+
out.add('themepack');
|
|
1968
|
+
}
|
|
1969
|
+
if (/备份|backup/i.test(query))
|
|
1970
|
+
out.add('backup');
|
|
1971
|
+
if (/恢复|restore/i.test(query))
|
|
1972
|
+
out.add('restore');
|
|
1973
|
+
if (/锁屏|screenlock|keyguard/i.test(query)) {
|
|
1974
|
+
out.add('screenlock');
|
|
1975
|
+
out.add('keyguard');
|
|
1976
|
+
}
|
|
1977
|
+
return [...out].slice(0, 12);
|
|
1978
|
+
}
|
|
1979
|
+
/** Class/file looks like a domain Manager/Service under matching path or name. */
|
|
1980
|
+
function isDomainRoleSymbol(name, filePath, domainTokens) {
|
|
1981
|
+
if (!exports.IMPLEMENTATION_ENTRY_NAME_RE.test(name))
|
|
1982
|
+
return false;
|
|
1983
|
+
if (domainTokens.length === 0)
|
|
1984
|
+
return /Manager|Subscriber|Listener$/i.test(name);
|
|
1985
|
+
const blob = `${name}\n${filePath}`.toLowerCase().replace(/\\/g, '/');
|
|
1986
|
+
return domainTokens.some((t) => {
|
|
1987
|
+
const tl = t.toLowerCase();
|
|
1988
|
+
if (tl.length < 4)
|
|
1989
|
+
return false;
|
|
1990
|
+
return blob.includes(tl) || blob.includes(`/${tl}/`);
|
|
1991
|
+
});
|
|
1992
|
+
}
|
|
1716
1993
|
function isImplementationEntrySymbol(name, domainTerms) {
|
|
1717
1994
|
if (!exports.IMPLEMENTATION_ENTRY_NAME_RE.test(name))
|
|
1718
1995
|
return false;
|
|
@@ -2043,6 +2320,8 @@ function isTestFile(filePath) {
|
|
|
2043
2320
|
lower.includes('/__tests__/') || lower.includes('/spec/') ||
|
|
2044
2321
|
lower.includes('/specs/') || lower.includes('/testlib/') ||
|
|
2045
2322
|
lower.includes('/testing/') ||
|
|
2323
|
+
// HarmonyOS / OpenHarmony instrumented test trees
|
|
2324
|
+
lower.includes('/ohostest/') ||
|
|
2046
2325
|
lower.startsWith('test/') || lower.startsWith('tests/') ||
|
|
2047
2326
|
lower.startsWith('spec/') || lower.startsWith('specs/') ||
|
|
2048
2327
|
// CamelCase test source-set dirs (Kotlin Multiplatform / Gradle / Xcode):
|