grov 0.5.3 → 0.5.5

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/README.md CHANGED
@@ -6,45 +6,60 @@
6
6
 
7
7
  <p align="center"><strong>Collective AI memory for engineering teams.</strong></p>
8
8
 
9
+ <p align="center"><em>When one dev's Claude figures something out, every dev's Claude knows it.</em></p>
10
+
9
11
  <p align="center">
10
12
  <a href="https://www.npmjs.com/package/grov"><img src="https://img.shields.io/npm/v/grov" alt="npm version"></a>
11
13
  <a href="https://www.npmjs.com/package/grov"><img src="https://img.shields.io/npm/dm/grov" alt="npm downloads"></a>
12
14
  <a href="https://github.com/TonyStef/Grov/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache%202.0-blue" alt="license"></a>
15
+ <a href="https://app.grov.dev"><img src="https://img.shields.io/badge/Dashboard-app.grov.dev-22c55e" alt="dashboard"></a>
13
16
  </p>
14
17
 
15
18
  <p align="center">
16
19
  <a href="https://grov.dev">Website</a> •
17
20
  <a href="https://app.grov.dev">Dashboard</a> •
18
21
  <a href="#quick-start">Quick Start</a> •
19
- <a href="#team-sync">Team Sync</a> •
22
+ <a href="#features">Features</a> •
20
23
  <a href="#contributing">Contributing</a>
21
24
  </p>
22
25
 
23
- Grov captures reasoning from your Claude Code sessions and injects it into future sessions. Your AI remembers what it learned.
26
+ ---
24
27
 
25
28
  ## The Problem
26
29
 
27
- Every time you start a new Claude Code session:
28
- - Claude re-explores your codebase from scratch
29
- - It reads the same files again
30
- - It rediscovers patterns you've already established
31
- - You burn tokens on redundant exploration
32
-
33
- **Measured impact:** A typical task takes 10+ minutes, 7%+ token usage, and 3+ explore agents just to understand the codebase.*
30
+ Your team's AI agents are learning in silos.
34
31
 
35
- ## The Solution
32
+ - Dev A's Claude spends 10 minutes understanding your auth system
33
+ - Dev B's Claude does the exact same exploration the next day
34
+ - Dev C asks a question that was already answered last week
35
+ - Every new session starts from zero
36
36
 
37
- Grov captures what Claude learns and injects it back on the next session.
37
+ **The waste:** Redundant exploration, duplicate token spend, knowledge that disappears when sessions end.
38
38
 
39
- ![grov demo](demo-converted.gif)
39
+ ## The Solution
40
40
 
41
- ### What Gets Captured
41
+ Grov captures what your team's AI learns and shares it automatically.
42
42
 
43
- Real reasoning, not just file lists:
43
+ ```
44
+ Dev A: "How does auth work in this codebase?"
45
+
46
+ Claude investigates, figures it out
47
+
48
+ Grov captures the reasoning + decisions
49
+
50
+ Syncs to team dashboard
51
+
52
+ Dev B: "Should we add password salting?"
53
+
54
+ Claude already knows: "Based on verified team knowledge,
55
+ no - this codebase uses OAuth-only, no passwords stored"
56
+
57
+ No exploration needed. Instant expert answer.
58
+ ```
44
59
 
45
- ![captured reasoning](docs/reasoning-output.jpeg)
60
+ **Measured impact:** Tasks drop from 10+ minutes to 1-2 minutes when team context is available.
46
61
 
47
- *Architectural decisions, patterns, and rationale - automatically extracted.*
62
+ ---
48
63
 
49
64
  ## Quick Start
50
65
 
@@ -56,72 +71,60 @@ grov proxy # Start (keep running)
56
71
 
57
72
  Then use Claude Code normally in another terminal. That's it.
58
73
 
