* Handle codegraph_status
(args: Record<string, unknown>)
| 6382 | * Handle codegraph_status |
| 6383 | */ |
| 6384 | private async handleStatus(args: Record<string, unknown>): Promise<ToolResult> { |
| 6385 | let cg = this.getCodeGraph(args.projectPath as string | undefined); |
| 6386 | // Same trick as withStalenessNotice — when an explicit projectPath |
| 6387 | // resolves to the same project as the default session cg, prefer the |
| 6388 | // default so getPendingFiles() (only populated by the default's watcher) |
| 6389 | // is non-empty when there are pending edits. |
| 6390 | if (this.cg && cg !== this.cg) { |
| 6391 | try { |
| 6392 | if (resolvePath(this.cg.getProjectRoot()) === resolvePath(cg.getProjectRoot())) { |
| 6393 | cg = this.cg; |
| 6394 | } |
| 6395 | } catch { /* closed instance — leave as is */ } |
| 6396 | } |
| 6397 | const stats = cg.getStats(); |
| 6398 | |
| 6399 | // Warn when this index actually belongs to a different git working tree |
| 6400 | // (e.g. the server resolved up from a nested worktree to the main checkout). |
| 6401 | // Queries then reflect that tree's branch, not the worktree being edited. |
| 6402 | // status shows the verbose, multi-line form; the read tools get the compact |
| 6403 | // one-liner via withWorktreeNotice. Both share the cached detection. |
| 6404 | const mismatch = this.worktreeMismatchFor(args.projectPath as string | undefined); |
| 6405 | |
| 6406 | const lines: string[] = [ |
| 6407 | '**CodeGraph Status**', |
| 6408 | '', |
| 6409 | ]; |
| 6410 | if (mismatch) { |
| 6411 | lines.push(`> ⚠ ${worktreeMismatchWarning(mismatch).replace(/\n/g, '\n> ')}`, ''); |
| 6412 | } |
| 6413 | lines.push( |
| 6414 | `**Files indexed:** ${stats.fileCount}`, |
| 6415 | `**Total nodes:** ${stats.nodeCount}`, |
| 6416 | `**Total edges:** ${stats.edgeCount}`, |
| 6417 | `**Database size:** ${(stats.dbSizeBytes / 1024 / 1024).toFixed(2)} MB`, |
| 6418 | ); |
| 6419 | |
| 6420 | // Surface the active SQLite backend (node:sqlite, Node's built-in real |
| 6421 | // SQLite — full WAL + FTS5, no native build). |
| 6422 | lines.push(`**Backend:** node:sqlite (Node built-in) — full WAL + FTS5`); |
| 6423 | |
| 6424 | // Effective journal mode. 'wal' ⇒ concurrent reads never block on a writer; |
| 6425 | // anything else ⇒ they can ("database is locked"). node:sqlite supports WAL |
| 6426 | // everywhere, so a non-wal mode means the filesystem can't (network/ |
| 6427 | // virtualized mounts, WSL2 /mnt). See issue #238. |
| 6428 | const journalMode = cg.getJournalMode(); |
| 6429 | if (journalMode === 'wal') { |
| 6430 | lines.push(`**Journal mode:** wal (concurrent reads safe)`); |
| 6431 | } else { |
| 6432 | lines.push( |
| 6433 | `**Journal mode:** ⚠ ${journalMode || 'unknown'} — WAL not active, so reads ` + |
| 6434 | `can block on a concurrent write (WAL appears unsupported on this filesystem)` |
| 6435 | ); |
| 6436 | } |
| 6437 | |
| 6438 | // A newer release exists (#1243) — status is where users and agents look |
| 6439 | // when something seems off, so surface the drift here too. Cheap memoized |
| 6440 | // cache read; absent entirely when up to date or opted out. |
| 6441 | const updateNotice = getUpdateNotice(); |
no test coverage detected