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.
Files changed (39) hide show
  1. package/README.md +66 -87
  2. package/dist/cli.js +23 -37
  3. package/dist/commands/capture.js +1 -1
  4. package/dist/commands/disable.d.ts +1 -0
  5. package/dist/commands/disable.js +14 -0
  6. package/dist/commands/drift-test.js +56 -68
  7. package/dist/commands/init.js +29 -17
  8. package/dist/commands/proxy-status.d.ts +1 -0
  9. package/dist/commands/proxy-status.js +32 -0
  10. package/dist/commands/unregister.js +7 -1
  11. package/dist/lib/correction-builder-proxy.d.ts +16 -0
  12. package/dist/lib/correction-builder-proxy.js +125 -0
  13. package/dist/lib/correction-builder.js +1 -1
  14. package/dist/lib/drift-checker-proxy.d.ts +63 -0
  15. package/dist/lib/drift-checker-proxy.js +373 -0
  16. package/dist/lib/drift-checker.js +1 -1
  17. package/dist/lib/hooks.d.ts +11 -0
  18. package/dist/lib/hooks.js +33 -0
  19. package/dist/lib/llm-extractor.d.ts +60 -11
  20. package/dist/lib/llm-extractor.js +419 -98
  21. package/dist/lib/settings.d.ts +19 -0
  22. package/dist/lib/settings.js +63 -0
  23. package/dist/lib/store.d.ts +201 -43
  24. package/dist/lib/store.js +653 -90
  25. package/dist/proxy/action-parser.d.ts +58 -0
  26. package/dist/proxy/action-parser.js +196 -0
  27. package/dist/proxy/config.d.ts +26 -0
  28. package/dist/proxy/config.js +67 -0
  29. package/dist/proxy/forwarder.d.ts +24 -0
  30. package/dist/proxy/forwarder.js +119 -0
  31. package/dist/proxy/index.d.ts +1 -0
  32. package/dist/proxy/index.js +30 -0
  33. package/dist/proxy/request-processor.d.ts +12 -0
  34. package/dist/proxy/request-processor.js +94 -0
  35. package/dist/proxy/response-processor.d.ts +14 -0
  36. package/dist/proxy/response-processor.js +128 -0
  37. package/dist/proxy/server.d.ts +9 -0
  38. package/dist/proxy/server.js +911 -0
  39. 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
+ }
@@ -0,0 +1,9 @@
1
+ import { FastifyInstance } from 'fastify';
2
+ /**
3
+ * Create and configure the Fastify server
4
+ */
5
+ export declare function createServer(): FastifyInstance;
6
+ /**
7
+ * Start the proxy server
8
+ */
9
+ export declare function startServer(): Promise<FastifyInstance>;