59
- ## How It Works
60
-
61
- ```
62
- Session 1: Claude learns about your auth system
63
-
64
- grov captures: "Auth tokens refresh in middleware/token.ts:45,
65
- using 15-min window to handle long forms"
66
-
67
- Session 2: User asks about related feature
68
-
69
- grov injects: Previous context about auth
70
-
71
- Claude skips exploration, reads files directly
74
+ For team sync:
75
+ ```bash
76
+ grov login # Authenticate via GitHub
77
+ grov sync --enable --team ID # Enable sync for your team
72
78
  ```
73
79
 
74
- ## Commands
80
+ **Free for individuals and teams up to 3 developers.**
75
81
 
76
- ```bash
77
- grov init # Configure proxy URL (one-time)
78
- grov proxy # Start the proxy (required)
79
- grov proxy-status # Show active sessions
80
- grov status # Show captured tasks
81
- grov login # Login to cloud dashboard
82
- grov sync # Sync memories to team dashboard
83
- grov disable # Disable grov
84
- ```
82
+ ---
85
83
 
86
- ## Data Storage
84
+ ## What Gets Captured
87
85
 
88
- - **Database:** `~/.grov/memory.db` (SQLite)
89
- - **Per-project:** Context is filtered by project path
90
- - **Local by default:** Memories stay on your machine unless you enable team sync
86
+ Real reasoning, not just file lists:
91
87
 
92
- ## Team Sync
88
+ ![Dashboard showing captured reasoning](dashboard-showcase.jpeg)
93
89
 
94
- Share memories across your engineering team with the cloud dashboard.
90
+ *Architectural decisions, patterns, and rationale - automatically extracted and synced to your team.*
95
91
 
96
- ```bash
97
- grov login # Authenticate via GitHub
98
- grov sync --enable --team ID # Enable sync for a team
99
- ```
92
+ Every captured memory includes:
93
+ - **Reasoning trace** - The WHY behind decisions (CONCLUSION/INSIGHT pairs)
94
+ - **Key decisions** - What was chosen and why alternatives were rejected
95
+ - **Files touched** - Which parts of the codebase are relevant
96
+ - **Constraints discovered** - What can't break, what must stay compatible
100
97
 
101
- Once enabled, memories automatically sync to [app.grov.dev](https://app.grov.dev) where your team can:
102
- - Browse all captured reasoning
103
- - Search across sessions
104
- - Invite team members
105
- - See who learned what
98
+ ---
106
99
 
107
- Memories sync automatically when sessions complete - no manual intervention needed.
100
+ ## What Your Team Gets
108
101
 
109
- ## Requirements
102
+ When a teammate asks a related question, Claude already knows:
110
103
 
111
- - Node.js 18+
112
- - Claude Code
104
+ ![Claude using team knowledge](cli-showcase.jpeg)
105
+
106
+ *No exploration. No re-investigation. Instant expert answers from team memory.*
107
+
108
+ Claude receives verified context and skips the exploration phase entirely - no "let me investigate" or "I'll need to look at the codebase."
113
109
 
114
110
  ---
115
111
 
116
- ## Advanced Features
112
+ ## Features
117
113
 
118
- ### Anti-Drift Detection
114
+ ### Team Knowledge Sharing
115
+ The core value: what one dev's AI learns, everyone's AI knows.
119
116
 
120
- Grov monitors what Claude **does** (not what you ask) and corrects if it drifts from your goal.
117
+ - **Automatic capture** - Reasoning extracted when tasks complete
118
+ - **Automatic sync** - Memories sync to your team in real-time
119
+ - **Automatic injection** - Relevant context injected into new sessions
120
+ - **Hybrid search** - Semantic (AI understands meaning) + lexical (keyword matching)
121
+
122
+ ### Anti-Drift Detection
123
+ Grov monitors what Claude **does** (not what you ask) and corrects when it goes off-track.
121
124
 
122
125
  - Extracts your intent from the first prompt
123
126
  - Monitors Claude's actions (file edits, commands, explorations)
124
- - Uses Claude Haiku to score alignment (1-10)
127
+ - Scores alignment (1-10) using Claude Haiku
125
128
  - Injects corrections at 4 levels: nudge → correct → intervene → halt
126
129
 
127
130
  ```bash
@@ -129,25 +132,85 @@ Grov monitors what Claude **does** (not what you ask) and corrects if it drifts
129
132
  grov drift-test "refactor the auth system" --goal "fix login bug"
130
133
  ```
131
134
 
132
- ### Extended Cache (Experimental)
133
-
134
- Anthropic's prompt cache expires after 5 minutes of inactivity. If you pause to think between prompts, the cache expires and must be recreated (costs more, takes longer).
135
+ ### Extended Cache
136
+ Anthropic's prompt cache expires after 5 minutes of inactivity. Grov keeps it warm.
135
137
 
136
138
  ```bash
