homegraph 1.5.2 → 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 +156 -0
- package/README.md +63 -10
- 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/index.d.ts +4 -0
- package/dist/arkui/index.d.ts.map +1 -0
- package/dist/arkui/index.js +23 -0
- package/dist/arkui/index.js.map +1 -0
- package/dist/arkui/migrate-passage.d.ts +28 -0
- package/dist/arkui/migrate-passage.d.ts.map +1 -0
- package/dist/arkui/migrate-passage.js +310 -0
- package/dist/arkui/migrate-passage.js.map +1 -0
- package/dist/arkui/migrate-semantics.d.ts +47 -0
- package/dist/arkui/migrate-semantics.d.ts.map +1 -0
- package/dist/arkui/migrate-semantics.js +229 -0
- package/dist/arkui/migrate-semantics.js.map +1 -0
- package/dist/arkui/migrate-snapshot.d.ts +79 -0
- package/dist/arkui/migrate-snapshot.d.ts.map +1 -0
- package/dist/arkui/migrate-snapshot.js +364 -0
- package/dist/arkui/migrate-snapshot.js.map +1 -0
- 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/fatal-handler.js +2 -2
- package/dist/bin/homegraph.js +111 -157
- package/dist/bin/homegraph.js.map +1 -1
- package/dist/bin/node-version-check.d.ts +6 -15
- package/dist/bin/node-version-check.d.ts.map +1 -1
- package/dist/bin/node-version-check.js +8 -37
- package/dist/bin/node-version-check.js.map +1 -1
- package/dist/db/index.d.ts +36 -1
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +92 -6
- package/dist/db/index.js.map +1 -1
- package/dist/db/migrations.d.ts +1 -1
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +15 -1
- package/dist/db/migrations.js.map +1 -1
- package/dist/db/queries.d.ts +42 -0
- package/dist/db/queries.d.ts.map +1 -1
- package/dist/db/queries.js +177 -10
- package/dist/db/queries.js.map +1 -1
- package/dist/db/schema.sql +6 -1
- package/dist/db/sqlite-adapter.d.ts +7 -3
- package/dist/db/sqlite-adapter.d.ts.map +1 -1
- package/dist/db/sqlite-adapter.js +44 -3
- package/dist/db/sqlite-adapter.js.map +1 -1
- package/dist/extraction/extraction-version.d.ts +1 -1
- package/dist/extraction/extraction-version.js +1 -1
- package/dist/extraction/generated-detection.d.ts +42 -11
- package/dist/extraction/generated-detection.d.ts.map +1 -1
- package/dist/extraction/generated-detection.js +141 -20
- package/dist/extraction/generated-detection.js.map +1 -1
- package/dist/extraction/index.d.ts +42 -0
- package/dist/extraction/index.d.ts.map +1 -1
- package/dist/extraction/index.js +96 -0
- package/dist/extraction/index.js.map +1 -1
- package/dist/extraction/languages/arkts.d.ts +33 -2
- package/dist/extraction/languages/arkts.d.ts.map +1 -1
- package/dist/extraction/languages/arkts.js +525 -129
- package/dist/extraction/languages/arkts.js.map +1 -1
- package/dist/extraction/wasm-runtime-flags.d.ts.map +1 -1
- package/dist/extraction/wasm-runtime-flags.js +9 -6
- package/dist/extraction/wasm-runtime-flags.js.map +1 -1
- package/dist/graph-sources.d.ts +41 -0
- package/dist/graph-sources.d.ts.map +1 -0
- package/dist/graph-sources.js +82 -0
- package/dist/graph-sources.js.map +1 -0
- package/dist/index.d.ts +20 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +79 -9
- package/dist/index.js.map +1 -1
- package/dist/installer/index.d.ts.map +1 -1
- package/dist/installer/index.js +0 -48
- package/dist/installer/index.js.map +1 -1
- package/dist/installer/targets/antigravity.js +1 -1
- package/dist/installer/targets/antigravity.js.map +1 -1
- package/dist/installer/targets/deveco.js +1 -1
- package/dist/installer/targets/deveco.js.map +1 -1
- package/dist/installer/targets/hermes.d.ts +1 -1
- package/dist/installer/targets/hermes.js +2 -2
- package/dist/installer/targets/hermes.js.map +1 -1
- package/dist/installer/targets/opencode.js +1 -1
- package/dist/installer/targets/opencode.js.map +1 -1
- package/dist/installer/targets/shared.js +1 -1
- package/dist/installer/targets/shared.js.map +1 -1
- package/dist/mcp/daemon-paths.d.ts +5 -4
- package/dist/mcp/daemon-paths.d.ts.map +1 -1
- package/dist/mcp/daemon-paths.js +28 -13
- package/dist/mcp/daemon-paths.js.map +1 -1
- package/dist/mcp/daemon-registry.d.ts.map +1 -1
- package/dist/mcp/daemon-registry.js +4 -1
- package/dist/mcp/daemon-registry.js.map +1 -1
- package/dist/mcp/daemon.d.ts +1 -1
- package/dist/mcp/daemon.js +1 -1
- package/dist/mcp/engine.d.ts.map +1 -1
- package/dist/mcp/engine.js +12 -3
- package/dist/mcp/engine.js.map +1 -1
- package/dist/mcp/explore-dedup.d.ts +137 -0
- package/dist/mcp/explore-dedup.d.ts.map +1 -0
- package/dist/mcp/explore-dedup.js +236 -0
- package/dist/mcp/explore-dedup.js.map +1 -0
- 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 +237 -0
- package/dist/mcp/explore-session-state.d.ts.map +1 -0
- package/dist/mcp/explore-session-state.js +353 -0
- package/dist/mcp/explore-session-state.js.map +1 -0
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +4 -7
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/proxy.d.ts.map +1 -1
- package/dist/mcp/proxy.js +20 -18
- 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/query-worker.d.ts +1 -1
- package/dist/mcp/query-worker.js +1 -1
- package/dist/mcp/server-instructions.d.ts +5 -2
- package/dist/mcp/server-instructions.d.ts.map +1 -1
- package/dist/mcp/server-instructions.js +43 -32
- package/dist/mcp/server-instructions.js.map +1 -1
- package/dist/mcp/session.d.ts +14 -3
- package/dist/mcp/session.d.ts.map +1 -1
- package/dist/mcp/session.js +17 -14
- package/dist/mcp/session.js.map +1 -1
- package/dist/mcp/startup-handshake.d.ts +1 -1
- package/dist/mcp/startup-handshake.js +1 -1
- package/dist/mcp/tools.d.ts +149 -8
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +4265 -575
- 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/resolution/frameworks/arkts-napi.d.ts +14 -0
- package/dist/resolution/frameworks/arkts-napi.d.ts.map +1 -1
- package/dist/resolution/frameworks/arkts-napi.js +169 -49
- package/dist/resolution/frameworks/arkts-napi.js.map +1 -1
- package/dist/search/query-utils.d.ts +157 -5
- package/dist/search/query-utils.d.ts.map +1 -1
- package/dist/search/query-utils.js +1105 -70
- 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/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/upgrade/index.d.ts +14 -26
- package/dist/upgrade/index.d.ts.map +1 -1
- package/dist/upgrade/index.js +28 -123
- package/dist/upgrade/index.js.map +1 -1
- package/dist/upgrade/remove-binary.d.ts +19 -19
- package/dist/upgrade/remove-binary.d.ts.map +1 -1
- package/dist/upgrade/remove-binary.js +20 -21
- package/dist/upgrade/remove-binary.js.map +1 -1
- package/dist/upgrade/update-check.d.ts +4 -3
- package/dist/upgrade/update-check.d.ts.map +1 -1
- package/dist/upgrade/update-check.js +4 -3
- package/dist/upgrade/update-check.js.map +1 -1
- package/package.json +13 -9
- package/dist/telemetry/index.d.ts +0 -143
- package/dist/telemetry/index.d.ts.map +0 -1
- package/dist/telemetry/index.js +0 -541
- package/dist/telemetry/index.js.map +0 -1
|
@@ -38,7 +38,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
38
38
|
};
|
|
39
39
|
})();
|
|
40
40
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
41
|
-
exports.IMPLEMENTATION_ENTRY_NAME_RE = exports.STOP_WORDS = exports.QUERY_SOURCE_FILE_EXT = void 0;
|
|
41
|
+
exports.IMPLEMENTATION_ENTRY_NAME_RE = exports.GENERIC_VERB_ANCHOR_NOISE = exports.STOP_WORDS = exports.FRAMEWORK_UI_DECORATOR_NAMES = exports.QUERY_SOURCE_FILE_EXT = void 0;
|
|
42
42
|
exports.normalizeNameToken = normalizeNameToken;
|
|
43
43
|
exports.extractFileBasenamesFromQuery = extractFileBasenamesFromQuery;
|
|
44
44
|
exports.extractPathSegmentsFromQuery = extractPathSegmentsFromQuery;
|
|
@@ -47,11 +47,25 @@ exports.extractKitModuleNamesFromQuery = extractKitModuleNamesFromQuery;
|
|
|
47
47
|
exports.extractKitSubmoduleNamesFromQuery = extractKitSubmoduleNamesFromQuery;
|
|
48
48
|
exports.queryAsKitModuleCapabilitySurvey = queryAsKitModuleCapabilitySurvey;
|
|
49
49
|
exports.isMemberLikeIdentifier = isMemberLikeIdentifier;
|
|
50
|
+
exports.queryAsCoNamedTypeMethodInteraction = queryAsCoNamedTypeMethodInteraction;
|
|
50
51
|
exports.queryHasNamedMemberFocus = queryHasNamedMemberFocus;
|
|
51
52
|
exports.queryAsNamedComponentAction = queryAsNamedComponentAction;
|
|
52
53
|
exports.queryAsOutOfRepoSdkCatalog = queryAsOutOfRepoSdkCatalog;
|
|
54
|
+
exports.queryAsCodeChangeOrientation = queryAsCodeChangeOrientation;
|
|
55
|
+
exports.queryAsExternalManualOnly = queryAsExternalManualOnly;
|
|
56
|
+
exports.queryAsGreenfieldScaffold = queryAsGreenfieldScaffold;
|
|
57
|
+
exports.queryAsVcsHistoryOnly = queryAsVcsHistoryOnly;
|
|
58
|
+
exports.queryAsMediaAssetInventory = queryAsMediaAssetInventory;
|
|
59
|
+
exports.queryShouldDeferToBuiltinTools = queryShouldDeferToBuiltinTools;
|
|
60
|
+
exports.homegraphDeferGuidance = homegraphDeferGuidance;
|
|
53
61
|
exports.queryShouldPreferExploreOverSearch = queryShouldPreferExploreOverSearch;
|
|
62
|
+
exports.shouldBuildHoverHandlerSurvey = shouldBuildHoverHandlerSurvey;
|
|
63
|
+
exports.isFrameworkUiDecoratorName = isFrameworkUiDecoratorName;
|
|
64
|
+
exports.queryLooksLikeUiComponentType = queryLooksLikeUiComponentType;
|
|
65
|
+
exports.queryAsFocusedUiCluster = queryAsFocusedUiCluster;
|
|
66
|
+
exports.queryAsComponentSurfaceSurvey = queryAsComponentSurfaceSurvey;
|
|
54
67
|
exports.shouldBuildKitModuleUsageSurvey = shouldBuildKitModuleUsageSurvey;
|
|
68
|
+
exports.queryAsksKitInstallDeps = queryAsksKitInstallDeps;
|
|
55
69
|
exports.extractMemberAccessFromQuery = extractMemberAccessFromQuery;
|
|
56
70
|
exports.extractImportSearchTerms = extractImportSearchTerms;
|
|
57
71
|
exports.fileMatchesQueryBasename = fileMatchesQueryBasename;
|
|
@@ -62,6 +76,22 @@ exports.queryNamesConfigFile = queryNamesConfigFile;
|
|
|
62
76
|
exports.hasSymbolFilterInQuery = hasSymbolFilterInQuery;
|
|
63
77
|
exports.hasImportInventoryFilter = hasImportInventoryFilter;
|
|
64
78
|
exports.queryAsApiUsageSurvey = queryAsApiUsageSurvey;
|
|
79
|
+
exports.extractFieldLikeSymbolsFromQuery = extractFieldLikeSymbolsFromQuery;
|
|
80
|
+
exports.queryAsDeclarationSiteSurvey = queryAsDeclarationSiteSurvey;
|
|
81
|
+
exports.queryAsInRepoSystemCapabilityHowto = queryAsInRepoSystemCapabilityHowto;
|
|
82
|
+
exports.queryAsReturnValueConsumerSurvey = queryAsReturnValueConsumerSurvey;
|
|
83
|
+
exports.queryAsConstantUsageSurvey = queryAsConstantUsageSurvey;
|
|
84
|
+
exports.queryAsFieldUsageSurvey = queryAsFieldUsageSurvey;
|
|
85
|
+
exports.queryAsNativeRenderThreadSurvey = queryAsNativeRenderThreadSurvey;
|
|
86
|
+
exports.queryAsDtsWrapSurvey = queryAsDtsWrapSurvey;
|
|
87
|
+
exports.queryAsAssignedFlagImpactSurvey = queryAsAssignedFlagImpactSurvey;
|
|
88
|
+
exports.queryAsNamedControlStateSyncSurvey = queryAsNamedControlStateSyncSurvey;
|
|
89
|
+
exports.extractListedTypeMethodsFromQuery = extractListedTypeMethodsFromQuery;
|
|
90
|
+
exports.queryAsModuleExportSurvey = queryAsModuleExportSurvey;
|
|
91
|
+
exports.queryAsModuleDependencySurvey = queryAsModuleDependencySurvey;
|
|
92
|
+
exports.queryLooksLikeLiteralOrCopyHunt = queryLooksLikeLiteralOrCopyHunt;
|
|
93
|
+
exports.queryAsTypeLifecycleSurvey = queryAsTypeLifecycleSurvey;
|
|
94
|
+
exports.shouldPreferMemberUsageInventory = shouldPreferMemberUsageInventory;
|
|
65
95
|
exports.extractApiUsageTokens = extractApiUsageTokens;
|
|
66
96
|
exports.shouldBuildApiUsageSurvey = shouldBuildApiUsageSurvey;
|
|
67
97
|
exports.queryAsCallerOrMethodSurvey = queryAsCallerOrMethodSurvey;
|
|
@@ -71,6 +101,9 @@ exports.shouldBuildCallerInventory = shouldBuildCallerInventory;
|
|
|
71
101
|
exports.extractCallerSurveySymbols = extractCallerSurveySymbols;
|
|
72
102
|
exports.queryAsCrossModuleFlowSurvey = queryAsCrossModuleFlowSurvey;
|
|
73
103
|
exports.queryAsDataSourceSurvey = queryAsDataSourceSurvey;
|
|
104
|
+
exports.queryAsDataSourceDistinguishAsk = queryAsDataSourceDistinguishAsk;
|
|
105
|
+
exports.queryAsMultiTypeDependencySurvey = queryAsMultiTypeDependencySurvey;
|
|
106
|
+
exports.queryAsEventDispatchSurvey = queryAsEventDispatchSurvey;
|
|
74
107
|
exports.extractLocalDetailAnchors = extractLocalDetailAnchors;
|
|
75
108
|
exports.queryNeedsCoNamedUseBridge = queryNeedsCoNamedUseBridge;
|
|
76
109
|
exports.queryAsLocalSymbolDetail = queryAsLocalSymbolDetail;
|
|
@@ -80,6 +113,7 @@ exports.shouldFocusOnQueryNamedDefs = shouldFocusOnQueryNamedDefs;
|
|
|
80
113
|
exports.queryAsInterpretationSurvey = queryAsInterpretationSurvey;
|
|
81
114
|
exports.queryAsTestOnlyInterpretation = queryAsTestOnlyInterpretation;
|
|
82
115
|
exports.extractMechanismEntrySeeds = extractMechanismEntrySeeds;
|
|
116
|
+
exports.queryAsDomainMechanismBag = queryAsDomainMechanismBag;
|
|
83
117
|
exports.shouldTryLightMechanismExplore = shouldTryLightMechanismExplore;
|
|
84
118
|
exports.shouldTryFastInventoryExplore = shouldTryFastInventoryExplore;
|
|
85
119
|
exports.shouldBuildInheritanceSurvey = shouldBuildInheritanceSurvey;
|
|
@@ -89,6 +123,8 @@ exports.extractDomainSearchTerms = extractDomainSearchTerms;
|
|
|
89
123
|
exports.queryAsMechanismSurvey = queryAsMechanismSurvey;
|
|
90
124
|
exports.queryAsDomainFileSurvey = queryAsDomainFileSurvey;
|
|
91
125
|
exports.shouldBuildDomainFileSurvey = shouldBuildDomainFileSurvey;
|
|
126
|
+
exports.mechanismDomainPathTokens = mechanismDomainPathTokens;
|
|
127
|
+
exports.isDomainRoleSymbol = isDomainRoleSymbol;
|
|
92
128
|
exports.isImplementationEntrySymbol = isImplementationEntrySymbol;
|
|
93
129
|
exports.shouldCompactImportListing = shouldCompactImportListing;
|
|
94
130
|
exports.shouldLimitToQueryNamedFile = shouldLimitToQueryNamedFile;
|
|
@@ -178,16 +214,36 @@ function extractKitModuleNamesFromQuery(query) {
|
|
|
178
214
|
}
|
|
179
215
|
return [...names];
|
|
180
216
|
}
|
|
181
|
-
/** Submodule tokens from
|
|
217
|
+
/** Submodule / named-export tokens from kit usage questions.
|
|
218
|
+
* Covers `util模块`, `util 模块`, and `@kit.Foo的bar` / `@kit.Foo bar` (export focus).
|
|
219
|
+
*/
|
|
182
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
|
+
]);
|
|
183
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
|
+
};
|
|
184
235
|
for (const m of query.matchAll(/([a-z][a-z0-9_]{1,24})模块/gi)) {
|
|
185
|
-
|
|
186
|
-
names.add(m[1]);
|
|
236
|
+
add(m[1]);
|
|
187
237
|
}
|
|
188
238
|
for (const m of query.matchAll(/\b([a-z][a-z0-9_]*)\s+模块\b/gi)) {
|
|
189
|
-
|
|
190
|
-
|
|
239
|
+
add(m[1]);
|
|
240
|
+
}
|
|
241
|
+
// `@kit.ArkTS的taskpool` / `@kit.ArkTS的 foo` — named export, not a catalog.
|
|
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)) {
|
|
243
|
+
add(m[1]);
|
|
244
|
+
}
|
|
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)) {
|
|
246
|
+
add(m[1]);
|
|
191
247
|
}
|
|
192
248
|
return [...names];
|
|
193
249
|
}
|
|
@@ -198,7 +254,9 @@ function extractKitSubmoduleNamesFromQuery(query) {
|
|
|
198
254
|
function queryAsKitModuleCapabilitySurvey(query) {
|
|
199
255
|
if (extractKitModuleNamesFromQuery(query).length === 0)
|
|
200
256
|
return false;
|
|
201
|
-
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);
|
|
202
260
|
if (!capability)
|
|
203
261
|
return false;
|
|
204
262
|
return /@kit\.|模块|\bkit\b/i.test(query) || extractKitSubmoduleNamesFromQuery(query).length > 0;
|
|
@@ -224,6 +282,29 @@ function isMemberLikeIdentifier(token) {
|
|
|
224
282
|
// camelCase property/method: first lower, later upper
|
|
225
283
|
return /^[a-z][a-zA-Z0-9]*[A-Z]/.test(token);
|
|
226
284
|
}
|
|
285
|
+
/**
|
|
286
|
+
* Owning Type + co-named PascalCase methods (CanPlace/Place ↔ BinaryGrid).
|
|
287
|
+
* Not Type.member dotted form — agents name methods as sibling Types.
|
|
288
|
+
* Must stay on compact explore — 「是怎么」alone would light-mechanism dump.
|
|
289
|
+
*/
|
|
290
|
+
function queryAsCoNamedTypeMethodInteraction(query) {
|
|
291
|
+
// "who calls Type's Set/Test/Fill" is a caller inventory, not body interaction.
|
|
292
|
+
if (queryAsCallerOrMethodSurvey(query))
|
|
293
|
+
return false;
|
|
294
|
+
const types = extractTypeNamesFromQuery(query).filter((t) => !isFrameworkUiDecoratorName(t));
|
|
295
|
+
if (types.length < 2 || types.length > 4)
|
|
296
|
+
return false;
|
|
297
|
+
const owners = types.filter((t) => t.length >= 8
|
|
298
|
+
|| /(?:Grid|Manager|Service|Controller|Render|Plugin|Layout|Handler|Provider|Store)/i.test(t));
|
|
299
|
+
const methods = types.filter((t) => !owners.includes(t));
|
|
300
|
+
if (owners.length < 1 || methods.length < 1)
|
|
301
|
+
return false;
|
|
302
|
+
if (/交互|是怎么|如何.*(?:用|调|连|互)|how\s+(?:do|does|are).{0,48}(?:interact|relate|use|call)|与.+交互|和.+交互/i.test(query)) {
|
|
303
|
+
return true;
|
|
304
|
+
}
|
|
305
|
+
// Method-looking PascalCase co-named with an owner — even without 交互.
|
|
306
|
+
return methods.some((m) => /^(?:Can|Is|Has|Get|Set|Place|Fill|Test|Put|Add|Remove|Update|Draw|Check|Find)/.test(m));
|
|
307
|
+
}
|
|
227
308
|
/**
|
|
228
309
|
* Named Type + member (dot form, or co-named Type + member-like token).
|
|
229
310
|
* Structural — no product/question nouns.
|
|
@@ -231,6 +312,8 @@ function isMemberLikeIdentifier(token) {
|
|
|
231
312
|
function queryHasNamedMemberFocus(query) {
|
|
232
313
|
if (extractMemberAccessFromQuery(query).length > 0)
|
|
233
314
|
return true;
|
|
315
|
+
if (queryAsCoNamedTypeMethodInteraction(query))
|
|
316
|
+
return true;
|
|
234
317
|
const types = extractTypeNamesFromQuery(query);
|
|
235
318
|
if (types.length === 0 || types.length > 3)
|
|
236
319
|
return false;
|
|
@@ -248,21 +331,142 @@ function queryAsNamedComponentAction(query) {
|
|
|
248
331
|
if (!looksUi)
|
|
249
332
|
return false;
|
|
250
333
|
const deps = extractDependencySymbolsFromQuery(query);
|
|
251
|
-
if (deps.some((d) => /^on[A-Z]/.test(d) || /^(click|tap|press)$/i.test(d)))
|
|
334
|
+
if (deps.some((d) => /^on[A-Z]/.test(d) || /^(click|tap|press|hover)$/i.test(d)))
|
|
252
335
|
return true;
|
|
253
336
|
// Optional thin intent — only with a UI-looking Type already present.
|
|
254
|
-
return
|
|
337
|
+
return /点击|单击|按下|按钮|悬停|hover|onClick|onTap|onHover|会发生什么|what\s+happens|when\s+(?:clicked|pressed|hovered)/i.test(query);
|
|
255
338
|
}
|
|
256
339
|
/**
|
|
257
|
-
* 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.
|
|
258
342
|
*/
|
|
259
343
|
function queryAsOutOfRepoSdkCatalog(query) {
|
|
260
344
|
if (queryAsKitModuleCapabilitySurvey(query))
|
|
261
345
|
return true;
|
|
262
|
-
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)
|
|
263
|
-
|
|
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)
|
|
371
|
+
return false;
|
|
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)
|
|
264
403
|
return false;
|
|
265
|
-
return
|
|
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));
|
|
406
|
+
}
|
|
407
|
+
function queryShouldDeferToBuiltinTools(query) {
|
|
408
|
+
const q = query.trim();
|
|
409
|
+
if (!q)
|
|
410
|
+
return null;
|
|
411
|
+
const hasType = extractTypeNamesFromQuery(q).length > 0;
|
|
412
|
+
const hasFile = extractFileBasenamesFromQuery(q).length > 0;
|
|
413
|
+
const hasMember = extractMemberAccessFromQuery(q).length > 0;
|
|
414
|
+
const hasKit = /@kit\.|@ohos\./i.test(q);
|
|
415
|
+
const hasCaps = /\b[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+\b/.test(q);
|
|
416
|
+
const hasField = extractFieldLikeSymbolsFromQuery(q).length > 0;
|
|
417
|
+
const hasPath = extractPathSegmentsFromQuery(q).length > 0;
|
|
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.
|
|
439
|
+
if (!hasType
|
|
440
|
+
&& !hasFile
|
|
441
|
+
&& /哪些文件|有哪些.*文件|相关的?\s*文件|涉及.*文件|which\s+files?|files?\s+(?:are\s+)?related/i.test(q)) {
|
|
442
|
+
return 'file-listing';
|
|
443
|
+
}
|
|
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)) {
|
|
447
|
+
return 'concept-or-existence';
|
|
448
|
+
}
|
|
449
|
+
return null;
|
|
450
|
+
}
|
|
451
|
+
/** Short success-shaped reply when explore/search should not run. */
|
|
452
|
+
function homegraphDeferGuidance(kind, query) {
|
|
453
|
+
const q = query.trim().slice(0, 120);
|
|
454
|
+
const reasons = {
|
|
455
|
+
'file-listing': 'Topic → file lists need Grep/Glob (keyword paths), not the symbol graph.',
|
|
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.',
|
|
463
|
+
};
|
|
464
|
+
return [
|
|
465
|
+
'Skip HomeGraph for this question shape — do **not** retry any `homegraph_*` tool for it.',
|
|
466
|
+
reasons[kind],
|
|
467
|
+
`Query: "${q}${query.trim().length > 120 ? '…' : ''}"`,
|
|
468
|
+
'Next: Grep / Glob / Read / git / SDK docs / project generators as appropriate. Otherwise call `homegraph_explore` with the task or symbol names.',
|
|
469
|
+
].join('\n');
|
|
266
470
|
}
|
|
267
471
|
/**
|
|
268
472
|
* Question already names files/symbols/@kit — prefer explore over FTS search.
|
|
@@ -271,17 +475,97 @@ function queryShouldPreferExploreOverSearch(query) {
|
|
|
271
475
|
const q = query.trim();
|
|
272
476
|
if (!q)
|
|
273
477
|
return false;
|
|
478
|
+
if (queryLooksLikeLiteralOrCopyHunt(query) && !queryAsCodeChangeOrientation(query))
|
|
479
|
+
return false;
|
|
480
|
+
if (queryAsCodeChangeOrientation(query))
|
|
481
|
+
return true;
|
|
274
482
|
if (/^[A-Za-z_][\w]*$/.test(q))
|
|
275
483
|
return true;
|
|
276
484
|
if (extractFileBasenamesFromQuery(query).length > 0
|
|
277
485
|
|| extractTypeNamesFromQuery(query).length > 0
|
|
278
486
|
|| extractMemberAccessFromQuery(query).length > 0
|
|
279
487
|
|| extractImportSearchTerms(query).length > 0
|
|
280
|
-
|| extractKitModuleNamesFromQuery(query).length > 0
|
|
488
|
+
|| extractKitModuleNamesFromQuery(query).length > 0
|
|
489
|
+
|| extractFieldLikeSymbolsFromQuery(query).length > 0
|
|
490
|
+
|| queryAsConstantUsageSurvey(query)
|
|
491
|
+
|| queryAsDeclarationSiteSurvey(query)
|
|
492
|
+
|| queryAsFieldUsageSurvey(query)
|
|
493
|
+
|| queryAsModuleExportSurvey(query)
|
|
494
|
+
|| queryAsModuleDependencySurvey(query)
|
|
495
|
+
|| queryAsDtsWrapSurvey(query)
|
|
496
|
+
|| shouldBuildApiUsageSurvey(query)
|
|
497
|
+
|| queryAsAssignedFlagImpactSurvey(query)
|
|
498
|
+
|| queryAsNativeRenderThreadSurvey(query)
|
|
499
|
+
|| queryAsInRepoSystemCapabilityHowto(query)
|
|
500
|
+
|| shouldBuildHoverHandlerSurvey(query)
|
|
501
|
+
|| queryAsDataSourceSurvey(query)
|
|
502
|
+
|| queryAsksKitInstallDeps(query)
|
|
503
|
+
|| queryAsTypeLifecycleSurvey(query)
|
|
504
|
+
|| shouldBuildCallerInventory(query)) {
|
|
281
505
|
return true;
|
|
282
506
|
}
|
|
283
507
|
return extractDependencySymbolsFromQuery(query).some((d) => isDistinctiveIdentifier(d));
|
|
284
508
|
}
|
|
509
|
+
/**
|
|
510
|
+
* In-repo pointer/hover handler inventory — no named Type yet, but the graph
|
|
511
|
+
* still has onHover / Hover* symbols. Soft-skip→Grep lost accuracy; inventory wins.
|
|
512
|
+
*/
|
|
513
|
+
function shouldBuildHoverHandlerSurvey(query) {
|
|
514
|
+
if (extractTypeNamesFromQuery(query).length > 0)
|
|
515
|
+
return false;
|
|
516
|
+
if (extractMemberAccessFromQuery(query).length > 0)
|
|
517
|
+
return false;
|
|
518
|
+
if (queryAsNamedComponentAction(query))
|
|
519
|
+
return false;
|
|
520
|
+
return /悬停|\bhover\b|onHover|hoverEffect|HoverAnimation|HoverConstants/i.test(query);
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Framework decorator / ambient UI names — agents paste `@CustomDialog` etc.
|
|
524
|
+
* Keep real *Page/*Dialog types; drop these when counting UI surfaces / anchors.
|
|
525
|
+
*/
|
|
526
|
+
exports.FRAMEWORK_UI_DECORATOR_NAMES = new Set([
|
|
527
|
+
'customdialog', 'component', 'entry', 'builder', 'preview', 'observed', 'observable',
|
|
528
|
+
'state', 'prop', 'link', 'objectlink', 'provide', 'consume', 'watch', 'builderparam',
|
|
529
|
+
]);
|
|
530
|
+
function isFrameworkUiDecoratorName(name) {
|
|
531
|
+
return exports.FRAMEWORK_UI_DECORATOR_NAMES.has(name.toLowerCase());
|
|
532
|
+
}
|
|
533
|
+
/** PascalCase names that look like UI surfaces (Page / View / … / ThemeHome). */
|
|
534
|
+
function queryLooksLikeUiComponentType(name) {
|
|
535
|
+
// `@CustomDialog` / bare `Component` match the suffix regex but are not app Types.
|
|
536
|
+
if (isFrameworkUiDecoratorName(name))
|
|
537
|
+
return false;
|
|
538
|
+
return /(Button|Component|View|Page|Dialog|Bar|Item|Panel|Menu|Chip|Card|Home)$/i.test(name);
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
541
|
+
* 2–3 concrete UI Types named together (Page+Dialog, View+Panel, …).
|
|
542
|
+
* Must stay on compact explore — full findRelevantContext is a 15–30k / multi-minute
|
|
543
|
+
* dump for what is a local composition / resource question.
|
|
544
|
+
*/
|
|
545
|
+
function queryAsFocusedUiCluster(query) {
|
|
546
|
+
if (queryAsMechanismSurvey(query) || queryAsCrossModuleFlowSurvey(query))
|
|
547
|
+
return false;
|
|
548
|
+
const types = extractTypeNamesFromQuery(query).filter((t) => queryLooksLikeUiComponentType(t) && !isFrameworkUiDecoratorName(t));
|
|
549
|
+
return types.length >= 2 && types.length <= 3;
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Named Page/Component overview: which UI children / where does it navigate /
|
|
553
|
+
* how does Page embed Dialog. Needs component bodies, not full-graph explore.
|
|
554
|
+
*/
|
|
555
|
+
function queryAsComponentSurfaceSurvey(query) {
|
|
556
|
+
if (queryAsFocusedUiCluster(query))
|
|
557
|
+
return true;
|
|
558
|
+
const types = extractTypeNamesFromQuery(query).filter((t) => !isFrameworkUiDecoratorName(t));
|
|
559
|
+
if (types.length < 1 || types.length > 3)
|
|
560
|
+
return false;
|
|
561
|
+
if (!types.some(queryLooksLikeUiComponentType))
|
|
562
|
+
return false;
|
|
563
|
+
if (/使用了哪些|哪些UI|哪些组件|UI组件|跳转到|可以跳转|内嵌|嵌入|preview|加载|page\s+navigation|which\s+(?:ui\s+)?components|navigat|embed/i.test(query)) {
|
|
564
|
+
return true;
|
|
565
|
+
}
|
|
566
|
+
// Bare / near-bare `ThemeHome` / `FooPage` — agents search("ThemeHome") for overview.
|
|
567
|
+
return queryIsTypeNameFocus(query);
|
|
568
|
+
}
|
|
285
569
|
/**
|
|
286
570
|
* In-repo kit/import **usage** inventory (call sites / which files import).
|
|
287
571
|
*/
|
|
@@ -292,11 +576,23 @@ function shouldBuildKitModuleUsageSurvey(query) {
|
|
|
292
576
|
&& extractImportSearchTerms(query).length === 0) {
|
|
293
577
|
return false;
|
|
294
578
|
}
|
|
295
|
-
return /依赖|引用|哪里用|哪些代码|哪里调用|哪些.*(?:依赖|引用|使用)|import\s+sites?|usages?\b|\buses\b|call\s*sites?/i.test(query)
|
|
579
|
+
return (/依赖|引用|哪里用|哪些代码|哪里调用|哪些.*(?:依赖|引用|使用)|import\s+sites?|usages?\b|\buses\b|call\s*sites?/i.test(query)
|
|
580
|
+
// "调用 Kit 需要额外安装哪些依赖 / how to install deps for Kit"
|
|
581
|
+
|| queryAsksKitInstallDeps(query));
|
|
582
|
+
}
|
|
583
|
+
/** "需要额外安装哪些依赖" — kit survey must include oh-package, not only imports. */
|
|
584
|
+
function queryAsksKitInstallDeps(query) {
|
|
585
|
+
return (/额外安装|还需.*依赖|需要.*依赖|引入.*依赖|其他参数和依赖|other\s+(?:params?.{0,24})?deps?/i.test(query)
|
|
586
|
+
|| /install(?:ing)?\s+(?:extra\s+)?deps?|which\s+deps?|need(?:s)?\s+(?:other\s+)?deps?/i.test(query));
|
|
296
587
|
}
|
|
297
588
|
/**
|
|
298
589
|
* Member-access patterns from a query — `obj.method`, `Type.method`, or `.member`.
|
|
590
|
+
* Skips `@kit.X` / `@ohos.X` module paths (those are imports, not Type.member).
|
|
299
591
|
*/
|
|
592
|
+
/** Shared-object / binary suffixes — not Type.member (libfoo.so → member "so"). */
|
|
593
|
+
const FILE_EXT_MEMBER_NOISE = new Set([
|
|
594
|
+
'so', 'dll', 'dylib', 'a', 'lib', 'exe', 'apk', 'hap', 'bin', 'wasm', 'o', 'obj',
|
|
595
|
+
]);
|
|
300
596
|
function extractMemberAccessFromQuery(query) {
|
|
301
597
|
const results = [];
|
|
302
598
|
const seen = new Set();
|
|
@@ -304,12 +600,21 @@ function extractMemberAccessFromQuery(query) {
|
|
|
304
600
|
const dotted = m[1];
|
|
305
601
|
if (!dotted || seen.has(dotted))
|
|
306
602
|
continue;
|
|
603
|
+
const idx = m.index ?? 0;
|
|
604
|
+
// `@kit.ArkTS` / `@ohos.foo` — module specifier, not receiver.member
|
|
605
|
+
if (idx > 0 && query[idx - 1] === '@')
|
|
606
|
+
continue;
|
|
607
|
+
if (/^(?:kit|ohos)\./i.test(dotted))
|
|
608
|
+
continue;
|
|
307
609
|
const parts = dotted.split('.');
|
|
308
610
|
if (parts.length < 2)
|
|
309
611
|
continue;
|
|
310
612
|
const member = parts[parts.length - 1];
|
|
311
613
|
if (member.length < 2)
|
|
312
614
|
continue;
|
|
615
|
+
// `libeffectrender.so` / `foo.dll` — not a member access.
|
|
616
|
+
if (FILE_EXT_MEMBER_NOISE.has(member.toLowerCase()))
|
|
617
|
+
continue;
|
|
313
618
|
seen.add(dotted);
|
|
314
619
|
results.push({
|
|
315
620
|
receiver: parts.slice(0, -1).join('.'),
|
|
@@ -319,12 +624,29 @@ function extractMemberAccessFromQuery(query) {
|
|
|
319
624
|
}
|
|
320
625
|
for (const m of query.matchAll(/\.([A-Za-z_][\w]*)\b/g)) {
|
|
321
626
|
const member = m[1];
|
|
627
|
+
const idx = m.index ?? 0;
|
|
628
|
+
// Skip the `.X` inside `@kit.X` / `@ohos.X`
|
|
629
|
+
const before = query.slice(0, idx);
|
|
630
|
+
if (/@(?:kit|ohos)$/i.test(before))
|
|
631
|
+
continue;
|
|
632
|
+
if (FILE_EXT_MEMBER_NOISE.has(member.toLowerCase()))
|
|
633
|
+
continue;
|
|
322
634
|
const dotted = `.${member}`;
|
|
323
635
|
if (seen.has(dotted))
|
|
324
636
|
continue;
|
|
325
637
|
seen.add(dotted);
|
|
326
638
|
results.push({ member, dotted });
|
|
327
639
|
}
|
|
640
|
+
// C++ / ArkTS qualified `Type::method` — same shape as dotted member access.
|
|
641
|
+
for (const m of query.matchAll(/\b([A-Za-z_][\w]*)::([A-Za-z_][\w]*)\b/g)) {
|
|
642
|
+
const receiver = m[1];
|
|
643
|
+
const member = m[2];
|
|
644
|
+
const dotted = `${receiver}::${member}`;
|
|
645
|
+
if (seen.has(dotted) || member.length < 2)
|
|
646
|
+
continue;
|
|
647
|
+
seen.add(dotted);
|
|
648
|
+
results.push({ receiver, member, dotted });
|
|
649
|
+
}
|
|
328
650
|
return results;
|
|
329
651
|
}
|
|
330
652
|
/** Terms for targeted import-node FTS (kit modules and their @kit.* paths). */
|
|
@@ -436,22 +758,61 @@ exports.STOP_WORDS = new Set([
|
|
|
436
758
|
* Lowercase API / import symbol names in a dependency question (taskpool, formInfo).
|
|
437
759
|
* Used to filter import sites to the symbol actually asked about, not every @kit.ArkTS import.
|
|
438
760
|
*/
|
|
761
|
+
/**
|
|
762
|
+
* Generic verbs agents put in rewritten how-implemented bags ("xml parse").
|
|
763
|
+
* Not useful as dependency/import inventory filters or local-detail anchors —
|
|
764
|
+
* they match every `parse`/`load` method and drown the distinctive token (xml).
|
|
765
|
+
*/
|
|
766
|
+
exports.GENERIC_VERB_ANCHOR_NOISE = new Set([
|
|
767
|
+
'parse', 'parsing', 'load', 'save', 'read', 'write', 'update', 'delete', 'create',
|
|
768
|
+
'init', 'handle', 'process', 'run', 'start', 'stop', 'open', 'close', 'convert',
|
|
769
|
+
'get', 'set', 'add', 'remove', 'list', 'show', 'find',
|
|
770
|
+
// Lifetime / allocator verbs — agents ask "where new/delete" and these must not
|
|
771
|
+
// become explore seeds (AnimateEx.new / RdbStoreHelper.delete).
|
|
772
|
+
'new', 'pointer', 'alloc', 'allocate', 'dealloc', 'deallocate', 'free', 'release',
|
|
773
|
+
// Inventory / NL fillers agents leave in rewritten bags (not real symbols).
|
|
774
|
+
'usage', 'usages', 'use', 'uses', 'using', 'api', 'apis', 'endpoint', 'endpoints',
|
|
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',
|
|
788
|
+
// Shared-lib / GL thread NL leftovers (not symbols).
|
|
789
|
+
'context', 'opengl', 'gles', 'glesv3', 'egl',
|
|
790
|
+
]);
|
|
439
791
|
function extractDependencySymbolsFromQuery(query) {
|
|
440
792
|
const symbols = new Set();
|
|
441
793
|
for (const ma of extractMemberAccessFromQuery(query)) {
|
|
442
794
|
if (ma.member.length >= 3 && !exports.STOP_WORDS.has(ma.member.toLowerCase())) {
|
|
443
|
-
|
|
795
|
+
if (!exports.GENERIC_VERB_ANCHOR_NOISE.has(ma.member.toLowerCase()))
|
|
796
|
+
symbols.add(ma.member);
|
|
444
797
|
}
|
|
445
798
|
}
|
|
446
|
-
for (const
|
|
799
|
+
for (const f of extractFieldLikeSymbolsFromQuery(query))
|
|
800
|
+
symbols.add(f);
|
|
801
|
+
// ≥3-char lowercase tokens (includes xml); drop generic verbs.
|
|
802
|
+
for (const m of query.matchAll(/\b([a-z][a-zA-Z0-9]{2,})\b/g)) {
|
|
447
803
|
const sym = m[1];
|
|
448
|
-
if (
|
|
449
|
-
|
|
804
|
+
if (exports.STOP_WORDS.has(sym.toLowerCase()))
|
|
805
|
+
continue;
|
|
806
|
+
if (exports.GENERIC_VERB_ANCHOR_NOISE.has(sym.toLowerCase()))
|
|
807
|
+
continue;
|
|
808
|
+
symbols.add(sym);
|
|
450
809
|
}
|
|
451
810
|
// Lowercase API tokens (statfs, napi_wrap) when the query is clearly about code.
|
|
452
811
|
if (queryMentionsCodeContext(query)) {
|
|
453
812
|
for (const m of query.matchAll(/\b([a-z][a-z0-9_]{4,})\b/g)) {
|
|
454
813
|
const sym = m[1];
|
|
814
|
+
if (exports.GENERIC_VERB_ANCHOR_NOISE.has(sym))
|
|
815
|
+
continue;
|
|
455
816
|
if (!exports.STOP_WORDS.has(sym) && isDistinctiveIdentifier(sym))
|
|
456
817
|
symbols.add(sym);
|
|
457
818
|
else if (!exports.STOP_WORDS.has(sym) && sym.length >= 6)
|
|
@@ -495,7 +856,273 @@ function hasImportInventoryFilter(query) {
|
|
|
495
856
|
}
|
|
496
857
|
/** Where-is-API-used / call-site intent (statfs, snake_case APIs, "哪里使用了 X"). */
|
|
497
858
|
function queryAsApiUsageSurvey(query) {
|
|
498
|
-
return (/哪里使用|何处使用|哪些地方使用|在哪里使用|什么地方使用|项目中.*使用|使用了.*API|API端点|调用.*API
|
|
859
|
+
return (/哪里使用|何处使用|哪些地方使用|在哪里使用|什么地方使用|项目中.*使用|使用了.*API|API端点|调用.*API|使用了哪些调用|哪些调用方法|调用方法|使用了哪些方法|哪些组件使用|哪些.*使用了|使用了\s*\.|自定义绘制|where\s+(?:is|are).+(?:used|called)|which\s+(?:files?|code|components?)\s+(?:use|call)/i.test(query)
|
|
860
|
+
// Agent rewrites (Telephony API usages / call methods in the project).
|
|
861
|
+
|| /\bAPI\s+usages?\b/i.test(query)
|
|
862
|
+
|| /\busages?\s+(?:of|for|in)\b/i.test(query)
|
|
863
|
+
|| /\bcall\s+methods?\b/i.test(query)
|
|
864
|
+
|| /\b(?:used|called)\s+(?:methods?|APIs?)\b/i.test(query)
|
|
865
|
+
|| /\bin(?:\s+the)?\s+project\b.{0,40}\b(?:API|usages?|methods?|calls?)\b/i.test(query)
|
|
866
|
+
|| /\b(?:API|usages?|methods?|calls?)\b.{0,40}\bin(?:\s+the)?\s+project\b/i.test(query));
|
|
867
|
+
}
|
|
868
|
+
/**
|
|
869
|
+
* Member / field symbols agents paste for cross-file usage hunts (`m_eglMutex`,
|
|
870
|
+
* `drawModifier`). Distinct from PascalCase Types.
|
|
871
|
+
*/
|
|
872
|
+
function extractFieldLikeSymbolsFromQuery(query) {
|
|
873
|
+
const out = new Set();
|
|
874
|
+
for (const m of query.matchAll(/\b(m_[A-Za-z][\w]{2,})\b/g)) {
|
|
875
|
+
if (m[1])
|
|
876
|
+
out.add(m[1]);
|
|
877
|
+
}
|
|
878
|
+
for (const m of query.matchAll(/\b([A-Za-z][\w]*(?:Mutex|Lock))\b/g)) {
|
|
879
|
+
if (m[1] && m[1].length >= 4)
|
|
880
|
+
out.add(m[1]);
|
|
881
|
+
}
|
|
882
|
+
return [...out];
|
|
883
|
+
}
|
|
884
|
+
/** Named Type + declaration / id / native-binding sites across files. */
|
|
885
|
+
function queryAsDeclarationSiteSurvey(query) {
|
|
886
|
+
const types = extractTypeNamesFromQuery(query).filter((t) => !isFrameworkUiDecoratorName(t));
|
|
887
|
+
if (types.length < 1 || types.length > 3)
|
|
888
|
+
return false;
|
|
889
|
+
return (/在哪些文件|哪些文件.*(?:声明|定义|出现)|被声明|声明了|id\s*分别|各自绑定|绑定到|which\s+files?.{0,80}(?:declar|defin|appear)|where\s+(?:is|are).{0,40}declar/i.test(query)
|
|
890
|
+
// Agent English rewrites: "XComponent declaration id native render binding"
|
|
891
|
+
|| /\bdeclarations?\b/i.test(query)
|
|
892
|
+
|| /\bdeclared\b/i.test(query)
|
|
893
|
+
|| (/\bids?\b/i.test(query) && /\b(?:bind|binding|native|renderer|xcomponent)\b/i.test(query)));
|
|
894
|
+
}
|
|
895
|
+
/**
|
|
896
|
+
* How-to get a system setting/capability *as used in this repo* (language/locale/…).
|
|
897
|
+
* Must NOT become a light-mechanism dump of every `language` import.
|
|
898
|
+
*/
|
|
899
|
+
function queryAsInRepoSystemCapabilityHowto(query) {
|
|
900
|
+
if (extractTypeNamesFromQuery(query).some((t) => /Manager|Service|Controller/i.test(t))) {
|
|
901
|
+
// Named Manager data-source / lifecycle owns those questions.
|
|
902
|
+
if (queryAsDataSourceSurvey(query) || queryAsTypeLifecycleSurvey(query))
|
|
903
|
+
return false;
|
|
904
|
+
}
|
|
905
|
+
return (/如何获取系统|怎样获取系统|怎么获取系统|获取系统当前|系统当前设置|系统.*语言|当前设置的语言/i.test(query)
|
|
906
|
+
|| /how\s+to\s+get\s+(?:the\s+)?system\s+(?:language|locale|setting)/i.test(query)
|
|
907
|
+
|| (/\b(?:language|locale|i18n)\b/i.test(query)
|
|
908
|
+
&& /(?:获取|当前设置|get\s+system|system\s+(?:language|locale))/i.test(query)));
|
|
909
|
+
}
|
|
910
|
+
/**
|
|
911
|
+
* "Who uses the return value of Type.member / fn" — callers of the member, not a
|
|
912
|
+
* create→get flow dump or an import flood on leftover words like `state`.
|
|
913
|
+
*/
|
|
914
|
+
function queryAsReturnValueConsumerSurvey(query) {
|
|
915
|
+
const hasMember = extractMemberAccessFromQuery(query).length > 0
|
|
916
|
+
|| extractLocalDetailAnchors(query).some((n) => isMemberLikeIdentifier(n));
|
|
917
|
+
if (!hasMember && extractTypeNamesFromQuery(query).length === 0)
|
|
918
|
+
return false;
|
|
919
|
+
return (/返回结果被|返回值.*(?:被|由).*(?:使用|调用)|其返回.*使用|返回结果.*哪些/i.test(query)
|
|
920
|
+
|| /who\s+uses\s+the\s+(?:return|result)|return(?:ed)?\s+(?:value|result).{0,80}(?:used|consum)/i.test(query)
|
|
921
|
+
|| /哪些其他函数使用|被项目中哪些.{0,20}函数使用|which\s+(?:other\s+)?functions?\s+use/i.test(query));
|
|
922
|
+
}
|
|
923
|
+
/** ALL_CAPS constants — where used / which scenarios (not "what does this macro mean"). */
|
|
924
|
+
function queryAsConstantUsageSurvey(query) {
|
|
925
|
+
const caps = [...query.matchAll(/\b([A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+)\b/g)].map((m) => m[1]);
|
|
926
|
+
// Enum-style `Type.MEMBER` / `audio.Type.RINGTONE` — ALL_CAPS member (with or without `_`).
|
|
927
|
+
const dottedCaps = [
|
|
928
|
+
...query.matchAll(/\.[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)*\b/g),
|
|
929
|
+
]
|
|
930
|
+
.map((m) => m[0].slice(1))
|
|
931
|
+
.filter((s) => s === s.toUpperCase() && s.length >= 3);
|
|
932
|
+
const all = [...new Set([...caps, ...dottedCaps])];
|
|
933
|
+
if (all.length === 0)
|
|
934
|
+
return false;
|
|
935
|
+
return /用于|场景|哪里用|哪些.*用|依赖|调用|where\s+(?:is|are).+used|which\s+(?:scenarios?|functions?)|what\s+(?:are\s+)?(?:they|these)\s+for|which\s+methods?.{0,20}(?:call|depend)/i.test(query);
|
|
936
|
+
}
|
|
937
|
+
/** Field / mutex / lock — which other functions also touch it. */
|
|
938
|
+
function queryAsFieldUsageSurvey(query) {
|
|
939
|
+
if (extractFieldLikeSymbolsFromQuery(query).length === 0)
|
|
940
|
+
return false;
|
|
941
|
+
return (/哪些函数|还会用到|用到这个|哪些.*(?:用到|使用)|who\s+(?:else\s+)?(?:uses|locks)|which\s+functions?.{0,40}(?:use|lock|mutex)|\bmutex\b|这[个把]锁/i.test(query)
|
|
942
|
+
// Lifetime: where is m_foo new'd / delete'd / freed.
|
|
943
|
+
|| /new\s*出来|被\s*new|delete\s*掉|被\s*delete|new\s*\/\s*delete|(?:哪里|哪些地方).{0,12}(?:new|delete)|(?:new|delete).{0,20}(?:哪里|哪些)|被释放|释放掉|allocat|deallocat|where.{0,40}(?:new|delete|allocat|free)/i.test(query));
|
|
944
|
+
}
|
|
945
|
+
/**
|
|
946
|
+
* Native shared lib + GL/EGL thread questions (`libfoo.so` … OpenGL … 哪个线程).
|
|
947
|
+
* Light-mechanism (CMake + named Draw/Render/EGL owners), not `.so` member survey.
|
|
948
|
+
*/
|
|
949
|
+
function queryAsNativeRenderThreadSurvey(query) {
|
|
950
|
+
const hasLib = /\b\w+\.(?:so|dll|dylib)\b/i.test(query)
|
|
951
|
+
|| /\blib\w+\b/i.test(query);
|
|
952
|
+
const hasGl = /\b(?:GLES(?:v3)?|EGL|OpenGL)\b/i.test(query);
|
|
953
|
+
const hasThread = /线程|thread|UI\s*线程|主线程|JS\s*主?线程/i.test(query);
|
|
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;
|
|
962
|
+
}
|
|
963
|
+
/** Named `.d.ts` wrap — what calls / imports it in-repo. */
|
|
964
|
+
function queryAsDtsWrapSurvey(query) {
|
|
965
|
+
if (!/\.d\.ts\b/i.test(query) && extractFileBasenamesFromQuery(query).length === 0) {
|
|
966
|
+
return false;
|
|
967
|
+
}
|
|
968
|
+
if (!/\.d\.ts\b/i.test(query))
|
|
969
|
+
return false;
|
|
970
|
+
return /封装|wrap(?:s|ped)?|调用|哪里|功能|where|called|uses?|import/i.test(query);
|
|
971
|
+
}
|
|
972
|
+
/**
|
|
973
|
+
* Assigned flag / boolean field impact on later call timing
|
|
974
|
+
* (`isChangeSurface = true` … 如何影响 … 时序).
|
|
975
|
+
*/
|
|
976
|
+
function queryAsAssignedFlagImpactSurvey(query) {
|
|
977
|
+
const hasAssign = /=\s*(?:true|false)\b/i.test(query)
|
|
978
|
+
|| /设置\s*\w+.*=/.test(query)
|
|
979
|
+
|| /里设置\s+\w+/i.test(query)
|
|
980
|
+
|| /\bsets?\s+\w+\s*=\s*(?:true|false)\b/i.test(query);
|
|
981
|
+
const hasImpact = /影响|时序|后续|how\s+(?:does|will).{0,40}affect|affect.{0,40}timing/i.test(query);
|
|
982
|
+
if (!hasAssign || !hasImpact)
|
|
983
|
+
return false;
|
|
984
|
+
return extractLocalDetailAnchors(query).length >= 1;
|
|
985
|
+
}
|
|
986
|
+
/**
|
|
987
|
+
* Named Toggle/control kept consistent across surfaces — which module guarantees it.
|
|
988
|
+
*/
|
|
989
|
+
function queryAsNamedControlStateSyncSurvey(query) {
|
|
990
|
+
// Prefer Toggle/Switch anchors — bag-of-words rewrites often add Control/Center noise Types.
|
|
991
|
+
const types = extractTypeNamesFromQuery(query).filter((t) => !isFrameworkUiDecoratorName(t));
|
|
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)
|
|
995
|
+
return false;
|
|
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)));
|
|
999
|
+
}
|
|
1000
|
+
/**
|
|
1001
|
+
* Methods listed beside a Type for caller inventories
|
|
1002
|
+
* (`BinaryGrid … Set、Test 或 Fill` — including short verbs normally treated as noise).
|
|
1003
|
+
*/
|
|
1004
|
+
function extractListedTypeMethodsFromQuery(query) {
|
|
1005
|
+
if (!queryAsCallerOrMethodSurvey(query))
|
|
1006
|
+
return [];
|
|
1007
|
+
const types = extractTypeNamesFromQuery(query);
|
|
1008
|
+
if (types.length === 0)
|
|
1009
|
+
return [];
|
|
1010
|
+
// Owning Type(s): longer CamelCase — short Set/Test/Fill are method tokens, not owners.
|
|
1011
|
+
const owners = new Set(types.filter((t) => t.length >= 6 || /(?:Grid|Manager|Service|Controller|Render|Plugin|Layout)/i.test(t)));
|
|
1012
|
+
if (owners.size === 0) {
|
|
1013
|
+
// Fall back to longest type name as owner.
|
|
1014
|
+
const longest = [...types].sort((a, b) => b.length - a.length)[0];
|
|
1015
|
+
if (longest)
|
|
1016
|
+
owners.add(longest);
|
|
1017
|
+
}
|
|
1018
|
+
const out = new Set();
|
|
1019
|
+
// `Set、Test 或 Fill` / `Set, Test, or Fill` — list of PascalCase methods.
|
|
1020
|
+
for (const m of query.matchAll(/\b([A-Z][A-Za-z0-9]{1,})(?:\s*[、,]\s*([A-Z][A-Za-z0-9]{1,}))+(?:\s*(?:或|or)\s*([A-Z][A-Za-z0-9]{1,}))?/g)) {
|
|
1021
|
+
for (let i = 1; i < m.length; i++) {
|
|
1022
|
+
const name = m[i];
|
|
1023
|
+
if (name && !owners.has(name) && name.length >= 2)
|
|
1024
|
+
out.add(name);
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
// `的 Set` / `methods Set` / `调用了 Set` (owner already required above).
|
|
1028
|
+
for (const m of query.matchAll(/(?:的|of|模板类的|类的|methods?)\s+([A-Z][A-Za-z0-9]{1,})\b/g)) {
|
|
1029
|
+
const name = m[1];
|
|
1030
|
+
if (!owners.has(name) && name.length >= 2)
|
|
1031
|
+
out.add(name);
|
|
1032
|
+
}
|
|
1033
|
+
return [...out].slice(0, 8);
|
|
1034
|
+
}
|
|
1035
|
+
/** Path module + NAPI / exported API surface (or named Type + NAPI/expose). */
|
|
1036
|
+
function queryAsModuleExportSurvey(query) {
|
|
1037
|
+
const napi = /NAPI|napi|暴露了哪些|暴露哪些|暴露给|expose(?:d|s)?\s+to|napi_module_register|哪些\s*API|API\s*接口|exports?\s+(?:which|what)|which\s+(?:APIs?|exports?)/i.test(query);
|
|
1038
|
+
if (!napi)
|
|
1039
|
+
return false;
|
|
1040
|
+
if (extractPathSegmentsFromQuery(query).length > 0)
|
|
1041
|
+
return true;
|
|
1042
|
+
// "LayoutRotatePacking … NAPI expose to ArkTS" — no path segment required.
|
|
1043
|
+
if (extractTypeNamesFromQuery(query).length > 0)
|
|
1044
|
+
return true;
|
|
1045
|
+
return false;
|
|
1046
|
+
}
|
|
1047
|
+
/** Multi-module path interdependence (A/B/C… mutual deps). */
|
|
1048
|
+
function queryAsModuleDependencySurvey(query) {
|
|
1049
|
+
const paths = extractPathSegmentsFromQuery(query);
|
|
1050
|
+
const moduleTokens = query.match(/\b[A-Za-z][\w]*(?:common|service|component|constants)\b/gi) ?? [];
|
|
1051
|
+
const circular = /循环依赖|circular\s+depend|互为依赖/i.test(query);
|
|
1052
|
+
// "commonconstants … 循环依赖" — one module token + cycle intent is enough.
|
|
1053
|
+
if (circular && (paths.length + moduleTokens.length >= 1 || /\b[a-z][a-z0-9_]{5,}\b/.test(query))) {
|
|
1054
|
+
return true;
|
|
1055
|
+
}
|
|
1056
|
+
if (paths.length + moduleTokens.length < 2)
|
|
1057
|
+
return false;
|
|
1058
|
+
return /相互依赖|互相依赖|之间.*依赖|依赖关系|depend(?:ency|encies| on each other)|cross-?depend/i.test(query);
|
|
1059
|
+
}
|
|
1060
|
+
/**
|
|
1061
|
+
* Single named Type + state/lifecycle/callback surface — needs the type body,
|
|
1062
|
+
* not a thin callers stub.
|
|
1063
|
+
*/
|
|
1064
|
+
/**
|
|
1065
|
+
* Repo-wide literal / copy / "imported text object" hunts — Grep territory.
|
|
1066
|
+
* Shape-only: no PascalCase Type / file / member / kit anchors.
|
|
1067
|
+
*/
|
|
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
|
+
}
|
|
1079
|
+
if (extractTypeNamesFromQuery(query).length > 0)
|
|
1080
|
+
return false;
|
|
1081
|
+
if (extractFileBasenamesFromQuery(query).length > 0)
|
|
1082
|
+
return false;
|
|
1083
|
+
if (extractMemberAccessFromQuery(query).length > 0)
|
|
1084
|
+
return false;
|
|
1085
|
+
if (extractKitModuleNamesFromQuery(query).length > 0)
|
|
1086
|
+
return false;
|
|
1087
|
+
if (extractFieldLikeSymbolsFromQuery(query).length > 0)
|
|
1088
|
+
return false;
|
|
1089
|
+
return (/全仓|全搜|字面量|中文\s*(?:text|字符串)|绑了.*(?:text|文案)|literal\s+strings?/i.test(query)
|
|
1090
|
+
|| /从.{0,16}包.{0,40}(?:导入|import).{0,20}\btext\b|导入的\s*text\s*对象|imported\s+text\s+objects?/i.test(query));
|
|
1091
|
+
}
|
|
1092
|
+
function queryAsTypeLifecycleSurvey(query) {
|
|
1093
|
+
if (queryAsCrossModuleFlowSurvey(query))
|
|
1094
|
+
return false;
|
|
1095
|
+
// "状态来源" is a data-source inventory, not a lifecycle body dump.
|
|
1096
|
+
if (/状态来源|status\s+source|state\s+source/i.test(query))
|
|
1097
|
+
return false;
|
|
1098
|
+
// Release ↔ destructor compare may name CB + Manager + Render.
|
|
1099
|
+
if (/析构|destructor/i.test(query)
|
|
1100
|
+
&& /Release|做了哪些|有没有重复|跟.+做的事|same\s+(?:work|things?)|overlap/i.test(query)) {
|
|
1101
|
+
return extractLocalDetailAnchors(query).length >= 1;
|
|
1102
|
+
}
|
|
1103
|
+
const types = extractTypeNamesFromQuery(query).filter((t) => !isFrameworkUiDecoratorName(t));
|
|
1104
|
+
if (types.length < 1 || types.length > 2)
|
|
1105
|
+
return false;
|
|
1106
|
+
return /状态机|状态变化|状态转换|状态.*回调|回调.*状态|foreground|background|lifecycle|state\s*machine|哪些状态|state\s+change|how\s+(?:are|is)\s+.+states?\s+(?:unified|distinguished)/i.test(query);
|
|
1107
|
+
}
|
|
1108
|
+
/**
|
|
1109
|
+
* Member-access inventory ("which files use .drawModifier") — not Type×method
|
|
1110
|
+
* interaction / Export fail wiring / Release↔dtor (those need compact bodies).
|
|
1111
|
+
*/
|
|
1112
|
+
function shouldPreferMemberUsageInventory(query) {
|
|
1113
|
+
if (queryAsCoNamedTypeMethodInteraction(query))
|
|
1114
|
+
return false;
|
|
1115
|
+
if (queryAsTypeLifecycleSurvey(query))
|
|
1116
|
+
return false;
|
|
1117
|
+
if (queryAsFieldUsageSurvey(query))
|
|
1118
|
+
return true;
|
|
1119
|
+
if (extractMemberAccessFromQuery(query).length === 0)
|
|
1120
|
+
return false;
|
|
1121
|
+
// Conditional wiring / interaction / purpose → compact, not member-file list.
|
|
1122
|
+
if (/失败时|还会被|是怎么|交互|析构|destructor|做了哪些|什么作用|做什么|purpose|what\s+does/i.test(query)) {
|
|
1123
|
+
return false;
|
|
1124
|
+
}
|
|
1125
|
+
return /哪些|哪里|where|which|使用了|谁用|call\s*sites?/i.test(query);
|
|
499
1126
|
}
|
|
500
1127
|
/** API / SDK tokens named in the query — lowercase deps + PascalCase modules (Telephony). */
|
|
501
1128
|
function extractApiUsageTokens(query) {
|
|
@@ -505,18 +1132,51 @@ function extractApiUsageTokens(query) {
|
|
|
505
1132
|
tokens.add(d);
|
|
506
1133
|
}
|
|
507
1134
|
for (const t of extractTypeNamesFromQuery(query)) {
|
|
508
|
-
if (t.length >= 4)
|
|
1135
|
+
if (t.length >= 4 && !isFrameworkUiDecoratorName(t))
|
|
509
1136
|
tokens.add(t);
|
|
510
1137
|
}
|
|
511
|
-
|
|
1138
|
+
for (const ma of extractMemberAccessFromQuery(query)) {
|
|
1139
|
+
if (ma.member.length >= 3)
|
|
1140
|
+
tokens.add(ma.member);
|
|
1141
|
+
}
|
|
1142
|
+
for (const f of extractFieldLikeSymbolsFromQuery(query))
|
|
1143
|
+
tokens.add(f);
|
|
1144
|
+
for (const m of query.matchAll(/\b([A-Z][A-Z0-9]*(?:_[A-Z0-9]+)+)\b/g)) {
|
|
1145
|
+
if (m[1] && m[1].length >= 6)
|
|
1146
|
+
tokens.add(m[1]);
|
|
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
|
+
}
|
|
1153
|
+
// When a PascalCase SDK/module token is present (Telephony, DrawContext), drop
|
|
1154
|
+
// short lowercase bag noise agents add (`call`/`radio`/`usage`) — those flood
|
|
1155
|
+
// false-positive files and tank precision.
|
|
1156
|
+
const primary = [...tokens].filter((t) => (/^[A-Z]/.test(t) && t.length >= 4)
|
|
1157
|
+
|| t.startsWith('@')
|
|
1158
|
+
|| /^(?:statfs|napi_\w+)$/i.test(t)
|
|
1159
|
+
|| extractFieldLikeSymbolsFromQuery(query).includes(t)
|
|
1160
|
+
|| extractMemberAccessFromQuery(query).some((m) => m.member === t || m.dotted === t));
|
|
1161
|
+
if (primary.length > 0)
|
|
1162
|
+
return primary.slice(0, 8);
|
|
1163
|
+
return [...tokens].filter((t) => t.length >= 4 && !exports.GENERIC_VERB_ANCHOR_NOISE.has(t.toLowerCase())).slice(0, 8);
|
|
512
1164
|
}
|
|
513
1165
|
function shouldBuildApiUsageSurvey(query) {
|
|
1166
|
+
// Declaration-site surveys have their own section — do NOT also claim API-usage
|
|
1167
|
+
// (that used to fire after an empty declaration scan and dump include hits).
|
|
1168
|
+
if (queryAsDeclarationSiteSurvey(query))
|
|
1169
|
+
return false;
|
|
1170
|
+
if (queryAsConstantUsageSurvey(query))
|
|
1171
|
+
return true;
|
|
1172
|
+
if (queryAsFieldUsageSurvey(query))
|
|
1173
|
+
return true;
|
|
514
1174
|
return queryAsApiUsageSurvey(query) && extractApiUsageTokens(query).length > 0;
|
|
515
1175
|
}
|
|
516
1176
|
/** Caller / method survey intent — not every PascalCase token. */
|
|
517
1177
|
function queryAsCallerOrMethodSurvey(query) {
|
|
518
|
-
return (
|
|
519
|
-
|| /哪些方法|which\s+methods|methods?\s+(?:are\s+)?called/i.test(query)
|
|
1178
|
+
return (/哪里调用|何处调用|谁调用|调用了|被调用|callers?\s+of|who\s+calls|called\s+by|哪些.*调用|外部.*调用|\bexternal\b/i.test(query)
|
|
1179
|
+
|| /哪些方法|which\s+methods|methods?\s+(?:are\s+)?called|which\s+files?.{0,20}(?:call|invoke)/i.test(query)
|
|
520
1180
|
// Agents often write "Type … methods … callers" / bare "callers" without "of".
|
|
521
1181
|
|| /\bcallers?\b/i.test(query)
|
|
522
1182
|
|| /methods?.{0,40}\bcall/i.test(query));
|
|
@@ -563,6 +1223,9 @@ function shouldBuildCallerInventory(query) {
|
|
|
563
1223
|
&& /使用了哪些调用|哪些调用方法|调用方法|使用了哪些方法/.test(query)) {
|
|
564
1224
|
return false;
|
|
565
1225
|
}
|
|
1226
|
+
// Return-value consumers: list callers of the named member/fn.
|
|
1227
|
+
if (queryAsReturnValueConsumerSurvey(query))
|
|
1228
|
+
return true;
|
|
566
1229
|
// Require real caller/method intent — bare PascalCase alone is NOT enough
|
|
567
1230
|
// (that emptied inventory → blocked compact → 15K full explore on callbacks).
|
|
568
1231
|
return queryAsCallerOrMethodSurvey(query);
|
|
@@ -570,24 +1233,105 @@ function shouldBuildCallerInventory(query) {
|
|
|
570
1233
|
/** Symbols to list callers for — types, free functions (SortWidgets), snake_case APIs. */
|
|
571
1234
|
function extractCallerSurveySymbols(query) {
|
|
572
1235
|
const names = new Set(extractTypeNamesFromQuery(query));
|
|
573
|
-
|
|
574
|
-
|
|
1236
|
+
const wantMembers = queryAsCallerOrMethodSurvey(query) || queryAsReturnValueConsumerSurvey(query);
|
|
1237
|
+
if (!wantMembers)
|
|
1238
|
+
return [...names].filter((n) => n.length >= 3);
|
|
575
1239
|
for (const d of extractDependencySymbolsFromQuery(query)) {
|
|
576
1240
|
if (d.length >= 4)
|
|
577
1241
|
names.add(d);
|
|
578
1242
|
}
|
|
579
|
-
|
|
1243
|
+
for (const ma of extractMemberAccessFromQuery(query)) {
|
|
1244
|
+
names.add(ma.member);
|
|
1245
|
+
if (ma.receiver)
|
|
1246
|
+
names.add(ma.receiver);
|
|
1247
|
+
}
|
|
1248
|
+
for (const a of extractLocalDetailAnchors(query)) {
|
|
1249
|
+
if (isMemberLikeIdentifier(a) || /^(?:get|set|is|has|create|on)[A-Z]/.test(a)) {
|
|
1250
|
+
names.add(a);
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
// Type + listed methods (BinaryGrid Set/Test/Fill) — keep short verbs co-named with a Type.
|
|
1254
|
+
for (const m of extractListedTypeMethodsFromQuery(query))
|
|
1255
|
+
names.add(m);
|
|
1256
|
+
// "通过 getConnectionState 获取…" — bare camelCase after 通过/via is the consumer target.
|
|
1257
|
+
for (const m of query.matchAll(/(?:通过|经由|via|using|call(?:ing)?)\s*([a-z][a-zA-Z0-9]{3,})\b/g)) {
|
|
1258
|
+
if (m[1] && (/^(?:get|set|is|has|create|on)[A-Z]/.test(m[1]) || isMemberLikeIdentifier(m[1]))) {
|
|
1259
|
+
names.add(m[1]);
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
const all = [...names].filter((n) => n.length >= 3);
|
|
1263
|
+
if (!queryAsReturnValueConsumerSurvey(query))
|
|
1264
|
+
return all;
|
|
1265
|
+
// Prefer the member whose return value is consumed over a preceding create/factory.
|
|
1266
|
+
const preferred = all.filter((n) => /^(?:get|is|has)[A-Z]/.test(n) || /State|Result|Status|Value$/i.test(n));
|
|
1267
|
+
if (preferred.length === 0)
|
|
1268
|
+
return all;
|
|
1269
|
+
const rest = all.filter((n) => !preferred.includes(n));
|
|
1270
|
+
return [...preferred, ...rest];
|
|
580
1271
|
}
|
|
581
1272
|
/** Cross-module call-chain intent (A → B → engine). */
|
|
582
1273
|
function queryAsCrossModuleFlowSurvey(query) {
|
|
583
1274
|
const types = extractTypeNamesFromQuery(query);
|
|
584
1275
|
if (types.length < 2)
|
|
585
1276
|
return false;
|
|
586
|
-
|
|
1277
|
+
// Note: bare 渲染 alone is too common (flag-impact / UI surface) — require a
|
|
1278
|
+
// real cross-hop cue with it.
|
|
1279
|
+
return (/经过|跨模块|调用链|链路|流程|到达|落到|再到|落盘|then\s+to|across\s+modules/i.test(query)
|
|
1280
|
+
|| (/渲染/.test(query) && /跨模块|经过|再到|落到|链路|call\s*chain/i.test(query)));
|
|
587
1281
|
}
|
|
588
1282
|
/** Data-source / upstream-service intent (来源于哪个服务 / which service). */
|
|
589
1283
|
function queryAsDataSourceSurvey(query) {
|
|
590
|
-
|
|
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);
|
|
591
1335
|
}
|
|
592
1336
|
/**
|
|
593
1337
|
* Local one/few-symbol behavior or contract — NOT multi-file mechanism / inventory.
|
|
@@ -611,6 +1355,8 @@ function extractLocalDetailAnchors(query) {
|
|
|
611
1355
|
if (m[1] && m[1].length >= 4)
|
|
612
1356
|
names.add(m[1]);
|
|
613
1357
|
}
|
|
1358
|
+
for (const f of extractFieldLikeSymbolsFromQuery(query))
|
|
1359
|
+
names.add(f);
|
|
614
1360
|
// Drop path/extension/verb noise that long NL explores otherwise seed on
|
|
615
1361
|
// (`cpp`, `calls`, `include`, `render`…) — that ballooned neighbor fan-out.
|
|
616
1362
|
const ANCHOR_NOISE = new Set([
|
|
@@ -619,6 +1365,16 @@ function extractLocalDetailAnchors(query) {
|
|
|
619
1365
|
'calls', 'call', 'calling', 'called', 'callers', 'caller', 'include', 'includes', 'import', 'imports',
|
|
620
1366
|
'render', 'frame', 'sync', 'thread', 'subthread', 'layout', 'method', 'methods',
|
|
621
1367
|
'function', 'functions', 'file', 'files', 'src', 'main', 'define', 'visible',
|
|
1368
|
+
'usage', 'usages', 'api', 'apis', 'project', 'codebase', 'repo',
|
|
1369
|
+
'language', 'locale', 'i18n', 'radio', 'state', 'communication', 'binding',
|
|
1370
|
+
'renderer', 'native', 'declaration', 'declarations', 'declared',
|
|
1371
|
+
// Generic UI nouns agents leave in NL (not the PascalCase Type).
|
|
1372
|
+
'dialog', 'page', 'view', 'button', 'component', 'card', 'icon', 'background',
|
|
1373
|
+
'animation', 'hover', 'preview', 'image', 'resource', 'network', 'application',
|
|
1374
|
+
'text', 'layout', 'layouts', 'string', 'strings', 'constant', 'constants',
|
|
1375
|
+
// Shared-lib / GL leftovers after stripping `.so`.
|
|
1376
|
+
'so', 'dll', 'dylib', 'libeffectrender', 'glesv3', 'opengl', 'context',
|
|
1377
|
+
...exports.GENERIC_VERB_ANCHOR_NOISE,
|
|
622
1378
|
]);
|
|
623
1379
|
const ranked = [...names].filter((n) => n.length >= 3 && !ANCHOR_NOISE.has(n.toLowerCase()));
|
|
624
1380
|
// Prefer PascalCase / dotted members first — they're the real anchors.
|
|
@@ -626,7 +1382,13 @@ function extractLocalDetailAnchors(query) {
|
|
|
626
1382
|
const score = (s) => (/^[A-Z]/.test(s) ? 2 : 0) + (s.includes('.') ? 1 : 0) + Math.min(s.length, 20) / 20;
|
|
627
1383
|
return score(b) - score(a) || a.localeCompare(b);
|
|
628
1384
|
});
|
|
629
|
-
|
|
1385
|
+
// Drop framework decorator names when a concrete UI Type is also present
|
|
1386
|
+
// (`@CustomDialog` + `FooDialog` → keep only the concrete UI types).
|
|
1387
|
+
const hasConcreteUi = ranked.some((n) => queryLooksLikeUiComponentType(n) && !isFrameworkUiDecoratorName(n));
|
|
1388
|
+
const filtered = hasConcreteUi
|
|
1389
|
+
? ranked.filter((n) => !isFrameworkUiDecoratorName(n))
|
|
1390
|
+
: ranked;
|
|
1391
|
+
return filtered.slice(0, 4);
|
|
630
1392
|
}
|
|
631
1393
|
/**
|
|
632
1394
|
* Caller survey that also asks how a co-named type becomes visible / used.
|
|
@@ -638,8 +1400,8 @@ function queryNeedsCoNamedUseBridge(query) {
|
|
|
638
1400
|
const anchors = extractLocalDetailAnchors(query);
|
|
639
1401
|
if (anchors.length < 2)
|
|
640
1402
|
return false;
|
|
641
|
-
// Narrow intent
|
|
642
|
-
return /定义可见|确保.*可见|头文件可见|definition\s+visible|visible\s+definition|how\s+.+\s+visible
|
|
1403
|
+
// Narrow intent — how a co-named type becomes visible / included.
|
|
1404
|
+
return /定义可见|确保.*可见|头文件可见|definition\s+visible|visible\s+definition|how\s+.+\s+visible|makes?\s+.+\s+visible|如何确保.*可见/i.test(query);
|
|
643
1405
|
}
|
|
644
1406
|
function queryAsLocalSymbolDetail(query) {
|
|
645
1407
|
if (queryAsCrossModuleFlowSurvey(query))
|
|
@@ -648,7 +1410,25 @@ function queryAsLocalSymbolDetail(query) {
|
|
|
648
1410
|
return false;
|
|
649
1411
|
if (shouldBuildKitModuleUsageSurvey(query))
|
|
650
1412
|
return false;
|
|
651
|
-
|
|
1413
|
+
// Cross-file API / declaration / constant / field inventories — not definition-only.
|
|
1414
|
+
if (shouldBuildApiUsageSurvey(query) && !queryAsTypeLifecycleSurvey(query))
|
|
1415
|
+
return false;
|
|
1416
|
+
if (queryAsModuleExportSurvey(query) || queryAsModuleDependencySurvey(query))
|
|
1417
|
+
return false;
|
|
1418
|
+
if (queryAsInRepoSystemCapabilityHowto(query))
|
|
1419
|
+
return false;
|
|
1420
|
+
if (queryAsReturnValueConsumerSurvey(query))
|
|
1421
|
+
return false;
|
|
1422
|
+
if (queryAsDeclarationSiteSurvey(query))
|
|
1423
|
+
return false;
|
|
1424
|
+
// lib*.so + GL thread → light-mechanism, not compact OpenGL/context seeds.
|
|
1425
|
+
if (queryAsNativeRenderThreadSurvey(query))
|
|
1426
|
+
return false;
|
|
1427
|
+
// Assigned flag impact → compact body. Named Toggle sync may have zero FTS
|
|
1428
|
+
// hits for the Type — inventory owns that shape instead.
|
|
1429
|
+
if (queryAsAssignedFlagImpactSurvey(query))
|
|
1430
|
+
return true;
|
|
1431
|
+
if (queryAsNamedControlStateSyncSurvey(query))
|
|
652
1432
|
return false;
|
|
653
1433
|
// Caller + co-named visibility → compact (body + callers), not inventory-only.
|
|
654
1434
|
if (queryNeedsCoNamedUseBridge(query))
|
|
@@ -657,11 +1437,24 @@ function queryAsLocalSymbolDetail(query) {
|
|
|
657
1437
|
return false;
|
|
658
1438
|
if (queryAsDataSourceSurvey(query))
|
|
659
1439
|
return false;
|
|
1440
|
+
if (queryAsEventDispatchSurvey(query))
|
|
1441
|
+
return false;
|
|
660
1442
|
// Named UI control + event: compact body + callees (not import inventory).
|
|
661
1443
|
if (queryAsNamedComponentAction(query))
|
|
662
1444
|
return true;
|
|
663
|
-
//
|
|
664
|
-
if (
|
|
1445
|
+
// Page/Component surface or 2–3 UI Type cluster — body, not full-graph explore.
|
|
1446
|
+
if (queryAsComponentSurfaceSurvey(query) || queryAsFocusedUiCluster(query))
|
|
1447
|
+
return true;
|
|
1448
|
+
// Named Type + state/lifecycle surface — full type body.
|
|
1449
|
+
if (queryAsTypeLifecycleSurvey(query))
|
|
1450
|
+
return true;
|
|
1451
|
+
// Release vs destructor / multi-method compare on named anchors.
|
|
1452
|
+
if (extractLocalDetailAnchors(query).length >= 2
|
|
1453
|
+
&& /析构|destructor|有没有重复|是否重复|跟.+做的事|做了哪些事情/i.test(query)) {
|
|
1454
|
+
return true;
|
|
1455
|
+
}
|
|
1456
|
+
// Type.member / Type + isFoo co-named — even if the agent used 怎么/如何 NL.
|
|
1457
|
+
if (queryHasNamedMemberFocus(query))
|
|
665
1458
|
return true;
|
|
666
1459
|
if (queryAsMechanismSurvey(query))
|
|
667
1460
|
return false;
|
|
@@ -689,7 +1482,12 @@ function queryHasFocusedNamedAnchors(query) {
|
|
|
689
1482
|
if (shouldTryFastInventoryExplore(query))
|
|
690
1483
|
return false;
|
|
691
1484
|
const anchors = extractLocalDetailAnchors(query);
|
|
692
|
-
|
|
1485
|
+
if (anchors.length < 1 || anchors.length > 3)
|
|
1486
|
+
return false;
|
|
1487
|
+
// Require a real code anchor (PascalCase Type / member-like), not leftover
|
|
1488
|
+
// English topic nouns that survived domain extraction (application, …).
|
|
1489
|
+
return (extractMemberAccessFromQuery(query).length > 0
|
|
1490
|
+
|| anchors.some((a) => /^[A-Z]/.test(a) || isMemberLikeIdentifier(a)));
|
|
693
1491
|
}
|
|
694
1492
|
/**
|
|
695
1493
|
* Prefer a tight explore budget: local-detail questions, or named-symbol
|
|
@@ -702,13 +1500,14 @@ function shouldUseCompactExploreBudget(query) {
|
|
|
702
1500
|
// do not shrink those into a definition-only budget.
|
|
703
1501
|
if (shouldTryFastInventoryExplore(query))
|
|
704
1502
|
return false;
|
|
705
|
-
if (queryAsLocalSymbolDetail(query))
|
|
1503
|
+
if (queryAsLocalSymbolDetail(query) || queryAsFocusedUiCluster(query) || queryAsComponentSurfaceSurvey(query)) {
|
|
706
1504
|
return true;
|
|
1505
|
+
}
|
|
707
1506
|
if (queryIsTypeNameFocus(query))
|
|
708
1507
|
return false;
|
|
709
|
-
const types = extractTypeNamesFromQuery(query);
|
|
1508
|
+
const types = extractTypeNamesFromQuery(query).filter((t) => !isFrameworkUiDecoratorName(t));
|
|
710
1509
|
const deps = extractDependencySymbolsFromQuery(query);
|
|
711
|
-
return types.length + deps.length >= 1 && types.length <=
|
|
1510
|
+
return types.length + deps.length >= 1 && types.length <= 3;
|
|
712
1511
|
}
|
|
713
1512
|
/** Keep rendering to files that define symbols named in the query. */
|
|
714
1513
|
function shouldFocusOnQueryNamedDefs(query, hasFlowPath, multiAnchorQuery) {
|
|
@@ -762,21 +1561,144 @@ function extractMechanismEntrySeeds(query) {
|
|
|
762
1561
|
seeds.add(term);
|
|
763
1562
|
}
|
|
764
1563
|
}
|
|
1564
|
+
// Shared-lib + GLES/EGL thread — seed Draw/Render/EGL owners named in the query.
|
|
1565
|
+
if (queryAsNativeRenderThreadSurvey(query)) {
|
|
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
|
+
}
|
|
1572
|
+
if (/\bCMakeLists\b|\.so\b|链接|link/i.test(query))
|
|
1573
|
+
seeds.add('CMakeLists');
|
|
1574
|
+
}
|
|
765
1575
|
return [...seeds].filter((s) => s.length >= 3).slice(0, 12);
|
|
766
1576
|
}
|
|
767
1577
|
/**
|
|
768
1578
|
* Lightweight mechanism explore — seed symbols + flow spine only, no full
|
|
769
1579
|
* findRelevantContext (keeps MCP calls fast and avoids agent grep fallback).
|
|
1580
|
+
*
|
|
1581
|
+
* Domain-mechanism *bag*: agents often strip the how-phrase and keep only
|
|
1582
|
+
* keywords (`xml parse`, `foo convert`). Structural — distinctive ASCII token
|
|
1583
|
+
* plus an action verb or a CJK domain token; named Types take other paths.
|
|
770
1584
|
*/
|
|
1585
|
+
function queryAsDomainMechanismBag(query) {
|
|
1586
|
+
if (queryAsMechanismSurvey(query))
|
|
1587
|
+
return false;
|
|
1588
|
+
if (queryAsInterpretationSurvey(query))
|
|
1589
|
+
return false;
|
|
1590
|
+
// Named Type / Type.member / UI control → compact / inventory / click-flow.
|
|
1591
|
+
if (extractTypeNamesFromQuery(query).length > 0)
|
|
1592
|
+
return false;
|
|
1593
|
+
if (extractMemberAccessFromQuery(query).length > 0)
|
|
1594
|
+
return false;
|
|
1595
|
+
if (queryAsNamedComponentAction(query))
|
|
1596
|
+
return false;
|
|
1597
|
+
// Hover/悬停 bags without a how-implemented cue are UI-behavior, not mechanism.
|
|
1598
|
+
if (/悬停|\bhover\b|onHover/i.test(query)
|
|
1599
|
+
&& !/\b(?:parse|implement|manage|handle|process|subscribe|convert)\b/i.test(query)) {
|
|
1600
|
+
return false;
|
|
1601
|
+
}
|
|
1602
|
+
const domain = extractDomainSearchTerms(query);
|
|
1603
|
+
const distinct = domain.filter((t) => /^[A-Za-z][A-Za-z0-9._-]{2,}$/.test(t) && !exports.GENERIC_VERB_ANCHOR_NOISE.has(t.toLowerCase()));
|
|
1604
|
+
if (distinct.length === 0)
|
|
1605
|
+
return false;
|
|
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
|
+
})
|
|
1626
|
+
|| /\b(?:parse|implement|manage|handle|process|subscribe|convert|encode|decode)(?:s|d|ing)?\b/i.test(query);
|
|
1627
|
+
// Remaining CJK tokens are the topic half of a rewritten how-question bag.
|
|
1628
|
+
const hasCjkDomain = domain.some((t) => /[\u4e00-\u9fff]/.test(t));
|
|
1629
|
+
return hasActionVerb || hasCjkDomain;
|
|
1630
|
+
}
|
|
771
1631
|
function shouldTryLightMechanismExplore(query) {
|
|
1632
|
+
if (queryShouldDeferToBuiltinTools(query))
|
|
1633
|
+
return false;
|
|
772
1634
|
if (queryAsCrossModuleFlowSurvey(query))
|
|
773
1635
|
return false;
|
|
774
1636
|
if (queryAsInterpretationSurvey(query))
|
|
775
1637
|
return false;
|
|
776
|
-
//
|
|
777
|
-
if (
|
|
778
|
-
return
|
|
779
|
-
|
|
1638
|
+
// Literal / copy hunts → Grep (never light dump), unless this is an edit/fix task.
|
|
1639
|
+
if (queryLooksLikeLiteralOrCopyHunt(query) && !queryAsCodeChangeOrientation(query))
|
|
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
|
+
}
|
|
1650
|
+
// System-setting howto → lean capability inventory, not every `language` import.
|
|
1651
|
+
if (queryAsInRepoSystemCapabilityHowto(query))
|
|
1652
|
+
return false;
|
|
1653
|
+
// Return-value consumers → callers of the member, not a seed+flow dump.
|
|
1654
|
+
if (queryAsReturnValueConsumerSurvey(query))
|
|
1655
|
+
return false;
|
|
1656
|
+
// Manager data/status source → inventory, not light-mechanism.
|
|
1657
|
+
if (queryAsDataSourceSurvey(query))
|
|
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;
|
|
1665
|
+
// Named UI control + event → compact (body + callees + usage sites), not light-mechanism.
|
|
1666
|
+
if (queryAsNamedComponentAction(query))
|
|
1667
|
+
return false;
|
|
1668
|
+
if (queryAsAssignedFlagImpactSurvey(query) || queryAsNamedControlStateSyncSurvey(query)) {
|
|
1669
|
+
return false;
|
|
1670
|
+
}
|
|
1671
|
+
// Kit in-repo usage / extra-deps → kit inventory, not a mechanism dump.
|
|
1672
|
+
if (shouldBuildKitModuleUsageSurvey(query))
|
|
1673
|
+
return false;
|
|
1674
|
+
// Caller + "how is Type visible" → compact (callers + include), not light.
|
|
1675
|
+
if (queryNeedsCoNamedUseBridge(query))
|
|
1676
|
+
return false;
|
|
1677
|
+
// Named Type.member / UI cluster / local pinpoint → compact, even if NL has 怎么/如何.
|
|
1678
|
+
if (queryHasNamedMemberFocus(query)
|
|
1679
|
+
|| queryAsFocusedUiCluster(query)
|
|
1680
|
+
|| queryAsComponentSurfaceSurvey(query)
|
|
1681
|
+
|| queryAsLocalSymbolDetail(query)) {
|
|
1682
|
+
return false;
|
|
1683
|
+
}
|
|
1684
|
+
// Declaration / constant / field / module-export inventories own these shapes.
|
|
1685
|
+
if (queryAsDeclarationSiteSurvey(query)
|
|
1686
|
+
|| queryAsConstantUsageSurvey(query)
|
|
1687
|
+
|| queryAsFieldUsageSurvey(query)
|
|
1688
|
+
|| queryAsModuleExportSurvey(query)
|
|
1689
|
+
|| queryAsModuleDependencySurvey(query)
|
|
1690
|
+
|| queryAsTypeLifecycleSurvey(query)
|
|
1691
|
+
|| shouldBuildApiUsageSurvey(query)
|
|
1692
|
+
|| queryAsDtsWrapSurvey(query)) {
|
|
1693
|
+
return false;
|
|
1694
|
+
}
|
|
1695
|
+
// lib*.so + GLES/EGL + which thread → CMake/EGLCore spine, not `.so` member dump.
|
|
1696
|
+
if (queryAsNativeRenderThreadSurvey(query))
|
|
1697
|
+
return true;
|
|
1698
|
+
if (queryAsDomainMechanismBag(query)) {
|
|
1699
|
+
if (queryLooksLikeLiteralOrCopyHunt(query))
|
|
1700
|
+
return false;
|
|
1701
|
+
return extractDomainSearchTerms(query).length >= 1;
|
|
780
1702
|
}
|
|
781
1703
|
if (!queryAsMechanismSurvey(query))
|
|
782
1704
|
return false;
|
|
@@ -787,44 +1709,86 @@ function shouldTryLightMechanismExplore(query) {
|
|
|
787
1709
|
* Skip expensive subgraph gathering — inventory sections alone answer the query.
|
|
788
1710
|
*/
|
|
789
1711
|
function shouldTryFastInventoryExplore(query) {
|
|
1712
|
+
if (queryShouldDeferToBuiltinTools(query))
|
|
1713
|
+
return false;
|
|
790
1714
|
if (queryAsCrossModuleFlowSurvey(query))
|
|
791
1715
|
return false;
|
|
792
1716
|
if (shouldTryLightMechanismExplore(query))
|
|
793
1717
|
return false;
|
|
794
1718
|
if (queryAsInterpretationSurvey(query))
|
|
795
1719
|
return false;
|
|
1720
|
+
if (queryLooksLikeLiteralOrCopyHunt(query))
|
|
1721
|
+
return false;
|
|
796
1722
|
// Caller paths alone cannot answer "which call makes Type X visible" — compact.
|
|
797
1723
|
if (queryNeedsCoNamedUseBridge(query))
|
|
798
1724
|
return false;
|
|
799
|
-
//
|
|
800
|
-
|
|
801
|
-
|
|
1725
|
+
// Type lifecycle / Release↔destructor compares need bodies, not path lists.
|
|
1726
|
+
if (queryAsTypeLifecycleSurvey(query))
|
|
1727
|
+
return false;
|
|
1728
|
+
// Type×method interaction (CanPlace/Place ↔ Grid) → compact, not member inventory.
|
|
1729
|
+
if (queryAsCoNamedTypeMethodInteraction(query))
|
|
1730
|
+
return false;
|
|
1731
|
+
// Import / kit-usage / domain / API / config / data-source listings win even if
|
|
1732
|
+
// a dotted `@kit.X` once looked like Type.member (defense in depth).
|
|
1733
|
+
// Member-pattern inventories only when the question is a usage listing.
|
|
1734
|
+
if (shouldBuildKitModuleUsageSurvey(query)
|
|
1735
|
+
|| shouldBuildApiUsageSurvey(query)
|
|
1736
|
+
|| shouldBuildDomainFileSurvey(query)
|
|
1737
|
+
|| shouldBuildConfigSection(query)
|
|
1738
|
+
|| queryAsDataSourceSurvey(query)
|
|
1739
|
+
|| queryAsEventDispatchSurvey(query)
|
|
1740
|
+
|| queryAsMultiTypeDependencySurvey(query)
|
|
1741
|
+
|| shouldBuildHoverHandlerSurvey(query)
|
|
1742
|
+
|| queryAsModuleExportSurvey(query)
|
|
1743
|
+
|| queryAsModuleDependencySurvey(query)
|
|
1744
|
+
|| queryAsDtsWrapSurvey(query)
|
|
1745
|
+
|| queryAsNamedControlStateSyncSurvey(query)
|
|
1746
|
+
|| shouldPreferMemberUsageInventory(query)
|
|
1747
|
+
|| queryAsInRepoSystemCapabilityHowto(query)
|
|
1748
|
+
|| queryAsReturnValueConsumerSurvey(query)
|
|
1749
|
+
|| queryAsDeclarationSiteSurvey(query)) {
|
|
1750
|
+
return true;
|
|
1751
|
+
}
|
|
1752
|
+
// One named symbol / UI action / Type.member / component surface — inventory is wrong.
|
|
1753
|
+
if (queryAsLocalSymbolDetail(query)
|
|
1754
|
+
|| queryHasNamedMemberFocus(query)
|
|
1755
|
+
|| queryAsNamedComponentAction(query)
|
|
1756
|
+
|| queryAsComponentSurfaceSurvey(query)
|
|
1757
|
+
|| queryAsFocusedUiCluster(query)) {
|
|
802
1758
|
return false;
|
|
803
1759
|
}
|
|
804
1760
|
const types = extractTypeNamesFromQuery(query);
|
|
805
|
-
if (types.length >= 2 && !queryAsCallerOrMethodSurvey(query))
|
|
1761
|
+
if (types.length >= 2 && !queryAsCallerOrMethodSurvey(query) && !queryAsInheritanceSurvey(query)) {
|
|
806
1762
|
return false;
|
|
1763
|
+
}
|
|
807
1764
|
const inventoryDeps = extractDependencySymbolsFromQuery(query).filter((d) => !isMemberLikeIdentifier(d));
|
|
808
|
-
return (
|
|
809
|
-
||
|
|
810
|
-
|
|
811
|
-
|| (hasImportInventoryFilter(query)
|
|
812
|
-
&& (inventoryDeps.length > 0 || extractKitModuleNamesFromQuery(query).length > 0)
|
|
813
|
-
&& inventoryDeps.length > 0)
|
|
1765
|
+
return ((hasImportInventoryFilter(query)
|
|
1766
|
+
&& (inventoryDeps.length > 0 || extractKitModuleNamesFromQuery(query).length > 0)
|
|
1767
|
+
&& inventoryDeps.length > 0)
|
|
814
1768
|
|| shouldBuildCallerInventory(query)
|
|
815
|
-
|| shouldBuildInheritanceSurvey(query)
|
|
816
|
-
|| shouldBuildMemberSurvey(query)
|
|
817
|
-
|| shouldBuildConfigSection(query)
|
|
818
|
-
|| queryAsDataSourceSurvey(query));
|
|
1769
|
+
|| shouldBuildInheritanceSurvey(query));
|
|
819
1770
|
}
|
|
820
1771
|
function shouldBuildInheritanceSurvey(query) {
|
|
821
1772
|
if (queryAsInheritanceSurvey(query) && extractTypeNamesFromQuery(query).length > 0)
|
|
822
1773
|
return true;
|
|
1774
|
+
// UI Page/Component overview needs the body — not an empty subtype list.
|
|
1775
|
+
if (queryAsComponentSurfaceSurvey(query))
|
|
1776
|
+
return false;
|
|
823
1777
|
// Bare / near-bare type queries — agent search("Foo") for subtypes/overview.
|
|
824
|
-
|
|
1778
|
+
if (queryIsTypeNameFocus(query)) {
|
|
1779
|
+
const types = extractTypeNamesFromQuery(query);
|
|
1780
|
+
if (types.some(queryLooksLikeUiComponentType))
|
|
1781
|
+
return false;
|
|
1782
|
+
return true;
|
|
1783
|
+
}
|
|
1784
|
+
return false;
|
|
825
1785
|
}
|
|
826
1786
|
function shouldBuildMemberSurvey(query) {
|
|
827
|
-
|
|
1787
|
+
const members = extractMemberAccessFromQuery(query);
|
|
1788
|
+
if (members.length > 0)
|
|
1789
|
+
return true;
|
|
1790
|
+
// Field/mutex co-use without a leading dot still needs the text-usage inventory.
|
|
1791
|
+
return queryAsFieldUsageSurvey(query);
|
|
828
1792
|
}
|
|
829
1793
|
function shouldBuildConfigSection(query) {
|
|
830
1794
|
return queryNamesConfigFile(query);
|
|
@@ -851,28 +1815,35 @@ function extractDomainSearchTerms(query) {
|
|
|
851
1815
|
terms.delete(kit);
|
|
852
1816
|
terms.delete(kit.charAt(0).toLowerCase() + kit.slice(1));
|
|
853
1817
|
}
|
|
1818
|
+
// Always keep ASCII code tokens (xml, parse, subscribe…) — mechanism NL often
|
|
1819
|
+
// mixes them with Chinese and used to drop them unless a @kit/path was present.
|
|
1820
|
+
for (const m of query.matchAll(/\b([A-Za-z][A-Za-z0-9]{2,})\b/g)) {
|
|
1821
|
+
const w = m[1];
|
|
1822
|
+
if (!exports.STOP_WORDS.has(w.toLowerCase()))
|
|
1823
|
+
terms.add(w);
|
|
1824
|
+
}
|
|
854
1825
|
const stripped = query
|
|
855
1826
|
.replace(/[@#][\w.]+/g, ' ')
|
|
856
|
-
.replace(
|
|
1827
|
+
.replace(/哪些文件|有哪些|什么|如何|怎样|怎么|项目中|项目里|项目|涉及|相关的?|文件|模块|功能|吗|?|\?|有使用|是否|有没有|使用|不同|区别|对比|这个|那个|是怎样|是如何|怎么|如何|它与|它和|实现|的/g, ' ')
|
|
857
1828
|
.replace(/\s+/g, ' ')
|
|
858
1829
|
.trim();
|
|
859
|
-
for (const m of stripped.matchAll(/[\u4e00-\u9fff]{2,
|
|
1830
|
+
for (const m of stripped.matchAll(/[\u4e00-\u9fff]{2,8}/g)) {
|
|
860
1831
|
let t = m[0].replace(/^与/, '');
|
|
861
1832
|
if (t.length >= 2)
|
|
862
1833
|
terms.add(t);
|
|
863
1834
|
}
|
|
864
|
-
if (queryMentionsCodeContext(query)) {
|
|
865
|
-
for (const m of query.matchAll(/\b([a-z][a-zA-Z0-9]{4,})\b/g)) {
|
|
866
|
-
const w = m[1];
|
|
867
|
-
if (!exports.STOP_WORDS.has(w.toLowerCase()))
|
|
868
|
-
terms.add(w);
|
|
869
|
-
}
|
|
870
|
-
}
|
|
871
1835
|
return [...terms].filter((t) => t.length >= 2).slice(0, 12);
|
|
872
1836
|
}
|
|
873
1837
|
/** How/implementation/mechanism intent — needs entry symbols + flow, not flat file list. */
|
|
874
1838
|
function queryAsMechanismSurvey(query) {
|
|
875
|
-
|
|
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);
|
|
876
1847
|
}
|
|
877
1848
|
/**
|
|
878
1849
|
* Broad domain survey — related files, usage existence, or concept comparison.
|
|
@@ -881,6 +1852,8 @@ function queryAsMechanismSurvey(query) {
|
|
|
881
1852
|
function queryAsDomainFileSurvey(query) {
|
|
882
1853
|
if (queryAsKitModuleCapabilitySurvey(query))
|
|
883
1854
|
return false;
|
|
1855
|
+
if (queryLooksLikeLiteralOrCopyHunt(query))
|
|
1856
|
+
return false;
|
|
884
1857
|
if (queryAsCallerOrMethodSurvey(query))
|
|
885
1858
|
return false;
|
|
886
1859
|
if (shouldBuildApiUsageSurvey(query))
|
|
@@ -893,6 +1866,16 @@ function queryAsDomainFileSurvey(query) {
|
|
|
893
1866
|
return false;
|
|
894
1867
|
if (queryAsMechanismSurvey(query))
|
|
895
1868
|
return false;
|
|
1869
|
+
// Module dep → dedicated cycle survey. Module NAPI export → dedicated export
|
|
1870
|
+
// survey (must NOT become a 50-file domain dump of every "API"/"NAPI" token).
|
|
1871
|
+
if (queryAsModuleDependencySurvey(query))
|
|
1872
|
+
return true;
|
|
1873
|
+
if (queryAsModuleExportSurvey(query) || queryAsDtsWrapSurvey(query))
|
|
1874
|
+
return false;
|
|
1875
|
+
// Step / "which code runs" flow questions are mechanism — not domain file lists.
|
|
1876
|
+
if (/会走到|步骤中|解析和安装|下载完|下载后|call\s*chain|which\s+code\s+(?:runs|paths?)/i.test(query)) {
|
|
1877
|
+
return false;
|
|
1878
|
+
}
|
|
896
1879
|
const listing = /哪些文件|有哪些.*文件|相关的?\s*文件|涉及.*文件|which\s+files?|files?\s+(?:are\s+)?related/i.test(query);
|
|
897
1880
|
const usage = /有使用|是否使用|有没有使用|使用了.*吗|is\s+.+\s+used/i.test(query);
|
|
898
1881
|
const compare = /有什么不同|区别|difference|vs\.?|versus|对比/i.test(query);
|
|
@@ -903,7 +1886,57 @@ function shouldBuildDomainFileSurvey(query) {
|
|
|
903
1886
|
return queryAsDomainFileSurvey(query) && extractDomainSearchTerms(query).length > 0;
|
|
904
1887
|
}
|
|
905
1888
|
/** Callable/class names that commonly anchor implementation flows. */
|
|
906
|
-
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
|
+
}
|
|
907
1940
|
function isImplementationEntrySymbol(name, domainTerms) {
|
|
908
1941
|
if (!exports.IMPLEMENTATION_ENTRY_NAME_RE.test(name))
|
|
909
1942
|
return false;
|
|
@@ -1234,6 +2267,8 @@ function isTestFile(filePath) {
|
|
|
1234
2267
|
lower.includes('/__tests__/') || lower.includes('/spec/') ||
|
|
1235
2268
|
lower.includes('/specs/') || lower.includes('/testlib/') ||
|
|
1236
2269
|
lower.includes('/testing/') ||
|
|
2270
|
+
// HarmonyOS / OpenHarmony instrumented test trees
|
|
2271
|
+
lower.includes('/ohostest/') ||
|
|
1237
2272
|
lower.startsWith('test/') || lower.startsWith('tests/') ||
|
|
1238
2273
|
lower.startsWith('spec/') || lower.startsWith('specs/') ||
|
|
1239
2274
|
// CamelCase test source-set dirs (Kotlin Multiplatform / Gradle / Xcode):
|