@pimzino/sgrep 1.3.40 → 1.3.44
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/build/install/claude-code.d.ts +3 -8
- package/build/install/claude-code.d.ts.map +1 -1
- package/build/install/claude-code.js +78 -386
- package/build/install/claude-code.js.map +1 -1
- package/build/plugins/sgrep/.claude-plugin/plugin.json +1 -1
- package/build/plugins/sgrep/hooks/hooks.json +4 -47
- package/build/plugins/sgrep/hooks/sgrep_prompt_hint.js +23 -0
- package/build/plugins/sgrep/hooks/sgrep_watch_kill.js +169 -169
- package/build/plugins/sgrep/skills/sgrep/SKILL.md +19 -77
- package/package.json +1 -1
- package/build/plugins/sgrep/hooks/sgrep_context.js +0 -91
- package/build/plugins/sgrep/hooks/sgrep_enhance.js +0 -188
- package/build/plugins/sgrep/hooks/sgrep_project_summary.js +0 -236
- package/build/plugins/sgrep/hooks/sgrep_tool_reminder.js +0 -34
|
@@ -1,32 +1,20 @@
|
|
|
1
1
|
{
|
|
2
|
-
"description": "sgrep
|
|
2
|
+
"description": "sgrep hooks - prompt hint, index watcher, and watcher cleanup",
|
|
3
3
|
"hooks": {
|
|
4
|
-
"PreToolUse": [
|
|
5
|
-
{
|
|
6
|
-
"matcher": "Grep|Glob",
|
|
7
|
-
"hooks": [
|
|
8
|
-
{
|
|
9
|
-
"type": "command",
|
|
10
|
-
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/sgrep_tool_reminder.js",
|
|
11
|
-
"timeout": 5
|
|
12
|
-
}
|
|
13
|
-
]
|
|
14
|
-
}
|
|
15
|
-
],
|
|
16
4
|
"UserPromptSubmit": [
|
|
17
5
|
{
|
|
18
6
|
"hooks": [
|
|
19
7
|
{
|
|
20
8
|
"type": "command",
|
|
21
|
-
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/
|
|
22
|
-
"timeout":
|
|
9
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/sgrep_prompt_hint.js",
|
|
10
|
+
"timeout": 5
|
|
23
11
|
}
|
|
24
12
|
]
|
|
25
13
|
}
|
|
26
14
|
],
|
|
27
15
|
"SessionStart": [
|
|
28
16
|
{
|
|
29
|
-
"matcher": "startup|resume",
|
|
17
|
+
"matcher": "startup|resume|clear",
|
|
30
18
|
"hooks": [
|
|
31
19
|
{
|
|
32
20
|
"type": "command",
|
|
@@ -34,37 +22,6 @@
|
|
|
34
22
|
"timeout": 15
|
|
35
23
|
}
|
|
36
24
|
]
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
"matcher": "startup|compact",
|
|
40
|
-
"hooks": [
|
|
41
|
-
{
|
|
42
|
-
"type": "command",
|
|
43
|
-
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/sgrep_project_summary.js",
|
|
44
|
-
"timeout": 90
|
|
45
|
-
}
|
|
46
|
-
]
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
"matcher": "resume|clear",
|
|
50
|
-
"hooks": [
|
|
51
|
-
{
|
|
52
|
-
"type": "command",
|
|
53
|
-
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/sgrep_context.js",
|
|
54
|
-
"timeout": 5
|
|
55
|
-
}
|
|
56
|
-
]
|
|
57
|
-
}
|
|
58
|
-
],
|
|
59
|
-
"SubagentStart": [
|
|
60
|
-
{
|
|
61
|
-
"hooks": [
|
|
62
|
-
{
|
|
63
|
-
"type": "command",
|
|
64
|
-
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/sgrep_context.js",
|
|
65
|
-
"timeout": 5
|
|
66
|
-
}
|
|
67
|
-
]
|
|
68
25
|
}
|
|
69
26
|
],
|
|
70
27
|
"SessionEnd": [
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* sgrep_prompt_hint.js - UserPromptSubmit hook
|
|
5
|
+
*
|
|
6
|
+
* Appends a short reminder to every prompt so the model knows
|
|
7
|
+
* sgrep is available for codebase search and understanding.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
let data = "";
|
|
11
|
+
process.stdin.setEncoding("utf8");
|
|
12
|
+
process.stdin.on("data", (chunk) => (data += chunk));
|
|
13
|
+
process.stdin.on("end", () => {
|
|
14
|
+
console.log(
|
|
15
|
+
JSON.stringify({
|
|
16
|
+
hookSpecificOutput: {
|
|
17
|
+
hookEventName: "UserPromptSubmit",
|
|
18
|
+
additionalContext:
|
|
19
|
+
'Before making changes, gather context: use sgrep "query" for codebase search/understanding.',
|
|
20
|
+
},
|
|
21
|
+
})
|
|
22
|
+
);
|
|
23
|
+
});
|
|
@@ -1,169 +1,169 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const fs = require("fs");
|
|
4
|
-
const path = require("path");
|
|
5
|
-
const os = require("os");
|
|
6
|
-
const { execSync } = require("child_process");
|
|
7
|
-
|
|
8
|
-
const DEBUG_ENABLED = process.env.SGREP_DEBUG === "1" || process.env.SGREP_DEBUG === "true";
|
|
9
|
-
const DEBUG_LOG_FILE = process.env.SGREP_WATCH_KILL_LOG || path.join(os.tmpdir(), "sgrep-watch-kill.log");
|
|
10
|
-
|
|
11
|
-
function debugLog(message) {
|
|
12
|
-
if (!DEBUG_ENABLED) return;
|
|
13
|
-
try {
|
|
14
|
-
const dir = path.dirname(DEBUG_LOG_FILE);
|
|
15
|
-
if (!fs.existsSync(dir)) {
|
|
16
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
17
|
-
}
|
|
18
|
-
const stamp = new Date().toISOString();
|
|
19
|
-
fs.appendFileSync(DEBUG_LOG_FILE, `[${stamp}] ${message}\n`);
|
|
20
|
-
} catch (e) {
|
|
21
|
-
// Ignore errors
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function debugLogSection(title, content) {
|
|
26
|
-
debugLog(`\n========== ${title} ==========`);
|
|
27
|
-
debugLog(content);
|
|
28
|
-
debugLog(`========== END ${title} ==========\n`);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Kill a process by PID, with platform-specific handling
|
|
33
|
-
*/
|
|
34
|
-
function killProcess(pid) {
|
|
35
|
-
debugLog(`Attempting to kill process with PID: ${pid}`);
|
|
36
|
-
|
|
37
|
-
// First try Node.js process.kill
|
|
38
|
-
try {
|
|
39
|
-
process.kill(pid, "SIGTERM");
|
|
40
|
-
debugLog(`SUCCESS: Sent SIGTERM to process ${pid}`);
|
|
41
|
-
return true;
|
|
42
|
-
} catch (e) {
|
|
43
|
-
if (e.code === "ESRCH") {
|
|
44
|
-
debugLog(`INFO: Process ${pid} already exited`);
|
|
45
|
-
return true; // Consider success if already gone
|
|
46
|
-
}
|
|
47
|
-
debugLog(`process.kill failed: ${e.message} (code: ${e.code})`);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// On Windows, try taskkill as fallback
|
|
51
|
-
if (process.platform === "win32") {
|
|
52
|
-
try {
|
|
53
|
-
execSync(`taskkill /PID ${pid} /F`, {
|
|
54
|
-
encoding: "utf8",
|
|
55
|
-
timeout: 5000,
|
|
56
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
57
|
-
});
|
|
58
|
-
debugLog(`SUCCESS: Killed process ${pid} using taskkill`);
|
|
59
|
-
return true;
|
|
60
|
-
} catch (e) {
|
|
61
|
-
debugLog(`taskkill failed: ${e.message}`);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return false;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function readHookInput() {
|
|
69
|
-
return new Promise((resolve) => {
|
|
70
|
-
let data = "";
|
|
71
|
-
process.stdin.setEncoding("utf8");
|
|
72
|
-
process.stdin.on("data", (chunk) => {
|
|
73
|
-
data += chunk;
|
|
74
|
-
});
|
|
75
|
-
process.stdin.on("end", () => {
|
|
76
|
-
if (!data.trim()) {
|
|
77
|
-
debugLog("No input data received from stdin");
|
|
78
|
-
resolve(null);
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
try {
|
|
82
|
-
const parsed = JSON.parse(data);
|
|
83
|
-
debugLogSection("RAW HOOK INPUT", JSON.stringify(parsed, null, 2));
|
|
84
|
-
resolve(parsed);
|
|
85
|
-
} catch (e) {
|
|
86
|
-
debugLog(`Failed to decode JSON: ${e.message}`);
|
|
87
|
-
debugLog(`Raw data: ${data}`);
|
|
88
|
-
resolve(null);
|
|
89
|
-
}
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
async function main() {
|
|
95
|
-
debugLog("\n\n====================================================");
|
|
96
|
-
debugLog("SGREP WATCH KILL HOOK TRIGGERED - SessionEnd");
|
|
97
|
-
debugLog("====================================================");
|
|
98
|
-
|
|
99
|
-
const payload = await readHookInput();
|
|
100
|
-
if (!payload) {
|
|
101
|
-
debugLog("ERROR: No payload received - exiting with error");
|
|
102
|
-
process.exit(1);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Log all payload fields for debugging
|
|
106
|
-
debugLog(`Hook Event: ${payload.hook_event_name || 'unknown'}`);
|
|
107
|
-
debugLog(`Session ID: ${payload.session_id || 'unknown'}`);
|
|
108
|
-
debugLog(`Reason: ${payload.reason || 'unknown'} (clear/logout/prompt_input_exit/other)`);
|
|
109
|
-
debugLog(`CWD: ${payload.cwd || 'unknown'}`);
|
|
110
|
-
debugLog(`Permission Mode: ${payload.permission_mode || 'unknown'}`);
|
|
111
|
-
debugLog(`Transcript Path: ${payload.transcript_path || 'unknown'}`);
|
|
112
|
-
|
|
113
|
-
const sessionId = payload.session_id || "default";
|
|
114
|
-
const pidFile = path.join(os.tmpdir(), `sgrep-watch-pid-${sessionId}.txt`);
|
|
115
|
-
|
|
116
|
-
debugLog(`Looking for PID file: ${pidFile}`);
|
|
117
|
-
|
|
118
|
-
if (!fs.existsSync(pidFile)) {
|
|
119
|
-
debugLog(`SKIP: PID file not found - sgrep watch may not have been started`);
|
|
120
|
-
process.exit(0); // Not an error - process may not have been started
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
let killed = false;
|
|
124
|
-
|
|
125
|
-
try {
|
|
126
|
-
const pidContent = fs.readFileSync(pidFile, "utf8").trim();
|
|
127
|
-
debugLog(`PID file content: "${pidContent}"`);
|
|
128
|
-
|
|
129
|
-
const pid = parseInt(pidContent, 10);
|
|
130
|
-
debugLog(`Parsed PID: ${pid}`);
|
|
131
|
-
|
|
132
|
-
if (!isNaN(pid) && pid > 0) {
|
|
133
|
-
killed = killProcess(pid);
|
|
134
|
-
} else {
|
|
135
|
-
debugLog(`WARNING: Invalid PID (${pid}), cannot kill process`);
|
|
136
|
-
}
|
|
137
|
-
} catch (e) {
|
|
138
|
-
debugLog(`ERROR reading PID file: ${e.message}`);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// Clean up PID file (sgrep watch should also clean it up on exit, but be safe)
|
|
142
|
-
try {
|
|
143
|
-
if (fs.existsSync(pidFile)) {
|
|
144
|
-
fs.unlinkSync(pidFile);
|
|
145
|
-
debugLog(`SUCCESS: Removed PID file: ${pidFile}`);
|
|
146
|
-
}
|
|
147
|
-
} catch (cleanupErr) {
|
|
148
|
-
debugLog(`Failed to clean up PID file: ${cleanupErr.message}`);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Clean up ready marker file
|
|
152
|
-
const readyFile = path.join(os.tmpdir(), `sgrep-watch-ready-${sessionId}.txt`);
|
|
153
|
-
try {
|
|
154
|
-
if (fs.existsSync(readyFile)) {
|
|
155
|
-
fs.unlinkSync(readyFile);
|
|
156
|
-
debugLog(`SUCCESS: Removed ready file: ${readyFile}`);
|
|
157
|
-
}
|
|
158
|
-
} catch (cleanupErr) {
|
|
159
|
-
debugLog(`Failed to clean up ready file: ${cleanupErr.message}`);
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
debugLog(`Kill operation completed. Success: ${killed}`);
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
debugLog("====================================================\n");
|
|
166
|
-
process.exit(0);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
main();
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const os = require("os");
|
|
6
|
+
const { execSync } = require("child_process");
|
|
7
|
+
|
|
8
|
+
const DEBUG_ENABLED = process.env.SGREP_DEBUG === "1" || process.env.SGREP_DEBUG === "true";
|
|
9
|
+
const DEBUG_LOG_FILE = process.env.SGREP_WATCH_KILL_LOG || path.join(os.tmpdir(), "sgrep-watch-kill.log");
|
|
10
|
+
|
|
11
|
+
function debugLog(message) {
|
|
12
|
+
if (!DEBUG_ENABLED) return;
|
|
13
|
+
try {
|
|
14
|
+
const dir = path.dirname(DEBUG_LOG_FILE);
|
|
15
|
+
if (!fs.existsSync(dir)) {
|
|
16
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
17
|
+
}
|
|
18
|
+
const stamp = new Date().toISOString();
|
|
19
|
+
fs.appendFileSync(DEBUG_LOG_FILE, `[${stamp}] ${message}\n`);
|
|
20
|
+
} catch (e) {
|
|
21
|
+
// Ignore errors
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function debugLogSection(title, content) {
|
|
26
|
+
debugLog(`\n========== ${title} ==========`);
|
|
27
|
+
debugLog(content);
|
|
28
|
+
debugLog(`========== END ${title} ==========\n`);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Kill a process by PID, with platform-specific handling
|
|
33
|
+
*/
|
|
34
|
+
function killProcess(pid) {
|
|
35
|
+
debugLog(`Attempting to kill process with PID: ${pid}`);
|
|
36
|
+
|
|
37
|
+
// First try Node.js process.kill
|
|
38
|
+
try {
|
|
39
|
+
process.kill(pid, "SIGTERM");
|
|
40
|
+
debugLog(`SUCCESS: Sent SIGTERM to process ${pid}`);
|
|
41
|
+
return true;
|
|
42
|
+
} catch (e) {
|
|
43
|
+
if (e.code === "ESRCH") {
|
|
44
|
+
debugLog(`INFO: Process ${pid} already exited`);
|
|
45
|
+
return true; // Consider success if already gone
|
|
46
|
+
}
|
|
47
|
+
debugLog(`process.kill failed: ${e.message} (code: ${e.code})`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// On Windows, try taskkill as fallback
|
|
51
|
+
if (process.platform === "win32") {
|
|
52
|
+
try {
|
|
53
|
+
execSync(`taskkill /PID ${pid} /F`, {
|
|
54
|
+
encoding: "utf8",
|
|
55
|
+
timeout: 5000,
|
|
56
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
57
|
+
});
|
|
58
|
+
debugLog(`SUCCESS: Killed process ${pid} using taskkill`);
|
|
59
|
+
return true;
|
|
60
|
+
} catch (e) {
|
|
61
|
+
debugLog(`taskkill failed: ${e.message}`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function readHookInput() {
|
|
69
|
+
return new Promise((resolve) => {
|
|
70
|
+
let data = "";
|
|
71
|
+
process.stdin.setEncoding("utf8");
|
|
72
|
+
process.stdin.on("data", (chunk) => {
|
|
73
|
+
data += chunk;
|
|
74
|
+
});
|
|
75
|
+
process.stdin.on("end", () => {
|
|
76
|
+
if (!data.trim()) {
|
|
77
|
+
debugLog("No input data received from stdin");
|
|
78
|
+
resolve(null);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
const parsed = JSON.parse(data);
|
|
83
|
+
debugLogSection("RAW HOOK INPUT", JSON.stringify(parsed, null, 2));
|
|
84
|
+
resolve(parsed);
|
|
85
|
+
} catch (e) {
|
|
86
|
+
debugLog(`Failed to decode JSON: ${e.message}`);
|
|
87
|
+
debugLog(`Raw data: ${data}`);
|
|
88
|
+
resolve(null);
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function main() {
|
|
95
|
+
debugLog("\n\n====================================================");
|
|
96
|
+
debugLog("SGREP WATCH KILL HOOK TRIGGERED - SessionEnd");
|
|
97
|
+
debugLog("====================================================");
|
|
98
|
+
|
|
99
|
+
const payload = await readHookInput();
|
|
100
|
+
if (!payload) {
|
|
101
|
+
debugLog("ERROR: No payload received - exiting with error");
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Log all payload fields for debugging
|
|
106
|
+
debugLog(`Hook Event: ${payload.hook_event_name || 'unknown'}`);
|
|
107
|
+
debugLog(`Session ID: ${payload.session_id || 'unknown'}`);
|
|
108
|
+
debugLog(`Reason: ${payload.reason || 'unknown'} (clear/logout/prompt_input_exit/other)`);
|
|
109
|
+
debugLog(`CWD: ${payload.cwd || 'unknown'}`);
|
|
110
|
+
debugLog(`Permission Mode: ${payload.permission_mode || 'unknown'}`);
|
|
111
|
+
debugLog(`Transcript Path: ${payload.transcript_path || 'unknown'}`);
|
|
112
|
+
|
|
113
|
+
const sessionId = payload.session_id || "default";
|
|
114
|
+
const pidFile = path.join(os.tmpdir(), `sgrep-watch-pid-${sessionId}.txt`);
|
|
115
|
+
|
|
116
|
+
debugLog(`Looking for PID file: ${pidFile}`);
|
|
117
|
+
|
|
118
|
+
if (!fs.existsSync(pidFile)) {
|
|
119
|
+
debugLog(`SKIP: PID file not found - sgrep watch may not have been started`);
|
|
120
|
+
process.exit(0); // Not an error - process may not have been started
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
let killed = false;
|
|
124
|
+
|
|
125
|
+
try {
|
|
126
|
+
const pidContent = fs.readFileSync(pidFile, "utf8").trim();
|
|
127
|
+
debugLog(`PID file content: "${pidContent}"`);
|
|
128
|
+
|
|
129
|
+
const pid = parseInt(pidContent, 10);
|
|
130
|
+
debugLog(`Parsed PID: ${pid}`);
|
|
131
|
+
|
|
132
|
+
if (!isNaN(pid) && pid > 0) {
|
|
133
|
+
killed = killProcess(pid);
|
|
134
|
+
} else {
|
|
135
|
+
debugLog(`WARNING: Invalid PID (${pid}), cannot kill process`);
|
|
136
|
+
}
|
|
137
|
+
} catch (e) {
|
|
138
|
+
debugLog(`ERROR reading PID file: ${e.message}`);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Clean up PID file (sgrep watch should also clean it up on exit, but be safe)
|
|
142
|
+
try {
|
|
143
|
+
if (fs.existsSync(pidFile)) {
|
|
144
|
+
fs.unlinkSync(pidFile);
|
|
145
|
+
debugLog(`SUCCESS: Removed PID file: ${pidFile}`);
|
|
146
|
+
}
|
|
147
|
+
} catch (cleanupErr) {
|
|
148
|
+
debugLog(`Failed to clean up PID file: ${cleanupErr.message}`);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
// Clean up ready marker file
|
|
152
|
+
const readyFile = path.join(os.tmpdir(), `sgrep-watch-ready-${sessionId}.txt`);
|
|
153
|
+
try {
|
|
154
|
+
if (fs.existsSync(readyFile)) {
|
|
155
|
+
fs.unlinkSync(readyFile);
|
|
156
|
+
debugLog(`SUCCESS: Removed ready file: ${readyFile}`);
|
|
157
|
+
}
|
|
158
|
+
} catch (cleanupErr) {
|
|
159
|
+
debugLog(`Failed to clean up ready file: ${cleanupErr.message}`);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
debugLog(`Kill operation completed. Success: ${killed}`);
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
debugLog("====================================================\n");
|
|
166
|
+
process.exit(0);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
main();
|
|
@@ -1,90 +1,32 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sgrep
|
|
3
|
-
description: "Semantic
|
|
3
|
+
description: "Semantic codebase search and understanding. Use when exploring code, finding where something is implemented, understanding architecture or patterns, locating how a feature works, or answering any question about this repository. Invoke BEFORE reading or editing files to gather context. Replaces multiple grep/glob calls with a single semantic query."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
##
|
|
6
|
+
## How to Use
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
## Execution Method
|
|
11
|
-
|
|
12
|
-
Execute sgrep commands via Bash tool. Always run from project root directory.
|
|
8
|
+
Run via Bash from the project root:
|
|
13
9
|
|
|
14
10
|
```bash
|
|
15
|
-
# Ask
|
|
16
|
-
sgrep "how does authentication work
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
11
|
+
# Ask about the codebase (default - returns explanations with file references)
|
|
12
|
+
sgrep "how does authentication work?"
|
|
13
|
+
sgrep "where are API routes defined?"
|
|
14
|
+
sgrep "what does the build pipeline do?"
|
|
15
|
+
|
|
16
|
+
# Search for code snippets by meaning
|
|
17
|
+
sgrep search "error handling middleware"
|
|
18
|
+
sgrep search "database connection setup"
|
|
20
19
|
```
|
|
21
20
|
|
|
22
|
-
##
|
|
23
|
-
|
|
24
|
-
<use-sgrep>
|
|
25
|
-
- Question targets code that EXISTS in this repository
|
|
26
|
-
- Need to understand this project's architecture or patterns
|
|
27
|
-
- Exploring this codebase before making changes
|
|
28
|
-
- Finding implementations within this repository
|
|
29
|
-
</use-sgrep>
|
|
30
|
-
|
|
31
|
-
<do-not-use-sgrep>
|
|
32
|
-
- External API documentation (Microsoft Graph, AWS SDK, etc.)
|
|
33
|
-
- Library/framework docs (React hooks, Express middleware, etc.)
|
|
34
|
-
- General programming concepts (dependency injection, OAuth, etc.)
|
|
35
|
-
- Third-party CLI usage (kubectl, az, gh, etc.)
|
|
36
|
-
- Best practices not specific to this codebase
|
|
37
|
-
- Any knowledge that exists outside this repository
|
|
38
|
-
</do-not-use-sgrep>
|
|
39
|
-
|
|
40
|
-
<decision-rule>
|
|
41
|
-
IF answer requires knowledge from outside this repository THEN use WebSearch/WebFetch
|
|
42
|
-
IF answer is in the code files of this project THEN use sgrep
|
|
43
|
-
</decision-rule>
|
|
44
|
-
|
|
45
|
-
## Commands
|
|
21
|
+
## When to Use
|
|
46
22
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
sgrep "what patterns are used for API endpoints?"
|
|
52
|
-
sgrep "where is user validation handled?"
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### Search (raw code snippets only)
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
sgrep search "authentication middleware"
|
|
59
|
-
sgrep search "database connection handling"
|
|
60
|
-
```
|
|
23
|
+
- Before editing code, to understand what exists and where
|
|
24
|
+
- When asked to find, locate, or explain any code in this repo
|
|
25
|
+
- To understand architecture, patterns, or how features connect
|
|
26
|
+
- When exploring unfamiliar parts of the codebase
|
|
61
27
|
|
|
62
28
|
## Constraints
|
|
63
29
|
|
|
64
|
-
-
|
|
65
|
-
-
|
|
66
|
-
- For
|
|
67
|
-
|
|
68
|
-
## Examples
|
|
69
|
-
|
|
70
|
-
### Correct Usage
|
|
71
|
-
|
|
72
|
-
```bash
|
|
73
|
-
sgrep "how does this project handle routing?" # Local codebase question
|
|
74
|
-
sgrep "where is the config loaded?" # Local implementation
|
|
75
|
-
sgrep search "HashRouter configuration" # Local code search
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
### Incorrect Usage (use WebSearch instead)
|
|
79
|
-
|
|
80
|
-
```bash
|
|
81
|
-
# WRONG - these require external knowledge
|
|
82
|
-
sgrep "How do Microsoft Graph cmdlets work?" # External API
|
|
83
|
-
sgrep "What are React best practices?" # General knowledge
|
|
84
|
-
sgrep "How to use kubectl?" # External CLI docs
|
|
85
|
-
sgrep "What is OAuth 2.0?" # General concept
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
## Keywords
|
|
89
|
-
|
|
90
|
-
codebase questions, local code, repository code, project architecture, code understanding, semantic search, find implementations
|
|
30
|
+
- Run from project root (never cd into subdirectories first)
|
|
31
|
+
- For exact text/symbol matching, use Grep instead
|
|
32
|
+
- For external docs or general knowledge, use WebSearch instead
|
package/package.json
CHANGED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* sgrep_context.js - Injects sgrep awareness into Claude Code sessions and subagents
|
|
5
|
-
*
|
|
6
|
-
* This hook runs on:
|
|
7
|
-
* - SessionStart (startup, resume, clear, compact) - main session context
|
|
8
|
-
* - SubagentStart - subagent (Task tool) context
|
|
9
|
-
*
|
|
10
|
-
* Ensures Claude is always aware of the sgrep semantic search tool.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
const fs = require("fs");
|
|
14
|
-
const path = require("path");
|
|
15
|
-
const os = require("os");
|
|
16
|
-
|
|
17
|
-
const DEBUG_ENABLED = process.env.SGREP_DEBUG === "1" || process.env.SGREP_DEBUG === "true";
|
|
18
|
-
const DEBUG_LOG_FILE = process.env.SGREP_CONTEXT_LOG || path.join(os.tmpdir(), "sgrep-context.log");
|
|
19
|
-
|
|
20
|
-
function debugLog(message) {
|
|
21
|
-
if (!DEBUG_ENABLED) return;
|
|
22
|
-
try {
|
|
23
|
-
const dir = path.dirname(DEBUG_LOG_FILE);
|
|
24
|
-
if (!fs.existsSync(dir)) {
|
|
25
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
26
|
-
}
|
|
27
|
-
const stamp = new Date().toISOString();
|
|
28
|
-
fs.appendFileSync(DEBUG_LOG_FILE, `[${stamp}] ${message}\n`);
|
|
29
|
-
} catch (e) {
|
|
30
|
-
// Ignore errors
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function readHookInput() {
|
|
35
|
-
return new Promise((resolve) => {
|
|
36
|
-
let data = "";
|
|
37
|
-
process.stdin.setEncoding("utf8");
|
|
38
|
-
process.stdin.on("data", (chunk) => {
|
|
39
|
-
data += chunk;
|
|
40
|
-
});
|
|
41
|
-
process.stdin.on("end", () => {
|
|
42
|
-
if (!data.trim()) {
|
|
43
|
-
debugLog("No input data received from stdin");
|
|
44
|
-
resolve(null);
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
try {
|
|
48
|
-
const parsed = JSON.parse(data);
|
|
49
|
-
debugLog(`Received hook input: ${JSON.stringify(parsed, null, 2)}`);
|
|
50
|
-
resolve(parsed);
|
|
51
|
-
} catch (e) {
|
|
52
|
-
debugLog(`Failed to decode JSON: ${e.message}`);
|
|
53
|
-
resolve(null);
|
|
54
|
-
}
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
async function main() {
|
|
60
|
-
debugLog("\n====================================================");
|
|
61
|
-
debugLog("SGREP CONTEXT HOOK TRIGGERED");
|
|
62
|
-
debugLog("====================================================");
|
|
63
|
-
|
|
64
|
-
const payload = await readHookInput();
|
|
65
|
-
if (!payload) {
|
|
66
|
-
debugLog("ERROR: No payload received - exiting with error");
|
|
67
|
-
process.exit(1);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const eventName = payload.hook_event_name || "unknown";
|
|
71
|
-
debugLog(`Hook event: ${eventName}`);
|
|
72
|
-
|
|
73
|
-
// Log event-specific info
|
|
74
|
-
if (eventName === "SessionStart") {
|
|
75
|
-
debugLog(`Session source: ${payload.source || "unknown"}`);
|
|
76
|
-
} else if (eventName === "SubagentStart") {
|
|
77
|
-
debugLog(`Subagent ID: ${payload.agent_id || "unknown"}`);
|
|
78
|
-
debugLog(`Subagent type: ${payload.agent_type || "unknown"}`);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Same context message for both session and subagents
|
|
82
|
-
// Make it directive - tell Claude to USE sgrep, not just that it exists
|
|
83
|
-
const sgrepInstruction = `CODEBASE EXPLORATION: Before using Grep, Glob, or Read to explore code, run \`sgrep "your query"\` first via Bash. sgrep uses semantic search to find code by meaning (e.g., \`sgrep "authentication logic"\`, \`sgrep "database queries"\`). For questions about the codebase, use \`sgrep ask "how does X work?"\`. This is faster and more accurate than pattern matching.`;
|
|
84
|
-
|
|
85
|
-
debugLog(`Outputting context: ${sgrepInstruction}`);
|
|
86
|
-
console.log(sgrepInstruction);
|
|
87
|
-
debugLog("====================================================\n");
|
|
88
|
-
process.exit(0);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
main();
|