137
139
  grov proxy --extended-cache
138
140
  ```
139
141
 
140
- **What this does:** Sends minimal keep-alive requests (~$0.002 each) during idle periods to preserve your cache.
142
+ - Sends minimal keep-alive requests (~$0.002 each) during idle periods
143
+ - Saves ~$0.18 per idle period by avoiding cache recreation
144
+ - Your next prompt is faster and cheaper
145
+
146
+ **Opt-in only.** By using `--extended-cache`, you consent to Grov making API requests on your behalf.
147
+
148
+ ### Auto-Compaction
149
+ When your context window fills up, Grov automatically compacts while preserving what matters.
150
+
151
+ - Pre-computes summary at 85% capacity
152
+ - Preserves: original goal, key decisions with reasoning, current state, next steps
153
+ - Drops: verbose exploration, redundant file reads, superseded reasoning
154
+ - Claude continues seamlessly without losing important context
155
+
156
+ No manual `/compact` needed. No lost reasoning.
157
+
158
+ ---
159
+
160
+ ## Commands
161
+
162
+ ```bash
163
+ grov init # Configure proxy URL (one-time)
164
+ grov proxy # Start the proxy (required)
165
+ grov proxy-status # Show active sessions
166
+ grov status # Show captured tasks
167
+ grov login # Login to cloud dashboard
168
+ grov sync # Sync memories to team dashboard
169
+ grov disable # Disable grov
170
+ grov drift-test # Test drift detection
171
+ ```
172
+
173
+ ---
141
174
 
142
- **Important:** By using `--extended-cache`, you consent to Grov making API requests on your behalf to keep the cache active. These requests:
143
- - Use your Anthropic API key
144
- - Are sent automatically during idle periods (every ~4 minutes)
145
- - Cost approximately $0.002 per keep-alive
146
- - Are discarded (not added to your conversation)
175
+ ## How It Works
147
176
 
148
- This feature is **disabled by default** and requires explicit opt-in.
177
+ ```
178
+ ┌─────────────────────────────────────────────────────────────┐
179
+ │ Claude Code │
180
+ │ │ │
181
+ │ ▼ │
182
+ │ Grov Proxy (localhost:8080) │
183
+ │ │ │
184
+ │ ├──► Inject team memory from past sessions │
185
+ │ ├──► Forward to Anthropic API │
186
+ │ ├──► Monitor for drift, inject corrections │
187
+ │ ├──► Track context usage, auto-compact if needed │
188
+ │ └──► Capture reasoning when task completes │
189
+ │ │ │
190
+ │ ▼ │
191
+ │ Team Dashboard (app.grov.dev) │
192
+ │ │ │
193
+ │ ▼ │
194
+ │ Available to entire team │
195
+ └─────────────────────────────────────────────────────────────┘
196
+ ```
149
197
 
150
- ### Environment Variables
198
+ **Local by default:** Memories stay on your machine in `~/.grov/memory.db` (SQLite) unless you enable team sync.
199
+
200
+ ---
201
+
202
+ ## Dashboard
203
+
204
+ Browse, search, and manage your team's AI knowledge at [app.grov.dev](https://app.grov.dev).
205
+
206
+ - **Search across all sessions** - Hybrid semantic + keyword search
207
+ - **Browse reasoning traces** - See the WHY behind every decision
208
+ - **Team visibility** - See who learned what, when
209
+ - **Invite teammates** - Share knowledge automatically
210
+
211
+ ---
212
+
213
+ ## Environment Variables
151
214
 
152
215
  ```bash
153
216
  # Required for drift detection and LLM extraction
@@ -159,45 +222,21 @@ export PROXY_HOST=127.0.0.1 # Proxy host
159
222
  export PROXY_PORT=8080 # Proxy port
160
223
  ```
161
224
 
162
- Without an API key, grov uses basic extraction and disables drift detection.
163
-
164
- ### What Gets Stored
165
-
166
- ```json
167
- {
168
- "task": "Fix auth logout bug",
169
- "goal": "Prevent random user logouts",
170
- "files_touched": ["src/auth/session.ts", "src/middleware/token.ts"],
171
- "reasoning_trace": [
172
- "Investigated token refresh logic",
173
- "Found refresh window was too short",
174
- "Extended from 5min to 15min"
175
- ],
176
- "status": "complete"
177
- }
178
- ```
225
+ Without an API key, Grov uses basic extraction and disables drift detection.
179
226
 
180
- ### What Gets Injected
227
+ ---
181
228
 
182
- ```
183
- VERIFIED CONTEXT FROM PREVIOUS SESSIONS:
229
+ ## Requirements
184
230
 
