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 +8 -0
- package/dist/commands/doctor.d.ts +1 -0
- package/dist/commands/doctor.js +88 -0
- package/package.json +1 -1
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