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 +152 -107
- package/dist/commands/login.js +66 -12
- package/dist/lib/llm-extractor.d.ts +0 -1
- package/dist/lib/llm-extractor.js +1 -3
- package/dist/proxy/server.js +28 -20
- package/package.json +3 -1
- package/postinstall.js +19 -0
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="#
|
|
22
|
+
<a href="#features">Features</a> •
|
|
20
23
|
<a href="#contributing">Contributing</a>
|
|
21
24
|
</p>
|
|
22
25
|
|
|
23
|
-
|
|
26
|
+
---
|
|
24
27
|
|
|
25
28
|
## The Problem
|
|
26
29
|
|
|
27
|
-
|
|
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
|
-
|
|
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
|
-
|
|
37
|
+
**The waste:** Redundant exploration, duplicate token spend, knowledge that disappears when sessions end.
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
## The Solution
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
Grov captures what your team's AI learns and shares it automatically.
|
|
42
42
|
|
|
43
|
-
|
|
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
|
-
|
|
60
|
+
**Measured impact:** Tasks drop from 10+ minutes to 1-2 minutes when team context is available.
|
|
46
61
|
|
|
47
|
-
|
|
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
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
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
|
-
|
|
80
|
+
**Free for individuals and teams up to 3 developers.**
|
|
75
81
|
|
|
76
|
-
|
|
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
|
-
##
|
|
84
|
+
## What Gets Captured
|
|
87
85
|
|
|
88
|
-
|
|
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
|
-
|
|
88
|
+

|
|
93
89
|
|
|
94
|
-
|
|
90
|
+
*Architectural decisions, patterns, and rationale - automatically extracted and synced to your team.*
|
|
95
91
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
-
|
|
102
|
-
- Browse all captured reasoning
|
|
103
|
-
- Search across sessions
|
|
104
|
-
- Invite team members
|
|
105
|
-
- See who learned what
|
|
98
|
+
---
|
|
106
99
|
|
|
107
|
-
|
|
100
|
+
## What Your Team Gets
|
|
108
101
|
|
|
109
|
-
|
|
102
|
+
When a teammate asks a related question, Claude already knows:
|
|
110
103
|
|
|
111
|
-
-
|
|
112
|
-
|
|
104
|
+

|
|
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
|
-
##
|
|
112
|
+
## Features
|
|
117
113
|
|
|
118
|
-
###
|
|
114
|
+
### Team Knowledge Sharing
|
|
115
|
+
The core value: what one dev's AI learns, everyone's AI knows.
|
|
119
116
|
|
|
120
|
-
|
|
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
|
-
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
227
|
+
---
|
|
181
228
|
|
|
182
|
-
|
|
183
|
-
VERIFIED CONTEXT FROM PREVIOUS SESSIONS:
|
|
229
|
+
## Requirements
|
|
184
230
|
|
|
185
|
-
|
|
186
|
-
-
|
|
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
|
-
|
|
191
|
-
```
|
|
234
|
+
---
|
|
192
235
|
|
|
193
|
-
|
|
236
|
+
## Pricing
|
|
194
237
|
|
|
195
|
-
|
|
196
|
-
|
|
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
|
-
- [
|
|
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.
|
package/dist/commands/login.js
CHANGED
|
@@ -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
|
|
5
|
-
import {
|
|
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
|
-
|
|
96
|
-
console.log('
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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},
|
|
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
|
};
|
package/dist/proxy/server.js
CHANGED
|
@@ -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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
+
"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
|
+
`);
|