homegraph 1.5.5 → 1.5.6

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.
Files changed (47) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/bin/homegraph.js +6 -0
  3. package/dist/bin/homegraph.js.map +1 -1
  4. package/dist/db/migrations.d.ts +1 -1
  5. package/dist/db/migrations.d.ts.map +1 -1
  6. package/dist/db/migrations.js +37 -1
  7. package/dist/db/migrations.js.map +1 -1
  8. package/dist/db/queries.d.ts +25 -0
  9. package/dist/db/queries.d.ts.map +1 -1
  10. package/dist/db/queries.js +50 -2
  11. package/dist/db/queries.js.map +1 -1
  12. package/dist/db/schema.sql +24 -0
  13. package/dist/extraction/languages/arkts.d.ts +15 -0
  14. package/dist/extraction/languages/arkts.d.ts.map +1 -1
  15. package/dist/extraction/languages/arkts.js +118 -0
  16. package/dist/extraction/languages/arkts.js.map +1 -1
  17. package/dist/index.d.ts +31 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +87 -1
  20. package/dist/index.js.map +1 -1
  21. package/dist/mcp/engine.d.ts +26 -0
  22. package/dist/mcp/engine.d.ts.map +1 -1
  23. package/dist/mcp/engine.js +229 -8
  24. package/dist/mcp/engine.js.map +1 -1
  25. package/dist/mcp/index.d.ts.map +1 -1
  26. package/dist/mcp/index.js +16 -1
  27. package/dist/mcp/index.js.map +1 -1
  28. package/dist/mcp/query-pool.js +4 -4
  29. package/dist/mcp/server-instructions.d.ts +1 -1
  30. package/dist/mcp/server-instructions.d.ts.map +1 -1
  31. package/dist/mcp/server-instructions.js +2 -0
  32. package/dist/mcp/server-instructions.js.map +1 -1
  33. package/dist/mcp/tools.d.ts +10 -0
  34. package/dist/mcp/tools.d.ts.map +1 -1
  35. package/dist/mcp/tools.js +138 -3
  36. package/dist/mcp/tools.js.map +1 -1
  37. package/dist/project-map/index.d.ts +33 -0
  38. package/dist/project-map/index.d.ts.map +1 -0
  39. package/dist/project-map/index.js +260 -0
  40. package/dist/project-map/index.js.map +1 -0
  41. package/dist/sync/watcher.d.ts +15 -3
  42. package/dist/sync/watcher.d.ts.map +1 -1
  43. package/dist/sync/watcher.js +14 -1
  44. package/dist/sync/watcher.js.map +1 -1
  45. package/dist/types.d.ts +6 -0
  46. package/dist/types.d.ts.map +1 -1
  47. package/package.json +1 -1
package/dist/mcp/tools.js CHANGED
@@ -944,6 +944,27 @@ exports.tools = [
944
944
  },
945
945
  annotations: READ_ONLY_ANNOTATIONS,
946
946
  },
947
+ {
948
+ name: 'homegraph_project',
949
+ description: 'Shallow project map: modules + files per module (no symbols/call edges). ' +
950
+ 'PRIMARY for engineering overview while the full index is still building; also useful after full index. ' +
951
+ 'Optional `module` filters by name/path; `includeFiles` defaults true.',
952
+ inputSchema: {
953
+ type: 'object',
954
+ properties: {
955
+ module: {
956
+ type: 'string',
957
+ description: 'Optional module name or root path substring to filter.',
958
+ },
959
+ includeFiles: {
960
+ type: 'boolean',
961
+ description: 'Include per-module file lists (default true). Set false for module list only.',
962
+ },
963
+ projectPath: projectPathProperty,
964
+ },
965
+ },
966
+ annotations: READ_ONLY_ANNOTATIONS,
967
+ },
947
968
  {
948
969
  name: 'homegraph_arkui_migrate',
949
970
  description: 'ArkUI migrate / state-semantics snapshot in ONE call (components, state decorators + args, ' +
@@ -1459,6 +1480,7 @@ class ToolHandler {
1459
1480
  'homegraph_search',
1460
1481
  'homegraph_node',
1461
1482
  'homegraph_diff_impact',
1483
+ 'homegraph_project',
1462
1484
  ]);