185
- [Task: Fix auth logout bug]
186
- - Files: session.ts, token.ts
187
- - Extended token refresh window from 5min to 15min
188
- - Reason: Users were getting logged out during long forms
231
+ - Node.js 18+
232
+ - Claude Code
189
233
 
190
- YOU MAY SKIP EXPLORE AGENTS for files mentioned above.
191
- ```
234
+ ---
192
235
 
193
- ### How the Proxy Works
236
+ ## Pricing
194
237
 
195
- 1. **`grov init`** sets `ANTHROPIC_BASE_URL=http://127.0.0.1:8080` in Claude's settings
196
- 2. **`grov proxy`** intercepts all API calls and:
197
- - Extracts intent from first prompt
198
- - Injects context from team memory
199
- - Tracks actions and detects drift
200
- - Saves reasoning when tasks complete
238
+ - **Free** - Individuals and teams up to 3 developers
239
+ - **Team** - Larger teams with additional features (coming soon)
201
240
 
202
241
  ---
203
242
 
@@ -209,9 +248,13 @@ YOU MAY SKIP EXPLORE AGENTS for files mentioned above.
209
248
  - [x] Anti-drift detection & correction
210
249
  - [x] Team sync (cloud backend)
211
250
  - [x] Web dashboard
212
- - [ ] Semantic search
251
+ - [x] Hybrid search (semantic + lexical)
252
+ - [x] Extended cache (keep prompt cache warm)
253
+ - [x] Auto-compaction with reasoning preservation
213
254
  - [ ] VS Code extension
214
255
 
256
+ ---
257
+
215
258
  ## Contributing
216
259
 
217
260
  1. **Fork the repo** and clone locally
@@ -226,6 +269,8 @@ node dist/cli.js init # Test CLI
226
269
 
227
270
  Found a bug? [Open an issue](https://github.com/TonyStef/Grov/issues).
228
271
 
272
+ ---
273
+
229
274
  ## License
230
275
 
231
276
  Apache License 2.0 - see [LICENSE](LICENSE) file for details.
@@ -1,8 +1,24 @@
1
1
  // Login command - Device authorization flow
2
2
  // Authenticates CLI with Grov cloud using OAuth-like device flow
3
3
  import open from 'open';
4
- import { writeCredentials, isAuthenticated, readCredentials } from '../lib/credentials.js';
5
- import { startDeviceFlow, pollDeviceFlow, sleep } from '../lib/api-client.js';
4
+ import * as readline from 'readline';
5
+ import { writeCredentials, isAuthenticated, readCredentials, setTeamId, setSyncEnabled } from '../lib/credentials.js';
6
+ import { startDeviceFlow, pollDeviceFlow, sleep, fetchTeams } from '../lib/api-client.js';
7
+ /**
8
+ * Prompt user for input
9
+ */
10
+ function prompt(question) {
11
+ const rl = readline.createInterface({
12
+ input: process.stdin,
13
+ output: process.stdout,
14
+ });
15
+ return new Promise((resolve) => {
16
+ rl.question(question, (answer) => {
17
+ rl.close();
18
+ resolve(answer.trim().toLowerCase());
19
+ });
20
+ });
21
+ }
6
22
  /**
7
23
  * Decode JWT payload to extract user info
8
24
  */
@@ -91,16 +107,54 @@ export async function login() {
91
107
  email: userInfo.email,
92
108
  sync_enabled: false,
93
109
  });
