homegraph 1.1.3 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -18
- package/dist/arkts/ohos-api-index.d.ts +15 -0
- package/dist/arkts/ohos-api-index.d.ts.map +1 -0
- package/dist/arkts/ohos-api-index.js +190 -0
- package/dist/arkts/ohos-api-index.js.map +1 -0
- package/dist/arkts/ohos-sdk-input.d.ts +36 -0
- package/dist/arkts/ohos-sdk-input.d.ts.map +1 -0
- package/dist/arkts/ohos-sdk-input.js +214 -0
- package/dist/arkts/ohos-sdk-input.js.map +1 -0
- package/dist/bin/command-supervision.d.ts +12 -0
- package/dist/bin/command-supervision.d.ts.map +1 -0
- package/dist/bin/command-supervision.js +86 -0
- package/dist/bin/command-supervision.js.map +1 -0
- package/dist/bin/homegraph.d.ts +1 -1
- package/dist/bin/homegraph.js +706 -168
- package/dist/bin/homegraph.js.map +1 -1
- package/dist/db/index.d.ts +20 -0
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +39 -0
- 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 +40 -1
- package/dist/db/migrations.js.map +1 -1
- package/dist/db/queries.d.ts +14 -0
- package/dist/db/queries.d.ts.map +1 -1
- package/dist/db/queries.js +174 -3
- package/dist/db/queries.js.map +1 -1
- package/dist/db/schema.sql +20 -0
- package/dist/directory.d.ts +32 -0
- package/dist/directory.d.ts.map +1 -1
- package/dist/directory.js +83 -0
- package/dist/directory.js.map +1 -1
- package/dist/extraction/arkts-batch-worker.d.ts +2 -0
- package/dist/extraction/arkts-batch-worker.d.ts.map +1 -0
- package/dist/extraction/arkts-batch-worker.js +28 -0
- package/dist/extraction/arkts-batch-worker.js.map +1 -0
- package/dist/extraction/context.d.ts +11 -0
- package/dist/extraction/context.d.ts.map +1 -1
- package/dist/extraction/context.js +20 -0
- package/dist/extraction/context.js.map +1 -1
- package/dist/extraction/index.d.ts +16 -2
- package/dist/extraction/index.d.ts.map +1 -1
- package/dist/extraction/index.js +619 -380
- package/dist/extraction/index.js.map +1 -1
- package/dist/extraction/languages/arkts-state-decorators.d.ts +13 -0
- package/dist/extraction/languages/arkts-state-decorators.d.ts.map +1 -0
- package/dist/extraction/languages/arkts-state-decorators.js +26 -0
- package/dist/extraction/languages/arkts-state-decorators.js.map +1 -0
- package/dist/extraction/languages/arkts-viewtree.d.ts +4 -2
- package/dist/extraction/languages/arkts-viewtree.d.ts.map +1 -1
- package/dist/extraction/languages/arkts-viewtree.js +21 -6
- package/dist/extraction/languages/arkts-viewtree.js.map +1 -1
- package/dist/extraction/languages/arkts.d.ts +98 -2
- package/dist/extraction/languages/arkts.d.ts.map +1 -1
- package/dist/extraction/languages/arkts.js +1290 -61
- package/dist/extraction/languages/arkts.js.map +1 -1
- package/dist/extraction/languages/c-cpp.d.ts +56 -0
- package/dist/extraction/languages/c-cpp.d.ts.map +1 -1
- package/dist/extraction/languages/c-cpp.js +198 -1
- package/dist/extraction/languages/c-cpp.js.map +1 -1
- package/dist/extraction/languages/ohos-api-consumer.d.ts +34 -0
- package/dist/extraction/languages/ohos-api-consumer.d.ts.map +1 -0
- package/dist/extraction/languages/ohos-api-consumer.js +283 -0
- package/dist/extraction/languages/ohos-api-consumer.js.map +1 -0
- package/dist/extraction/parse-pool.d.ts +126 -0
- package/dist/extraction/parse-pool.d.ts.map +1 -0
- package/dist/extraction/parse-pool.js +319 -0
- package/dist/extraction/parse-pool.js.map +1 -0
- package/dist/extraction/tree-sitter-types.d.ts +17 -0
- package/dist/extraction/tree-sitter-types.d.ts.map +1 -1
- package/dist/extraction/tree-sitter.d.ts +21 -0
- package/dist/extraction/tree-sitter.d.ts.map +1 -1
- package/dist/extraction/tree-sitter.js +198 -27
- package/dist/extraction/tree-sitter.js.map +1 -1
- package/dist/graph/traversal.d.ts.map +1 -1
- package/dist/graph/traversal.js +76 -17
- package/dist/graph/traversal.js.map +1 -1
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +78 -4
- package/dist/index.js.map +1 -1
- package/dist/mcp/daemon-paths.d.ts +30 -3
- package/dist/mcp/daemon-paths.d.ts.map +1 -1
- package/dist/mcp/daemon-paths.js +50 -10
- 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 +7 -3
- package/dist/mcp/daemon-registry.js.map +1 -1
- package/dist/mcp/daemon.d.ts +48 -0
- package/dist/mcp/daemon.d.ts.map +1 -1
- package/dist/mcp/daemon.js +196 -32
- package/dist/mcp/daemon.js.map +1 -1
- package/dist/mcp/engine.d.ts +17 -0
- package/dist/mcp/engine.d.ts.map +1 -1
- package/dist/mcp/engine.js +73 -1
- package/dist/mcp/engine.js.map +1 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +25 -43
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/ppid-watchdog.d.ts +18 -0
- package/dist/mcp/ppid-watchdog.d.ts.map +1 -1
- package/dist/mcp/ppid-watchdog.js +37 -0
- package/dist/mcp/ppid-watchdog.js.map +1 -1
- package/dist/mcp/query-cache.d.ts +25 -0
- package/dist/mcp/query-cache.d.ts.map +1 -0
- package/dist/mcp/query-cache.js +191 -0
- package/dist/mcp/query-cache.js.map +1 -0
- package/dist/mcp/query-pool.d.ts +94 -0
- package/dist/mcp/query-pool.d.ts.map +1 -0
- package/dist/mcp/query-pool.js +297 -0
- package/dist/mcp/query-pool.js.map +1 -0
- package/dist/mcp/query-worker.d.ts +24 -0
- package/dist/mcp/query-worker.d.ts.map +1 -0
- package/dist/mcp/query-worker.js +87 -0
- package/dist/mcp/query-worker.js.map +1 -0
- package/dist/mcp/server-instructions.d.ts +5 -7
- package/dist/mcp/server-instructions.d.ts.map +1 -1
- package/dist/mcp/server-instructions.js +12 -14
- package/dist/mcp/server-instructions.js.map +1 -1
- package/dist/mcp/tools.d.ts +77 -0
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +696 -60
- package/dist/mcp/tools.js.map +1 -1
- package/dist/project-config.d.ts +20 -0
- package/dist/project-config.d.ts.map +1 -1
- package/dist/project-config.js +42 -2
- package/dist/project-config.js.map +1 -1
- package/dist/reasoning/login.js +1 -1
- package/dist/reasoning/login.js.map +1 -1
- package/dist/resolution/c-fnptr-synthesizer.d.ts +0 -28
- package/dist/resolution/c-fnptr-synthesizer.d.ts.map +1 -1
- package/dist/resolution/c-fnptr-synthesizer.js +765 -79
- package/dist/resolution/c-fnptr-synthesizer.js.map +1 -1
- package/dist/resolution/callback-synthesizer.d.ts +1 -1
- package/dist/resolution/callback-synthesizer.d.ts.map +1 -1
- package/dist/resolution/callback-synthesizer.js +72 -11
- package/dist/resolution/callback-synthesizer.js.map +1 -1
- package/dist/resolution/cooperative-yield.d.ts +32 -0
- package/dist/resolution/cooperative-yield.d.ts.map +1 -0
- package/dist/resolution/cooperative-yield.js +42 -0
- package/dist/resolution/cooperative-yield.js.map +1 -0
- package/dist/resolution/index.d.ts +11 -2
- package/dist/resolution/index.d.ts.map +1 -1
- package/dist/resolution/index.js +72 -4
- package/dist/resolution/index.js.map +1 -1
- package/dist/resolution/name-matcher.d.ts +22 -0
- package/dist/resolution/name-matcher.d.ts.map +1 -1
- package/dist/resolution/name-matcher.js +317 -20
- package/dist/resolution/name-matcher.js.map +1 -1
- package/dist/spec/config.d.ts +7 -11
- package/dist/spec/config.d.ts.map +1 -1
- package/dist/spec/config.js +77 -48
- package/dist/spec/config.js.map +1 -1
- package/dist/spec/db/fragment-node.d.ts +1 -0
- package/dist/spec/db/fragment-node.d.ts.map +1 -1
- package/dist/spec/db/fragment-node.js +8 -0
- package/dist/spec/db/fragment-node.js.map +1 -1
- package/dist/spec/db/fts.d.ts +14 -0
- package/dist/spec/db/fts.d.ts.map +1 -1
- package/dist/spec/db/fts.js +43 -4
- package/dist/spec/db/fts.js.map +1 -1
- package/dist/spec/db/schema.d.ts +6 -3
- package/dist/spec/db/schema.d.ts.map +1 -1
- package/dist/spec/db/schema.js +36 -4
- package/dist/spec/db/schema.js.map +1 -1
- package/dist/spec/db/schema.sql +11 -1
- package/dist/spec/evolve/logic-checker.d.ts +2 -2
- package/dist/spec/evolve/logic-checker.d.ts.map +1 -1
- package/dist/spec/evolve/logic-checker.js +3 -27
- package/dist/spec/evolve/logic-checker.js.map +1 -1
- package/dist/spec/evolve/pipeline.d.ts +21 -19
- package/dist/spec/evolve/pipeline.d.ts.map +1 -1
- package/dist/spec/evolve/pipeline.js +284 -31
- package/dist/spec/evolve/pipeline.js.map +1 -1
- package/dist/spec/evolve/spec-rewriter.d.ts +2 -2
- package/dist/spec/evolve/spec-rewriter.d.ts.map +1 -1
- package/dist/spec/evolve/spec-rewriter.js +7 -31
- package/dist/spec/evolve/spec-rewriter.js.map +1 -1
- package/dist/spec/graph/queries.d.ts +97 -0
- package/dist/spec/graph/queries.d.ts.map +1 -1
- package/dist/spec/graph/queries.js +225 -0
- package/dist/spec/graph/queries.js.map +1 -1
- package/dist/spec/llm/client.d.ts +29 -0
- package/dist/spec/llm/client.d.ts.map +1 -0
- package/dist/spec/llm/client.js +123 -0
- package/dist/spec/llm/client.js.map +1 -0
- package/dist/spec/llm/index.d.ts +3 -0
- package/dist/spec/llm/index.d.ts.map +1 -0
- package/dist/spec/llm/index.js +11 -0
- package/dist/spec/llm/index.js.map +1 -0
- package/dist/spec/llm/prompts.d.ts +13 -0
- package/dist/spec/llm/prompts.d.ts.map +1 -0
- package/dist/spec/llm/prompts.js +75 -0
- package/dist/spec/llm/prompts.js.map +1 -0
- package/dist/spec/mining/git-scanner.d.ts +12 -0
- package/dist/spec/mining/git-scanner.d.ts.map +1 -1
- package/dist/spec/mining/git-scanner.js +41 -0
- package/dist/spec/mining/git-scanner.js.map +1 -1
- package/dist/spec/mining/pipeline.d.ts.map +1 -1
- package/dist/spec/mining/pipeline.js +14 -1
- package/dist/spec/mining/pipeline.js.map +1 -1
- package/dist/spec/utils.d.ts +2 -1
- package/dist/spec/utils.d.ts.map +1 -1
- package/dist/spec/utils.js +3 -1
- package/dist/spec/utils.js.map +1 -1
- package/dist/sync/worktree.d.ts +9 -0
- package/dist/sync/worktree.d.ts.map +1 -1
- package/dist/sync/worktree.js +40 -0
- package/dist/sync/worktree.js.map +1 -1
- package/dist/types.d.ts +6 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/shimmer-progress.d.ts +2 -0
- package/dist/ui/shimmer-progress.d.ts.map +1 -1
- package/dist/ui/shimmer-progress.js +19 -2
- package/dist/ui/shimmer-progress.js.map +1 -1
- package/dist/upgrade/index.js +1 -1
- package/dist/upgrade/index.js.map +1 -1
- package/package.json +3 -3
- package/scripts/agent-eval/repro-concurrent-explore.mjs +119 -0
- package/scripts/agent-eval/repro-daemon-clients.mjs +125 -0
- package/scripts/exp_boundary_eval/README.md +247 -0
- package/scripts/exp_boundary_eval/__pycache__/_utils.cpython-310.pyc +0 -0
- package/scripts/exp_boundary_eval/__pycache__/analyze.cpython-310.pyc +0 -0
- package/scripts/exp_boundary_eval/__pycache__/deveco_arm.cpython-310.pyc +0 -0
- package/scripts/exp_boundary_eval/__pycache__/run_one.cpython-310.pyc +0 -0
- package/scripts/exp_boundary_eval/__pycache__/run_session.cpython-310.pyc +0 -0
- package/scripts/exp_boundary_eval/__pycache__/setup.cpython-310.pyc +0 -0
- package/scripts/exp_boundary_eval/_test_mcp_chain.py +78 -0
- package/scripts/exp_boundary_eval/_test_stdin.py +8 -0
- package/scripts/exp_boundary_eval/_utils.py +1116 -0
- package/scripts/exp_boundary_eval/analyze.py +1313 -0
- package/scripts/exp_boundary_eval/data/agents.json +109 -0
- package/scripts/exp_boundary_eval/data/experiments.json +140 -0
- package/scripts/exp_boundary_eval/deveco_arm.py +519 -0
- package/scripts/exp_boundary_eval/run_all.py +378 -0
- package/scripts/exp_boundary_eval/run_one.py +165 -0
- package/scripts/exp_boundary_eval/run_session.py +158 -0
- package/scripts/exp_boundary_eval/setup.py +120 -0
- package/scripts/exp_boundary_eval/win_mcp_launcher.py +73 -0
- package/scripts/exp_boundary_eval/win_mcp_stdio_wrap.js +36 -0
- package/scripts/exp_boundary_eval/win_node_launcher.py +24 -0
- package/scripts/npm-shim.js +25 -3
- package/scripts/ohos-sdk-publish.mjs +133 -0
- package/scripts/qa_eval/README.md +1 -1
- package/scripts/qa_eval/agent_runner.py +1 -1
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MCP query cache — stores serialized tool responses in homegraph.db.
|
|
4
|
+
*
|
|
5
|
+
* Invalidated wholesale when the index stamp or cache format version changes.
|
|
6
|
+
* Per-call staleness/worktree notices are applied AFTER cache lookup so hits
|
|
7
|
+
* stay fresh.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.QUERY_CACHE_FORMAT_VERSION = void 0;
|
|
11
|
+
exports.isMcpQueryCacheEnabled = isMcpQueryCacheEnabled;
|
|
12
|
+
exports.isCacheableMcpTool = isCacheableMcpTool;
|
|
13
|
+
exports.normalizeExploreQueryTerms = normalizeExploreQueryTerms;
|
|
14
|
+
exports.buildMcpQueryCacheFingerprint = buildMcpQueryCacheFingerprint;
|
|
15
|
+
exports.buildMcpQueryCacheKey = buildMcpQueryCacheKey;
|
|
16
|
+
exports.ensureMcpQueryCacheValid = ensureMcpQueryCacheValid;
|
|
17
|
+
exports.getMcpQueryCacheEntry = getMcpQueryCacheEntry;
|
|
18
|
+
exports.setMcpQueryCacheEntry = setMcpQueryCacheEntry;
|
|
19
|
+
const node_crypto_1 = require("node:crypto");
|
|
20
|
+
/** Mirrors `getExploreOutputBudget` tier breakpoints — cache-key only. */
|
|
21
|
+
function defaultExploreMaxFiles(fileCount) {
|
|
22
|
+
if (fileCount < 150)
|
|
23
|
+
return 4;
|
|
24
|
+
if (fileCount < 500)
|
|
25
|
+
return 5;
|
|
26
|
+
return 8;
|
|
27
|
+
}
|
|
28
|
+
/** Bump when cache-key normalization or cached payload shape changes. */
|
|
29
|
+
exports.QUERY_CACHE_FORMAT_VERSION = 1;
|
|
30
|
+
const METADATA_INDEX_STAMP = 'query_cache_index_stamp';
|
|
31
|
+
const METADATA_FORMAT_VERSION = 'query_cache_format_version';
|
|
32
|
+
/** Tools that must stay live — never cached. */
|
|
33
|
+
const NON_CACHEABLE_TOOLS = new Set(['homegraph_status', 'homegraph_spec_match']);
|
|
34
|
+
function isMcpQueryCacheEnabled() {
|
|
35
|
+
const raw = process.env.HOMEGRAPH_MCP_CACHE;
|
|
36
|
+
return raw === '1' || raw === 'true';
|
|
37
|
+
}
|
|
38
|
+
function isCacheableMcpTool(toolName) {
|
|
39
|
+
return !NON_CACHEABLE_TOOLS.has(toolName);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Tokenize a natural-language explore query into a stable, order-independent
|
|
43
|
+
* symbol bag for cache keys — different phrasing, same symbols → same key.
|
|
44
|
+
*/
|
|
45
|
+
function normalizeExploreQueryTerms(query) {
|
|
46
|
+
const terms = query
|
|
47
|
+
.toLowerCase()
|
|
48
|
+
.split(/[\s,;:()]+/)
|
|
49
|
+
.flatMap((token) => token.split(/[./\\]/))
|
|
50
|
+
.map((t) => t.trim())
|
|
51
|
+
.filter((t) => t.length > 0);
|
|
52
|
+
return [...new Set(terms)].sort();
|
|
53
|
+
}
|
|
54
|
+
function exploreEnvFingerprint() {
|
|
55
|
+
const linums = process.env.HOMEGRAPH_EXPLORE_LINENUMS === '0' ? '0' : '1';
|
|
56
|
+
const adaptive = process.env.HOMEGRAPH_ADAPTIVE_EXPLORE === '0' ||
|
|
57
|
+
process.env.HOMEGRAPH_ADAPTIVE_EXPLORE === 'false'
|
|
58
|
+
? '0'
|
|
59
|
+
: '1';
|
|
60
|
+
const rankMultiterm = process.env.HOMEGRAPH_RANK_NO_MULTITERM === '1' ? '0' : '1';
|
|
61
|
+
return `linums:${linums}|adaptive:${adaptive}|rankMultiterm:${rankMultiterm}`;
|
|
62
|
+
}
|
|
63
|
+
function normalizeString(value) {
|
|
64
|
+
if (typeof value !== 'string')
|
|
65
|
+
return undefined;
|
|
66
|
+
const trimmed = value.trim();
|
|
67
|
+
return trimmed.length > 0 ? trimmed : undefined;
|
|
68
|
+
}
|
|
69
|
+
function intParam(value, fallback) {
|
|
70
|
+
const n = Number(value);
|
|
71
|
+
return Number.isFinite(n) && n > 0 ? Math.floor(Math.floor(n)) : fallback;
|
|
72
|
+
}
|
|
73
|
+
/** Build the pre-hash fingerprint string for a tool + args pair. */
|
|
74
|
+
function buildMcpQueryCacheFingerprint(toolName, args, fileCount) {
|
|
75
|
+
const parts = [toolName.replace(/^homegraph_/, '')];
|
|
76
|
+
switch (toolName) {
|
|
77
|
+
case 'homegraph_explore': {
|
|
78
|
+
const query = normalizeString(args.query) ?? '';
|
|
79
|
+
parts.push(`terms:${normalizeExploreQueryTerms(query).join(',')}`);
|
|
80
|
+
if (args.maxFiles != null) {
|
|
81
|
+
parts.push(`maxFiles:${intParam(args.maxFiles, 12)}`);
|
|
82
|
+
}
|
|
83
|
+
else if (fileCount != null) {
|
|
84
|
+
parts.push(`maxFiles:default:${defaultExploreMaxFiles(fileCount)}`);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
parts.push('maxFiles:default');
|
|
88
|
+
}
|
|
89
|
+
parts.push(exploreEnvFingerprint());
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
case 'homegraph_search': {
|
|
93
|
+
parts.push(`query:${(normalizeString(args.query) ?? '').toLowerCase()}`);
|
|
94
|
+
if (args.kind != null) {
|
|
95
|
+
const kind = args.kind === 'type' ? 'type_alias' : String(args.kind);
|
|
96
|
+
parts.push(`kind:${kind}`);
|
|
97
|
+
}
|
|
98
|
+
parts.push(`limit:${intParam(args.limit, 10)}`);
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
case 'homegraph_callers':
|
|
102
|
+
case 'homegraph_callees': {
|
|
103
|
+
parts.push(`symbol:${(normalizeString(args.symbol) ?? '').toLowerCase()}`);
|
|
104
|
+
parts.push(`limit:${intParam(args.limit, 20)}`);
|
|
105
|
+
if (args.file != null)
|
|
106
|
+
parts.push(`file:${normalizeString(args.file) ?? ''}`);
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
case 'homegraph_impact': {
|
|
110
|
+
parts.push(`symbol:${(normalizeString(args.symbol) ?? '').toLowerCase()}`);
|
|
111
|
+
parts.push(`depth:${intParam(args.depth, 2)}`);
|
|
112
|
+
if (args.file != null)
|
|
113
|
+
parts.push(`file:${normalizeString(args.file) ?? ''}`);
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
case 'homegraph_node': {
|
|
117
|
+
if (args.symbol != null)
|
|
118
|
+
parts.push(`symbol:${(normalizeString(args.symbol) ?? '').toLowerCase()}`);
|
|
119
|
+
if (args.file != null)
|
|
120
|
+
parts.push(`file:${normalizeString(args.file) ?? ''}`);
|
|
121
|
+
parts.push(`includeCode:${args.includeCode === true ? '1' : '0'}`);
|
|
122
|
+
if (args.line != null)
|
|
123
|
+
parts.push(`line:${intParam(args.line, 0)}`);
|
|
124
|
+
if (args.offset != null)
|
|
125
|
+
parts.push(`offset:${intParam(args.offset, 0)}`);
|
|
126
|
+
if (args.limit != null)
|
|
127
|
+
parts.push(`limit:${intParam(args.limit, 0)}`);
|
|
128
|
+
parts.push(`symbolsOnly:${args.symbolsOnly === true ? '1' : '0'}`);
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
case 'homegraph_files': {
|
|
132
|
+
if (args.path != null)
|
|
133
|
+
parts.push(`path:${normalizeString(args.path) ?? ''}`);
|
|
134
|
+
if (args.pattern != null)
|
|
135
|
+
parts.push(`pattern:${normalizeString(args.pattern) ?? ''}`);
|
|
136
|
+
parts.push(`format:${normalizeString(args.format) ?? 'tree'}`);
|
|
137
|
+
parts.push(`includeMetadata:${args.includeMetadata === false ? '0' : '1'}`);
|
|
138
|
+
if (args.maxDepth != null)
|
|
139
|
+
parts.push(`maxDepth:${intParam(args.maxDepth, 1)}`);
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
default:
|
|
143
|
+
parts.push(`args:${stableJson(args)}`);
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
return parts.join('|');
|
|
147
|
+
}
|
|
148
|
+
function stableJson(value) {
|
|
149
|
+
if (value === null || typeof value !== 'object')
|
|
150
|
+
return JSON.stringify(value);
|
|
151
|
+
if (Array.isArray(value))
|
|
152
|
+
return `[${value.map(stableJson).join(',')}]`;
|
|
153
|
+
const obj = value;
|
|
154
|
+
const keys = Object.keys(obj).sort();
|
|
155
|
+
return `{${keys.map((k) => `${JSON.stringify(k)}:${stableJson(obj[k])}`).join(',')}}`;
|
|
156
|
+
}
|
|
157
|
+
function buildMcpQueryCacheKey(toolName, args, fileCount) {
|
|
158
|
+
const fingerprint = buildMcpQueryCacheFingerprint(toolName, args, fileCount);
|
|
159
|
+
return (0, node_crypto_1.createHash)('sha256').update(fingerprint, 'utf8').digest('hex');
|
|
160
|
+
}
|
|
161
|
+
function ensureMcpQueryCacheValid(queries, getIndexStamp) {
|
|
162
|
+
const currentStamp = String(getIndexStamp() ?? 0);
|
|
163
|
+
const storedStamp = queries.getMetadata(METADATA_INDEX_STAMP);
|
|
164
|
+
const storedFormat = queries.getMetadata(METADATA_FORMAT_VERSION);
|
|
165
|
+
const currentFormat = String(exports.QUERY_CACHE_FORMAT_VERSION);
|
|
166
|
+
if (storedStamp === currentStamp && storedFormat === currentFormat) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
queries.clearMcpQueryCache();
|
|
170
|
+
queries.setMetadata(METADATA_INDEX_STAMP, currentStamp);
|
|
171
|
+
queries.setMetadata(METADATA_FORMAT_VERSION, currentFormat);
|
|
172
|
+
}
|
|
173
|
+
function getMcpQueryCacheEntry(queries, cacheKey) {
|
|
174
|
+
const row = queries.getMcpQueryCache(cacheKey);
|
|
175
|
+
if (!row)
|
|
176
|
+
return null;
|
|
177
|
+
try {
|
|
178
|
+
const parsed = JSON.parse(row.response);
|
|
179
|
+
if (!parsed || !Array.isArray(parsed.content))
|
|
180
|
+
return null;
|
|
181
|
+
return parsed;
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
function setMcpQueryCacheEntry(queries, cacheKey, toolName, result) {
|
|
188
|
+
const shortTool = toolName.replace(/^homegraph_/, '');
|
|
189
|
+
queries.setMcpQueryCache(cacheKey, shortTool, JSON.stringify(result), Date.now());
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=query-cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-cache.js","sourceRoot":"","sources":["../../src/mcp/query-cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query pool — runs CPU-heavy read-tool calls on a pool of worker threads so
|
|
3
|
+
* the shared daemon's main event loop stays free for the MCP transport.
|
|
4
|
+
*
|
|
5
|
+
* Why this exists: see {@link ./query-worker}. One daemon, one event loop, one
|
|
6
|
+
* synchronous SQLite connection serializes every concurrent `codegraph_explore`
|
|
7
|
+
* AND starves the transport (a 10-way wave delivered 0 transport heartbeats in
|
|
8
|
+
* 25s — responses can't flush until the whole batch drains, so clients time
|
|
9
|
+
* out). Spreading the dispatch across worker threads (each its own WAL read
|
|
10
|
+
* connection) restores true multi-core parallelism and an idle main loop.
|
|
11
|
+
*
|
|
12
|
+
* Properties:
|
|
13
|
+
* - lazy growth: one warm worker on construct, grows to `size` on demand, so a
|
|
14
|
+
* single-agent session pays for one connection and a 10-subagent burst grows
|
|
15
|
+
* to the core budget.
|
|
16
|
+
* - crash recovery: a dead worker is respawned and its in-flight call retried
|
|
17
|
+
* once; a poison call that keeps crashing fails gracefully (never wedges the
|
|
18
|
+
* pool). A crash budget trips a circuit breaker (`healthy` → false) so the
|
|
19
|
+
* caller falls back to in-process dispatch instead of thrashing respawns.
|
|
20
|
+
* - graceful backstop: a call that can't be served within `softTimeoutMs`
|
|
21
|
+
* resolves with SUCCESS-shaped "busy, retry" guidance — never `isError`, so
|
|
22
|
+
* a momentary overload can't teach the agent to abandon codegraph — instead
|
|
23
|
+
* of hanging past the client's hard timeout.
|
|
24
|
+
*/
|
|
25
|
+
import type { ToolResult } from './tools';
|
|
26
|
+
/**
|
|
27
|
+
* Minimal worker surface the pool drives — satisfied by a real `worker_threads`
|
|
28
|
+
* Worker. Abstracted so tests can inject a fake worker and exercise the pool's
|
|
29
|
+
* queue / growth / crash-recovery / backstop logic without spawning threads or
|
|
30
|
+
* needing a built `dist/`.
|
|
31
|
+
*/
|
|
32
|
+
export interface PoolWorker {
|
|
33
|
+
postMessage(msg: unknown): void;
|
|
34
|
+
terminate(): Promise<number> | void;
|
|
35
|
+
on(event: 'message', cb: (m: unknown) => void): void;
|
|
36
|
+
on(event: 'error', cb: (e: Error) => void): void;
|
|
37
|
+
on(event: 'exit', cb: (code: number) => void): void;
|
|
38
|
+
}
|
|
39
|
+
export interface QueryPoolOptions {
|
|
40
|
+
/** Default project root each worker opens at spawn. */
|
|
41
|
+
root: string;
|
|
42
|
+
/** Max worker threads. Defaults to `clamp(cores-1, 1, 16)`. */
|
|
43
|
+
size?: number;
|
|
44
|
+
/** Linger before a queued call gets busy-guidance. Default 45s. */
|
|
45
|
+
softTimeoutMs?: number;
|
|
46
|
+
/** Retries for an in-flight call whose worker crashed. Default 1. */
|
|
47
|
+
maxRetries?: number;
|
|
48
|
+
/** Worker factory (tests inject a fake). Defaults to a real `worker_threads` Worker. */
|
|
49
|
+
createWorker?: () => PoolWorker;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Resolve the pool size from the `CODEGRAPH_QUERY_POOL_SIZE` override and the
|
|
53
|
+
* machine's core count. `0` (or a negative) explicitly disables the pool (the
|
|
54
|
+
* caller serves in-process — today's behavior). Unset → `clamp(cores-1, 1, 16)`:
|
|
55
|
+
* leave a core for the main loop + OS, but never zero, since even one worker
|
|
56
|
+
* frees the transport and lets responses flush incrementally.
|
|
57
|
+
*/
|
|
58
|
+
export declare function resolvePoolSize(envVal: string | undefined, cpuCount: number): number;
|
|
59
|
+
export declare class QueryPool {
|
|
60
|
+
private idle;
|
|
61
|
+
private queue;
|
|
62
|
+
private inflight;
|
|
63
|
+
private workers;
|
|
64
|
+
private pendingWorkers;
|
|
65
|
+
private nextId;
|
|
66
|
+
private totalCrashes;
|
|
67
|
+
private destroyed;
|
|
68
|
+
private readonly root;
|
|
69
|
+
private readonly maxSize;
|
|
70
|
+
private readonly softTimeoutMs;
|
|
71
|
+
private readonly maxRetries;
|
|
72
|
+
private readonly createWorker;
|
|
73
|
+
constructor(opts: QueryPoolOptions);
|
|
74
|
+
/** Pool size cap (for logging/status). */
|
|
75
|
+
get size(): number;
|
|
76
|
+
/** Live worker count (for tests/status). */
|
|
77
|
+
get liveWorkers(): number;
|
|
78
|
+
/**
|
|
79
|
+
* False once the crash budget is exhausted (or after destroy). The ToolHandler
|
|
80
|
+
* checks this and falls back to in-process dispatch — a broken worker platform
|
|
81
|
+
* degrades to today's behavior instead of failing tool calls.
|
|
82
|
+
*/
|
|
83
|
+
get healthy(): boolean;
|
|
84
|
+
private spawnOne;
|
|
85
|
+
private onMessage;
|
|
86
|
+
private onWorkerGone;
|
|
87
|
+
private drain;
|
|
88
|
+
private settle;
|
|
89
|
+
/** Run a read tool on the pool. Always resolves (never rejects). */
|
|
90
|
+
run(toolName: string, args: Record<string, unknown>): Promise<ToolResult>;
|
|
91
|
+
/** Terminate all workers and answer any outstanding calls gracefully. */
|
|
92
|
+
destroy(): Promise<void>;
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=query-pool.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-pool.d.ts","sourceRoot":"","sources":["../../src/mcp/query-pool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAK1C;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;IAChC,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC;IACpC,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI,CAAC;IACrD,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAAC;IACjD,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAAC;CACrD;AA6CD,MAAM,WAAW,gBAAgB;IAC/B,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,wFAAwF;IACxF,YAAY,CAAC,EAAE,MAAM,UAAU,CAAC;CACjC;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAOpF;AAwBD,qBAAa,SAAS;IACpB,OAAO,CAAC,IAAI,CAAoB;IAChC,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,QAAQ,CAA8B;IAC9C,OAAO,CAAC,OAAO,CAAyB;IAMxC,OAAO,CAAC,cAAc,CAAyB;IAC/C,OAAO,CAAC,MAAM,CAAK;IACnB,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAmB;gBAEpC,IAAI,EAAE,gBAAgB;IASlC,0CAA0C;IAC1C,IAAI,IAAI,IAAI,MAAM,CAAyB;IAE3C,4CAA4C;IAC5C,IAAI,WAAW,IAAI,MAAM,CAA8B;IAEvD;;;;OAIG;IACH,IAAI,OAAO,IAAI,OAAO,CAErB;IAED,OAAO,CAAC,QAAQ;IAgBhB,OAAO,CAAC,SAAS;IAqBjB,OAAO,CAAC,YAAY;IAqBpB,OAAO,CAAC,KAAK;IAuBb,OAAO,CAAC,MAAM;IAOd,oEAAoE;IACpE,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC;IAkBzE,yEAAyE;IACnE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAc/B"}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Query pool — runs CPU-heavy read-tool calls on a pool of worker threads so
|
|
4
|
+
* the shared daemon's main event loop stays free for the MCP transport.
|
|
5
|
+
*
|
|
6
|
+
* Why this exists: see {@link ./query-worker}. One daemon, one event loop, one
|
|
7
|
+
* synchronous SQLite connection serializes every concurrent `codegraph_explore`
|
|
8
|
+
* AND starves the transport (a 10-way wave delivered 0 transport heartbeats in
|
|
9
|
+
* 25s — responses can't flush until the whole batch drains, so clients time
|
|
10
|
+
* out). Spreading the dispatch across worker threads (each its own WAL read
|
|
11
|
+
* connection) restores true multi-core parallelism and an idle main loop.
|
|
12
|
+
*
|
|
13
|
+
* Properties:
|
|
14
|
+
* - lazy growth: one warm worker on construct, grows to `size` on demand, so a
|
|
15
|
+
* single-agent session pays for one connection and a 10-subagent burst grows
|
|
16
|
+
* to the core budget.
|
|
17
|
+
* - crash recovery: a dead worker is respawned and its in-flight call retried
|
|
18
|
+
* once; a poison call that keeps crashing fails gracefully (never wedges the
|
|
19
|
+
* pool). A crash budget trips a circuit breaker (`healthy` → false) so the
|
|
20
|
+
* caller falls back to in-process dispatch instead of thrashing respawns.
|
|
21
|
+
* - graceful backstop: a call that can't be served within `softTimeoutMs`
|
|
22
|
+
* resolves with SUCCESS-shaped "busy, retry" guidance — never `isError`, so
|
|
23
|
+
* a momentary overload can't teach the agent to abandon codegraph — instead
|
|
24
|
+
* of hanging past the client's hard timeout.
|
|
25
|
+
*/
|
|
26
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
27
|
+
if (k2 === undefined) k2 = k;
|
|
28
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
29
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
30
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
31
|
+
}
|
|
32
|
+
Object.defineProperty(o, k2, desc);
|
|
33
|
+
}) : (function(o, m, k, k2) {
|
|
34
|
+
if (k2 === undefined) k2 = k;
|
|
35
|
+
o[k2] = m[k];
|
|
36
|
+
}));
|
|
37
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
38
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
39
|
+
}) : function(o, v) {
|
|
40
|
+
o["default"] = v;
|
|
41
|
+
});
|
|
42
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
43
|
+
var ownKeys = function(o) {
|
|
44
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
45
|
+
var ar = [];
|
|
46
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
47
|
+
return ar;
|
|
48
|
+
};
|
|
49
|
+
return ownKeys(o);
|
|
50
|
+
};
|
|
51
|
+
return function (mod) {
|
|
52
|
+
if (mod && mod.__esModule) return mod;
|
|
53
|
+
var result = {};
|
|
54
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
55
|
+
__setModuleDefault(result, mod);
|
|
56
|
+
return result;
|
|
57
|
+
};
|
|
58
|
+
})();
|
|
59
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
60
|
+
exports.QueryPool = void 0;
|
|
61
|
+
exports.resolvePoolSize = resolvePoolSize;
|
|
62
|
+
const worker_threads_1 = require("worker_threads");
|
|
63
|
+
const path = __importStar(require("path"));
|
|
64
|
+
const os = __importStar(require("os"));
|
|
65
|
+
/** Compiled sibling — `query-worker.js` lives next to this file in `dist/mcp/`. */
|
|
66
|
+
const WORKER_FILE = path.join(__dirname, 'query-worker.js');
|
|
67
|
+
/** Default linger before a queued call is answered with busy-guidance. */
|
|
68
|
+
const DEFAULT_BUSY_TIMEOUT_MS = 45_000; // < the ~60s MCP client request timeout
|
|
69
|
+
/** Hard ceiling on pool size regardless of core count / env. */
|
|
70
|
+
const MAX_POOL_SIZE = 16;
|
|
71
|
+
/**
|
|
72
|
+
* Total worker deaths before the pool declares itself unhealthy and the caller
|
|
73
|
+
* reverts to in-process dispatch. High enough to ride out a few transient
|
|
74
|
+
* crashes, low enough that a systematically-broken worker (e.g. a platform that
|
|
75
|
+
* can't spawn threads) degrades quickly instead of respawning forever.
|
|
76
|
+
*/
|
|
77
|
+
const CRASH_BUDGET = 12;
|
|
78
|
+
/**
|
|
79
|
+
* Max workers cold-starting at once. A worker's cold start is heavy — full
|
|
80
|
+
* module load (tree-sitter etc.) + opening a large WAL DB — and starting the
|
|
81
|
+
* whole pool simultaneously thrashes CPU/I-O so badly it can stall the daemon's
|
|
82
|
+
* main loop for tens of seconds. Warming a couple at a time keeps each start
|
|
83
|
+
* fast; as one reports ready the next begins, so the pool still reaches full
|
|
84
|
+
* size within a few calls of a burst, just without the thundering herd.
|
|
85
|
+
*/
|
|
86
|
+
const MAX_CONCURRENT_SPAWN = 2;
|
|
87
|
+
/**
|
|
88
|
+
* Resolve the pool size from the `CODEGRAPH_QUERY_POOL_SIZE` override and the
|
|
89
|
+
* machine's core count. `0` (or a negative) explicitly disables the pool (the
|
|
90
|
+
* caller serves in-process — today's behavior). Unset → `clamp(cores-1, 1, 16)`:
|
|
91
|
+
* leave a core for the main loop + OS, but never zero, since even one worker
|
|
92
|
+
* frees the transport and lets responses flush incrementally.
|
|
93
|
+
*/
|
|
94
|
+
function resolvePoolSize(envVal, cpuCount) {
|
|
95
|
+
if (envVal !== undefined && envVal !== '') {
|
|
96
|
+
const n = Number(envVal);
|
|
97
|
+
if (Number.isFinite(n) && n >= 0)
|
|
98
|
+
return Math.min(Math.floor(n), MAX_POOL_SIZE);
|
|
99
|
+
// non-numeric / negative → fall through to the default
|
|
100
|
+
}
|
|
101
|
+
return Math.max(1, Math.min(cpuCount - 1, MAX_POOL_SIZE));
|
|
102
|
+
}
|
|
103
|
+
function resolveBusyTimeoutMs() {
|
|
104
|
+
const raw = process.env.CODEGRAPH_QUERY_BUSY_TIMEOUT_MS;
|
|
105
|
+
if (raw === undefined || raw === '')
|
|
106
|
+
return DEFAULT_BUSY_TIMEOUT_MS;
|
|
107
|
+
const n = Number(raw);
|
|
108
|
+
if (!Number.isFinite(n) || n < 1000)
|
|
109
|
+
return DEFAULT_BUSY_TIMEOUT_MS;
|
|
110
|
+
return Math.floor(n);
|
|
111
|
+
}
|
|
112
|
+
/** Success-shaped overload guidance (NEVER isError — see the abandonment rule). */
|
|
113
|
+
function busyGuidance(waitedMs) {
|
|
114
|
+
const secs = Math.max(1, Math.round(waitedMs / 1000));
|
|
115
|
+
return {
|
|
116
|
+
content: [{
|
|
117
|
+
type: 'text',
|
|
118
|
+
text: `CodeGraph is busy serving other concurrent requests right now (this call waited ${secs}s in the queue). ` +
|
|
119
|
+
`This is NOT an error and the index is fine — wait a few seconds and retry this exact call; it will return normally. ` +
|
|
120
|
+
`If you can't wait, use your built-in tools for just this one step.`,
|
|
121
|
+
}],
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
class QueryPool {
|
|
125
|
+
idle = [];
|
|
126
|
+
queue = [];
|
|
127
|
+
inflight = new Map();
|
|
128
|
+
workers = new Set();
|
|
129
|
+
// Workers spawned but not yet 'ready'. Growth must count these so a single
|
|
130
|
+
// first call (with the eager worker still starting) doesn't spawn the WHOLE
|
|
131
|
+
// pool at once — N simultaneous cold worker starts (each a full module load +
|
|
132
|
+
// a large DB open) saturate the box and starve the main loop. Grow only when
|
|
133
|
+
// the queue outstrips idle + pending.
|
|
134
|
+
pendingWorkers = new Set();
|
|
135
|
+
nextId = 1;
|
|
136
|
+
totalCrashes = 0;
|
|
137
|
+
destroyed = false;
|
|
138
|
+
root;
|
|
139
|
+
maxSize;
|
|
140
|
+
softTimeoutMs;
|
|
141
|
+
maxRetries;
|
|
142
|
+
createWorker;
|
|
143
|
+
constructor(opts) {
|
|
144
|
+
this.root = opts.root;
|
|
145
|
+
this.maxSize = Math.max(1, Math.min(opts.size ?? Math.max(1, os.cpus().length - 1), MAX_POOL_SIZE));
|
|
146
|
+
this.softTimeoutMs = opts.softTimeoutMs ?? resolveBusyTimeoutMs();
|
|
147
|
+
this.maxRetries = opts.maxRetries ?? 1;
|
|
148
|
+
this.createWorker = opts.createWorker ?? (() => new worker_threads_1.Worker(WORKER_FILE, { workerData: { root: this.root } }));
|
|
149
|
+
this.spawnOne(); // one eager warm worker, ready for the first call
|
|
150
|
+
}
|
|
151
|
+
/** Pool size cap (for logging/status). */
|
|
152
|
+
get size() { return this.maxSize; }
|
|
153
|
+
/** Live worker count (for tests/status). */
|
|
154
|
+
get liveWorkers() { return this.workers.size; }
|
|
155
|
+
/**
|
|
156
|
+
* False once the crash budget is exhausted (or after destroy). The ToolHandler
|
|
157
|
+
* checks this and falls back to in-process dispatch — a broken worker platform
|
|
158
|
+
* degrades to today's behavior instead of failing tool calls.
|
|
159
|
+
*/
|
|
160
|
+
get healthy() {
|
|
161
|
+
return !this.destroyed && this.totalCrashes < CRASH_BUDGET;
|
|
162
|
+
}
|
|
163
|
+
spawnOne() {
|
|
164
|
+
if (this.destroyed || this.workers.size >= this.maxSize)
|
|
165
|
+
return;
|
|
166
|
+
let w;
|
|
167
|
+
try {
|
|
168
|
+
w = this.createWorker();
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
this.totalCrashes++; // counts toward the circuit breaker
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
this.workers.add(w);
|
|
175
|
+
this.pendingWorkers.add(w);
|
|
176
|
+
w.on('message', (m) => this.onMessage(w, (m ?? {})));
|
|
177
|
+
w.on('error', () => this.onWorkerGone(w));
|
|
178
|
+
w.on('exit', (code) => { if (code !== 0)
|
|
179
|
+
this.onWorkerGone(w); });
|
|
180
|
+
}
|
|
181
|
+
onMessage(w, m) {
|
|
182
|
+
if (!m)
|
|
183
|
+
return;
|
|
184
|
+
if (m.type === 'ready') {
|
|
185
|
+
this.pendingWorkers.delete(w);
|
|
186
|
+
if (m.ok === false)
|
|
187
|
+
this.totalCrashes++; // hard open failure
|
|
188
|
+
this.idle.push(w);
|
|
189
|
+
this.drain();
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
if (m.type === 'result') {
|
|
193
|
+
const job = this.inflight.get(w);
|
|
194
|
+
this.inflight.delete(w);
|
|
195
|
+
this.idle.push(w);
|
|
196
|
+
if (job)
|
|
197
|
+
this.settle(job, m.result ?? busyGuidance(0));
|
|
198
|
+
this.drain();
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
// A worker died (crash hook, OOM, segfault, exit≠0). Respawn a replacement and
|
|
202
|
+
// retry its in-flight job once; a job that keeps crashing workers fails
|
|
203
|
+
// gracefully so it can't loop the pool forever.
|
|
204
|
+
onWorkerGone(w) {
|
|
205
|
+
if (!this.workers.has(w))
|
|
206
|
+
return; // already handled (error+exit both fire)
|
|
207
|
+
this.workers.delete(w);
|
|
208
|
+
this.pendingWorkers.delete(w);
|
|
209
|
+
this.idle = this.idle.filter((x) => x !== w);
|
|
210
|
+
this.totalCrashes++;
|
|
211
|
+
const job = this.inflight.get(w);
|
|
212
|
+
this.inflight.delete(w);
|
|
213
|
+
try {
|
|
214
|
+
void w.terminate();
|
|
215
|
+
}
|
|
216
|
+
catch { /* already gone */ }
|
|
217
|
+
if (this.healthy)
|
|
218
|
+
this.spawnOne(); // keep capacity
|
|
219
|
+
if (job) {
|
|
220
|
+
if (job.retries < this.maxRetries && this.healthy) {
|
|
221
|
+
job.retries++;
|
|
222
|
+
this.queue.unshift(job); // head of line — retry promptly
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
this.settle(job, { isError: true, content: [{ type: 'text', text: 'codegraph worker crashed; please retry the call.' }] });
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
this.drain();
|
|
229
|
+
}
|
|
230
|
+
drain() {
|
|
231
|
+
// Grow toward maxSize while queued work outstrips workers that are idle OR
|
|
232
|
+
// already on their way up (pending) — so we never spawn the whole pool for a
|
|
233
|
+
// single call whose eager worker just hasn't reported ready yet.
|
|
234
|
+
while (this.queue.length > this.idle.length + this.pendingWorkers.size &&
|
|
235
|
+
this.workers.size < this.maxSize &&
|
|
236
|
+
this.pendingWorkers.size < MAX_CONCURRENT_SPAWN &&
|
|
237
|
+
this.healthy) {
|
|
238
|
+
this.spawnOne();
|
|
239
|
+
}
|
|
240
|
+
while (this.idle.length && this.queue.length) {
|
|
241
|
+
// Skip jobs the backstop already answered.
|
|
242
|
+
let job;
|
|
243
|
+
while (this.queue.length && (job = this.queue.shift()) && job.settled)
|
|
244
|
+
job = undefined;
|
|
245
|
+
if (!job || job.settled)
|
|
246
|
+
break;
|
|
247
|
+
const w = this.idle.pop();
|
|
248
|
+
this.inflight.set(w, job);
|
|
249
|
+
w.postMessage({ type: 'call', id: job.id, toolName: job.toolName, args: job.args });
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
settle(job, result) {
|
|
253
|
+
if (job.settled)
|
|
254
|
+
return; // already answered (by backstop or worker)
|
|
255
|
+
job.settled = true;
|
|
256
|
+
if (job.softTimer)
|
|
257
|
+
clearTimeout(job.softTimer);
|
|
258
|
+
job.resolve(result);
|
|
259
|
+
}
|
|
260
|
+
/** Run a read tool on the pool. Always resolves (never rejects). */
|
|
261
|
+
run(toolName, args) {
|
|
262
|
+
return new Promise((resolve) => {
|
|
263
|
+
const job = {
|
|
264
|
+
id: this.nextId++, toolName, args, resolve,
|
|
265
|
+
retries: 0, settled: false, enqueuedAt: Date.now(),
|
|
266
|
+
};
|
|
267
|
+
// Don't let the caller wait past softTimeoutMs. The worker may still be
|
|
268
|
+
// busy (we can't cancel synchronous CPU), but the CLIENT gets a prompt,
|
|
269
|
+
// success-shaped "retry" instead of a hard timeout.
|
|
270
|
+
job.softTimer = setTimeout(() => {
|
|
271
|
+
if (!job.settled)
|
|
272
|
+
this.settle(job, busyGuidance(Date.now() - job.enqueuedAt));
|
|
273
|
+
}, this.softTimeoutMs);
|
|
274
|
+
job.softTimer.unref?.();
|
|
275
|
+
this.queue.push(job);
|
|
276
|
+
this.drain();
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
/** Terminate all workers and answer any outstanding calls gracefully. */
|
|
280
|
+
async destroy() {
|
|
281
|
+
if (this.destroyed)
|
|
282
|
+
return;
|
|
283
|
+
this.destroyed = true;
|
|
284
|
+
const ws = [...this.workers];
|
|
285
|
+
this.workers.clear();
|
|
286
|
+
this.pendingWorkers.clear();
|
|
287
|
+
this.idle = [];
|
|
288
|
+
for (const job of [...this.inflight.values(), ...this.queue]) {
|
|
289
|
+
this.settle(job, { isError: true, content: [{ type: 'text', text: 'codegraph is shutting down; retry shortly.' }] });
|
|
290
|
+
}
|
|
291
|
+
this.inflight.clear();
|
|
292
|
+
this.queue = [];
|
|
293
|
+
await Promise.all(ws.map((w) => Promise.resolve(w.terminate()).catch(() => { })));
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
exports.QueryPool = QueryPool;
|
|
297
|
+
//# sourceMappingURL=query-pool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-pool.js","sourceRoot":"","sources":["../../src/mcp/query-pool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Query worker thread — issue: concurrent MCP tool calls starve the daemon.
|
|
3
|
+
*
|
|
4
|
+
* The shared daemon serves every session on ONE event loop with synchronous
|
|
5
|
+
* `node:sqlite`. `codegraph_explore` is CPU-heavy (FTS + RWR/personalized-
|
|
6
|
+
* PageRank + impact + output building) stitched together by microtask `await`s,
|
|
7
|
+
* so N concurrent explores keep the microtask queue continuously full and
|
|
8
|
+
* starve the macrotask phases — timers AND socket I/O. The transport freezes:
|
|
9
|
+
* no response flushes, no request is read, until the whole batch drains. With
|
|
10
|
+
* ~10 subagents that routinely exceeds the MCP client's request timeout.
|
|
11
|
+
*
|
|
12
|
+
* This worker moves the heavy read-tool dispatch OFF the daemon's main loop.
|
|
13
|
+
* Each worker owns its OWN read connection (node:sqlite WAL allows N concurrent
|
|
14
|
+
* readers across connections — verified: a worker reader sees the main writer's
|
|
15
|
+
* committed catch-up/watcher writes), so {@link QueryPool} runs N tool calls in
|
|
16
|
+
* true parallel up to core count while the main loop stays free for the MCP
|
|
17
|
+
* transport. The worker runs {@link ToolHandler.executeReadTool} — validation +
|
|
18
|
+
* dispatch + error classification — and returns the raw {@link ToolResult}; the
|
|
19
|
+
* MAIN thread keeps the catch-up gate, the watcher-state notices (staleness /
|
|
20
|
+
* worktree), `codegraph_status`, and telemetry, none of which a watcher-less
|
|
21
|
+
* read connection can answer.
|
|
22
|
+
*/
|
|
23
|
+
export {};
|
|
24
|
+
//# sourceMappingURL=query-worker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-worker.d.ts","sourceRoot":"","sources":["../../src/mcp/query-worker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG"}
|