1463
1485
  if (stats.fileCount < TINY_REPO_FILE_THRESHOLD) {
1464
1486
  visible = visible.filter(t => TINY_REPO_CORE_TOOLS.has(t.name));
@@ -1953,6 +1975,19 @@ class ToolHandler {
1953
1975
  if (toolName === 'homegraph_status') {
1954
1976
  return await this.handleStatus(args);
1955
1977
  }
1978
+ // While auto-init is still on the fast/indexing phases (no symbols yet),
1979
+ // deep tools return guidance so the agent uses homegraph_project instead
1980
+ // of abandoning HomeGraph after empty explore results.
1981
+ if (toolName !== 'homegraph_project') {
1982
+ try {
1983
+ const gated = this.maybeDeepToolPhaseGate(this.getHomeGraph(projectPath), toolName);
1984
+ if (gated)
1985
+ return gated;
1986
+ }
1987
+ catch {
1988
+ /* NotIndexed / sources disabled — fall through to normal handlers */
1989
+ }
1990
+ }
1956
1991
  // Every read tool races a deadline ≪ MCP client ~60s hard timeout and
1957
1992
  // Named-member / local-compact questions finish in tens of ms on the warm
1958
1993
  // main connection. Serving them here — before the query-pool offload —
@@ -2155,7 +2190,8 @@ class ToolHandler {
2155
2190
  || toolName === 'homegraph_node'
2156
2191
  || toolName === 'homegraph_callers'
2157
2192
  || toolName === 'homegraph_callees'
2158
- || toolName === 'homegraph_files';
2193
+ || toolName === 'homegraph_files'
2194
+ || toolName === 'homegraph_project';
2159
2195
  const work = () => {
2160
2196
  if (!light && this.queryPool && this.queryPool.healthy) {
2161
2197
  return this.queryPool.run(toolName, args, {
@@ -2240,6 +2276,16 @@ class ToolHandler {
2240
2276
  * NotIndexed/PathRefusal, which {@link executeReadTool} classifies.
2241
2277
  */
2242
2278
  async dispatchTool(toolName, args) {
2279
+ if (toolName !== 'homegraph_project' && toolName !== 'homegraph_status') {
2280
+ try {
2281
+ const gated = this.maybeDeepToolPhaseGate(this.getHomeGraph(args.projectPath), toolName);
2282
+ if (gated)
2283
+ return gated;
2284
+ }
2285
+ catch {
2286
+ /* fall through */
2287
+ }
2288
+ }
2243
2289
  switch (toolName) {
2244
2290
  case 'homegraph_search': return await this.handleSearch(args);
2245
2291
  case 'homegraph_callers': return await this.handleCallers(args);
@@ -2252,6 +2298,7 @@ class ToolHandler {
2252
2298
  case 'homegraph_native': return await this.handleSpecializedNative(args);
2253
2299
  case 'homegraph_node': return await this.handleNode(args);
2254
2300
  case 'homegraph_files': return await this.handleFiles(args);
2301
+ case 'homegraph_project': return await this.handleProject(args);
2255
2302
  case 'homegraph_arkui_migrate': return await this.handleArkuiMigrate(args);
2256
2303
  case 'homegraph_spec_match': return await this.handleSpecMatch(args);
2257
2304
  case 'homegraph_spec_find': return await this.handleSpecFind(args);
@@ -2259,6 +2306,36 @@ class ToolHandler {
2259
2306
  default: return this.errorResult(`Unknown tool: ${toolName}`);
2260
2307
  }
2261
2308
  }
2309
+ /**
2310
+ * Gate symbol/graph tools while auto-init is still on the fast map or
2311
+ * background full index (and no nodes exist yet). Success-shaped guidance —
2312
+ * never isError — so agents keep using HomeGraph.
2313
+ */
2314
+ maybeDeepToolPhaseGate(cg, _toolName) {
2315
+ const phase = cg.getBuildPhase();
2316
+ if (phase === 'full')
2317
+ return null;
2318
+ try {
2319
+ if (cg.getStats().nodeCount > 0)
2320
+ return null;
2321
+ }
2322
+ catch {
2323
+ /* ignore */
2324
+ }
2325
+ if (phase === 'fast' || phase === 'indexing') {
2326
+ return this.textResult([
2327
+ `Full symbol index is still building (phase=${phase}).`,
2328
+ 'Use `homegraph_project` for the module/file map now, then retry this tool once indexing finishes.',
2329
+ ].join('\n'));
2330
+ }
2331
+ if (phase === 'building_fast' || phase === 'none') {
2332
+ return this.textResult([
2333
+ 'HomeGraph is still preparing the project map.',
2334
+ 'Retry in a few seconds, or call `homegraph_project` once the fast build completes.',
2335
+ ].join('\n'));
2336
+ }
2337
+ return null;
2338
+ }
2262
2339
  async handleSearch(args) {
2263
2340
  const query = this.validateString(args.query, 'query');
2264
2341
  if (typeof query !== 'string')
@@ -5318,7 +5395,7 @@ class ToolHandler {
5318
5395
  tryFastInventoryExplore(cg, query, projectRoot) {
5319
5396
  if (!(0, query_utils_1.shouldTryFastInventoryExplore)(query))
5320
5397
  return null;
5321
- // Multi-Type dependency asks: inventory-only early exit (avoids fat compact / 25s busy).
5398
+ // Multi-Type dependency asks: inventory-only early exit (avoids fat compact / busy timeout).
5322
5399
  if ((0, query_utils_1.queryAsMultiTypeDependencySurvey)(query)) {
5323
5400
  const multi = this.buildMultiTypeDependencySection(cg, query);
5324
5401
  if (multi.section) {
@@ -11317,7 +11394,7 @@ class ToolHandler {
11317
11394
  if (mismatch) {
11318
11395
  lines.push(`> ⚠ ${(0, worktree_1.worktreeMismatchWarning)(mismatch).replace(/\n/g, '\n> ')}`, '');
11319
11396
  }
11320
- lines.push(`**Files indexed:** ${stats.fileCount}`, `**Total nodes:** ${stats.nodeCount}`, `**Total edges:** ${stats.edgeCount}`, `**Database size:** ${(stats.dbSizeBytes / 1024 / 1024).toFixed(2)} MB`, ...(stats.walSizeBytes > 0
11397
+ lines.push(`**Build phase:** ${cg.getBuildPhase()}`, `**Files indexed:** ${stats.fileCount}`, `**Total nodes:** ${stats.nodeCount}`, `**Total edges:** ${stats.edgeCount}`, `**Database size:** ${(stats.dbSizeBytes / 1024 / 1024).toFixed(2)} MB`, ...(stats.walSizeBytes > 0
11321
11398
  ? [`**WAL size:** ${(stats.walSizeBytes / 1024 / 1024).toFixed(2)} MB`]
11322
11399
  : []), `**Graph sources:** ${cg.getGraphSources()}`);
11323
11400
  // Surface the active SQLite backend: node:sqlite → better-sqlite3 → wasm.
@@ -11382,6 +11459,64 @@ class ToolHandler {
11382
11459
  }
11383
11460
  return this.textResult(lines.join('\n'));
11384
11461
  }
11462
+ /**
11463
+ * Handle homegraph_project — shallow module → file map (fast build).
11464
+ */
11465
+ async handleProject(args) {
11466
+ const cg = this.getHomeGraph(args.projectPath);
11467
+ const phase = cg.getBuildPhase();
11468
+ if (phase === 'building_fast') {
11469
+ return this.textResult('Fast project map is still building — retry in a few seconds.');
11470
+ }
11471
+ let map = cg.getProjectMap({
11472
+ module: typeof args.module === 'string' ? args.module : undefined,
11473
+ includeFiles: args.includeFiles !== false,
11474
+ });
11475
+ // On-demand build for indexes that never ran the fast path (legacy / CLI init).
11476
+ if (map.modules.length === 0) {
11477
+ try {
11478
+ cg.buildProjectMap();
11479
+ if (phase === 'none') {
11480
+ cg.setBuildPhase(cg.getStats().nodeCount > 0 ? 'full' : 'fast');
11481
+ }
11482
+ map = cg.getProjectMap({
11483
+ module: typeof args.module === 'string' ? args.module : undefined,
11484
+ includeFiles: args.includeFiles !== false,
11485
+ });
11486
+ }
11487
+ catch (err) {
11488
+ const message = err instanceof Error ? err.message : String(err);
11489
+ return this.textResult(`Failed to build project map: ${message}`);
11490
+ }
11491
+ }
11492
+ if (map.modules.length === 0) {
11493
+ return this.textResult('No modules found in the project map.');
11494
+ }
11495
+ const FILE_CAP = 80;
11496
+ const lines = [
11497
+ `**Project map** (phase=${map.phase})`,
11498
+ `modules: ${map.modules.length} · files: ${map.fileCount}`,
11499
+ '',
11500
+ ];
11501
+ if (map.phase === 'fast' || map.phase === 'indexing') {
11502
+ lines.push('_Full symbol index still building — this map has modules/files only (no call graph)._', '');
11503
+ }
11504
+ for (const m of map.modules) {
11505
+ const rootLabel = m.rootPath || '.';
11506
+ lines.push(`### ${m.name} (\`${rootLabel}\`) · ${m.kind} · ${m.fileCount} files`);
11507
+ if (m.files && m.files.length > 0) {
11508
+ const shown = m.files.slice(0, FILE_CAP);
11509
+ for (const f of shown) {
11510
+ lines.push(`- ${f.path}`);
11511
+ }
11512
+ if (m.files.length > FILE_CAP) {
11513
+ lines.push(`- … +${m.files.length - FILE_CAP} more`);
11514
+ }
11515
+ }
11516
+ lines.push('');
11517
+ }
11518
+ return this.textResult(lines.join('\n').trimEnd());
11519
+ }
11385
11520
  /**
11386
11521
  * Handle homegraph_arkui_migrate — one-shot ArkUI migrate / state snapshot (spec 0007).
11387
11522
  */