94
- console.log('╔═════════════════════════════════════════╗');
95
- console.log('║ ║');
96
- console.log('║ Successfully logged in! ║');
97
- console.log('║ ║');
98
- console.log('╚═════════════════════════════════════════╝');
99
- console.log(`\nLogged in as: ${userInfo.email}\n`);
100
- console.log('Next steps:');
101
- console.log(' 1. Run "grov sync --status" to check sync settings');
102
- console.log(' 2. Run "grov sync --enable --team <team-id>" to enable sync');
103
- console.log(' 3. Run "grov status" to view local memories\n');
110
+ console.log('\n✓ Logged in as:', userInfo.email);
111
+ // Auto-setup: Fetch teams and configure sync
112
+ console.log('\nSetting up cloud sync...');
113
+ try {
114
+ const teams = await fetchTeams();
115
+ if (teams.length === 0) {
116
+ console.log('\n⚠ No teams found.');
117
+ console.log('Create one at: https://app.grov.dev/team');
118
+ console.log('Then run: grov sync --enable --team <team-id>\n');
119
+ return;
120
+ }
121
+ let selectedTeam = teams[0];
122
+ // If multiple teams, let user choose
123
+ if (teams.length > 1) {
124
+ console.log('\nYour teams:');
125
+ teams.forEach((team, i) => {
126
+ console.log(` ${i + 1}. ${team.name} (${team.slug})`);
127
+ });
128
+ const choice = await prompt(`\nSelect team [1-${teams.length}] (default: 1): `);
129
+ const index = parseInt(choice, 10) - 1;
130
+ if (index >= 0 && index < teams.length) {
131
+ selectedTeam = teams[index];
132
+ }
133
+ }
134
+ // Ask to enable sync (default yes)
135
+ const enableSync = await prompt(`Enable cloud sync to "${selectedTeam.name}"? [Y/n]: `);
136
+ if (enableSync !== 'n' && enableSync !== 'no') {
137
+ setTeamId(selectedTeam.id);
138
+ setSyncEnabled(true);
139
+ console.log('\n╔═════════════════════════════════════════╗');
140
+ console.log('║ ║');
141
+ console.log('║ ✓ Cloud sync enabled! ║');
142
+ console.log('║ ║');
143
+ console.log('╚═════════════════════════════════════════╝');
144
+ console.log(`\nSyncing to: ${selectedTeam.name}`);
145
+ console.log('\nYou\'re all set! Your AI sessions will now be saved.');
146
+ console.log('View them at: https://app.grov.dev/memories\n');
147
+ }
148
+ else {
149
+ console.log('\n✓ Logged in. Sync not enabled.');
150
+ console.log('Run "grov sync --enable" later to start syncing.\n');
151
+ }
152
+ }
153
+ catch (err) {
154
+ console.log('\n⚠ Could not auto-configure sync.');
155
+ console.log('Run "grov sync --enable --team <team-id>" manually.');
156
+ console.log('Find your team ID at: https://app.grov.dev/team\n');
157
+ }
104
158
  return;
105
159
  }
