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.
Files changed (190) hide show
  1. package/dist/cli/agents/registry.d.ts +17 -0
  2. package/dist/cli/agents/registry.js +132 -0
  3. package/dist/cli/commands/agents.d.ts +1 -0
  4. package/dist/cli/commands/agents.js +48 -0
  5. package/dist/cli/commands/disable.d.ts +1 -0
  6. package/dist/cli/commands/disable.js +179 -0
  7. package/dist/cli/commands/doctor.d.ts +1 -0
  8. package/dist/cli/commands/doctor.js +157 -0
  9. package/dist/{commands → cli/commands}/drift-test.js +39 -26
  10. package/dist/cli/commands/init.d.ts +1 -0
  11. package/dist/cli/commands/init.js +90 -0
  12. package/dist/{commands → cli/commands}/login.js +19 -18
  13. package/dist/{commands → cli/commands}/logout.js +1 -1
  14. package/dist/{commands → cli/commands}/proxy-status.js +1 -1
  15. package/dist/cli/commands/setup.d.ts +6 -0
  16. package/dist/cli/commands/setup.js +309 -0
  17. package/dist/{commands → cli/commands}/status.js +1 -1
  18. package/dist/{commands → cli/commands}/sync.d.ts +1 -0
  19. package/dist/{commands → cli/commands}/sync.js +59 -4
  20. package/dist/{commands → cli/commands}/uninstall.js +2 -2
  21. package/dist/cli/index.js +270 -0
  22. package/dist/{lib → core/cloud}/cloud-sync.d.ts +3 -3
  23. package/dist/{lib → core/cloud}/cloud-sync.js +10 -10
  24. package/dist/{lib → core/extraction}/correction-builder-proxy.d.ts +1 -1
  25. package/dist/{lib → core/extraction}/correction-builder-proxy.js +0 -4
  26. package/dist/{lib → core/extraction}/drift-checker-proxy.d.ts +13 -9
  27. package/dist/core/extraction/drift-checker-proxy.js +510 -0
  28. package/dist/{lib → core/extraction}/llm-extractor.d.ts +8 -38
  29. package/dist/{lib → core/extraction}/llm-extractor.js +132 -220
  30. package/dist/{lib → core}/store/sessions.js +3 -19
  31. package/dist/core/store/store.d.ts +1 -0
  32. package/dist/{lib → core/store}/store.js +1 -1
  33. package/dist/{lib → core}/store/types.d.ts +0 -4
  34. package/dist/integrations/mcp/cache.d.ts +27 -0
  35. package/dist/integrations/mcp/cache.js +106 -0
  36. package/dist/integrations/mcp/capture/antigravity-parser.d.ts +26 -0
  37. package/dist/integrations/mcp/capture/antigravity-parser.js +272 -0
  38. package/dist/integrations/mcp/capture/antigravity-scanner.d.ts +24 -0
  39. package/dist/integrations/mcp/capture/antigravity-scanner.js +153 -0
  40. package/dist/integrations/mcp/capture/antigravity-sync-tracker.d.ts +29 -0
  41. package/dist/integrations/mcp/capture/antigravity-sync-tracker.js +115 -0
  42. package/dist/integrations/mcp/capture/cli-extractor.d.ts +18 -0
  43. package/dist/integrations/mcp/capture/cli-extractor.js +258 -0
  44. package/dist/integrations/mcp/capture/cli-synced.d.ts +4 -0
  45. package/dist/integrations/mcp/capture/cli-synced.js +62 -0
  46. package/dist/integrations/mcp/capture/cli-transform.d.ts +30 -0
  47. package/dist/integrations/mcp/capture/cli-transform.js +62 -0
  48. package/dist/integrations/mcp/capture/cli-watcher.d.ts +31 -0
  49. package/dist/integrations/mcp/capture/cli-watcher.js +106 -0
  50. package/dist/integrations/mcp/capture/hook-handler.d.ts +2 -0
  51. package/dist/integrations/mcp/capture/hook-handler.js +157 -0
  52. package/dist/integrations/mcp/capture/sqlite-reader.d.ts +35 -0
  53. package/dist/integrations/mcp/capture/sqlite-reader.js +388 -0
  54. package/dist/integrations/mcp/capture/sync-tracker.d.ts +16 -0
  55. package/dist/integrations/mcp/capture/sync-tracker.js +102 -0
  56. package/dist/integrations/mcp/clients/cursor/rules-installer.d.ts +19 -0
  57. package/dist/integrations/mcp/clients/cursor/rules-installer.js +123 -0
  58. package/dist/integrations/mcp/index.d.ts +1 -0
  59. package/dist/integrations/mcp/index.js +94 -0
  60. package/dist/integrations/mcp/logger.d.ts +8 -0
  61. package/dist/integrations/mcp/logger.js +50 -0
  62. package/dist/integrations/mcp/server.d.ts +5 -0
  63. package/dist/integrations/mcp/server.js +58 -0
  64. package/dist/integrations/mcp/tools/expand.d.ts +1 -0
  65. package/dist/integrations/mcp/tools/expand.js +53 -0
  66. package/dist/integrations/mcp/tools/preview.d.ts +1 -0
  67. package/dist/integrations/mcp/tools/preview.js +64 -0
  68. package/dist/integrations/proxy/agents/base.d.ts +43 -0
  69. package/dist/integrations/proxy/agents/base.js +13 -0
  70. package/dist/{proxy/utils → integrations/proxy/agents/claude}/extractors.d.ts +4 -8
  71. package/dist/{proxy/utils → integrations/proxy/agents/claude}/extractors.js +4 -33
  72. package/dist/{proxy → integrations/proxy/agents/claude}/forwarder.d.ts +1 -1
  73. package/dist/{proxy → integrations/proxy/agents/claude}/forwarder.js +22 -6
  74. package/dist/integrations/proxy/agents/claude/index.d.ts +43 -0
  75. package/dist/integrations/proxy/agents/claude/index.js +386 -0
  76. package/dist/{proxy/action-parser.d.ts → integrations/proxy/agents/claude/parser.d.ts} +1 -1
  77. package/dist/integrations/proxy/agents/codex/extractors.d.ts +6 -0
  78. package/dist/integrations/proxy/agents/codex/extractors.js +49 -0
  79. package/dist/integrations/proxy/agents/codex/forwarder.d.ts +9 -0
  80. package/dist/integrations/proxy/agents/codex/forwarder.js +125 -0
  81. package/dist/integrations/proxy/agents/codex/index.d.ts +44 -0
  82. package/dist/integrations/proxy/agents/codex/index.js +371 -0
  83. package/dist/integrations/proxy/agents/codex/parser.d.ts +11 -0
  84. package/dist/integrations/proxy/agents/codex/parser.js +104 -0
  85. package/dist/integrations/proxy/agents/codex/patch.d.ts +12 -0
  86. package/dist/integrations/proxy/agents/codex/patch.js +40 -0
  87. package/dist/integrations/proxy/agents/codex/settings.d.ts +18 -0
  88. package/dist/integrations/proxy/agents/codex/settings.js +73 -0
  89. package/dist/integrations/proxy/agents/codex/types.d.ts +59 -0
  90. package/dist/integrations/proxy/agents/codex/types.js +2 -0
  91. package/dist/integrations/proxy/agents/index.d.ts +11 -0
  92. package/dist/integrations/proxy/agents/index.js +25 -0
  93. package/dist/integrations/proxy/agents/types.d.ts +77 -0
  94. package/dist/integrations/proxy/agents/types.js +2 -0
  95. package/dist/{proxy → integrations/proxy/cache}/extended-cache.js +2 -6
  96. package/dist/{proxy → integrations/proxy}/config.js +1 -1
  97. package/dist/{proxy → integrations/proxy}/handlers/preprocess.d.ts +3 -3
  98. package/dist/integrations/proxy/handlers/preprocess.js +194 -0
  99. package/dist/integrations/proxy/index.js +20 -0
  100. package/dist/integrations/proxy/injection/memory-injection.d.ts +56 -0
  101. package/dist/integrations/proxy/injection/memory-injection.js +252 -0
  102. package/dist/integrations/proxy/orchestrator.d.ts +30 -0
  103. package/dist/integrations/proxy/orchestrator.js +954 -0
  104. package/dist/integrations/proxy/request-processor.d.ts +14 -0
  105. package/dist/integrations/proxy/request-processor.js +68 -0
  106. package/dist/{proxy → integrations/proxy}/response-processor.d.ts +4 -3
  107. package/dist/{proxy → integrations/proxy}/response-processor.js +51 -43
  108. package/dist/{proxy → integrations/proxy}/server.d.ts +0 -1
  109. package/dist/integrations/proxy/server.js +146 -0
  110. package/dist/{proxy → integrations/proxy}/types.d.ts +4 -0
  111. package/dist/{proxy → integrations/proxy}/utils/logging.d.ts +1 -0
  112. package/dist/{proxy → integrations/proxy}/utils/logging.js +5 -0
  113. package/package.json +31 -10
  114. package/postinstall.js +62 -6
  115. package/dist/cli.js +0 -149
  116. package/dist/commands/capture.d.ts +0 -6
  117. package/dist/commands/capture.js +0 -324
  118. package/dist/commands/disable.d.ts +0 -1
  119. package/dist/commands/disable.js +0 -14
  120. package/dist/commands/doctor.d.ts +0 -1
  121. package/dist/commands/doctor.js +0 -89
  122. package/dist/commands/init.d.ts +0 -1
  123. package/dist/commands/init.js +0 -52
  124. package/dist/commands/inject.d.ts +0 -5
  125. package/dist/commands/inject.js +0 -88
  126. package/dist/commands/prompt-inject.d.ts +0 -4
  127. package/dist/commands/prompt-inject.js +0 -451
  128. package/dist/commands/unregister.d.ts +0 -1
  129. package/dist/commands/unregister.js +0 -28
  130. package/dist/lib/anchor-extractor.d.ts +0 -30
  131. package/dist/lib/anchor-extractor.js +0 -296
  132. package/dist/lib/correction-builder.d.ts +0 -10
  133. package/dist/lib/correction-builder.js +0 -226
  134. package/dist/lib/drift-checker-proxy.js +0 -373
  135. package/dist/lib/drift-checker.d.ts +0 -66
  136. package/dist/lib/drift-checker.js +0 -341
  137. package/dist/lib/hooks.d.ts +0 -38
  138. package/dist/lib/hooks.js +0 -291
  139. package/dist/lib/jsonl-parser.d.ts +0 -87
  140. package/dist/lib/jsonl-parser.js +0 -281
  141. package/dist/lib/session-parser.d.ts +0 -44
  142. package/dist/lib/session-parser.js +0 -256
  143. package/dist/lib/store.d.ts +0 -1
  144. package/dist/proxy/cache.d.ts +0 -32
  145. package/dist/proxy/cache.js +0 -47
  146. package/dist/proxy/handlers/preprocess.js +0 -186
  147. package/dist/proxy/index.js +0 -30
  148. package/dist/proxy/injection/delta-tracking.d.ts +0 -11
  149. package/dist/proxy/injection/delta-tracking.js +0 -94
  150. package/dist/proxy/injection/injectors.d.ts +0 -7
  151. package/dist/proxy/injection/injectors.js +0 -139
  152. package/dist/proxy/request-processor.d.ts +0 -27
  153. package/dist/proxy/request-processor.js +0 -233
  154. package/dist/proxy/server.js +0 -1289
  155. /package/dist/{commands → cli/commands}/drift-test.d.ts +0 -0
  156. /package/dist/{commands → cli/commands}/login.d.ts +0 -0
  157. /package/dist/{commands → cli/commands}/logout.d.ts +0 -0
  158. /package/dist/{commands → cli/commands}/proxy-status.d.ts +0 -0
  159. /package/dist/{commands → cli/commands}/status.d.ts +0 -0
  160. /package/dist/{commands → cli/commands}/uninstall.d.ts +0 -0
  161. /package/dist/{cli.d.ts → cli/index.d.ts} +0 -0
  162. /package/dist/{lib → core/cloud}/api-client.d.ts +0 -0
  163. /package/dist/{lib → core/cloud}/api-client.js +0 -0
  164. /package/dist/{lib → core/cloud}/credentials.d.ts +0 -0
  165. /package/dist/{lib → core/cloud}/credentials.js +0 -0
  166. /package/dist/{lib → core}/store/convenience.d.ts +0 -0
  167. /package/dist/{lib → core}/store/convenience.js +0 -0
  168. /package/dist/{lib → core}/store/database.d.ts +0 -0
  169. /package/dist/{lib → core}/store/database.js +0 -0
  170. /package/dist/{lib → core}/store/drift.d.ts +0 -0
  171. /package/dist/{lib → core}/store/drift.js +0 -0
  172. /package/dist/{lib → core}/store/index.d.ts +0 -0
  173. /package/dist/{lib → core}/store/index.js +0 -0
  174. /package/dist/{lib → core}/store/sessions.d.ts +0 -0
  175. /package/dist/{lib → core}/store/steps.d.ts +0 -0
  176. /package/dist/{lib → core}/store/steps.js +0 -0
  177. /package/dist/{lib → core}/store/tasks.d.ts +0 -0
  178. /package/dist/{lib → core}/store/tasks.js +0 -0
  179. /package/dist/{lib → core}/store/types.js +0 -0
  180. /package/dist/{proxy/action-parser.js → integrations/proxy/agents/claude/parser.js} +0 -0
  181. /package/dist/{lib → integrations/proxy/agents/claude}/settings.d.ts +0 -0
  182. /package/dist/{lib → integrations/proxy/agents/claude}/settings.js +0 -0
  183. /package/dist/{proxy → integrations/proxy/cache}/extended-cache.d.ts +0 -0
  184. /package/dist/{proxy → integrations/proxy}/config.d.ts +0 -0
  185. /package/dist/{proxy → integrations/proxy}/index.d.ts +0 -0
  186. /package/dist/{proxy → integrations/proxy}/types.js +0 -0
  187. /package/dist/{lib → utils}/debug.d.ts +0 -0
  188. /package/dist/{lib → utils}/debug.js +0 -0
  189. /package/dist/{lib → utils}/utils.d.ts +0 -0
  190. /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();
@@ -1,6 +0,0 @@
1
- import 'dotenv/config';
2
- interface CaptureOptions {
3
- sessionDir?: string;
4
- }
5
- export declare function capture(options: CaptureOptions): Promise<void>;
6
- export {};
@@ -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>;
@@ -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>;
@@ -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
- }
@@ -1 +0,0 @@
1
- export declare function init(): Promise<void>;
@@ -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
- }
@@ -1,5 +0,0 @@
1
- interface InjectOptions {
2
- task?: string;
3
- }
4
- export declare function inject(options: InjectOptions): Promise<void>;
5
- export {};