grov 0.1.2 → 0.2.3

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 +73 -88
  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 +431 -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 +120 -0
  35. package/dist/proxy/response-processor.d.ts +14 -0
  36. package/dist/proxy/response-processor.js +138 -0
  37. package/dist/proxy/server.d.ts +9 -0
  38. package/dist/proxy/server.js +904 -0
  39. package/package.json +8 -3
@@ -0,0 +1,138 @@
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 (tool_use actions)
28
+ const stepFiles = steps.flatMap(s => s.files);
29
+ // Also extract file paths mentioned in reasoning text (Claude's text responses)
30
+ const reasoningFiles = steps
31
+ .filter(s => s.reasoning)
32
+ .flatMap(s => {
33
+ // Match common code file extensions
34
+ const matches = s.reasoning?.match(/[\w\/.-]+\.(ts|js|tsx|jsx|py|go|rs|java|css|html|md|json|yaml|yml)/g) || [];
35
+ // Filter out obvious non-paths (urls, version numbers)
36
+ return matches.filter(m => !m.includes('://') && !m.match(/^\d+\.\d+/));
37
+ });
38
+ const filesTouched = [...new Set([...stepFiles, ...reasoningFiles])];
39
+ // Build basic reasoning trace from steps (fallback)
40
+ const basicReasoningTrace = steps
41
+ .filter(s => s.is_key_decision || s.action_type === 'edit' || s.action_type === 'write')
42
+ .slice(-10)
43
+ .map(s => {
44
+ if (s.action_type === 'edit' || s.action_type === 'write') {
45
+ return `${s.action_type}: ${s.files.join(', ')}`;
46
+ }
47
+ if (s.action_type === 'bash' && s.command) {
48
+ return `bash: ${s.command.substring(0, 50)}`;
49
+ }
50
+ return `${s.action_type}: ${s.files.length} files`;
51
+ });
52
+ // Try to use Anthropic Haiku for better reasoning & decisions extraction
53
+ let reasoningTrace = basicReasoningTrace;
54
+ let decisions = [];
55
+ let constraints = sessionState.constraints || [];
56
+ if (isReasoningExtractionAvailable() && steps.length > 0) {
57
+ try {
58
+ // Collect reasoning from steps
59
+ const stepsReasoning = steps
60
+ .map(s => s.reasoning)
61
+ .filter((r) => !!r && r.length > 10);
62
+ if (stepsReasoning.length > 0) {
63
+ const extracted = await extractReasoningAndDecisions(stepsReasoning, sessionState.original_goal || '');
64
+ if (extracted.reasoning_trace.length > 0) {
65
+ reasoningTrace = extracted.reasoning_trace;
66
+ }
67
+ if (extracted.decisions.length > 0) {
68
+ decisions = extracted.decisions;
69
+ }
70
+ }
71
+ }
72
+ catch {
73
+ // Fall back to basic extraction
74
+ }
75
+ }
76
+ else if (isLLMAvailable() && steps.length > 0) {
77
+ // Fallback to OpenAI-based extraction if Anthropic not available
78
+ try {
79
+ const pseudoSession = buildPseudoSession(sessionState, steps);
80
+ const extracted = await extractReasoning(pseudoSession);
81
+ if (extracted.decisions.length > 0) {
82
+ decisions = extracted.decisions;
83
+ }
84
+ if (extracted.constraints.length > 0) {
85
+ constraints = [...new Set([...constraints, ...extracted.constraints])];
86
+ }
87
+ }
88
+ catch {
89
+ // Fall back to basic extraction
90
+ }
91
+ }
92
+ return {
93
+ project_path: sessionState.project_path,
94
+ user: sessionState.user_id,
95
+ original_query: sessionState.original_goal || 'Unknown task',
96
+ goal: sessionState.original_goal,
97
+ reasoning_trace: reasoningTrace,
98
+ files_touched: filesTouched,
99
+ decisions,
100
+ constraints,
101
+ status: triggerReason === 'abandoned' ? 'abandoned' : 'complete',
102
+ trigger_reason: triggerReason,
103
+ };
104
+ }
105
+ /**
106
+ * Build pseudo ParsedSession for LLM extraction
107
+ */
108
+ function buildPseudoSession(sessionState, steps) {
109
+ return {
110
+ sessionId: sessionState.session_id,
111
+ projectPath: sessionState.project_path,
112
+ startTime: sessionState.start_time,
113
+ endTime: sessionState.last_update,
114
+ userMessages: [sessionState.original_goal || ''],
115
+ assistantMessages: steps.map(s => `[${s.action_type}] ${s.files.join(', ')}`),
116
+ toolCalls: steps.map(s => ({
117
+ name: s.action_type,
118
+ input: { files: s.files, command: s.command },
119
+ })),
120
+ filesRead: steps.filter(s => s.action_type === 'read').flatMap(s => s.files),
121
+ filesWritten: steps.filter(s => s.action_type === 'write' || s.action_type === 'edit').flatMap(s => s.files),
122
+ rawEntries: [],
123
+ };
124
+ }
125
+ /**
126
+ * Clean up session data after save
127
+ */
128
+ export function cleanupSession(sessionId) {
129
+ deleteStepsForSession(sessionId);
130
+ deleteSessionState(sessionId);
131
+ }
132
+ /**
133
+ * Save and cleanup session (for session end)
134
+ */
135
+ export async function saveAndCleanupSession(sessionId, triggerReason) {
136
+ await saveToTeamMemory(sessionId, triggerReason);
137
+ cleanupSession(sessionId);
138
+ }
@@ -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>;