106
160
  if (status === 'expired') {
@@ -32,7 +32,6 @@ export interface TaskAnalysis {
32
32
  task_type: 'information' | 'planning' | 'implementation';
33
33
  action: 'continue' | 'new_task' | 'subtask' | 'parallel_task' | 'task_complete' | 'subtask_complete';
34
34
  task_id: string;
35
- current_goal: string;
36
35
  parent_task_id?: string;
37
36
  reasoning: string;
38
37
  step_reasoning?: string;
@@ -311,7 +311,6 @@ Return a JSON object with these fields:
311
311
  - task_type: one of "information", "planning", or "implementation"
312
312
  - action: one of "continue", "task_complete", "new_task", or "subtask_complete"
313
313
  - task_id: existing session_id "${currentSession?.session_id || 'NEW'}" or "NEW" for new task
314
- - current_goal: the goal based on the latest user message
315
314
  - reasoning: brief explanation of why you made this decision${compressionInstruction}
316
315
  </output>
317
316
 
@@ -481,7 +480,7 @@ RESPONSE RULES:
481
480
  if (!needsCompression && assistantResponse.length > 0) {
482
481
  analysis.step_reasoning = assistantResponse.substring(0, 1000);
483
482
  }
484
- debugLLM('analyzeTaskContext', `Result: task_type=${analysis.task_type}, action=${analysis.action}, goal="${analysis.current_goal?.substring(0, 50) || 'N/A'}" reasoning="${analysis.reasoning?.substring(0, 150) || 'none'}"`);
483
+ debugLLM('analyzeTaskContext', `Result: task_type=${analysis.task_type}, action=${analysis.action}, reasoning="${analysis.reasoning?.substring(0, 150) || 'none'}"`);
485
484
  return analysis;
486
485
  }
487
486
  catch (parseError) {
@@ -491,7 +490,6 @@ RESPONSE RULES:
491
490
  task_type: 'implementation',
492
491
  action: currentSession ? 'continue' : 'new_task',
493
492
  task_id: currentSession?.session_id || 'NEW',
494
- current_goal: latestUserMessage.substring(0, 200),
495
493
  reasoning: 'Fallback due to parse error',
496
494
  step_reasoning: assistantResponse.substring(0, 1000),
497
495
  };
@@ -406,10 +406,21 @@ async function postProcessResponse(response, sessionInfo, requestBody, logger, e
406
406
  else if (!activeSession) {
407
407
  // First request, create session without task analysis
408
408
  const newSessionId = randomUUID();
409
+ // Extract clean goal summary instead of using raw text
410
+ let goalSummary = latestUserMessage.substring(0, 500) || 'Task in progress';
411
+ if (isIntentExtractionAvailable() && latestUserMessage.length > 10) {
412
+ try {
413
+ const intentData = await extractIntent(latestUserMessage);
414
+ goalSummary = intentData.goal;
415
+ }
416
+ catch {
417
+ // Keep fallback goalSummary
418
+ }
419
+ }
409
420
  activeSession = createSessionState({
410
421
  session_id: newSessionId,
411
422
  project_path: sessionInfo.projectPath,
412
- original_goal: latestUserMessage.substring(0, 500) || 'Task in progress',
423
+ original_goal: goalSummary,
413
424
  task_type: 'main',
414
425
  });
415
426
  activeSessionId = newSessionId;
@@ -432,7 +443,6 @@ async function postProcessResponse(response, sessionInfo, requestBody, logger, e
432
443
  msg: 'Task analysis',
433
444
  action: taskAnalysis.action,
434
445
  task_type: taskAnalysis.task_type,
435
- goal: taskAnalysis.current_goal?.substring(0, 50),
436
446
  reasoning: taskAnalysis.reasoning,
437
447
  });
438
448
  // TASK LOG: Analysis result
@@ -440,7 +450,6 @@ async function postProcessResponse(response, sessionInfo, requestBody, logger, e
440
450
  sessionId: sessionInfo.sessionId,
441
451
  action: taskAnalysis.action,
442
452
  task_type: taskAnalysis.task_type,
443
- goal: taskAnalysis.current_goal || '',
444
453
  reasoning: taskAnalysis.reasoning || '',
445
454
  userMessage: latestUserMessage.substring(0, 80),
446
455
  hasCurrentSession: !!sessionInfo.currentSession,
@@ -464,22 +473,11 @@ async function postProcessResponse(response, sessionInfo, requestBody, logger, e
464
473
  if (sessionInfo.currentSession) {
465
474
  activeSessionId = sessionInfo.currentSession.session_id;
466
475
  activeSession = sessionInfo.currentSession;
467
- // Update goal if Haiku detected a new instruction from user
468
- // (same task/topic, but new specific instruction)
469
- if (taskAnalysis.current_goal &&
470
- taskAnalysis.current_goal !== activeSession.original_goal &&
471
- latestUserMessage.length > 30) {
472
- updateSessionState(activeSessionId, {
473
- original_goal: taskAnalysis.current_goal,
474
- });
475
- activeSession.original_goal = taskAnalysis.current_goal;
476
- }
477
476
  // TASK LOG: Continue existing session
478
477
  taskLog('ORCHESTRATION_CONTINUE', {
479
478
  sessionId: activeSessionId,
480
479
  source: 'current_session',
481
480
  goal: activeSession.original_goal,
482
- goalUpdated: taskAnalysis.current_goal !== activeSession.original_goal,
483
481
  });
484
482
  }
485
483
  else if (sessionInfo.completedSession) {
@@ -488,7 +486,6 @@ async function postProcessResponse(response, sessionInfo, requestBody, logger, e
488
486
  activeSession = sessionInfo.completedSession;
489
487
  updateSessionState(activeSessionId, {
490
488
  status: 'active',
491
- original_goal: taskAnalysis.current_goal || activeSession.original_goal,
492
489
  });
493
490
  activeSession.status = 'active';
494
491
  activeSessions.set(activeSessionId, {
@@ -513,7 +510,7 @@ async function postProcessResponse(response, sessionInfo, requestBody, logger, e
513
510
  }
514
511
  // Extract full intent for new task (goal, scope, constraints, keywords)
515
512
  let intentData = {
516
- goal: taskAnalysis.current_goal,
513
+ goal: latestUserMessage.substring(0, 500),
517
514
  expected_scope: [],
518
515
  constraints: [],
519
516
  keywords: [],
@@ -600,7 +597,7 @@ async function postProcessResponse(response, sessionInfo, requestBody, logger, e
600
597
  case 'subtask': {
601
598
  // Extract intent for subtask
602
599
  let intentData = {
603
- goal: taskAnalysis.current_goal,
600
+ goal: latestUserMessage.substring(0, 500),
604
601
  expected_scope: [],
605
602
  constraints: [],
606
603
  keywords: [],
@@ -650,7 +647,7 @@ async function postProcessResponse(response, sessionInfo, requestBody, logger, e
650
647
  case 'parallel_task': {
651
648
  // Extract intent for parallel task
652
649
  let intentData = {
653
- goal: taskAnalysis.current_goal,
650
+ goal: latestUserMessage.substring(0, 500),
654
651
  expected_scope: [],
655
652
  constraints: [],
656
653
  keywords: [],
@@ -748,10 +745,21 @@ async function postProcessResponse(response, sessionInfo, requestBody, logger, e
748
745
  // Example: user asks clarification question, answer is provided in single turn
749
746
  try {
750
747
  const newSessionId = randomUUID();
748
+ // Extract clean goal summary instead of using raw text
749
+ let goalSummary = latestUserMessage.substring(0, 500);
750
+ if (isIntentExtractionAvailable() && latestUserMessage.length > 10) {
751
+ try {
752
+ const intentData = await extractIntent(latestUserMessage);
753
+ goalSummary = intentData.goal;
754
+ }
755
+ catch {
756
+ // Keep fallback goalSummary
757
+ }
758
+ }
751
759
  const instantSession = createSessionState({
752
760
  session_id: newSessionId,
753
761
  project_path: sessionInfo.projectPath,
754
- original_goal: taskAnalysis.current_goal || latestUserMessage.substring(0, 500),
762
+ original_goal: goalSummary,
755
763
  task_type: 'main',
756
764
  });
757
765
  // Set final_response for reasoning extraction
@@ -764,7 +772,7 @@ async function postProcessResponse(response, sessionInfo, requestBody, logger, e
764
772
  // TASK LOG: Instant complete (new task that finished in one turn)
765
773
  taskLog('ORCHESTRATION_TASK_COMPLETE', {
766
774
  sessionId: newSessionId,
767
- goal: taskAnalysis.current_goal || latestUserMessage.substring(0, 80),
775
+ goal: goalSummary,
768
776
  source: 'instant_complete',
769
777
  });
770
778
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "grov",
3
- "version": "0.5.3",
3
+ "version": "0.5.5",
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",
@@ -13,6 +13,7 @@
13
13
  "dist/**/*.d.ts",
14
14
  "!dist/**/*.test.js",
15
15
  "!dist/**/*.test.d.ts",
16
+ "postinstall.js",
16
17
  "README.md",
17
18
  "LICENSE"
18
19
  ],
@@ -34,6 +35,7 @@
34
35
  "test:watch": "vitest",
35
36
  "test:all": "turbo run test",
36
37
  "typecheck": "turbo run typecheck",
38
+ "postinstall": "node postinstall.js",
37
39
  "prepublishOnly": "npm run build && npm test && npm run security:scan",
38
40
  "prepare": "husky",
39
41
  "security:scan": "./scripts/scan-secrets.sh"
package/postinstall.js ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+
3
+ const green = '\x1b[32m';
4
+ const cyan = '\x1b[36m';
5
+ const dim = '\x1b[2m';
6
+ const reset = '\x1b[0m';
7
+ const bold = '\x1b[1m';
8
+
9
+ console.log(`
10
+ ${green}✓${reset} ${bold}grov installed successfully${reset}
11
+
12
+ ${dim}Sync your AI memories across your team:${reset}
13
+ ${cyan}https://app.grov.dev${reset}
14
+
15
+ ${dim}Quick start:${reset}
16
+ ${green}grov init${reset} Configure proxy
17
+ ${green}grov proxy${reset} Start capturing
18
+ ${green}grov login${reset} Connect to dashboard
19
+ `);