greprag 0.1.0 → 0.1.1
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/dist/hook.d.ts +6 -10
- package/dist/hook.js +34 -153
- package/dist/hook.js.map +1 -1
- package/package.json +1 -1
package/dist/hook.d.ts
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
/** GrepRAG
|
|
2
|
+
/** GrepRAG Hook — thin HTTP pipe for Claude Code hooks.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* retrieve — UserPromptSubmit:
|
|
6
|
-
* store — Stop:
|
|
4
|
+
* Subcommands:
|
|
5
|
+
* retrieve — UserPromptSubmit: POST prompt to API, return additionalContext
|
|
6
|
+
* store — Stop: read transcript, POST raw content to API for server-side parsing
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* Stderr: diagnostics
|
|
11
|
-
*
|
|
12
|
-
* Env: GREPRAG_API_KEY (required), GREPRAG_API_URL (optional)
|
|
13
|
-
* MEMORY_HOOK_ENABLED=true to activate */
|
|
8
|
+
* All processing (agreement filter, transcript parsing, chunking) is server-side.
|
|
9
|
+
* This hook is a pure HTTP client — zero IP, zero local logic. */
|
|
14
10
|
export {};
|
package/dist/hook.js
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
-
/** GrepRAG
|
|
3
|
+
/** GrepRAG Hook — thin HTTP pipe for Claude Code hooks.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* retrieve — UserPromptSubmit:
|
|
7
|
-
* store — Stop:
|
|
5
|
+
* Subcommands:
|
|
6
|
+
* retrieve — UserPromptSubmit: POST prompt to API, return additionalContext
|
|
7
|
+
* store — Stop: read transcript, POST raw content to API for server-side parsing
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* Stderr: diagnostics
|
|
12
|
-
*
|
|
13
|
-
* Env: GREPRAG_API_KEY (required), GREPRAG_API_URL (optional)
|
|
14
|
-
* MEMORY_HOOK_ENABLED=true to activate */
|
|
9
|
+
* All processing (agreement filter, transcript parsing, chunking) is server-side.
|
|
10
|
+
* This hook is a pure HTTP client — zero IP, zero local logic. */
|
|
15
11
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
16
12
|
if (k2 === undefined) k2 = k;
|
|
17
13
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
@@ -58,99 +54,6 @@ function getConfig(cwd) {
|
|
|
58
54
|
enabled: process.env.MEMORY_HOOK_ENABLED === 'true',
|
|
59
55
|
};
|
|
60
56
|
}
|
|
61
|
-
// -- Agreement filter ------------------------------------------------------
|
|
62
|
-
const AGREEMENT_WORDS = new Set([
|
|
63
|
-
'yes', 'yeah', 'yep', 'yup', 'sure', 'ok', 'okay', 'k',
|
|
64
|
-
'proceed', 'thanks', 'thank you', 'ty', 'thx',
|
|
65
|
-
'agreed', 'correct', 'right', 'exactly', 'indeed',
|
|
66
|
-
'absolutely', 'definitely', 'perfect', 'great', 'nice', 'awesome',
|
|
67
|
-
'lgtm',
|
|
68
|
-
]);
|
|
69
|
-
const AGREEMENT_PHRASES = [
|
|
70
|
-
'go ahead', 'do it', 'sounds good', 'looks good', 'ship it',
|
|
71
|
-
];
|
|
72
|
-
function isShortAgreement(text) {
|
|
73
|
-
if (!text || text.trim().length === 0)
|
|
74
|
-
return true;
|
|
75
|
-
const normalized = text.trim().toLowerCase();
|
|
76
|
-
const wordCount = normalized.split(/\s+/).length;
|
|
77
|
-
if (wordCount > 8)
|
|
78
|
-
return false;
|
|
79
|
-
if (AGREEMENT_WORDS.has(normalized))
|
|
80
|
-
return true;
|
|
81
|
-
for (const phrase of AGREEMENT_PHRASES) {
|
|
82
|
-
if (normalized === phrase || normalized.startsWith(phrase + ' ') || normalized.startsWith(phrase + ',')) {
|
|
83
|
-
return true;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return false;
|
|
87
|
-
}
|
|
88
|
-
function extractText(content) {
|
|
89
|
-
if (typeof content === 'string')
|
|
90
|
-
return content.trim();
|
|
91
|
-
if (Array.isArray(content)) {
|
|
92
|
-
const parts = [];
|
|
93
|
-
for (const block of content) {
|
|
94
|
-
if (block && typeof block === 'object' && block.type === 'text') {
|
|
95
|
-
parts.push(String(block.text || ''));
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
return parts.join('\n').trim();
|
|
99
|
-
}
|
|
100
|
-
return '';
|
|
101
|
-
}
|
|
102
|
-
function parseLastTurn(transcriptPath) {
|
|
103
|
-
let data;
|
|
104
|
-
try {
|
|
105
|
-
data = fs.readFileSync(transcriptPath, 'utf-8');
|
|
106
|
-
}
|
|
107
|
-
catch {
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
let lastUserMessage = '';
|
|
111
|
-
const agentTextByRequestId = new Map();
|
|
112
|
-
let userMessageCount = 0;
|
|
113
|
-
const lines = data.split('\n');
|
|
114
|
-
for (const line of lines) {
|
|
115
|
-
const trimmed = line.trim();
|
|
116
|
-
if (!trimmed)
|
|
117
|
-
continue;
|
|
118
|
-
let entry;
|
|
119
|
-
try {
|
|
120
|
-
entry = JSON.parse(trimmed);
|
|
121
|
-
}
|
|
122
|
-
catch {
|
|
123
|
-
continue;
|
|
124
|
-
}
|
|
125
|
-
const message = entry.message || entry;
|
|
126
|
-
const role = String(message.role || entry.type || '');
|
|
127
|
-
const content = message.content;
|
|
128
|
-
const requestId = String(entry.requestId || '');
|
|
129
|
-
if (role === 'user') {
|
|
130
|
-
const text = extractText(content);
|
|
131
|
-
if (text && text.length > 5) {
|
|
132
|
-
if (!text.startsWith('<system') && !text.startsWith('{')) {
|
|
133
|
-
lastUserMessage = text;
|
|
134
|
-
userMessageCount++;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
if (role === 'assistant') {
|
|
139
|
-
const text = extractText(content);
|
|
140
|
-
if (text && text.trim().length > 20 && requestId) {
|
|
141
|
-
const prev = agentTextByRequestId.get(requestId) || '';
|
|
142
|
-
if (text.length > prev.length) {
|
|
143
|
-
agentTextByRequestId.set(requestId, text);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
if (!lastUserMessage)
|
|
149
|
-
return null;
|
|
150
|
-
const agentTexts = Array.from(agentTextByRequestId.values());
|
|
151
|
-
const agentProse = agentTexts.length > 0 ? agentTexts[agentTexts.length - 1] : '';
|
|
152
|
-
return { userMessage: lastUserMessage, agentProse, turnIndex: userMessageCount };
|
|
153
|
-
}
|
|
154
57
|
// -- Env loader ------------------------------------------------------------
|
|
155
58
|
function loadEnvFile(filePath) {
|
|
156
59
|
try {
|
|
@@ -185,17 +88,15 @@ function ensureEnv(cwd) {
|
|
|
185
88
|
loadEnvFile(path.join(cwd, '.env'));
|
|
186
89
|
}
|
|
187
90
|
// -- HTTP client -----------------------------------------------------------
|
|
188
|
-
async function apiCall(url, apiKey,
|
|
189
|
-
const
|
|
190
|
-
method,
|
|
91
|
+
async function apiCall(url, apiKey, body) {
|
|
92
|
+
const res = await fetch(url, {
|
|
93
|
+
method: 'POST',
|
|
191
94
|
headers: {
|
|
192
95
|
'Authorization': `Bearer ${apiKey}`,
|
|
193
96
|
'Content-Type': 'application/json',
|
|
194
97
|
},
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
opts.body = JSON.stringify(body);
|
|
198
|
-
const res = await fetch(url, opts);
|
|
98
|
+
body: JSON.stringify(body),
|
|
99
|
+
});
|
|
199
100
|
if (!res.ok) {
|
|
200
101
|
process.stderr.write(`[greprag-hook] API ${res.status}: ${await res.text()}\n`);
|
|
201
102
|
return null;
|
|
@@ -203,65 +104,45 @@ async function apiCall(url, apiKey, method, body) {
|
|
|
203
104
|
return res.json();
|
|
204
105
|
}
|
|
205
106
|
async function retrieve(input) {
|
|
206
|
-
const prompt = input.prompt || '';
|
|
207
107
|
const cwd = input.cwd || process.cwd();
|
|
208
108
|
const cfg = getConfig(cwd);
|
|
209
109
|
if (!cfg.enabled || !cfg.apiKey)
|
|
210
110
|
return;
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
const output = {
|
|
226
|
-
hookSpecificOutput: {
|
|
227
|
-
hookEventName: 'UserPromptSubmit',
|
|
228
|
-
additionalContext: formattedBlock,
|
|
229
|
-
},
|
|
230
|
-
};
|
|
231
|
-
process.stdout.write(JSON.stringify(output));
|
|
232
|
-
}
|
|
111
|
+
const result = await apiCall(`${cfg.apiUrl}/v1/memory/retrieve`, cfg.apiKey, {
|
|
112
|
+
query: input.prompt || '',
|
|
113
|
+
profileId: path.basename(cwd),
|
|
114
|
+
sessionId: input.session_id,
|
|
115
|
+
});
|
|
116
|
+
if (result?.ok) {
|
|
117
|
+
const r = result.result;
|
|
118
|
+
if (r?.totalWords > 0 && r?.formattedBlock) {
|
|
119
|
+
process.stdout.write(JSON.stringify({
|
|
120
|
+
hookSpecificOutput: {
|
|
121
|
+
hookEventName: 'UserPromptSubmit',
|
|
122
|
+
additionalContext: r.formattedBlock,
|
|
123
|
+
},
|
|
124
|
+
}));
|
|
233
125
|
}
|
|
234
126
|
}
|
|
235
|
-
catch (err) {
|
|
236
|
-
process.stderr.write(`[greprag-hook:retrieve] Error: ${err.message}\n`);
|
|
237
|
-
}
|
|
238
127
|
}
|
|
239
128
|
async function store(input) {
|
|
240
129
|
const transcriptPath = input.transcript_path || '';
|
|
241
130
|
const cwd = input.cwd || process.cwd();
|
|
242
|
-
const sessionId = input.session_id || '';
|
|
243
131
|
const cfg = getConfig(cwd);
|
|
244
132
|
if (!transcriptPath || !cfg.enabled || !cfg.apiKey)
|
|
245
133
|
return;
|
|
246
|
-
|
|
134
|
+
let transcriptContent;
|
|
247
135
|
try {
|
|
248
|
-
|
|
249
|
-
if (!parsed) {
|
|
250
|
-
process.stderr.write('[greprag-hook:store] No valid turn found in transcript\n');
|
|
251
|
-
return;
|
|
252
|
-
}
|
|
253
|
-
await apiCall(`${cfg.apiUrl}/v1/memory/store`, cfg.apiKey, 'POST', {
|
|
254
|
-
profileId: profile,
|
|
255
|
-
sessionId: sessionId || `hook-${Date.now()}`,
|
|
256
|
-
turnIndex: parsed.turnIndex,
|
|
257
|
-
userMessage: parsed.userMessage,
|
|
258
|
-
agentProse: parsed.agentProse,
|
|
259
|
-
});
|
|
260
|
-
process.stderr.write(`[greprag-hook:store] Stored turn ${parsed.turnIndex} (${profile})\n`);
|
|
136
|
+
transcriptContent = fs.readFileSync(transcriptPath, 'utf-8');
|
|
261
137
|
}
|
|
262
|
-
catch
|
|
263
|
-
|
|
138
|
+
catch {
|
|
139
|
+
return;
|
|
264
140
|
}
|
|
141
|
+
await apiCall(`${cfg.apiUrl}/v1/memory/store`, cfg.apiKey, {
|
|
142
|
+
profileId: path.basename(cwd),
|
|
143
|
+
sessionId: input.session_id || `hook-${Date.now()}`,
|
|
144
|
+
transcriptContent,
|
|
145
|
+
});
|
|
265
146
|
}
|
|
266
147
|
// -- Main ------------------------------------------------------------------
|
|
267
148
|
async function main() {
|
package/dist/hook.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hook.js","sourceRoot":"","sources":["../src/hook.ts"],"names":[],"mappings":";;AACA
|
|
1
|
+
{"version":3,"file":"hook.js","sourceRoot":"","sources":["../src/hook.ts"],"names":[],"mappings":"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"}
|