grov 0.5.5 → 0.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.
package/dist/cli.js CHANGED
@@ -127,4 +127,12 @@ program
127
127
  const { sync } = await import('./commands/sync.js');
128
128
  await sync(options);
129
129
  }));
130
+ // grov doctor - Diagnose setup issues
131
+ program
132
+ .command('doctor')
133
+ .description('Check grov setup and diagnose issues')
134
+ .action(safeAction(async () => {
135
+ const { doctor } = await import('./commands/doctor.js');
136
+ await doctor();
137
+ }));
130
138
  program.parse();
@@ -0,0 +1 @@
1
+ export declare function doctor(): Promise<void>;
@@ -0,0 +1,88 @@
1
+ // grov doctor - Check setup and diagnose issues
2
+ import { existsSync, readFileSync } from 'fs';
3
+ import { homedir } from 'os';
4
+ import { join } from 'path';
5
+ import { request } from 'undici';
6
+ import { readCredentials, getSyncStatus } from '../lib/credentials.js';
7
+ import { initDatabase } from '../lib/store/database.js';
8
+ const CLAUDE_SETTINGS_PATH = join(homedir(), '.claude', 'settings.json');
9
+ const DB_PATH = join(homedir(), '.grov', 'memory.db');
10
+ export async function doctor() {
11
+ console.log('\nGrov Doctor');
12
+ console.log('===========\n');
13
+ // Check proxy
14
+ const proxyRunning = await checkProxy();
15
+ printCheck('Proxy', proxyRunning, 'Running on port 8080', 'Not running', 'grov proxy');
16
+ // Check Claude settings
17
+ const baseUrlConfigured = checkBaseUrl();
18
+ printCheck('ANTHROPIC_BASE_URL', baseUrlConfigured, 'Configured for proxy', 'Not configured', 'grov init');
19
+ // Check API key
20
+ const apiKey = process.env.ANTHROPIC_API_KEY;
21
+ const hasApiKey = !!(apiKey && apiKey.length > 10);
22
+ const apiKeyFix = process.platform === 'win32'
23
+ ? 'set ANTHROPIC_API_KEY=sk-ant-...'
24
+ : 'export ANTHROPIC_API_KEY=sk-ant-... (add to shell profile)';
25
+ printCheck('ANTHROPIC_API_KEY', hasApiKey, 'Set', 'Not set (task detection disabled)', apiKeyFix);
26
+ // Check login
27
+ const creds = readCredentials();
28
+ printCheck('Login', !!creds, creds ? `Logged in as ${creds.email}` : 'Not logged in', 'Not logged in', 'grov login');
29
+ // Check sync
30
+ const syncStatus = getSyncStatus();
31
+ const syncOk = syncStatus?.enabled && syncStatus?.teamId;
32
+ const syncMsg = syncOk
33
+ ? `Team ${syncStatus.teamId.substring(0, 8)}...`
34
+ : syncStatus?.teamId ? 'Disabled' : 'No team';
35
+ printCheck('Cloud Sync', !!syncOk, syncMsg, syncMsg, 'grov sync --enable --team <id>');
36
+ // Check database
37
+ const dbStats = checkDatabase();
38
+ const dbOk = dbStats.tasks > 0 || dbStats.sessions > 0;
39
+ const dbMsg = `${dbStats.tasks} tasks, ${dbStats.unsynced} unsynced, ${dbStats.sessions} active`;
40
+ printCheck('Local Database', dbOk, dbMsg, 'Empty', 'Use Claude Code with proxy running');
41
+ console.log('');
42
+ }
43
+ async function checkProxy() {
44
+ try {
45
+ const res = await request('http://127.0.0.1:8080/health', {
46
+ headersTimeout: 2000,
47
+ bodyTimeout: 2000
48
+ });
49
+ return res.statusCode === 200;
50
+ }
51
+ catch {
52
+ return false;
53
+ }
54
+ }
55
+ function checkBaseUrl() {
56
+ if (!existsSync(CLAUDE_SETTINGS_PATH))
57
+ return false;
58
+ try {
59
+ const settings = JSON.parse(readFileSync(CLAUDE_SETTINGS_PATH, 'utf-8'));
60
+ return settings.env?.ANTHROPIC_BASE_URL === 'http://127.0.0.1:8080';
61
+ }
62
+ catch {
63
+ return false;
64
+ }
65
+ }
66
+ function checkDatabase() {
67
+ if (!existsSync(DB_PATH)) {
68
+ return { tasks: 0, unsynced: 0, sessions: 0 };
69
+ }
70
+ try {
71
+ const db = initDatabase();
72
+ const tasks = db.prepare('SELECT COUNT(*) as c FROM tasks').get().c;
73
+ const unsynced = db.prepare('SELECT COUNT(*) as c FROM tasks WHERE synced_at IS NULL').get().c;
74
+ const sessions = db.prepare("SELECT COUNT(*) as c FROM session_states WHERE status = 'active'").get().c;
75
+ return { tasks, unsynced, sessions };
76
+ }
77
+ catch {
78
+ return { tasks: 0, unsynced: 0, sessions: 0 };
79
+ }
80
+ }
81
+ function printCheck(name, ok, successMsg, failMsg, fix) {
82
+ const icon = ok ? '\x1b[32m✓\x1b[0m' : '\x1b[31m✗\x1b[0m';
83
+ const msg = ok ? successMsg : failMsg;
84
+ console.log(`${icon} ${name}: ${msg}`);
85
+ if (!ok) {
86
+ console.log(` \x1b[90m→ ${fix}\x1b[0m`);
87
+ }
88
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grov",
3
- "version": "0.5.5",
3
+ "version": "0.5.6",
4
4
  "description": "Collective AI memory for Claude Code - captures reasoning from sessions and injects context into future sessions",
5
5
  "type": "module",
6
6
  "main": "dist/cli.js",