grov 0.1.1 → 0.2.2
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 +66 -87
- package/dist/cli.js +23 -37
- package/dist/commands/capture.js +1 -1
- package/dist/commands/disable.d.ts +1 -0
- package/dist/commands/disable.js +14 -0
- package/dist/commands/drift-test.js +56 -68
- package/dist/commands/init.js +29 -17
- package/dist/commands/proxy-status.d.ts +1 -0
- package/dist/commands/proxy-status.js +32 -0
- package/dist/commands/unregister.js +7 -1
- package/dist/lib/correction-builder-proxy.d.ts +16 -0
- package/dist/lib/correction-builder-proxy.js +125 -0
- package/dist/lib/correction-builder.js +1 -1
- package/dist/lib/drift-checker-proxy.d.ts +63 -0
- package/dist/lib/drift-checker-proxy.js +373 -0
- package/dist/lib/drift-checker.js +1 -1
- package/dist/lib/hooks.d.ts +11 -0
- package/dist/lib/hooks.js +33 -0
- package/dist/lib/llm-extractor.d.ts +60 -11
- package/dist/lib/llm-extractor.js +419 -98
- package/dist/lib/settings.d.ts +19 -0
- package/dist/lib/settings.js +63 -0
- package/dist/lib/store.d.ts +201 -43
- package/dist/lib/store.js +653 -90
- package/dist/proxy/action-parser.d.ts +58 -0
- package/dist/proxy/action-parser.js +196 -0
- package/dist/proxy/config.d.ts +26 -0
- package/dist/proxy/config.js +67 -0
- package/dist/proxy/forwarder.d.ts +24 -0
- package/dist/proxy/forwarder.js +119 -0
- package/dist/proxy/index.d.ts +1 -0
- package/dist/proxy/index.js +30 -0
- package/dist/proxy/request-processor.d.ts +12 -0
- package/dist/proxy/request-processor.js +94 -0
- package/dist/proxy/response-processor.d.ts +14 -0
- package/dist/proxy/response-processor.js +128 -0
- package/dist/proxy/server.d.ts +9 -0
- package/dist/proxy/server.js +911 -0
- package/package.json +10 -4
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
// Response processor - handles team memory save triggers and cleanup
|
|
2
|
+
// Reference: plan_proxy_local.md Section 4.6
|
|
3
|
+
import { getSessionState, getValidatedSteps, deleteStepsForSession, deleteSessionState, createTask, } from '../lib/store.js';
|
|
4
|
+
import { extractReasoning, isLLMAvailable, extractReasoningAndDecisions, isReasoningExtractionAvailable, } from '../lib/llm-extractor.js';
|
|
5
|
+
/**
|
|
6
|
+
* Save session to team memory
|
|
7
|
+
* Called on: task complete, subtask complete, session abandoned
|
|
8
|
+
*/
|
|
9
|
+
export async function saveToTeamMemory(sessionId, triggerReason) {
|
|
10
|
+
const sessionState = getSessionState(sessionId);
|
|
11
|
+
if (!sessionState) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const steps = getValidatedSteps(sessionId);
|
|
15
|
+
if (steps.length === 0 && triggerReason !== 'abandoned') {
|
|
16
|
+
return; // Nothing to save
|
|
17
|
+
}
|
|
18
|
+
// Build task data from session state and steps
|
|
19
|
+
const taskData = await buildTaskFromSession(sessionState, steps, triggerReason);
|
|
20
|
+
// Create task in team memory
|
|
21
|
+
createTask(taskData);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Build task data from session state and steps
|
|
25
|
+
*/
|
|
26
|
+
async function buildTaskFromSession(sessionState, steps, triggerReason) {
|
|
27
|
+
// Aggregate files from steps
|
|
28
|
+
const filesTouched = [...new Set(steps.flatMap(s => s.files))];
|
|
29
|
+
// Build basic reasoning trace from steps (fallback)
|
|
30
|
+
const basicReasoningTrace = steps
|
|
31
|
+
.filter(s => s.is_key_decision || s.action_type === 'edit' || s.action_type === 'write')
|
|
32
|
+
.slice(-10)
|
|
33
|
+
.map(s => {
|
|
34
|
+
if (s.action_type === 'edit' || s.action_type === 'write') {
|
|
35
|
+
return `${s.action_type}: ${s.files.join(', ')}`;
|
|
36
|
+
}
|
|
37
|
+
if (s.action_type === 'bash' && s.command) {
|
|
38
|
+
return `bash: ${s.command.substring(0, 50)}`;
|
|
39
|
+
}
|
|
40
|
+
return `${s.action_type}: ${s.files.length} files`;
|
|
41
|
+
});
|
|
42
|
+
// Try to use Anthropic Haiku for better reasoning & decisions extraction
|
|
43
|
+
let reasoningTrace = basicReasoningTrace;
|
|
44
|
+
let decisions = [];
|
|
45
|
+
let constraints = sessionState.constraints || [];
|
|
46
|
+
if (isReasoningExtractionAvailable() && steps.length > 0) {
|
|
47
|
+
try {
|
|
48
|
+
// Collect reasoning from steps
|
|
49
|
+
const stepsReasoning = steps
|
|
50
|
+
.map(s => s.reasoning)
|
|
51
|
+
.filter((r) => !!r && r.length > 10);
|
|
52
|
+
if (stepsReasoning.length > 0) {
|
|
53
|
+
const extracted = await extractReasoningAndDecisions(stepsReasoning, sessionState.original_goal || '');
|
|
54
|
+
if (extracted.reasoning_trace.length > 0) {
|
|
55
|
+
reasoningTrace = extracted.reasoning_trace;
|
|
56
|
+
}
|
|
57
|
+
if (extracted.decisions.length > 0) {
|
|
58
|
+
decisions = extracted.decisions;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// Fall back to basic extraction
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
else if (isLLMAvailable() && steps.length > 0) {
|
|
67
|
+
// Fallback to OpenAI-based extraction if Anthropic not available
|
|
68
|
+
try {
|
|
69
|
+
const pseudoSession = buildPseudoSession(sessionState, steps);
|
|
70
|
+
const extracted = await extractReasoning(pseudoSession);
|
|
71
|
+
if (extracted.decisions.length > 0) {
|
|
72
|
+
decisions = extracted.decisions;
|
|
73
|
+
}
|
|
74
|
+
if (extracted.constraints.length > 0) {
|
|
75
|
+
constraints = [...new Set([...constraints, ...extracted.constraints])];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// Fall back to basic extraction
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return {
|
|
83
|
+
project_path: sessionState.project_path,
|
|
84
|
+
user: sessionState.user_id,
|
|
85
|
+
original_query: sessionState.original_goal || 'Unknown task',
|
|
86
|
+
goal: sessionState.original_goal,
|
|
87
|
+
reasoning_trace: reasoningTrace,
|
|
88
|
+
files_touched: filesTouched,
|
|
89
|
+
decisions,
|
|
90
|
+
constraints,
|
|
91
|
+
status: triggerReason === 'abandoned' ? 'abandoned' : 'complete',
|
|
92
|
+
trigger_reason: triggerReason,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Build pseudo ParsedSession for LLM extraction
|
|
97
|
+
*/
|
|
98
|
+
function buildPseudoSession(sessionState, steps) {
|
|
99
|
+
return {
|
|
100
|
+
sessionId: sessionState.session_id,
|
|
101
|
+
projectPath: sessionState.project_path,
|
|
102
|
+
startTime: sessionState.start_time,
|
|
103
|
+
endTime: sessionState.last_update,
|
|
104
|
+
userMessages: [sessionState.original_goal || ''],
|
|
105
|
+
assistantMessages: steps.map(s => `[${s.action_type}] ${s.files.join(', ')}`),
|
|
106
|
+
toolCalls: steps.map(s => ({
|
|
107
|
+
name: s.action_type,
|
|
108
|
+
input: { files: s.files, command: s.command },
|
|
109
|
+
})),
|
|
110
|
+
filesRead: steps.filter(s => s.action_type === 'read').flatMap(s => s.files),
|
|
111
|
+
filesWritten: steps.filter(s => s.action_type === 'write' || s.action_type === 'edit').flatMap(s => s.files),
|
|
112
|
+
rawEntries: [],
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Clean up session data after save
|
|
117
|
+
*/
|
|
118
|
+
export function cleanupSession(sessionId) {
|
|
119
|
+
deleteStepsForSession(sessionId);
|
|
120
|
+
deleteSessionState(sessionId);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Save and cleanup session (for session end)
|
|
124
|
+
*/
|
|
125
|
+
export async function saveAndCleanupSession(sessionId, triggerReason) {
|
|
126
|
+
await saveToTeamMemory(sessionId, triggerReason);
|
|
127
|
+
cleanupSession(sessionId);
|
|
128
|
+
}
|