homegraph 1.6.0 → 1.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/README.md +64 -14
- package/dist/db/queries.d.ts +4 -0
- package/dist/db/queries.js +15 -0
- package/dist/graph/evidence-paths.d.ts +2 -0
- package/dist/graph/evidence-paths.js +20 -3
- package/dist/mcp/arkts-evidence-packs.d.ts +17 -0
- package/dist/mcp/arkts-evidence-packs.js +218 -10
- package/dist/mcp/evidence-audit.d.ts +3 -0
- package/dist/mcp/evidence-audit.js +40 -0
- package/dist/mcp/implementation-context.d.ts +35 -0
- package/dist/mcp/implementation-context.js +232 -0
- package/dist/mcp/query-cache.d.ts +1 -15
- package/dist/mcp/query-cache.js +20 -11
- package/dist/mcp/request-evidence.d.ts +69 -0
- package/dist/mcp/request-evidence.js +297 -0
- package/dist/mcp/server-instructions.d.ts +2 -2
- package/dist/mcp/server-instructions.js +8 -8
- package/dist/mcp/tools.d.ts +18 -10
- package/dist/mcp/tools.js +129 -72
- package/dist/search/literal-evidence.js +11 -3
- package/dist/search/query-plan-provider.js +13 -5
- package/dist/search/query-plan.d.ts +3 -1
- package/dist/search/query-plan.js +11 -4
- package/dist/search/request-contract.d.ts +29 -0
- package/dist/search/request-contract.js +76 -0
- package/package.json +1 -1
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.lexEvidenceSource = lexEvidenceSource;
|
|
4
|
+
exports.createRequestEvidenceInspector = createRequestEvidenceInspector;
|
|
5
|
+
exports.renderRequestEvidence = renderRequestEvidence;
|
|
6
|
+
exports.inspectControlEvidence = inspectControlEvidence;
|
|
7
|
+
exports.renderControlEvidence = renderControlEvidence;
|
|
8
|
+
/** Conservative lexical witness reader. It does not evaluate ArkTS or infer data flow.
|
|
9
|
+
* Mask comments, strings, templates and regular expressions before reading structure.
|
|
10
|
+
* Escaped/interpolated strings are deliberately not used as exact literal witnesses.
|
|
11
|
+
*/
|
|
12
|
+
function lexEvidenceSource(source) {
|
|
13
|
+
const chars = source.split('');
|
|
14
|
+
const strings = [];
|
|
15
|
+
const mask = (from, to) => { for (let n = from; n < to; n++)
|
|
16
|
+
if (chars[n] !== '\n')
|
|
17
|
+
chars[n] = ' '; };
|
|
18
|
+
let valid = true;
|
|
19
|
+
for (let i = 0; i < source.length;) {
|
|
20
|
+
const c = source[i];
|
|
21
|
+
const start = i;
|
|
22
|
+
if (c === '/' && source[i + 1] === '/') {
|
|
23
|
+
i = source.indexOf('\n', i);
|
|
24
|
+
if (i < 0)
|
|
25
|
+
i = source.length;
|
|
26
|
+
mask(start, i);
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
if (c === '/' && source[i + 1] === '*') {
|
|
30
|
+
const end = source.indexOf('*/', i + 2);
|
|
31
|
+
valid &&= end >= 0;
|
|
32
|
+
i = end < 0 ? source.length : end + 2;
|
|
33
|
+
mask(start, i);
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
if (c === '"' || c === "'" || c === '`') {
|
|
37
|
+
let escaped = false;
|
|
38
|
+
i++;
|
|
39
|
+
for (; i < source.length && source[i] !== c; i++)
|
|
40
|
+
if (source[i] === '\\') {
|
|
41
|
+
escaped = true;
|
|
42
|
+
i++;
|
|
43
|
+
}
|
|
44
|
+
const closed = i < source.length;
|
|
45
|
+
valid &&= closed;
|
|
46
|
+
i = Math.min(source.length, i + 1);
|
|
47
|
+
if (closed && !escaped && c !== '`')
|
|
48
|
+
strings.push({ start, end: i, value: source.slice(start + 1, i - 1) });
|
|
49
|
+
// Template substitutions require parsing; never infer behavior from such a unit.
|
|
50
|
+
if (c === '`' && source.slice(start, i).includes('${'))
|
|
51
|
+
valid = false;
|
|
52
|
+
mask(start, i);
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
if (c === '/') {
|
|
56
|
+
const before = chars.slice(Math.max(0, i - 16), i).join('').trimEnd();
|
|
57
|
+
if (!before || /[=(:,[!&|?{};]$|\b(?:return|throw|case)$/.test(before)) {
|
|
58
|
+
i++;
|
|
59
|
+
let inClass = false;
|
|
60
|
+
for (; i < source.length; i++) {
|
|
61
|
+
if (source[i] === '\\') {
|
|
62
|
+
i++;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (source[i] === '[')
|
|
66
|
+
inClass = true;
|
|
67
|
+
if (source[i] === ']')
|
|
68
|
+
inClass = false;
|
|
69
|
+
if (source[i] === '/' && !inClass)
|
|
70
|
+
break;
|
|
71
|
+
if (source[i] === '\n') {
|
|
72
|
+
valid = false;
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
valid &&= i < source.length && source[i] === '/';
|
|
77
|
+
i = Math.min(source.length, i + 1);
|
|
78
|
+
while (/[a-z]/i.test(source[i] ?? '') && i < source.length)
|
|
79
|
+
i++;
|
|
80
|
+
mask(start, i);
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
i++;
|
|
85
|
+
}
|
|
86
|
+
const code = chars.join('');
|
|
87
|
+
const pairs = new Map();
|
|
88
|
+
const stack = [];
|
|
89
|
+
for (let i = 0; i < code.length; i++) {
|
|
90
|
+
if ('([{'.includes(code[i]))
|
|
91
|
+
stack.push(i);
|
|
92
|
+
else if (')]}'.includes(code[i])) {
|
|
93
|
+
const open = stack.pop();
|
|
94
|
+
if (open === undefined || '([{'.indexOf(code[open]) !== ')]}'.indexOf(code[i]))
|
|
95
|
+
valid = false;
|
|
96
|
+
else
|
|
97
|
+
pairs.set(open, i);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (stack.length)
|
|
101
|
+
valid = false;
|
|
102
|
+
return { code, strings, pairs, valid };
|
|
103
|
+
}
|
|
104
|
+
const escape = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
105
|
+
const identifierIn = (code, text) => /^[\p{L}_$][\p{L}\p{N}_$]*$/u.test(text)
|
|
106
|
+
&& new RegExp(`(?<![\\p{L}\\p{N}_$])${escape(text)}(?![\\p{L}\\p{N}_$])`, 'u').test(code);
|
|
107
|
+
const literalIn = (tokens, text) => tokens.some(s => s.value === text);
|
|
108
|
+
function objectKind(code) {
|
|
109
|
+
if (/\bextends\s+FormExtensionAbility\b/.test(code))
|
|
110
|
+
return 'form';
|
|
111
|
+
if (/\bnapi_(?:define_properties|module_register|create_function)\s*\(/.test(code))
|
|
112
|
+
return 'native';
|
|
113
|
+
if (/@(?:Component|Entry)\b|\b(?:Button|Image|Text|Column|Row)\s*\(/.test(code))
|
|
114
|
+
return 'ui';
|
|
115
|
+
return undefined;
|
|
116
|
+
}
|
|
117
|
+
function matches(target, parsed) {
|
|
118
|
+
// Paths alone are only hints. A target needs a code identifier or an exact string.
|
|
119
|
+
const text = literalIn(parsed.strings, target.text) || (target.role !== 'literal' && identifierIn(parsed.code, target.text));
|
|
120
|
+
return text && (!target.objectKind || objectKind(parsed.code) === target.objectKind);
|
|
121
|
+
}
|
|
122
|
+
function controls(parsed) {
|
|
123
|
+
if (!parsed.valid)
|
|
124
|
+
return [];
|
|
125
|
+
const { code, pairs } = parsed;
|
|
126
|
+
const out = [];
|
|
127
|
+
const skip = (i) => { while (/\s/.test(code[i] ?? '') && i < code.length)
|
|
128
|
+
i++; return i; };
|
|
129
|
+
for (const m of code.matchAll(/\b(Button|Image|Text|SymbolGlyph|Toggle|Checkbox|Radio|TextInput|TextArea|Select|Search|Slider)\s*\(/g)) {
|
|
130
|
+
const start = m.index;
|
|
131
|
+
if (/[\w$.]/.test(code[start - 1] ?? ''))
|
|
132
|
+
continue;
|
|
133
|
+
const open = start + m[0].lastIndexOf('(');
|
|
134
|
+
const close = pairs.get(open);
|
|
135
|
+
if (close === undefined)
|
|
136
|
+
continue;
|
|
137
|
+
let pos = skip(close + 1);
|
|
138
|
+
let contentEnd = close + 1;
|
|
139
|
+
if (code[pos] === '{') {
|
|
140
|
+
const end = pairs.get(pos);
|
|
141
|
+
if (end === undefined)
|
|
142
|
+
continue;
|
|
143
|
+
contentEnd = end + 1;
|
|
144
|
+
pos = skip(end + 1);
|
|
145
|
+
}
|
|
146
|
+
const attributes = [];
|
|
147
|
+
while (code[pos] === '.') {
|
|
148
|
+
const attribute = code.slice(pos).match(/^\.([A-Za-z_$][\w$]*)\s*\(/);
|
|
149
|
+
if (!attribute)
|
|
150
|
+
break;
|
|
151
|
+
const argStart = pos + attribute[0].lastIndexOf('(');
|
|
152
|
+
const argEnd = pairs.get(argStart);
|
|
153
|
+
if (argEnd === undefined)
|
|
154
|
+
break;
|
|
155
|
+
attributes.push({ name: attribute[1], start: argStart + 1, end: argEnd });
|
|
156
|
+
pos = skip(argEnd + 1);
|
|
157
|
+
}
|
|
158
|
+
// Unexpected syntax leaves the result unknown, never a negative assertion.
|
|
159
|
+
const complete = pos >= code.length || /[};]/.test(code[pos]) || /^(?:[A-Z]\w*\s*\(|if\s*\(|else\b)/.test(code.slice(pos));
|
|
160
|
+
out.push({ start, end: pos, contentEnd, attributes, complete });
|
|
161
|
+
}
|
|
162
|
+
return out;
|
|
163
|
+
}
|
|
164
|
+
/** Reuse one analysis per verified source unit; no disk reads or model calls. */
|
|
165
|
+
function createRequestEvidenceInspector(contract) {
|
|
166
|
+
const parsed = new Map();
|
|
167
|
+
const parsedControls = new Map();
|
|
168
|
+
const read = (unit) => { let p = parsed.get(unit); if (!p) {
|
|
169
|
+
p = lexEvidenceSource(unit.source);
|
|
170
|
+
parsed.set(unit, p);
|
|
171
|
+
} return p; };
|
|
172
|
+
const location = (unit, offset = 0) => `${unit.filePath}:${unit.start + unit.source.slice(0, offset).split('\n').length - 1}`;
|
|
173
|
+
const score = (units) => contract.targets.reduce((total, target) => {
|
|
174
|
+
if (!units.some(u => matches(target, read(u))))
|
|
175
|
+
return total;
|
|
176
|
+
return total + (target.presence === 'requested' ? 1 : target.role === 'page' ? 6 : 3);
|
|
177
|
+
}, 0);
|
|
178
|
+
const inspect = (units) => ({
|
|
179
|
+
scope: 'returned_source_only', runtimeVerified: false,
|
|
180
|
+
targets: contract.targets.map(target => {
|
|
181
|
+
const hits = units.filter(u => matches(target, read(u)));
|
|
182
|
+
const distinctFiles = new Set(hits.map(u => u.filePath));
|
|
183
|
+
return { id: target.id, text: target.text, presence: target.presence,
|
|
184
|
+
status: distinctFiles.size > 1 ? 'ambiguous' : hits.length ? 'observed' : target.presence === 'requested' ? 'requested_not_observed' : 'not_observed',
|
|
185
|
+
locations: hits.slice(0, 3).map(u => location(u)),
|
|
186
|
+
note: hits.length ? 'Exact source witness; page ownership and full requirement still need verification.'
|
|
187
|
+
: target.presence === 'requested' ? 'Requested output may not exist yet; absence is not a retrieval failure.'
|
|
188
|
+
: 'No verified witness in returned declarations; inspect the specified page/object or resource binding.' };
|
|
189
|
+
}),
|
|
190
|
+
behaviors: contract.obligations.map(obligation => {
|
|
191
|
+
const base = { id: obligation.id, text: obligation.text, kind: obligation.kind, locations: [] };
|
|
192
|
+
const target = contract.targets.find(t => t.id === obligation.targetId);
|
|
193
|
+
if (obligation.kind !== 'enabled' || !target)
|
|
194
|
+
return { ...base, status: 'unknown', note: 'Locate the specific control and verify this behavior; no static checker available for this obligation.' };
|
|
195
|
+
const pages = contract.targets.filter(t => t.role === 'page' && t.presence === 'existing');
|
|
196
|
+
const pageSources = new Set(units.filter(u => pages.some(t => matches(t, read(u)))));
|
|
197
|
+
if (pages.length && !pageSources.size)
|
|
198
|
+
return { ...base, status: 'unknown', note: 'Requested page has no returned source witness; locate page ownership before checking the control.' };
|
|
199
|
+
const found = [];
|
|
200
|
+
for (const unit of units) {
|
|
201
|
+
if (pages.length && !pageSources.has(unit))
|
|
202
|
+
continue;
|
|
203
|
+
const p = read(unit);
|
|
204
|
+
let list = parsedControls.get(p);
|
|
205
|
+
if (!list) {
|
|
206
|
+
list = controls(p);
|
|
207
|
+
parsedControls.set(p, list);
|
|
208
|
+
}
|
|
209
|
+
for (const control of list) {
|
|
210
|
+
// Match the declaration content, never strings inside onClick or other attributes.
|
|
211
|
+
const tokens = p.strings.filter(s => s.start >= control.start && s.end <= control.contentEnd);
|
|
212
|
+
const code = p.code.slice(control.start, control.contentEnd);
|
|
213
|
+
if ((literalIn(tokens, target.text) || (target.role === 'symbol' && identifierIn(code, target.text)))
|
|
214
|
+
&& (!target.objectKind || objectKind(p.code) === target.objectKind))
|
|
215
|
+
found.push({ unit, control, parsed: p });
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
// Nested Button { Text('label') } belongs to the outer interactive Button.
|
|
219
|
+
const candidates = found.filter(f => !found.some(parent => parent !== f && parent.unit === f.unit
|
|
220
|
+
&& parent.control.start < f.control.start && parent.control.contentEnd > f.control.contentEnd));
|
|
221
|
+
if (candidates.length !== 1)
|
|
222
|
+
return { ...base, status: 'unknown', note: candidates.length ? 'Several matching controls; disambiguate by page/owner before checking behavior.' : 'Target control absent or unsupported syntax/resource indirection; inspect its complete declaration.' };
|
|
223
|
+
const { unit, control, parsed: p } = candidates[0];
|
|
224
|
+
const bindings = control.attributes.filter(a => a.name === 'enabled');
|
|
225
|
+
const locations = [location(unit, control.start)];
|
|
226
|
+
if (!control.complete || bindings.length > 1)
|
|
227
|
+
return { ...base, locations, status: 'unknown', note: 'Incomplete or repeated enabled modifiers; inspect effective control attributes.' };
|
|
228
|
+
if (!bindings.length)
|
|
229
|
+
return { ...base, locations, status: 'binding_not_observed', note: 'No direct .enabled(...) on this returned control. Images and click guards do not establish enabled state; inspect inherited enablement or add the required binding.' };
|
|
230
|
+
const expression = p.code.slice(bindings[0].start, bindings[0].end).trim();
|
|
231
|
+
if (!expression || /^(?:true|false)$/.test(expression))
|
|
232
|
+
return { ...base, locations, status: 'unknown', note: 'Only a constant or unsupported enabled expression is visible; conditional behavior remains unverified.' };
|
|
233
|
+
return { ...base, locations, status: 'binding_observed', note: 'Direct .enabled(expression) exists on this control. Condition correctness, state updates and runtime behavior remain unverified.' };
|
|
234
|
+
}),
|
|
235
|
+
});
|
|
236
|
+
return { score, inspect };
|
|
237
|
+
}
|
|
238
|
+
function renderRequestEvidence(evidence, targets, behaviors) {
|
|
239
|
+
const safe = (s) => s.replace(/[`\r\n]/g, ' ');
|
|
240
|
+
const rows = [
|
|
241
|
+
...(targets ? evidence.targets.map(t => `- Target ${t.id} “${safe(t.text)}”: ${t.status}. ${t.locations.map(safe).join(', ')} ${t.note}`) : []),
|
|
242
|
+
...(behaviors ? evidence.behaviors.map(b => `- Behavior ${b.id} “${safe(b.text)}”: ${b.status}. ${b.locations.map(safe).join(', ')} ${b.note}`) : []),
|
|
243
|
+
];
|
|
244
|
+
return rows.length ? ['**Request evidence — source coverage is not behavioral completion**', ...rows] : [];
|
|
245
|
+
}
|
|
246
|
+
/** An inventory of returned controls, not a natural-language target match or a UI test.
|
|
247
|
+
* Resource names stay literal: an icon called "undo" is not translated into a task label.
|
|
248
|
+
*/
|
|
249
|
+
function inspectControlEvidence(units) {
|
|
250
|
+
const rows = [];
|
|
251
|
+
const seen = new Set();
|
|
252
|
+
for (const unit of units) {
|
|
253
|
+
if (!/\.ets$/i.test(unit.filePath) || /\.d\.ets$/i.test(unit.filePath))
|
|
254
|
+
continue;
|
|
255
|
+
const p = lexEvidenceSource(unit.source);
|
|
256
|
+
if (!p.valid)
|
|
257
|
+
continue;
|
|
258
|
+
const loc = (offset) => `${unit.filePath}:${unit.start + unit.source.slice(0, offset).split('\n').length - 1}`;
|
|
259
|
+
for (const control of controls(p)) {
|
|
260
|
+
const click = control.attributes.find(a => a.name === 'onClick');
|
|
261
|
+
const bindings = control.attributes.filter(a => a.name === 'enabled');
|
|
262
|
+
if (!click && !bindings.length)
|
|
263
|
+
continue;
|
|
264
|
+
const location = loc(control.start);
|
|
265
|
+
const key = `${location}:${control.start - unit.source.lastIndexOf('\n', control.start)}`;
|
|
266
|
+
if (seen.has(key))
|
|
267
|
+
continue;
|
|
268
|
+
seen.add(key);
|
|
269
|
+
const binding = bindings[0];
|
|
270
|
+
const expression = binding ? unit.source.slice(binding.start, binding.end).trim() : undefined;
|
|
271
|
+
const rawRefs = p.code.slice(control.start, control.contentEnd)
|
|
272
|
+
+ (binding ? p.code.slice(binding.start, binding.end) : '');
|
|
273
|
+
const refs = [...new Set([...rawRefs.matchAll(/\bthis(?:\.[A-Za-z_$][\w$]*)+/g)].map(m => m[0]))].slice(0, 4);
|
|
274
|
+
const state = refs.map(ref => ({ expression: ref, writeLocations: [...p.code.matchAll(new RegExp(`${escape(ref)}(?![\\w$.])\\s*(?:=(?!=|>)|\\+\\+|--|[+*/-]=)`, 'g'))].slice(0, 3).map(m => loc(m.index)) }));
|
|
275
|
+
rows.push({ location, control: p.code.slice(control.start).match(/^\w+/)?.[0] ?? 'control',
|
|
276
|
+
labels: p.strings.filter(t => t.start >= control.start && t.end <= control.contentEnd).map(t => t.value).slice(0, 4),
|
|
277
|
+
enabled: !control.complete || bindings.length > 1 || (expression !== undefined && /^(?:true|false)?$/.test(expression))
|
|
278
|
+
? 'unknown' : binding ? 'binding_observed' : 'binding_not_observed',
|
|
279
|
+
...(expression ? { expression: expression.slice(0, 180) } : {}),
|
|
280
|
+
...(click ? { click: unit.source.slice(click.start, click.end).trim().slice(0, 180) } : {}), state });
|
|
281
|
+
if (rows.length >= 8)
|
|
282
|
+
return rows;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return rows;
|
|
286
|
+
}
|
|
287
|
+
function renderControlEvidence(rows) {
|
|
288
|
+
if (!rows.length)
|
|
289
|
+
return [];
|
|
290
|
+
const safe = (s) => s.replace(/[`\r\n]/g, ' ');
|
|
291
|
+
return ['**Control evidence — static inventory, not requirement completion**',
|
|
292
|
+
'Resource labels identify code only. Missing direct enabled does not exclude inherited enablement. State write locations are local witnesses; conditions, ordering and runtime effects remain unverified.',
|
|
293
|
+
...rows.map(r => `- ${safe(r.location)} ${r.control} ${r.labels.map(safe).join(', ')}: ${r.enabled}`
|
|
294
|
+
+ `${r.expression ? ` (${safe(r.expression)})` : ''}; click: ${r.click ? safe(r.click) : 'not observed'}.`
|
|
295
|
+
+ r.state.map(s => ` State ${safe(s.expression)}: ${s.writeLocations.length ? `local writes at ${s.writeLocations.map(safe).join(', ')}` : 'updates not observed in this declaration'}.`).join(''))];
|
|
296
|
+
}
|
|
297
|
+
//# sourceMappingURL=request-evidence.js.map
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export declare const SERVER_INSTRUCTIONS = "# HomeGraph \u2014 optional structural evidence for this repo\n\n## When to call (path-first, bash-first)\n\nUse ordinary bash/search/read tools first for repository paths, symbols, literal strings and local changes. Skip HomeGraph when those tools provide sufficient evidence, including for difficult implementation tasks. A known path can be read directly; an adequate source result does not need a second graph lookup.\n\nHomeGraph is optional. Use it only for a concrete unresolved relationship that benefits from graph evidence: cross-file state/event propagation, callers/callees, module dependencies or ArkTS-to-native registration. Name the missing relation and use anchors from the current task or source. There is no mandatory number of bash searches before a useful graph query.\n\nChoose the smallest available tool for that gap:\n- Engineering overview / which module owns a feature / where `route_map.json` or resource dirs live \u2192 `homegraph_project` (module map + Harmony skeleton pointers + Module roster with local `file:` deps + bounded resources path inventory: string.json / form_config|shortcuts_config / rawfile / media / on-disk modules not in the graph). It does **not** return symbol bodies, call graphs, or JSON/media contents.\n-
|
|
2
|
-
export declare const SERVER_INSTRUCTIONS_NO_ROOT_INDEX = "# HomeGraph \u2014 optional per-project evidence\n\nPass `projectPath` to an already indexed folder with `.homegraph/`. No index \u2192 use ordinary tools; indexing is managed by the host.\n\n## When to call (path-first, bash-first)\n\nUse ordinary bash/search/read tools first for repository paths, symbols, literal strings and local changes. Skip HomeGraph when those tools provide sufficient evidence, including for difficult implementation tasks. A known path can be read directly; an adequate source result does not need a second graph lookup.\n\nHomeGraph is optional. Use it only for a concrete unresolved relationship that benefits from graph evidence: cross-file state/event propagation, callers/callees, module dependencies or ArkTS-to-native registration. Name the missing relation and use anchors from the current task or source. There is no mandatory number of bash searches before a useful graph query.\n\nChoose the smallest available tool for that gap:\n- Engineering overview / which module owns a feature / where `route_map.json` or resource dirs live \u2192 `homegraph_project` (module map + Harmony skeleton pointers + Module roster with local `file:` deps + bounded resources path inventory: string.json / form_config|shortcuts_config / rawfile / media / on-disk modules not in the graph). It does **not** return symbol bodies, call graphs, or JSON/media contents.\n-
|
|
1
|
+
export declare const SERVER_INSTRUCTIONS = "# HomeGraph \u2014 optional structural evidence for this repo\n\n## When to call (path-first, bash-first)\n\nUse ordinary bash/search/read tools first for repository paths, symbols, literal strings and local changes. Skip HomeGraph when those tools provide sufficient evidence, including for difficult implementation tasks. A known path can be read directly; an adequate source result does not need a second graph lookup.\n\nHomeGraph is optional. Use it only for a concrete unresolved relationship that benefits from graph evidence: cross-file state/event propagation, callers/callees, module dependencies or ArkTS-to-native registration. Name the missing relation and use anchors from the current task or source. There is no mandatory number of bash searches before a useful graph query.\n\nChoose the smallest available tool for that gap:\n- Engineering overview / which module owns a feature / where `route_map.json` or resource dirs live \u2192 `homegraph_project` (module map + Harmony skeleton pointers + Module roster with local `file:` deps + bounded resources path inventory: string.json / form_config|shortcuts_config / rawfile / media / on-disk modules not in the graph). It does **not** return symbol bodies, call graphs, or JSON/media contents.\n- An unresolved cross-symbol mechanism, usage/dependency/native-registration relation, or route registration edges \u2192 `homegraph_explore` (may include Spec 0039 Registration sources for route_map; Spec 0041 Resource hits for `element/string.json` literals; Spec 0048 Capability profiles for form/shortcuts, or an explicit no-in-repo form note; Seam notes for stubs). Do not use it for routine pre-edit orientation, a literal search, or to re-confirm source already found with bash. SDK contracts \u2192 project declarations or SDK documentation.\n- Harmony `element/string.json` key/value lookup is searchable via explore (Resource hits may include bound `.ets` anchors; no graph edges). Project lists resource **paths**; color/other non-allowlisted files still need Grep/Read.\n- Harmony `form_config.json` / `shortcuts_config.json` are indexed as capability profiles (paths + names; no UI edges). Card/shortcut tasks should use explore/project \u2014 do not treat SDK Form `.d.ts` as project wiring when the negative note says no in-repo form.\n\nKeep working directly once the edit location and affected behavior are sufficiently supported. Task difficulty and file count alone do not require graph use.\n\n## Query and recovery\n\nWrite one focused sentence: requested action + target + known anchors + unresolved relation + preservation constraints. Use the full public task as `taskContext` when needed. Keep UI labels verbatim; use exact symbols from the task or source instead of inventing names or piling up generic keywords. Tool replies may begin with `HomeGraph project root: `\u2026`` \u2014 that absolute root is the join base for repo-relative paths below; pass those paths to Read/Grep as-is, or join as `<root>/<relative>` (use `/`). Do not invent experiment/result directory prefixes; a path refusal requires valid in-repo relocation, not broader permissions. When this MCP session already has a bound project root, a mismatched `projectPath` is ignored (results stay on the bound root) with a short English notice \u2014 do not treat that as a hard error.\n\nA project map (`homegraph_project`) is navigation and Harmony skeleton pointers, not proof of a located feature and not a call graph. Preserve requested product/module scope and verify each candidate before editing. Start with one focused graph request; recover only a named missing body/relation. Budget: \u22642 `homegraph_explore` attempts per project. These are ceilings, never a required sequence. If evidence is still missing, use targeted bash/search/read and continue implementation. Do not expand into unrelated files merely to exhaust a budget.\n\n## Index status\n\nTool replies may start with `HomeGraph project root: \u2026` (absolute join base for relative paths) and end with `HomeGraph status=\u2026`. status: empty=not ready \u00B7 fast=map only (homegraph_project) \u00B7 full=fresh \u00B7 dirty=usable but listed paths outdated \u00B7 syncing=write lock, retry.\n\n\n- ArkTS implementation context may include actual imports, related types, module configuration and indexed SDK signatures alongside source. Read unresolved export/version notes; an import does not prove a dependency is installed. Render/navigation links show static wiring and shared users, not guaranteed page reachability.\n- Control evidence inventories the returned icons/labels, direct enabled expressions, click handlers and local state writes. Missing direct enabled does not exclude a parent binding; appearance and click guards alone do not prove disabled state. Continue checking public requirements and runtime behavior.\n\n- ArkTS evidence packs keep complete declarations and the source dependencies of displayed static relations together. Gaps identify omitted, stale or unindexed evidence; inspect only a gap relevant to the task. A static link does not prove runtime ordering or value propagation, and a complete declaration does not prove its enclosing call conditions.\n- ArkTS path evidence follows typed, directed relations between named anchors within a bounded search. A provided path includes intermediate declarations and registration sites. Check its goal and stop reason; no path in scope does not prove no relationship. Qualify ambiguous symbols with their owning type or file.\n- When request evidence is supplied, check target page/object and behavioral gaps before editing. Requested new text need not already exist. A direct enabled binding, full source pack, or connected call path does not establish requirement completion or runtime correctness; inspect unsupported behavior explicitly.\n- Reuse complete, unchanged, line-numbered source ranges already visible. An outline, path list, truncated body or SDK declaration cannot replace missing implementation evidence. A slice hash identifies that excerpt, not the whole file. Refresh affected ranges after edits.\n- An empty edge set means the relation may be unindexed, not absent. For partial, stale or irrelevant results, inspect the exact missing source with scoped search/read. After a query adds no evidence, change the method or scope rather than paraphrasing the same explore.\n- Retrieval completion is not task completion. Continue the requested edits and validation; check the original task's behavior and preservation constraints. Build success alone does not establish functional correctness.\n\nNo index \u2192 use ordinary tools; indexing is managed by the host. Do not run HomeGraph initialization as part of solving the task.\n";
|
|
2
|
+
export declare const SERVER_INSTRUCTIONS_NO_ROOT_INDEX = "# HomeGraph \u2014 optional per-project evidence\n\nPass `projectPath` to an already indexed folder with `.homegraph/`. No index \u2192 use ordinary tools; indexing is managed by the host.\n\n## When to call (path-first, bash-first)\n\nUse ordinary bash/search/read tools first for repository paths, symbols, literal strings and local changes. Skip HomeGraph when those tools provide sufficient evidence, including for difficult implementation tasks. A known path can be read directly; an adequate source result does not need a second graph lookup.\n\nHomeGraph is optional. Use it only for a concrete unresolved relationship that benefits from graph evidence: cross-file state/event propagation, callers/callees, module dependencies or ArkTS-to-native registration. Name the missing relation and use anchors from the current task or source. There is no mandatory number of bash searches before a useful graph query.\n\nChoose the smallest available tool for that gap:\n- Engineering overview / which module owns a feature / where `route_map.json` or resource dirs live \u2192 `homegraph_project` (module map + Harmony skeleton pointers + Module roster with local `file:` deps + bounded resources path inventory: string.json / form_config|shortcuts_config / rawfile / media / on-disk modules not in the graph). It does **not** return symbol bodies, call graphs, or JSON/media contents.\n- An unresolved cross-symbol mechanism, usage/dependency/native-registration relation, or route registration edges \u2192 `homegraph_explore` (may include Spec 0039 Registration sources for route_map; Spec 0041 Resource hits for `element/string.json` literals; Spec 0048 Capability profiles for form/shortcuts, or an explicit no-in-repo form note; Seam notes for stubs). Do not use it for routine pre-edit orientation, a literal search, or to re-confirm source already found with bash. SDK contracts \u2192 project declarations or SDK documentation.\n- Harmony `element/string.json` key/value lookup is searchable via explore (Resource hits may include bound `.ets` anchors; no graph edges). Project lists resource **paths**; color/other non-allowlisted files still need Grep/Read.\n- Harmony `form_config.json` / `shortcuts_config.json` are indexed as capability profiles (paths + names; no UI edges). Card/shortcut tasks should use explore/project \u2014 do not treat SDK Form `.d.ts` as project wiring when the negative note says no in-repo form.\n\nKeep working directly once the edit location and affected behavior are sufficiently supported. Task difficulty and file count alone do not require graph use.\n\n## Query and recovery\n\nWrite one focused sentence: requested action + target + known anchors + unresolved relation + preservation constraints. Use the full public task as `taskContext` when needed. Keep UI labels verbatim; use exact symbols from the task or source instead of inventing names or piling up generic keywords. Tool replies may begin with `HomeGraph project root: `\u2026`` \u2014 that absolute root is the join base for repo-relative paths below; pass those paths to Read/Grep as-is, or join as `<root>/<relative>` (use `/`). Do not invent experiment/result directory prefixes; a path refusal requires valid in-repo relocation, not broader permissions. When this MCP session already has a bound project root, a mismatched `projectPath` is ignored (results stay on the bound root) with a short English notice \u2014 do not treat that as a hard error.\n\nA project map (`homegraph_project`) is navigation and Harmony skeleton pointers, not proof of a located feature and not a call graph. Preserve requested product/module scope and verify each candidate before editing. Start with one focused graph request; recover only a named missing body/relation. Budget: \u22642 `homegraph_explore` attempts per project. These are ceilings, never a required sequence. If evidence is still missing, use targeted bash/search/read and continue implementation. Do not expand into unrelated files merely to exhaust a budget.\n\n## Index status\n\nTool replies may start with `HomeGraph project root: \u2026` (absolute join base for relative paths) and end with `HomeGraph status=\u2026`. status: empty=not ready \u00B7 fast=map only (homegraph_project) \u00B7 full=fresh \u00B7 dirty=usable but listed paths outdated \u00B7 syncing=write lock, retry.\n\n\n- ArkTS implementation context may include actual imports, related types, module configuration and indexed SDK signatures alongside source. Read unresolved export/version notes; an import does not prove a dependency is installed. Render/navigation links show static wiring and shared users, not guaranteed page reachability.\n- Control evidence inventories the returned icons/labels, direct enabled expressions, click handlers and local state writes. Missing direct enabled does not exclude a parent binding; appearance and click guards alone do not prove disabled state. Continue checking public requirements and runtime behavior.\n\n- ArkTS evidence packs keep complete declarations and the source dependencies of displayed static relations together. Gaps identify omitted, stale or unindexed evidence; inspect only a gap relevant to the task. A static link does not prove runtime ordering or value propagation, and a complete declaration does not prove its enclosing call conditions.\n- ArkTS path evidence follows typed, directed relations between named anchors within a bounded search. A provided path includes intermediate declarations and registration sites. Check its goal and stop reason; no path in scope does not prove no relationship. Qualify ambiguous symbols with their owning type or file.\n- When request evidence is supplied, check target page/object and behavioral gaps before editing. Requested new text need not already exist. A direct enabled binding, full source pack, or connected call path does not establish requirement completion or runtime correctness; inspect unsupported behavior explicitly.\n- Reuse complete, unchanged, line-numbered source ranges already visible. An outline, path list, truncated body or SDK declaration cannot replace missing implementation evidence. A slice hash identifies that excerpt, not the whole file. Refresh affected ranges after edits.\n- An empty edge set means the relation may be unindexed, not absent. For partial, stale or irrelevant results, inspect the exact missing source with scoped search/read. After a query adds no evidence, change the method or scope rather than paraphrasing the same explore.\n- Retrieval completion is not task completion. Continue the requested edits and validation; check the original task's behavior and preservation constraints. Build success alone does not establish functional correctness.\n\n";
|
|
3
3
|
//# sourceMappingURL=server-instructions.d.ts.map
|
|
@@ -7,8 +7,12 @@ const index_availability_1 = require("./index-availability");
|
|
|
7
7
|
* 仅调整检索选择,不改变索引、查询语义或编码任务的验收要求。
|
|
8
8
|
*/
|
|
9
9
|
const SOURCE_AND_VALIDATION = `
|
|
10
|
+
- ArkTS implementation context may include actual imports, related types, module configuration and indexed SDK signatures alongside source. Read unresolved export/version notes; an import does not prove a dependency is installed. Render/navigation links show static wiring and shared users, not guaranteed page reachability.
|
|
11
|
+
- Control evidence inventories the returned icons/labels, direct enabled expressions, click handlers and local state writes. Missing direct enabled does not exclude a parent binding; appearance and click guards alone do not prove disabled state. Continue checking public requirements and runtime behavior.
|
|
12
|
+
|
|
10
13
|
- ArkTS evidence packs keep complete declarations and the source dependencies of displayed static relations together. Gaps identify omitted, stale or unindexed evidence; inspect only a gap relevant to the task. A static link does not prove runtime ordering or value propagation, and a complete declaration does not prove its enclosing call conditions.
|
|
11
14
|
- ArkTS path evidence follows typed, directed relations between named anchors within a bounded search. A provided path includes intermediate declarations and registration sites. Check its goal and stop reason; no path in scope does not prove no relationship. Qualify ambiguous symbols with their owning type or file.
|
|
15
|
+
- When request evidence is supplied, check target page/object and behavioral gaps before editing. Requested new text need not already exist. A direct enabled binding, full source pack, or connected call path does not establish requirement completion or runtime correctness; inspect unsupported behavior explicitly.
|
|
12
16
|
- Reuse complete, unchanged, line-numbered source ranges already visible. An outline, path list, truncated body or SDK declaration cannot replace missing implementation evidence. A slice hash identifies that excerpt, not the whole file. Refresh affected ranges after edits.
|
|
13
17
|
- An empty edge set means the relation may be unindexed, not absent. For partial, stale or irrelevant results, inspect the exact missing source with scoped search/read. After a query adds no evidence, change the method or scope rather than paraphrasing the same explore.
|
|
14
18
|
- Retrieval completion is not task completion. Continue the requested edits and validation; check the original task's behavior and preservation constraints. Build success alone does not establish functional correctness.
|
|
@@ -21,21 +25,17 @@ HomeGraph is optional. Use it only for a concrete unresolved relationship that b
|
|
|
21
25
|
|
|
22
26
|
Choose the smallest available tool for that gap:
|
|
23
27
|
- Engineering overview / which module owns a feature / where \`route_map.json\` or resource dirs live → \`homegraph_project\` (module map + Harmony skeleton pointers + Module roster with local \`file:\` deps + bounded resources path inventory: string.json / form_config|shortcuts_config / rawfile / media / on-disk modules not in the graph). It does **not** return symbol bodies, call graphs, or JSON/media contents.
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
- One missing symbol body → \`homegraph_node\`; prefer direct read if its path is already known.
|
|
27
|
-
- An unresolved cross-symbol mechanism or route registration edges → \`homegraph_explore\` (may include Spec 0039 Registration sources for route_map; Spec 0041 Resource hits for \`element/string.json\` literals; Spec 0048 Capability profiles for form/shortcuts, or an explicit no-in-repo form note; Seam notes for stubs). Do not use it for routine pre-edit orientation, a literal search, or to re-confirm source already found with bash.
|
|
28
|
-
- ArkUI migration analysis → \`homegraph_arkui_migrate\` when that analysis is needed; SDK contracts → project declarations or SDK documentation.
|
|
29
|
-
- Harmony \`element/string.json\` key/value lookup is searchable via explore/search (Resource hits may include bound \`.ets\` anchors; no graph edges). Project lists resource **paths**; color/other non-allowlisted files still need Grep/Read.
|
|
28
|
+
- An unresolved cross-symbol mechanism, usage/dependency/native-registration relation, or route registration edges → \`homegraph_explore\` (may include Spec 0039 Registration sources for route_map; Spec 0041 Resource hits for \`element/string.json\` literals; Spec 0048 Capability profiles for form/shortcuts, or an explicit no-in-repo form note; Seam notes for stubs). Do not use it for routine pre-edit orientation, a literal search, or to re-confirm source already found with bash. SDK contracts → project declarations or SDK documentation.
|
|
29
|
+
- Harmony \`element/string.json\` key/value lookup is searchable via explore (Resource hits may include bound \`.ets\` anchors; no graph edges). Project lists resource **paths**; color/other non-allowlisted files still need Grep/Read.
|
|
30
30
|
- Harmony \`form_config.json\` / \`shortcuts_config.json\` are indexed as capability profiles (paths + names; no UI edges). Card/shortcut tasks should use explore/project — do not treat SDK Form \`.d.ts\` as project wiring when the negative note says no in-repo form.
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
Keep working directly once the edit location and affected behavior are sufficiently supported. Task difficulty and file count alone do not require graph use.
|
|
33
33
|
`;
|
|
34
34
|
const QUERY = `## Query and recovery
|
|
35
35
|
|
|
36
36
|
Write one focused sentence: requested action + target + known anchors + unresolved relation + preservation constraints. Use the full public task as \`taskContext\` when needed. Keep UI labels verbatim; use exact symbols from the task or source instead of inventing names or piling up generic keywords. Tool replies may begin with \`HomeGraph project root: \`…\`\` — that absolute root is the join base for repo-relative paths below; pass those paths to Read/Grep as-is, or join as \`<root>/<relative>\` (use \`/\`). Do not invent experiment/result directory prefixes; a path refusal requires valid in-repo relocation, not broader permissions. When this MCP session already has a bound project root, a mismatched \`projectPath\` is ignored (results stay on the bound root) with a short English notice — do not treat that as a hard error.
|
|
37
37
|
|
|
38
|
-
A project map (\`homegraph_project\`) is navigation and Harmony skeleton pointers, not proof of a located feature and not a call graph. Preserve requested product/module scope and verify each candidate before editing. Start with one focused graph request; recover only a named missing body/relation. Budget: ≤2 \`homegraph_explore\` attempts per project
|
|
38
|
+
A project map (\`homegraph_project\`) is navigation and Harmony skeleton pointers, not proof of a located feature and not a call graph. Preserve requested product/module scope and verify each candidate before editing. Start with one focused graph request; recover only a named missing body/relation. Budget: ≤2 \`homegraph_explore\` attempts per project. These are ceilings, never a required sequence. If evidence is still missing, use targeted bash/search/read and continue implementation. Do not expand into unrelated files merely to exhaust a budget.
|
|
39
39
|
`;
|
|
40
40
|
const INDEX_STATUS = `## Index status
|
|
41
41
|
|
package/dist/mcp/tools.d.ts
CHANGED
|
@@ -238,15 +238,26 @@ export interface ToolResult {
|
|
|
238
238
|
_hgExploreEmission?: ExploreEmission;
|
|
239
239
|
}
|
|
240
240
|
/**
|
|
241
|
-
* All HomeGraph MCP
|
|
241
|
+
* All HomeGraph MCP tool definitions (handlers stay registered).
|
|
242
242
|
*
|
|
243
|
-
*
|
|
244
|
-
* explore
|
|
243
|
+
* Default tools/list is the slim pair in `DEFAULT_MCP_TOOL_SHORT_NAMES`
|
|
244
|
+
* (explore / project). Opt into the full catalog with
|
|
245
|
+
* `HOMEGRAPH_MCP_TOOLS=all`. Skip HomeGraph entirely for topic file-lists,
|
|
245
246
|
* concept compares, SDK catalogs, and literal greps.
|
|
246
247
|
*
|
|
247
248
|
* All tools support cross-project queries via the optional `projectPath` parameter.
|
|
248
249
|
*/
|
|
249
250
|
export declare const tools: ToolDefinition[];
|
|
251
|
+
/**
|
|
252
|
+
* Default MCP tools/list surface (product slim). Handlers for other tools remain
|
|
253
|
+
* in-tree; restore the full catalog with `HOMEGRAPH_MCP_TOOLS=all` (or `*`), or
|
|
254
|
+
* name a comma list (e.g. `explore,node,search,arkui_migrate`).
|
|
255
|
+
*/
|
|
256
|
+
export declare const DEFAULT_MCP_TOOL_SHORT_NAMES: readonly ["explore", "project"];
|
|
257
|
+
/** Parsed HOMEGRAPH_MCP_TOOLS: a short-name set, or `'all'` for the full catalog. */
|
|
258
|
+
export type McpToolAllowlist = Set<string> | 'all';
|
|
259
|
+
/** Resolve the exposed-tool allowlist from env (default = product slim pair). */
|
|
260
|
+
export declare function resolveMcpToolAllowlist(raw?: string | undefined): McpToolAllowlist;
|
|
250
261
|
/**
|
|
251
262
|
* Allowlist-filtered tool definitions WITHOUT an engine — the static surface the
|
|
252
263
|
* proxy answers `tools/list` with before any project is open. Mirrors
|
|
@@ -326,16 +337,13 @@ export declare class ToolHandler {
|
|
|
326
337
|
*/
|
|
327
338
|
hasDefaultHomeGraph(): boolean;
|
|
328
339
|
/**
|
|
329
|
-
* Optional allowlist of exposed tools, parsed from
|
|
330
|
-
*
|
|
331
|
-
*
|
|
332
|
-
* exposed. Lets an operator (or an A/B harness) trim the tool surface
|
|
333
|
-
* without rebuilding the client config; the ablated tool is then truly
|
|
334
|
-
* absent from ListTools rather than merely denied on call.
|
|
340
|
+
* Optional allowlist of exposed tools, parsed from HOMEGRAPH_MCP_TOOLS.
|
|
341
|
+
* Unset/empty → product slim default (`explore`, `project`).
|
|
342
|
+
* `all` / `*` → full catalog. Comma list → only those short names.
|
|
335
343
|
* Matching is on the short form, so "node" and "homegraph_node" both work.
|
|
336
344
|
*/
|
|
337
345
|
private toolAllowlist;
|
|
338
|
-
/** Whether a tool name passes the HOMEGRAPH_MCP_TOOLS allowlist
|
|
346
|
+
/** Whether a tool name passes the HOMEGRAPH_MCP_TOOLS allowlist. */
|
|
339
347
|
private isToolAllowed;
|
|
340
348
|
/**
|
|
341
349
|
* Get tool definitions with dynamic descriptions based on project size.
|