grov 0.5.11 → 0.6.13
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/agents/registry.d.ts +17 -0
- package/dist/cli/agents/registry.js +132 -0
- package/dist/cli/commands/agents.d.ts +1 -0
- package/dist/cli/commands/agents.js +48 -0
- package/dist/cli/commands/disable.d.ts +1 -0
- package/dist/cli/commands/disable.js +179 -0
- package/dist/cli/commands/doctor.d.ts +1 -0
- package/dist/cli/commands/doctor.js +157 -0
- package/dist/{commands → cli/commands}/drift-test.js +39 -26
- package/dist/cli/commands/init.d.ts +1 -0
- package/dist/cli/commands/init.js +90 -0
- package/dist/{commands → cli/commands}/login.js +19 -18
- package/dist/{commands → cli/commands}/logout.js +1 -1
- package/dist/{commands → cli/commands}/proxy-status.js +1 -1
- package/dist/cli/commands/setup.d.ts +6 -0
- package/dist/cli/commands/setup.js +309 -0
- package/dist/{commands → cli/commands}/status.js +1 -1
- package/dist/{commands → cli/commands}/sync.d.ts +1 -0
- package/dist/{commands → cli/commands}/sync.js +59 -4
- package/dist/{commands → cli/commands}/uninstall.js +2 -2
- package/dist/cli/index.js +270 -0
- package/dist/{lib → core/cloud}/cloud-sync.d.ts +3 -3
- package/dist/{lib → core/cloud}/cloud-sync.js +10 -10
- package/dist/{lib → core/extraction}/correction-builder-proxy.d.ts +1 -1
- package/dist/{lib → core/extraction}/correction-builder-proxy.js +0 -4
- package/dist/{lib → core/extraction}/drift-checker-proxy.d.ts +13 -9
- package/dist/core/extraction/drift-checker-proxy.js +510 -0
- package/dist/{lib → core/extraction}/llm-extractor.d.ts +8 -38
- package/dist/{lib → core/extraction}/llm-extractor.js +132 -220
- package/dist/{lib → core}/store/sessions.js +3 -19
- package/dist/core/store/store.d.ts +1 -0
- package/dist/{lib → core/store}/store.js +1 -1
- package/dist/{lib → core}/store/types.d.ts +0 -4
- package/dist/integrations/mcp/cache.d.ts +27 -0
- package/dist/integrations/mcp/cache.js +106 -0
- package/dist/integrations/mcp/capture/antigravity-parser.d.ts +26 -0
- package/dist/integrations/mcp/capture/antigravity-parser.js +272 -0
- package/dist/integrations/mcp/capture/antigravity-scanner.d.ts +24 -0
- package/dist/integrations/mcp/capture/antigravity-scanner.js +153 -0
- package/dist/integrations/mcp/capture/antigravity-sync-tracker.d.ts +29 -0
- package/dist/integrations/mcp/capture/antigravity-sync-tracker.js +115 -0
- package/dist/integrations/mcp/capture/cli-extractor.d.ts +18 -0
- package/dist/integrations/mcp/capture/cli-extractor.js +258 -0
- package/dist/integrations/mcp/capture/cli-synced.d.ts +4 -0
- package/dist/integrations/mcp/capture/cli-synced.js +62 -0
- package/dist/integrations/mcp/capture/cli-transform.d.ts +30 -0
- package/dist/integrations/mcp/capture/cli-transform.js +62 -0
- package/dist/integrations/mcp/capture/cli-watcher.d.ts +31 -0
- package/dist/integrations/mcp/capture/cli-watcher.js +106 -0
- package/dist/integrations/mcp/capture/hook-handler.d.ts +2 -0
- package/dist/integrations/mcp/capture/hook-handler.js +157 -0
- package/dist/integrations/mcp/capture/sqlite-reader.d.ts +35 -0
- package/dist/integrations/mcp/capture/sqlite-reader.js +388 -0
- package/dist/integrations/mcp/capture/sync-tracker.d.ts +16 -0
- package/dist/integrations/mcp/capture/sync-tracker.js +102 -0
- package/dist/integrations/mcp/clients/cursor/rules-installer.d.ts +19 -0
- package/dist/integrations/mcp/clients/cursor/rules-installer.js +123 -0
- package/dist/integrations/mcp/index.d.ts +1 -0
- package/dist/integrations/mcp/index.js +94 -0
- package/dist/integrations/mcp/logger.d.ts +8 -0
- package/dist/integrations/mcp/logger.js +50 -0
- package/dist/integrations/mcp/server.d.ts +5 -0
- package/dist/integrations/mcp/server.js +58 -0
- package/dist/integrations/mcp/tools/expand.d.ts +1 -0
- package/dist/integrations/mcp/tools/expand.js +53 -0
- package/dist/integrations/mcp/tools/preview.d.ts +1 -0
- package/dist/integrations/mcp/tools/preview.js +64 -0
- package/dist/integrations/proxy/agents/base.d.ts +43 -0
- package/dist/integrations/proxy/agents/base.js +13 -0
- package/dist/{proxy/utils → integrations/proxy/agents/claude}/extractors.d.ts +4 -8
- package/dist/{proxy/utils → integrations/proxy/agents/claude}/extractors.js +4 -33
- package/dist/{proxy → integrations/proxy/agents/claude}/forwarder.d.ts +1 -1
- package/dist/{proxy → integrations/proxy/agents/claude}/forwarder.js +22 -6
- package/dist/integrations/proxy/agents/claude/index.d.ts +43 -0
- package/dist/integrations/proxy/agents/claude/index.js +386 -0
- package/dist/{proxy/action-parser.d.ts → integrations/proxy/agents/claude/parser.d.ts} +1 -1
- package/dist/integrations/proxy/agents/codex/extractors.d.ts +6 -0
- package/dist/integrations/proxy/agents/codex/extractors.js +49 -0
- package/dist/integrations/proxy/agents/codex/forwarder.d.ts +9 -0
- package/dist/integrations/proxy/agents/codex/forwarder.js +125 -0
- package/dist/integrations/proxy/agents/codex/index.d.ts +44 -0
- package/dist/integrations/proxy/agents/codex/index.js +371 -0
- package/dist/integrations/proxy/agents/codex/parser.d.ts +11 -0
- package/dist/integrations/proxy/agents/codex/parser.js +104 -0
- package/dist/integrations/proxy/agents/codex/patch.d.ts +12 -0
- package/dist/integrations/proxy/agents/codex/patch.js +40 -0
- package/dist/integrations/proxy/agents/codex/settings.d.ts +18 -0
- package/dist/integrations/proxy/agents/codex/settings.js +73 -0
- package/dist/integrations/proxy/agents/codex/types.d.ts +59 -0
- package/dist/integrations/proxy/agents/codex/types.js +2 -0
- package/dist/integrations/proxy/agents/index.d.ts +11 -0
- package/dist/integrations/proxy/agents/index.js +25 -0
- package/dist/integrations/proxy/agents/types.d.ts +77 -0
- package/dist/integrations/proxy/agents/types.js +2 -0
- package/dist/{proxy → integrations/proxy/cache}/extended-cache.js +2 -6
- package/dist/{proxy → integrations/proxy}/config.js +1 -1
- package/dist/{proxy → integrations/proxy}/handlers/preprocess.d.ts +3 -3
- package/dist/integrations/proxy/handlers/preprocess.js +194 -0
- package/dist/integrations/proxy/index.js +20 -0
- package/dist/integrations/proxy/injection/memory-injection.d.ts +56 -0
- package/dist/integrations/proxy/injection/memory-injection.js +252 -0
- package/dist/integrations/proxy/orchestrator.d.ts +30 -0
- package/dist/integrations/proxy/orchestrator.js +954 -0
- package/dist/integrations/proxy/request-processor.d.ts +14 -0
- package/dist/integrations/proxy/request-processor.js +68 -0
- package/dist/{proxy → integrations/proxy}/response-processor.d.ts +4 -3
- package/dist/{proxy → integrations/proxy}/response-processor.js +51 -43
- package/dist/{proxy → integrations/proxy}/server.d.ts +0 -1
- package/dist/integrations/proxy/server.js +146 -0
- package/dist/{proxy → integrations/proxy}/types.d.ts +4 -0
- package/dist/{proxy → integrations/proxy}/utils/logging.d.ts +1 -0
- package/dist/{proxy → integrations/proxy}/utils/logging.js +5 -0
- package/package.json +31 -10
- package/postinstall.js +62 -6
- package/dist/cli.js +0 -149
- package/dist/commands/capture.d.ts +0 -6
- package/dist/commands/capture.js +0 -324
- package/dist/commands/disable.d.ts +0 -1
- package/dist/commands/disable.js +0 -14
- package/dist/commands/doctor.d.ts +0 -1
- package/dist/commands/doctor.js +0 -89
- package/dist/commands/init.d.ts +0 -1
- package/dist/commands/init.js +0 -52
- package/dist/commands/inject.d.ts +0 -5
- package/dist/commands/inject.js +0 -88
- package/dist/commands/prompt-inject.d.ts +0 -4
- package/dist/commands/prompt-inject.js +0 -451
- package/dist/commands/unregister.d.ts +0 -1
- package/dist/commands/unregister.js +0 -28
- package/dist/lib/anchor-extractor.d.ts +0 -30
- package/dist/lib/anchor-extractor.js +0 -296
- package/dist/lib/correction-builder.d.ts +0 -10
- package/dist/lib/correction-builder.js +0 -226
- package/dist/lib/drift-checker-proxy.js +0 -373
- package/dist/lib/drift-checker.d.ts +0 -66
- package/dist/lib/drift-checker.js +0 -341
- package/dist/lib/hooks.d.ts +0 -38
- package/dist/lib/hooks.js +0 -291
- package/dist/lib/jsonl-parser.d.ts +0 -87
- package/dist/lib/jsonl-parser.js +0 -281
- package/dist/lib/session-parser.d.ts +0 -44
- package/dist/lib/session-parser.js +0 -256
- package/dist/lib/store.d.ts +0 -1
- package/dist/proxy/cache.d.ts +0 -32
- package/dist/proxy/cache.js +0 -47
- package/dist/proxy/handlers/preprocess.js +0 -186
- package/dist/proxy/index.js +0 -30
- package/dist/proxy/injection/delta-tracking.d.ts +0 -11
- package/dist/proxy/injection/delta-tracking.js +0 -94
- package/dist/proxy/injection/injectors.d.ts +0 -7
- package/dist/proxy/injection/injectors.js +0 -139
- package/dist/proxy/request-processor.d.ts +0 -27
- package/dist/proxy/request-processor.js +0 -233
- package/dist/proxy/server.js +0 -1289
- /package/dist/{commands → cli/commands}/drift-test.d.ts +0 -0
- /package/dist/{commands → cli/commands}/login.d.ts +0 -0
- /package/dist/{commands → cli/commands}/logout.d.ts +0 -0
- /package/dist/{commands → cli/commands}/proxy-status.d.ts +0 -0
- /package/dist/{commands → cli/commands}/status.d.ts +0 -0
- /package/dist/{commands → cli/commands}/uninstall.d.ts +0 -0
- /package/dist/{cli.d.ts → cli/index.d.ts} +0 -0
- /package/dist/{lib → core/cloud}/api-client.d.ts +0 -0
- /package/dist/{lib → core/cloud}/api-client.js +0 -0
- /package/dist/{lib → core/cloud}/credentials.d.ts +0 -0
- /package/dist/{lib → core/cloud}/credentials.js +0 -0
- /package/dist/{lib → core}/store/convenience.d.ts +0 -0
- /package/dist/{lib → core}/store/convenience.js +0 -0
- /package/dist/{lib → core}/store/database.d.ts +0 -0
- /package/dist/{lib → core}/store/database.js +0 -0
- /package/dist/{lib → core}/store/drift.d.ts +0 -0
- /package/dist/{lib → core}/store/drift.js +0 -0
- /package/dist/{lib → core}/store/index.d.ts +0 -0
- /package/dist/{lib → core}/store/index.js +0 -0
- /package/dist/{lib → core}/store/sessions.d.ts +0 -0
- /package/dist/{lib → core}/store/steps.d.ts +0 -0
- /package/dist/{lib → core}/store/steps.js +0 -0
- /package/dist/{lib → core}/store/tasks.d.ts +0 -0
- /package/dist/{lib → core}/store/tasks.js +0 -0
- /package/dist/{lib → core}/store/types.js +0 -0
- /package/dist/{proxy/action-parser.js → integrations/proxy/agents/claude/parser.js} +0 -0
- /package/dist/{lib → integrations/proxy/agents/claude}/settings.d.ts +0 -0
- /package/dist/{lib → integrations/proxy/agents/claude}/settings.js +0 -0
- /package/dist/{proxy → integrations/proxy/cache}/extended-cache.d.ts +0 -0
- /package/dist/{proxy → integrations/proxy}/config.d.ts +0 -0
- /package/dist/{proxy → integrations/proxy}/index.d.ts +0 -0
- /package/dist/{proxy → integrations/proxy}/types.js +0 -0
- /package/dist/{lib → utils}/debug.d.ts +0 -0
- /package/dist/{lib → utils}/debug.js +0 -0
- /package/dist/{lib → utils}/utils.d.ts +0 -0
- /package/dist/{lib → utils}/utils.js +0 -0
package/dist/cli.js
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import 'dotenv/config';
|
|
3
|
-
import { Command } from 'commander';
|
|
4
|
-
import { createRequire } from 'module';
|
|
5
|
-
import { closeDatabase } from './lib/store.js';
|
|
6
|
-
const require = createRequire(import.meta.url);
|
|
7
|
-
const pkg = require('../package.json');
|
|
8
|
-
// SECURITY: Global error handlers to catch unhandled rejections from dynamic imports
|
|
9
|
-
process.on('unhandledRejection', (reason) => {
|
|
10
|
-
console.error('Error:', reason instanceof Error ? reason.message : 'Unknown error');
|
|
11
|
-
closeDatabase();
|
|
12
|
-
process.exit(1);
|
|
13
|
-
});
|
|
14
|
-
process.on('uncaughtException', (error) => {
|
|
15
|
-
console.error('Error:', error.message);
|
|
16
|
-
closeDatabase();
|
|
17
|
-
process.exit(1);
|
|
18
|
-
});
|
|
19
|
-
const program = new Command();
|
|
20
|
-
/**
|
|
21
|
-
* Wrap async action with error handling and cleanup.
|
|
22
|
-
* Ensures database connections are closed and errors are handled gracefully.
|
|
23
|
-
*/
|
|
24
|
-
function safeAction(fn) {
|
|
25
|
-
return async (options) => {
|
|
26
|
-
try {
|
|
27
|
-
await fn(options);
|
|
28
|
-
}
|
|
29
|
-
catch (error) {
|
|
30
|
-
console.error('Error:', error instanceof Error ? error.message : 'Unknown error');
|
|
31
|
-
process.exit(1);
|
|
32
|
-
}
|
|
33
|
-
finally {
|
|
34
|
-
closeDatabase();
|
|
35
|
-
}
|
|
36
|
-
};
|
|
37
|
-
}
|
|
38
|
-
program
|
|
39
|
-
.name('grov')
|
|
40
|
-
.description('Collective AI memory for engineering teams')
|
|
41
|
-
.version(pkg.version);
|
|
42
|
-
// grov init - Configure Claude Code to use grov proxy
|
|
43
|
-
program
|
|
44
|
-
.command('init')
|
|
45
|
-
.description('Configure Claude Code to use grov proxy (run once)')
|
|
46
|
-
.action(safeAction(async () => {
|
|
47
|
-
const { init } = await import('./commands/init.js');
|
|
48
|
-
await init();
|
|
49
|
-
}));
|
|
50
|
-
// grov disable - Remove proxy configuration
|
|
51
|
-
program
|
|
52
|
-
.command('disable')
|
|
53
|
-
.description('Disable grov and restore direct Anthropic connection')
|
|
54
|
-
.action(safeAction(async () => {
|
|
55
|
-
const { disable } = await import('./commands/disable.js');
|
|
56
|
-
await disable();
|
|
57
|
-
}));
|
|
58
|
-
// grov status - Show stored reasoning for current project
|
|
59
|
-
program
|
|
60
|
-
.command('status')
|
|
61
|
-
.description('Show stored reasoning for current project')
|
|
62
|
-
.option('--all', 'Show all tasks, not just completed')
|
|
63
|
-
.action(safeAction(async (options) => {
|
|
64
|
-
const { status } = await import('./commands/status.js');
|
|
65
|
-
await status(options);
|
|
66
|
-
}));
|
|
67
|
-
// grov drift-test - Test drift detection on a prompt
|
|
68
|
-
program
|
|
69
|
-
.command('drift-test')
|
|
70
|
-
.description('Test drift detection on a prompt (debug command)')
|
|
71
|
-
.argument('<prompt>', 'The prompt to test for drift')
|
|
72
|
-
.option('--session <id>', 'Session ID to use for context')
|
|
73
|
-
.option('--goal <text>', 'Original goal (if no session provided)')
|
|
74
|
-
.option('-v, --verbose', 'Show verbose output')
|
|
75
|
-
.action(async (prompt, options) => {
|
|
76
|
-
const { driftTest } = await import('./commands/drift-test.js');
|
|
77
|
-
await driftTest(prompt, options);
|
|
78
|
-
});
|
|
79
|
-
// grov proxy - Start the proxy server
|
|
80
|
-
program
|
|
81
|
-
.command('proxy')
|
|
82
|
-
.description('Start the Grov proxy server (intercepts Claude API calls)')
|
|
83
|
-
.option('-d, --debug', 'Enable debug logging to grov-proxy.log')
|
|
84
|
-
.option('--extended-cache', 'Keep Anthropic cache alive during idle (sends requests on your behalf)')
|
|
85
|
-
.action(async (options) => {
|
|
86
|
-
if (options.extendedCache) {
|
|
87
|
-
process.env.GROV_EXTENDED_CACHE = 'true';
|
|
88
|
-
console.log('\n⚠️ Extended Cache Enabled');
|
|
89
|
-
console.log(' By using --extended-cache, you consent to Grov making');
|
|
90
|
-
console.log(' minimal keep-alive requests on your behalf to preserve');
|
|
91
|
-
console.log(' Anthropic\'s prompt cache during idle periods.\n');
|
|
92
|
-
}
|
|
93
|
-
const { startServer } = await import('./proxy/server.js');
|
|
94
|
-
await startServer({ debug: options.debug ?? false });
|
|
95
|
-
});
|
|
96
|
-
// grov proxy-status - Show active proxy sessions
|
|
97
|
-
program
|
|
98
|
-
.command('proxy-status')
|
|
99
|
-
.description('Show active proxy sessions')
|
|
100
|
-
.action(safeAction(async () => {
|
|
101
|
-
const { proxyStatus } = await import('./commands/proxy-status.js');
|
|
102
|
-
await proxyStatus();
|
|
103
|
-
}));
|
|
104
|
-
// grov login - Authenticate with Grov cloud
|
|
105
|
-
program
|
|
106
|
-
.command('login')
|
|
107
|
-
.description('Login to Grov cloud (opens browser for authentication)')
|
|
108
|
-
.action(safeAction(async () => {
|
|
109
|
-
const { login } = await import('./commands/login.js');
|
|
110
|
-
await login();
|
|
111
|
-
}));
|
|
112
|
-
// grov logout - Clear stored credentials
|
|
113
|
-
program
|
|
114
|
-
.command('logout')
|
|
115
|
-
.description('Logout from Grov cloud')
|
|
116
|
-
.action(safeAction(async () => {
|
|
117
|
-
const { logout } = await import('./commands/logout.js');
|
|
118
|
-
await logout();
|
|
119
|
-
}));
|
|
120
|
-
// grov uninstall - Full cleanup
|
|
121
|
-
program
|
|
122
|
-
.command('uninstall')
|
|
123
|
-
.description('Remove all grov data and configuration')
|
|
124
|
-
.action(safeAction(async () => {
|
|
125
|
-
const { uninstall } = await import('./commands/uninstall.js');
|
|
126
|
-
await uninstall();
|
|
127
|
-
}));
|
|
128
|
-
// grov sync - Configure cloud sync
|
|
129
|
-
program
|
|
130
|
-
.command('sync')
|
|
131
|
-
.description('Configure cloud sync to team dashboard')
|
|
132
|
-
.option('--enable', 'Enable cloud sync')
|
|
133
|
-
.option('--disable', 'Disable cloud sync')
|
|
134
|
-
.option('--team <id>', 'Set team ID for sync')
|
|
135
|
-
.option('--status', 'Show sync status')
|
|
136
|
-
.option('--push', 'Upload any unsynced local tasks to the team')
|
|
137
|
-
.action(safeAction(async (options) => {
|
|
138
|
-
const { sync } = await import('./commands/sync.js');
|
|
139
|
-
await sync(options);
|
|
140
|
-
}));
|
|
141
|
-
// grov doctor - Diagnose setup issues
|
|
142
|
-
program
|
|
143
|
-
.command('doctor')
|
|
144
|
-
.description('Check grov setup and diagnose issues')
|
|
145
|
-
.action(safeAction(async () => {
|
|
146
|
-
const { doctor } = await import('./commands/doctor.js');
|
|
147
|
-
await doctor();
|
|
148
|
-
}));
|
|
149
|
-
program.parse();
|
package/dist/commands/capture.js
DELETED
|
@@ -1,324 +0,0 @@
|
|
|
1
|
-
// grov capture - Called by Stop hook, extracts and stores reasoning
|
|
2
|
-
import 'dotenv/config';
|
|
3
|
-
import { findLatestSessionFile, parseSession, getSessionIdFromPath, isPathWithinProject } from '../lib/jsonl-parser.js';
|
|
4
|
-
import { createTask, createFileReasoning, getSessionState, updateSessionState, shouldFlagForReview, getDriftSummary } from '../lib/store.js';
|
|
5
|
-
import { isLLMAvailable, extractReasoning } from '../lib/llm-extractor.js';
|
|
6
|
-
import { extractAnchors, findAnchorAtLine, computeCodeHash, estimateLineNumber } from '../lib/anchor-extractor.js';
|
|
7
|
-
import { debugCapture } from '../lib/debug.js';
|
|
8
|
-
import { truncate, capitalize } from '../lib/utils.js';
|
|
9
|
-
import { readFileSync, existsSync } from 'fs';
|
|
10
|
-
export async function capture(options) {
|
|
11
|
-
// Get project path from Claude Code env var, fallback to cwd
|
|
12
|
-
// CLAUDE_PROJECT_DIR is set by Claude Code when running hooks
|
|
13
|
-
const projectPath = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
14
|
-
// Find the latest session file
|
|
15
|
-
const sessionFile = findLatestSessionFile(projectPath);
|
|
16
|
-
if (!sessionFile) {
|
|
17
|
-
// No session file found - this is normal for new projects
|
|
18
|
-
// Silent exit - don't spam the user
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
try {
|
|
22
|
-
// Parse the session
|
|
23
|
-
const session = parseSession(sessionFile);
|
|
24
|
-
// Skip if no user messages (empty session)
|
|
25
|
-
if (session.userMessages.length === 0) {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
// Get the original query (first user message)
|
|
29
|
-
const originalQuery = session.userMessages[0];
|
|
30
|
-
let goal;
|
|
31
|
-
let reasoningTrace;
|
|
32
|
-
let filesTouched;
|
|
33
|
-
let status;
|
|
34
|
-
let tags;
|
|
35
|
-
// Use LLM extraction if available, otherwise fall back to basic extraction
|
|
36
|
-
if (isLLMAvailable()) {
|
|
37
|
-
try {
|
|
38
|
-
debugCapture('Using LLM extraction...');
|
|
39
|
-
const extracted = await extractReasoning(session);
|
|
40
|
-
goal = extracted.goal;
|
|
41
|
-
reasoningTrace = extracted.reasoning_trace;
|
|
42
|
-
filesTouched = extracted.files_touched;
|
|
43
|
-
status = extracted.status;
|
|
44
|
-
tags = extracted.tags;
|
|
45
|
-
debugCapture('LLM extraction complete: status=%s', status);
|
|
46
|
-
}
|
|
47
|
-
catch (llmError) {
|
|
48
|
-
debugCapture('LLM extraction failed, using fallback: %O', llmError);
|
|
49
|
-
// Fall back to basic extraction
|
|
50
|
-
const basic = basicExtraction(session);
|
|
51
|
-
goal = basic.goal;
|
|
52
|
-
reasoningTrace = basic.reasoningTrace;
|
|
53
|
-
filesTouched = basic.filesTouched;
|
|
54
|
-
status = basic.status;
|
|
55
|
-
tags = basic.tags;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
else {
|
|
59
|
-
// No API key - use basic extraction
|
|
60
|
-
const basic = basicExtraction(session);
|
|
61
|
-
goal = basic.goal;
|
|
62
|
-
reasoningTrace = basic.reasoningTrace;
|
|
63
|
-
filesTouched = basic.filesTouched;
|
|
64
|
-
status = basic.status;
|
|
65
|
-
tags = basic.tags;
|
|
66
|
-
}
|
|
67
|
-
// Get session ID for drift check
|
|
68
|
-
const sessionId = getSessionIdFromPath(sessionFile);
|
|
69
|
-
// === GRADUATION LOGIC: Check if task should be flagged for review ===
|
|
70
|
-
let finalStatus = status;
|
|
71
|
-
let finalTags = [...tags];
|
|
72
|
-
let finalReasoningTrace = [...reasoningTrace];
|
|
73
|
-
if (sessionId) {
|
|
74
|
-
const needsReview = shouldFlagForReview(sessionId);
|
|
75
|
-
const driftSummary = getDriftSummary(sessionId);
|
|
76
|
-
if (needsReview) {
|
|
77
|
-
debugCapture('Task flagged for review due to drift');
|
|
78
|
-
// Downgrade status if was complete
|
|
79
|
-
if (finalStatus === 'complete') {
|
|
80
|
-
finalStatus = 'partial';
|
|
81
|
-
debugCapture('Status downgraded from complete to partial');
|
|
82
|
-
}
|
|
83
|
-
// Add drift tags
|
|
84
|
-
finalTags.push('needs-review', 'had-drift');
|
|
85
|
-
// Add drift summary to reasoning trace
|
|
86
|
-
if (driftSummary.totalEvents > 0) {
|
|
87
|
-
finalReasoningTrace.push(`[Drift events: ${driftSummary.totalEvents} corrections given]`);
|
|
88
|
-
finalReasoningTrace.push(`[Drift ${driftSummary.resolved ? 'resolved' : 'unresolved'}: final score ${driftSummary.finalScore}]`);
|
|
89
|
-
if (driftSummary.hadHalt) {
|
|
90
|
-
finalReasoningTrace.push('[Warning: HALT-level drift occurred during session]');
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
else if (driftSummary.totalEvents > 0) {
|
|
95
|
-
// Had drift but recovered - still note it
|
|
96
|
-
finalReasoningTrace.push(`[Drift events: ${driftSummary.totalEvents} - all resolved]`);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
// Store the task
|
|
100
|
-
const task = createTask({
|
|
101
|
-
project_path: projectPath,
|
|
102
|
-
original_query: originalQuery,
|
|
103
|
-
goal,
|
|
104
|
-
reasoning_trace: finalReasoningTrace,
|
|
105
|
-
files_touched: filesTouched,
|
|
106
|
-
status: finalStatus,
|
|
107
|
-
tags: finalTags
|
|
108
|
-
});
|
|
109
|
-
// Create file_reasoning entries for each file touched
|
|
110
|
-
await createFileReasoningEntries(task.id, session, goal);
|
|
111
|
-
// Update session state if exists
|
|
112
|
-
if (sessionId) {
|
|
113
|
-
const sessionState = getSessionState(sessionId);
|
|
114
|
-
if (sessionState) {
|
|
115
|
-
updateSessionState(sessionId, {
|
|
116
|
-
status: finalStatus === 'complete' ? 'completed' : 'abandoned',
|
|
117
|
-
files_explored: [...new Set([...(sessionState.files_explored || []), ...filesTouched])],
|
|
118
|
-
original_goal: goal,
|
|
119
|
-
});
|
|
120
|
-
debugCapture('Updated session state: %s...', sessionId.substring(0, 8));
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
// Log for debugging
|
|
124
|
-
debugCapture('Captured task: %s...', task.id.substring(0, 8));
|
|
125
|
-
debugCapture('Query: %s...', originalQuery.substring(0, 50));
|
|
126
|
-
debugCapture('Files: %d', filesTouched.length);
|
|
127
|
-
debugCapture('Status: %s (original: %s)', finalStatus, status);
|
|
128
|
-
debugCapture('LLM: %s', isLLMAvailable() ? 'yes' : 'no');
|
|
129
|
-
}
|
|
130
|
-
catch (error) {
|
|
131
|
-
// Silent fail - don't interrupt user's workflow
|
|
132
|
-
debugCapture('Capture error: %O', error);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* Basic extraction without LLM
|
|
137
|
-
*/
|
|
138
|
-
function basicExtraction(session) {
|
|
139
|
-
const filesTouched = [...new Set([...session.filesRead, ...session.filesWritten])];
|
|
140
|
-
const status = session.filesWritten.length > 0 ? 'complete' : 'partial';
|
|
141
|
-
return {
|
|
142
|
-
goal: session.userMessages[0] || 'Unknown goal',
|
|
143
|
-
reasoningTrace: generateBasicReasoningTrace(session),
|
|
144
|
-
filesTouched,
|
|
145
|
-
status,
|
|
146
|
-
tags: generateTags(filesTouched)
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Generate tags from file paths
|
|
151
|
-
*/
|
|
152
|
-
function generateTags(files) {
|
|
153
|
-
const tags = new Set();
|
|
154
|
-
for (const file of files) {
|
|
155
|
-
const parts = file.split('/');
|
|
156
|
-
const filename = parts[parts.length - 1];
|
|
157
|
-
// Add directory names as tags
|
|
158
|
-
for (const part of parts) {
|
|
159
|
-
if (part && !part.includes('.') && part !== 'src' && part !== 'lib') {
|
|
160
|
-
tags.add(part.toLowerCase());
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
// Add file extension as tag
|
|
164
|
-
const ext = filename.split('.').pop();
|
|
165
|
-
if (ext && ext !== filename) {
|
|
166
|
-
tags.add(ext);
|
|
167
|
-
}
|
|
168
|
-
// Common patterns
|
|
169
|
-
if (filename.includes('auth'))
|
|
170
|
-
tags.add('auth');
|
|
171
|
-
if (filename.includes('api'))
|
|
172
|
-
tags.add('api');
|
|
173
|
-
if (filename.includes('test'))
|
|
174
|
-
tags.add('test');
|
|
175
|
-
if (filename.includes('config'))
|
|
176
|
-
tags.add('config');
|
|
177
|
-
if (filename.includes('route'))
|
|
178
|
-
tags.add('routes');
|
|
179
|
-
if (filename.includes('model'))
|
|
180
|
-
tags.add('models');
|
|
181
|
-
if (filename.includes('util'))
|
|
182
|
-
tags.add('utils');
|
|
183
|
-
}
|
|
184
|
-
return [...tags].slice(0, 10); // Limit to 10 tags
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* Generate basic reasoning trace from session data
|
|
188
|
-
*/
|
|
189
|
-
function generateBasicReasoningTrace(session) {
|
|
190
|
-
const trace = [];
|
|
191
|
-
// Count tool usage
|
|
192
|
-
const toolCounts = session.toolCalls.reduce((acc, t) => {
|
|
193
|
-
acc[t.name] = (acc[t.name] || 0) + 1;
|
|
194
|
-
return acc;
|
|
195
|
-
}, {});
|
|
196
|
-
// Add tool usage summary
|
|
197
|
-
if (toolCounts['Read']) {
|
|
198
|
-
trace.push(`Read ${toolCounts['Read']} files`);
|
|
199
|
-
}
|
|
200
|
-
if (toolCounts['Write']) {
|
|
201
|
-
trace.push(`Wrote ${toolCounts['Write']} files`);
|
|
202
|
-
}
|
|
203
|
-
if (toolCounts['Edit']) {
|
|
204
|
-
trace.push(`Edited ${toolCounts['Edit']} files`);
|
|
205
|
-
}
|
|
206
|
-
if (toolCounts['Grep'] || toolCounts['Glob']) {
|
|
207
|
-
trace.push(`Searched codebase`);
|
|
208
|
-
}
|
|
209
|
-
if (toolCounts['Bash']) {
|
|
210
|
-
trace.push(`Ran ${toolCounts['Bash']} commands`);
|
|
211
|
-
}
|
|
212
|
-
// Add file summaries
|
|
213
|
-
if (session.filesRead.length > 0) {
|
|
214
|
-
trace.push(`Files examined: ${session.filesRead.slice(0, 5).map(f => f.split('/').pop()).join(', ')}`);
|
|
215
|
-
}
|
|
216
|
-
if (session.filesWritten.length > 0) {
|
|
217
|
-
trace.push(`Files modified: ${session.filesWritten.map(f => f.split('/').pop()).join(', ')}`);
|
|
218
|
-
}
|
|
219
|
-
return trace;
|
|
220
|
-
}
|
|
221
|
-
/**
|
|
222
|
-
* Create file_reasoning entries for each file touched in the session
|
|
223
|
-
*/
|
|
224
|
-
async function createFileReasoningEntries(taskId, session, goal) {
|
|
225
|
-
try {
|
|
226
|
-
// Process files that were written/edited
|
|
227
|
-
for (const filePath of session.filesWritten) {
|
|
228
|
-
await createFileReasoningForFile(taskId, filePath, session, goal, true);
|
|
229
|
-
}
|
|
230
|
-
// Also process files that were only read (with less detail)
|
|
231
|
-
for (const filePath of session.filesRead) {
|
|
232
|
-
// Skip if already processed as written
|
|
233
|
-
if (session.filesWritten.includes(filePath))
|
|
234
|
-
continue;
|
|
235
|
-
await createFileReasoningForFile(taskId, filePath, session, goal, false);
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
catch (error) {
|
|
239
|
-
debugCapture('Error creating file reasoning entries: %O', error);
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
/**
|
|
243
|
-
* Create a file_reasoning entry for a specific file
|
|
244
|
-
*/
|
|
245
|
-
async function createFileReasoningForFile(taskId, filePath, session, goal, wasModified) {
|
|
246
|
-
try {
|
|
247
|
-
// SECURITY: Validate path is within project boundary to prevent path traversal
|
|
248
|
-
const projectPath = process.env.CLAUDE_PROJECT_DIR || process.cwd();
|
|
249
|
-
if (!isPathWithinProject(projectPath, filePath)) {
|
|
250
|
-
debugCapture('Skipping file outside project boundary: %s', filePath);
|
|
251
|
-
return;
|
|
252
|
-
}
|
|
253
|
-
// Check if file exists
|
|
254
|
-
if (!existsSync(filePath)) {
|
|
255
|
-
return;
|
|
256
|
-
}
|
|
257
|
-
// Read file content
|
|
258
|
-
const content = readFileSync(filePath, 'utf-8');
|
|
259
|
-
// Extract anchors from the file
|
|
260
|
-
const anchors = extractAnchors(filePath, content);
|
|
261
|
-
// Find the Edit tool call for this file to determine what was changed
|
|
262
|
-
const editCalls = session.toolCalls.filter(t => t.name === 'Edit' && t.input?.file_path === filePath);
|
|
263
|
-
if (editCalls.length > 0 && wasModified) {
|
|
264
|
-
// For each edit, try to find the anchor
|
|
265
|
-
for (const editCall of editCalls) {
|
|
266
|
-
const input = editCall.input;
|
|
267
|
-
if (input.old_string) {
|
|
268
|
-
const lineNumber = estimateLineNumber(input.old_string, content);
|
|
269
|
-
const anchor = lineNumber ? findAnchorAtLine(anchors, lineNumber) : null;
|
|
270
|
-
const lineStart = anchor?.lineStart || lineNumber || undefined;
|
|
271
|
-
const lineEnd = anchor?.lineEnd || lineNumber || undefined;
|
|
272
|
-
createFileReasoning({
|
|
273
|
-
task_id: taskId,
|
|
274
|
-
file_path: filePath,
|
|
275
|
-
anchor: anchor?.name,
|
|
276
|
-
line_start: lineStart,
|
|
277
|
-
line_end: lineEnd,
|
|
278
|
-
code_hash: lineStart && lineEnd ? computeCodeHash(content, lineStart, lineEnd) : undefined,
|
|
279
|
-
change_type: 'edit',
|
|
280
|
-
reasoning: buildReasoningString(anchor, goal, 'edited')
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
else if (wasModified) {
|
|
286
|
-
// File was created/written without Edit
|
|
287
|
-
const writeCalls = session.toolCalls.filter(t => t.name === 'Write' && t.input?.file_path === filePath);
|
|
288
|
-
const changeType = writeCalls.length > 0 ? 'create' : 'write';
|
|
289
|
-
createFileReasoning({
|
|
290
|
-
task_id: taskId,
|
|
291
|
-
file_path: filePath,
|
|
292
|
-
anchor: anchors.length > 0 ? anchors[0].name : undefined,
|
|
293
|
-
line_start: 1,
|
|
294
|
-
line_end: content.split('\n').length,
|
|
295
|
-
code_hash: computeCodeHash(content, 1, content.split('\n').length),
|
|
296
|
-
change_type: changeType,
|
|
297
|
-
reasoning: buildReasoningString(null, goal, changeType === 'create' ? 'created' : 'wrote')
|
|
298
|
-
});
|
|
299
|
-
}
|
|
300
|
-
else {
|
|
301
|
-
// File was only read
|
|
302
|
-
createFileReasoning({
|
|
303
|
-
task_id: taskId,
|
|
304
|
-
file_path: filePath,
|
|
305
|
-
anchor: anchors.length > 0 ? anchors[0].name : undefined,
|
|
306
|
-
change_type: 'read',
|
|
307
|
-
reasoning: `Read during: ${truncate(goal, 80)}`
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
}
|
|
311
|
-
catch (error) {
|
|
312
|
-
debugCapture('Error processing file %s: %O', filePath, error);
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
/**
|
|
316
|
-
* Build a reasoning string for a file modification
|
|
317
|
-
*/
|
|
318
|
-
function buildReasoningString(anchor, goal, action) {
|
|
319
|
-
const shortGoal = truncate(goal, 80);
|
|
320
|
-
if (anchor) {
|
|
321
|
-
return `${capitalize(action)} ${anchor.type} "${anchor.name}": ${shortGoal}`;
|
|
322
|
-
}
|
|
323
|
-
return `${capitalize(action)} file: ${shortGoal}`;
|
|
324
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function disable(): Promise<void>;
|
package/dist/commands/disable.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// grov disable - Remove proxy configuration and restore direct Anthropic connection
|
|
2
|
-
import { setProxyEnv, getSettingsPath } from '../lib/settings.js';
|
|
3
|
-
export async function disable() {
|
|
4
|
-
const result = setProxyEnv(false);
|
|
5
|
-
if (result.action === 'removed') {
|
|
6
|
-
console.log('Grov disabled.');
|
|
7
|
-
console.log(' - ANTHROPIC_BASE_URL removed from settings');
|
|
8
|
-
}
|
|
9
|
-
else {
|
|
10
|
-
console.log('Grov was not configured.');
|
|
11
|
-
}
|
|
12
|
-
console.log(`\nSettings file: ${getSettingsPath()}`);
|
|
13
|
-
console.log('\nClaude will now connect directly to Anthropic.');
|
|
14
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function doctor(): Promise<void>;
|
package/dist/commands/doctor.js
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
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 shell = process.env.SHELL?.includes('zsh') ? '~/.zshrc' : '~/.bashrc';
|
|
23
|
-
const apiKeyFix = process.platform === 'win32'
|
|
24
|
-
? 'setx ANTHROPIC_API_KEY "sk-ant-..." (permanent) or add to System Environment Variables'
|
|
25
|
-
: `Add to ${shell}: echo 'export ANTHROPIC_API_KEY=sk-ant-...' >> ${shell} && source ${shell}`;
|
|
26
|
-
printCheck('ANTHROPIC_API_KEY', hasApiKey, 'Set', 'NOT SET - memories will not sync!', apiKeyFix);
|
|
27
|
-
// Check login
|
|
28
|
-
const creds = readCredentials();
|
|
29
|
-
printCheck('Login', !!creds, creds ? `Logged in as ${creds.email}` : 'Not logged in', 'Not logged in', 'grov login');
|
|
30
|
-
// Check sync
|
|
31
|
-
const syncStatus = getSyncStatus();
|
|
32
|
-
const syncOk = syncStatus?.enabled && syncStatus?.teamId;
|
|
33
|
-
const syncMsg = syncOk
|
|
34
|
-
? `Team ${syncStatus.teamId.substring(0, 8)}...`
|
|
35
|
-
: syncStatus?.teamId ? 'Disabled' : 'No team';
|
|
36
|
-
printCheck('Cloud Sync', !!syncOk, syncMsg, syncMsg, 'grov sync --enable --team <id>');
|
|
37
|
-
// Check database
|
|
38
|
-
const dbStats = checkDatabase();
|
|
39
|
-
const dbOk = dbStats.tasks > 0 || dbStats.sessions > 0;
|
|
40
|
-
const dbMsg = `${dbStats.tasks} tasks, ${dbStats.unsynced} unsynced, ${dbStats.sessions} active`;
|
|
41
|
-
printCheck('Local Database', dbOk, dbMsg, 'Empty', 'Use Claude Code with proxy running');
|
|
42
|
-
console.log('');
|
|
43
|
-
}
|
|
44
|
-
async function checkProxy() {
|
|
45
|
-
try {
|
|
46
|
-
const res = await request('http://127.0.0.1:8080/health', {
|
|
47
|
-
headersTimeout: 2000,
|
|
48
|
-
bodyTimeout: 2000
|
|
49
|
-
});
|
|
50
|
-
return res.statusCode === 200;
|
|
51
|
-
}
|
|
52
|
-
catch {
|
|
53
|
-
return false;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
function checkBaseUrl() {
|
|
57
|
-
if (!existsSync(CLAUDE_SETTINGS_PATH))
|
|
58
|
-
return false;
|
|
59
|
-
try {
|
|
60
|
-
const settings = JSON.parse(readFileSync(CLAUDE_SETTINGS_PATH, 'utf-8'));
|
|
61
|
-
return settings.env?.ANTHROPIC_BASE_URL === 'http://127.0.0.1:8080';
|
|
62
|
-
}
|
|
63
|
-
catch {
|
|
64
|
-
return false;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
function checkDatabase() {
|
|
68
|
-
if (!existsSync(DB_PATH)) {
|
|
69
|
-
return { tasks: 0, unsynced: 0, sessions: 0 };
|
|
70
|
-
}
|
|
71
|
-
try {
|
|
72
|
-
const db = initDatabase();
|
|
73
|
-
const tasks = db.prepare('SELECT COUNT(*) as c FROM tasks').get().c;
|
|
74
|
-
const unsynced = db.prepare('SELECT COUNT(*) as c FROM tasks WHERE synced_at IS NULL').get().c;
|
|
75
|
-
const sessions = db.prepare("SELECT COUNT(*) as c FROM session_states WHERE status = 'active'").get().c;
|
|
76
|
-
return { tasks, unsynced, sessions };
|
|
77
|
-
}
|
|
78
|
-
catch {
|
|
79
|
-
return { tasks: 0, unsynced: 0, sessions: 0 };
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
function printCheck(name, ok, successMsg, failMsg, fix) {
|
|
83
|
-
const icon = ok ? '\x1b[32m✓\x1b[0m' : '\x1b[31m✗\x1b[0m';
|
|
84
|
-
const msg = ok ? successMsg : failMsg;
|
|
85
|
-
console.log(`${icon} ${name}: ${msg}`);
|
|
86
|
-
if (!ok) {
|
|
87
|
-
console.log(` \x1b[90m→ ${fix}\x1b[0m`);
|
|
88
|
-
}
|
|
89
|
-
}
|
package/dist/commands/init.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function init(): Promise<void>;
|
package/dist/commands/init.js
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
// grov init - Configure Claude Code to use grov proxy
|
|
2
|
-
import { setProxyEnv, getSettingsPath } from '../lib/settings.js';
|
|
3
|
-
export async function init() {
|
|
4
|
-
console.log('Configuring grov...\n');
|
|
5
|
-
try {
|
|
6
|
-
// Set up proxy URL in settings so users just type 'claude'
|
|
7
|
-
const result = setProxyEnv(true);
|
|
8
|
-
if (result.action === 'added') {
|
|
9
|
-
console.log(' + ANTHROPIC_BASE_URL → http://127.0.0.1:8080');
|
|
10
|
-
}
|
|
11
|
-
else if (result.action === 'unchanged') {
|
|
12
|
-
console.log(' = ANTHROPIC_BASE_URL already configured');
|
|
13
|
-
}
|
|
14
|
-
console.log(`\nSettings file: ${getSettingsPath()}`);
|
|
15
|
-
// Check for API key and provide helpful instructions
|
|
16
|
-
const isWindows = process.platform === 'win32';
|
|
17
|
-
const shell = process.env.SHELL?.includes('zsh') ? '~/.zshrc' : '~/.bashrc';
|
|
18
|
-
if (!process.env.ANTHROPIC_API_KEY) {
|
|
19
|
-
console.log('\n╔═══════════════════════════════════════════════════════════╗');
|
|
20
|
-
console.log('║ ⚠️ ANTHROPIC_API_KEY NOT SET - MEMORIES WILL NOT SYNC! ║');
|
|
21
|
-
console.log('╚═══════════════════════════════════════════════════════════╝');
|
|
22
|
-
console.log('\n 1. Get your API key at:');
|
|
23
|
-
console.log(' https://console.anthropic.com/settings/keys\n');
|
|
24
|
-
if (isWindows) {
|
|
25
|
-
console.log(' 2. Set PERMANENTLY (run in Command Prompt as Admin):');
|
|
26
|
-
console.log(' setx ANTHROPIC_API_KEY "sk-ant-..."\n');
|
|
27
|
-
console.log(' 3. Restart your terminal\n');
|
|
28
|
-
console.log(' ⚠️ Using "set" alone only works in THAT terminal!');
|
|
29
|
-
}
|
|
30
|
-
else {
|
|
31
|
-
console.log(' 2. Add PERMANENTLY to your shell:');
|
|
32
|
-
console.log(` echo 'export ANTHROPIC_API_KEY=sk-ant-...' >> ${shell}\n`);
|
|
33
|
-
console.log(' 3. Apply changes:');
|
|
34
|
-
console.log(` source ${shell}\n`);
|
|
35
|
-
console.log(' ⚠️ Using "export" alone only works in THAT terminal!');
|
|
36
|
-
}
|
|
37
|
-
console.log(' The key will be gone when you open a new terminal.\n');
|
|
38
|
-
}
|
|
39
|
-
else {
|
|
40
|
-
console.log('\n ✓ ANTHROPIC_API_KEY found');
|
|
41
|
-
}
|
|
42
|
-
console.log('\n--- Next Steps ---');
|
|
43
|
-
console.log('1. Terminal 1: grov proxy');
|
|
44
|
-
console.log('2. Terminal 2: claude');
|
|
45
|
-
console.log('\nRun "grov doctor" to verify your setup is complete.');
|
|
46
|
-
console.log('Grov will automatically capture reasoning and inject context.');
|
|
47
|
-
}
|
|
48
|
-
catch (error) {
|
|
49
|
-
console.error('Failed to configure grov:', error instanceof Error ? error.message : 'Unknown error');
|
|
50
|
-
process.exit(1);
|
|
51
|
-
}
|
|
52
|
-
}
|