@pimzino/sgrep 1.3.0
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 +413 -0
- package/build/.claude-plugin/marketplace.json +20 -0
- package/build/commands/ask.d.ts +11 -0
- package/build/commands/ask.d.ts.map +1 -0
- package/build/commands/ask.js +65 -0
- package/build/commands/ask.js.map +1 -0
- package/build/commands/enhance.d.ts +16 -0
- package/build/commands/enhance.d.ts.map +1 -0
- package/build/commands/enhance.js +107 -0
- package/build/commands/enhance.js.map +1 -0
- package/build/commands/search.d.ts +12 -0
- package/build/commands/search.d.ts.map +1 -0
- package/build/commands/search.js +65 -0
- package/build/commands/search.js.map +1 -0
- package/build/commands/watch.d.ts +13 -0
- package/build/commands/watch.d.ts.map +1 -0
- package/build/commands/watch.js +179 -0
- package/build/commands/watch.js.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +124 -0
- package/build/index.js.map +1 -0
- package/build/install/claude-code.d.ts +10 -0
- package/build/install/claude-code.d.ts.map +1 -0
- package/build/install/claude-code.js +255 -0
- package/build/install/claude-code.js.map +1 -0
- package/build/install/codex.d.ts +4 -0
- package/build/install/codex.d.ts.map +1 -0
- package/build/install/codex.js +123 -0
- package/build/install/codex.js.map +1 -0
- package/build/install/cursor.d.ts +4 -0
- package/build/install/cursor.d.ts.map +1 -0
- package/build/install/cursor.js +91 -0
- package/build/install/cursor.js.map +1 -0
- package/build/install/droid.d.ts +4 -0
- package/build/install/droid.d.ts.map +1 -0
- package/build/install/droid.js +226 -0
- package/build/install/droid.js.map +1 -0
- package/build/install/opencode.d.ts +4 -0
- package/build/install/opencode.d.ts.map +1 -0
- package/build/install/opencode.js +276 -0
- package/build/install/opencode.js.map +1 -0
- package/build/plugins/sgrep/.claude-plugin/plugin.json +9 -0
- package/build/plugins/sgrep/hooks/hooks.json +39 -0
- package/build/plugins/sgrep/hooks/sgrep_enhance.js +160 -0
- package/build/plugins/sgrep/hooks/sgrep_watch.js +240 -0
- package/build/plugins/sgrep/hooks/sgrep_watch_kill.js +158 -0
- package/build/plugins/sgrep/skills/sgrep/SKILL.md +97 -0
- package/build/utils/config.d.ts +26 -0
- package/build/utils/config.d.ts.map +1 -0
- package/build/utils/config.js +106 -0
- package/build/utils/config.js.map +1 -0
- package/build/utils/context-manager.d.ts +33 -0
- package/build/utils/context-manager.d.ts.map +1 -0
- package/build/utils/context-manager.js +244 -0
- package/build/utils/context-manager.js.map +1 -0
- package/build/utils/context.d.ts +25 -0
- package/build/utils/context.d.ts.map +1 -0
- package/build/utils/context.js +132 -0
- package/build/utils/context.js.map +1 -0
- package/build/utils/file-walker.d.ts +20 -0
- package/build/utils/file-walker.d.ts.map +1 -0
- package/build/utils/file-walker.js +239 -0
- package/build/utils/file-walker.js.map +1 -0
- package/build/utils/output.d.ts +38 -0
- package/build/utils/output.d.ts.map +1 -0
- package/build/utils/output.js +150 -0
- package/build/utils/output.js.map +1 -0
- package/build/utils/prompt-parser.d.ts +12 -0
- package/build/utils/prompt-parser.d.ts.map +1 -0
- package/build/utils/prompt-parser.js +54 -0
- package/build/utils/prompt-parser.js.map +1 -0
- package/package.json +59 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { Command } from "commander";
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
const PLUGIN_ROOT = process.env.DROID_PLUGIN_ROOT ||
|
|
10
|
+
path.resolve(__dirname, "../plugins/sgrep");
|
|
11
|
+
const PLUGIN_HOOKS_DIR = path.join(PLUGIN_ROOT, "hooks");
|
|
12
|
+
const PLUGIN_SKILL_PATH = path.join(PLUGIN_ROOT, "skills", "sgrep", "SKILL.md");
|
|
13
|
+
function resolveDroidRoot() {
|
|
14
|
+
const root = path.join(os.homedir(), ".factory");
|
|
15
|
+
if (!fs.existsSync(root)) {
|
|
16
|
+
throw new Error(`Factory Droid directory not found at ${root}. Start Factory Droid once to initialize it, then re-run the install.`);
|
|
17
|
+
}
|
|
18
|
+
return root;
|
|
19
|
+
}
|
|
20
|
+
function writeFileIfChanged(filePath, content) {
|
|
21
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
22
|
+
const already = fs.existsSync(filePath)
|
|
23
|
+
? fs.readFileSync(filePath, "utf-8")
|
|
24
|
+
: undefined;
|
|
25
|
+
if (already !== content) {
|
|
26
|
+
fs.writeFileSync(filePath, content);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function readPluginAsset(assetPath) {
|
|
30
|
+
if (!fs.existsSync(assetPath)) {
|
|
31
|
+
throw new Error(`Plugin asset missing: ${assetPath}`);
|
|
32
|
+
}
|
|
33
|
+
return fs.readFileSync(assetPath, "utf-8");
|
|
34
|
+
}
|
|
35
|
+
function parseJsonWithComments(content) {
|
|
36
|
+
const stripped = content
|
|
37
|
+
.split("\n")
|
|
38
|
+
.map((line) => line.replace(/^\s*\/\/.*$/, ""))
|
|
39
|
+
.join("\n");
|
|
40
|
+
const parsed = JSON.parse(stripped);
|
|
41
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
42
|
+
throw new Error("Factory Droid settings must be a JSON object");
|
|
43
|
+
}
|
|
44
|
+
return parsed;
|
|
45
|
+
}
|
|
46
|
+
function loadSettings(settingsPath) {
|
|
47
|
+
if (!fs.existsSync(settingsPath)) {
|
|
48
|
+
return {};
|
|
49
|
+
}
|
|
50
|
+
const raw = fs.readFileSync(settingsPath, "utf-8");
|
|
51
|
+
const parsed = parseJsonWithComments(raw);
|
|
52
|
+
return parsed;
|
|
53
|
+
}
|
|
54
|
+
function saveSettings(settingsPath, settings) {
|
|
55
|
+
fs.mkdirSync(path.dirname(settingsPath), { recursive: true });
|
|
56
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
57
|
+
}
|
|
58
|
+
function isHooksConfig(value) {
|
|
59
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
return Object.values(value).every((entry) => Array.isArray(entry));
|
|
63
|
+
}
|
|
64
|
+
function mergeHooks(existingHooks, newHooks) {
|
|
65
|
+
const merged = existingHooks
|
|
66
|
+
? JSON.parse(JSON.stringify(existingHooks))
|
|
67
|
+
: {};
|
|
68
|
+
for (const [event, entries] of Object.entries(newHooks)) {
|
|
69
|
+
const current = Array.isArray(merged[event])
|
|
70
|
+
? merged[event]
|
|
71
|
+
: [];
|
|
72
|
+
for (const entry of entries) {
|
|
73
|
+
const command = entry?.hooks?.[0]?.command;
|
|
74
|
+
const matcher = entry?.matcher ?? null;
|
|
75
|
+
const duplicate = current.some((item) => (item?.matcher ?? null) === matcher &&
|
|
76
|
+
item?.hooks?.[0]?.command === command &&
|
|
77
|
+
item?.hooks?.[0]?.type === entry?.hooks?.[0]?.type);
|
|
78
|
+
if (!duplicate) {
|
|
79
|
+
current.push(entry);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
merged[event] = current;
|
|
83
|
+
}
|
|
84
|
+
return merged;
|
|
85
|
+
}
|
|
86
|
+
async function installPlugin() {
|
|
87
|
+
console.log(chalk.cyan("Installing sgrep plugin for Factory Droid..."));
|
|
88
|
+
console.log("");
|
|
89
|
+
try {
|
|
90
|
+
const root = resolveDroidRoot();
|
|
91
|
+
const hooksDir = path.join(root, "hooks", "sgrep");
|
|
92
|
+
const skillsDir = path.join(root, "skills", "sgrep");
|
|
93
|
+
const settingsPath = path.join(root, "settings.json");
|
|
94
|
+
const watchHook = readPluginAsset(path.join(PLUGIN_HOOKS_DIR, "sgrep_watch.js"));
|
|
95
|
+
const killHook = readPluginAsset(path.join(PLUGIN_HOOKS_DIR, "sgrep_watch_kill.js"));
|
|
96
|
+
const enhanceHook = readPluginAsset(path.join(PLUGIN_HOOKS_DIR, "sgrep_enhance.js"));
|
|
97
|
+
const skillContent = readPluginAsset(PLUGIN_SKILL_PATH);
|
|
98
|
+
const watchJs = path.join(hooksDir, "sgrep_watch.js");
|
|
99
|
+
const killJs = path.join(hooksDir, "sgrep_watch_kill.js");
|
|
100
|
+
const enhanceJs = path.join(hooksDir, "sgrep_enhance.js");
|
|
101
|
+
writeFileIfChanged(watchJs, watchHook);
|
|
102
|
+
writeFileIfChanged(killJs, killHook);
|
|
103
|
+
writeFileIfChanged(enhanceJs, enhanceHook);
|
|
104
|
+
const hookConfig = {
|
|
105
|
+
UserPromptSubmit: [
|
|
106
|
+
{
|
|
107
|
+
hooks: [
|
|
108
|
+
{
|
|
109
|
+
type: "command",
|
|
110
|
+
command: `node "${enhanceJs}"`,
|
|
111
|
+
timeout: 60,
|
|
112
|
+
},
|
|
113
|
+
],
|
|
114
|
+
},
|
|
115
|
+
],
|
|
116
|
+
SessionStart: [
|
|
117
|
+
{
|
|
118
|
+
matcher: "startup|resume",
|
|
119
|
+
hooks: [
|
|
120
|
+
{
|
|
121
|
+
type: "command",
|
|
122
|
+
command: `node "${watchJs}"`,
|
|
123
|
+
timeout: 10,
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
},
|
|
127
|
+
],
|
|
128
|
+
SessionEnd: [
|
|
129
|
+
{
|
|
130
|
+
hooks: [
|
|
131
|
+
{
|
|
132
|
+
type: "command",
|
|
133
|
+
command: `node "${killJs}"`,
|
|
134
|
+
timeout: 10,
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
},
|
|
138
|
+
],
|
|
139
|
+
};
|
|
140
|
+
writeFileIfChanged(path.join(skillsDir, "SKILL.md"), skillContent.trimStart());
|
|
141
|
+
const settings = loadSettings(settingsPath);
|
|
142
|
+
settings.enableHooks = true;
|
|
143
|
+
settings.allowBackgroundProcesses = true;
|
|
144
|
+
settings.hooks = mergeHooks(isHooksConfig(settings.hooks) ? settings.hooks : undefined, hookConfig);
|
|
145
|
+
saveSettings(settingsPath, settings);
|
|
146
|
+
console.log(chalk.green(`Installed sgrep hooks and skill in ${root}`));
|
|
147
|
+
console.log("");
|
|
148
|
+
console.log(chalk.green("Installation complete!"));
|
|
149
|
+
console.log("");
|
|
150
|
+
console.log(chalk.gray("To uninstall: sgrep uninstall-droid"));
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
154
|
+
console.error(chalk.red(`Error installing plugin: ${errorMessage}`));
|
|
155
|
+
process.exit(1);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
async function uninstallPlugin() {
|
|
159
|
+
console.log(chalk.cyan("Uninstalling sgrep plugin from Factory Droid..."));
|
|
160
|
+
console.log("");
|
|
161
|
+
try {
|
|
162
|
+
const root = resolveDroidRoot();
|
|
163
|
+
const hooksDir = path.join(root, "hooks", "sgrep");
|
|
164
|
+
const skillsDir = path.join(root, "skills", "sgrep");
|
|
165
|
+
const settingsPath = path.join(root, "settings.json");
|
|
166
|
+
if (fs.existsSync(hooksDir)) {
|
|
167
|
+
fs.rmSync(hooksDir, { recursive: true, force: true });
|
|
168
|
+
console.log(chalk.green("Removed sgrep hooks from Factory Droid"));
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
console.log(chalk.yellow("No sgrep hooks found for Factory Droid"));
|
|
172
|
+
}
|
|
173
|
+
if (fs.existsSync(skillsDir)) {
|
|
174
|
+
fs.rmSync(skillsDir, { recursive: true, force: true });
|
|
175
|
+
console.log(chalk.green("Removed sgrep skill from Factory Droid"));
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
console.log(chalk.yellow("No sgrep skill found for Factory Droid"));
|
|
179
|
+
}
|
|
180
|
+
if (fs.existsSync(settingsPath)) {
|
|
181
|
+
try {
|
|
182
|
+
const settings = loadSettings(settingsPath);
|
|
183
|
+
const hooks = isHooksConfig(settings.hooks) ? settings.hooks : undefined;
|
|
184
|
+
if (hooks) {
|
|
185
|
+
for (const event of Object.keys(hooks)) {
|
|
186
|
+
const filtered = hooks[event].filter((entry) => {
|
|
187
|
+
const cmd = entry?.hooks?.[0]?.command || "";
|
|
188
|
+
return !cmd.includes("sgrep_watch") && !cmd.includes("sgrep_enhance");
|
|
189
|
+
});
|
|
190
|
+
if (filtered.length === 0) {
|
|
191
|
+
delete hooks[event];
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
hooks[event] = filtered;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (Object.keys(hooks).length === 0) {
|
|
198
|
+
delete settings.hooks;
|
|
199
|
+
}
|
|
200
|
+
saveSettings(settingsPath, settings);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
console.warn(chalk.yellow(`Failed to update Factory Droid settings: ${error}`));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
console.log("");
|
|
208
|
+
console.log(chalk.green("Uninstallation complete!"));
|
|
209
|
+
}
|
|
210
|
+
catch (error) {
|
|
211
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
212
|
+
console.error(chalk.red(`Error uninstalling plugin: ${errorMessage}`));
|
|
213
|
+
process.exit(1);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
export const installDroid = new Command("install-droid")
|
|
217
|
+
.description("Install the sgrep hooks and skill for Factory Droid")
|
|
218
|
+
.action(async () => {
|
|
219
|
+
await installPlugin();
|
|
220
|
+
});
|
|
221
|
+
export const uninstallDroid = new Command("uninstall-droid")
|
|
222
|
+
.description("Uninstall the sgrep hooks and skill from Factory Droid")
|
|
223
|
+
.action(async () => {
|
|
224
|
+
await uninstallPlugin();
|
|
225
|
+
});
|
|
226
|
+
//# sourceMappingURL=droid.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"droid.js","sourceRoot":"","sources":["../../src/install/droid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAE3C,MAAM,WAAW,GACf,OAAO,CAAC,GAAG,CAAC,iBAAiB;IAC7B,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC;AAC9C,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;AACzD,MAAM,iBAAiB,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;AAqBhF,SAAS,gBAAgB;IACvB,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,CAAC;IACjD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CACb,wCAAwC,IAAI,uEAAuE,CACpH,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,kBAAkB,CAAC,QAAgB,EAAE,OAAe;IAC3D,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1D,MAAM,OAAO,GAAG,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;QACrC,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC;QACpC,CAAC,CAAC,SAAS,CAAC;IACd,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;QACxB,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACtC,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,SAAiB;IACxC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,yBAAyB,SAAS,EAAE,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,qBAAqB,CAAC,OAAe;IAC5C,MAAM,QAAQ,GAAG,OAAO;SACrB,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;SAC9C,IAAI,CAAC,IAAI,CAAC,CAAC;IACd,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAC7C,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACnE,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IACD,OAAO,MAAiC,CAAC;AAC3C,CAAC;AAED,SAAS,YAAY,CAAC,YAAoB;IACxC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QACjC,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAC1C,OAAO,MAAkB,CAAC;AAC5B,CAAC;AAED,SAAS,YAAY,CACnB,YAAoB,EACpB,QAAiC;IAEjC,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9D,EAAE,CAAC,aAAa,CAAC,YAAY,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AACpE,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAChE,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;AACrE,CAAC;AAED,SAAS,UAAU,CACjB,aAAsC,EACtC,QAAqB;IAErB,MAAM,MAAM,GAAgB,aAAa;QACvC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,CAAiB;QAC5D,CAAC,CAAC,EAAE,CAAC;IACP,KAAK,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxD,MAAM,OAAO,GAAgB,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvD,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;YACf,CAAC,CAAC,EAAE,CAAC;QACP,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,OAAO,GAAG,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC;YAC3C,MAAM,OAAO,GAAG,KAAK,EAAE,OAAO,IAAI,IAAI,CAAC;YACvC,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAC5B,CAAC,IAAI,EAAE,EAAE,CACP,CAAC,IAAI,EAAE,OAAO,IAAI,IAAI,CAAC,KAAK,OAAO;gBACnC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,KAAK,OAAO;gBACrC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,KAAK,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CACrD,CAAC;YACF,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACtB,CAAC;QACH,CAAC;QACD,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC;IAC1B,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,KAAK,UAAU,aAAa;IAC1B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC,CAAC;IACxE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,gBAAgB,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACnD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QACrD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;QAEtD,MAAM,SAAS,GAAG,eAAe,CAC/B,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAC9C,CAAC;QACF,MAAM,QAAQ,GAAG,eAAe,CAC9B,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,qBAAqB,CAAC,CACnD,CAAC;QACF,MAAM,WAAW,GAAG,eAAe,CACjC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,kBAAkB,CAAC,CAChD,CAAC;QACF,MAAM,YAAY,GAAG,eAAe,CAAC,iBAAiB,CAAC,CAAC;QAExD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;QACtD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,qBAAqB,CAAC,CAAC;QAC1D,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,kBAAkB,CAAC,CAAC;QAC1D,kBAAkB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QACvC,kBAAkB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACrC,kBAAkB,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC;QAE3C,MAAM,UAAU,GAAgB;YAC9B,gBAAgB,EAAE;gBAChB;oBACE,KAAK,EAAE;wBACL;4BACE,IAAI,EAAE,SAAS;4BACf,OAAO,EAAE,SAAS,SAAS,GAAG;4BAC9B,OAAO,EAAE,EAAE;yBACZ;qBACF;iBACF;aACF;YACD,YAAY,EAAE;gBACZ;oBACE,OAAO,EAAE,gBAAgB;oBACzB,KAAK,EAAE;wBACL;4BACE,IAAI,EAAE,SAAS;4BACf,OAAO,EAAE,SAAS,OAAO,GAAG;4BAC5B,OAAO,EAAE,EAAE;yBACZ;qBACF;iBACF;aACF;YACD,UAAU,EAAE;gBACV;oBACE,KAAK,EAAE;wBACL;4BACE,IAAI,EAAE,SAAS;4BACf,OAAO,EAAE,SAAS,MAAM,GAAG;4BAC3B,OAAO,EAAE,EAAE;yBACZ;qBACF;iBACF;aACF;SACF,CAAC;QACF,kBAAkB,CAChB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,CAAC,EAChC,YAAY,CAAC,SAAS,EAAE,CACzB,CAAC;QAEF,MAAM,QAAQ,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;QAC5C,QAAQ,CAAC,WAAW,GAAG,IAAI,CAAC;QAC5B,QAAQ,CAAC,wBAAwB,GAAG,IAAI,CAAC;QACzC,QAAQ,CAAC,KAAK,GAAG,UAAU,CACzB,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,EAC1D,UAAU,CACX,CAAC;QACF,YAAY,CAAC,YAAY,EAAE,QAAmC,CAAC,CAAC;QAEhE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,sCAAsC,IAAI,EAAE,CAAC,CAAC,CAAC;QACvE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC,CAAC;IACjE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5E,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,4BAA4B,YAAY,EAAE,CAAC,CAAC,CAAC;QACrE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,KAAK,UAAU,eAAe;IAC5B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,iDAAiD,CAAC,CAAC,CAAC;IAC3E,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,gBAAgB,EAAE,CAAC;QAChC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QACnD,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QACrD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;QAEtD,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC5B,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACtD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC,CAAC;QACrE,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,wCAAwC,CAAC,CAAC,CAAC;QACtE,CAAC;QAED,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC7B,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACvD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,wCAAwC,CAAC,CAAC,CAAC;QACrE,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,wCAAwC,CAAC,CAAC,CAAC;QACtE,CAAC;QAED,IAAI,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YAChC,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,YAAY,CAAC,YAAY,CAAC,CAAC;gBAC5C,MAAM,KAAK,GAAG,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;gBACzE,IAAI,KAAK,EAAE,CAAC;oBACV,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;wBACvC,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAClC,CAAC,KAAK,EAAE,EAAE;4BACR,MAAM,GAAG,GAAG,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,IAAI,EAAE,CAAC;4BAC7C,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;wBACxE,CAAC,CACF,CAAC;wBACF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;4BAC1B,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC;wBACtB,CAAC;6BAAM,CAAC;4BACN,KAAK,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC;wBAC1B,CAAC;oBACH,CAAC;oBACD,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;wBACpC,OAAO,QAAQ,CAAC,KAAK,CAAC;oBACxB,CAAC;oBACD,YAAY,CAAC,YAAY,EAAE,QAAmC,CAAC,CAAC;gBAClE,CAAC;YACH,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CACV,KAAK,CAAC,MAAM,CAAC,4CAA4C,KAAK,EAAE,CAAC,CAClE,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC,CAAC;IACvD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5E,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,8BAA8B,YAAY,EAAE,CAAC,CAAC,CAAC;QACvE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,OAAO,CAAC,eAAe,CAAC;KACrD,WAAW,CAAC,qDAAqD,CAAC;KAClE,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,aAAa,EAAE,CAAC;AACxB,CAAC,CAAC,CAAC;AAEL,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,OAAO,CAAC,iBAAiB,CAAC;KACzD,WAAW,CAAC,wDAAwD,CAAC;KACrE,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,eAAe,EAAE,CAAC;AAC1B,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode.d.ts","sourceRoot":"","sources":["../../src/install/opencode.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoSpC,eAAO,MAAM,eAAe,SAIxB,CAAC;AAEL,eAAO,MAAM,iBAAiB,SAI1B,CAAC"}
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { Command } from "commander";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
// OpenCode plugins go in ~/.config/opencode/plugins/ (plural)
|
|
7
|
+
// Tools are defined inside plugins, not in a separate directory
|
|
8
|
+
const PLUGIN_PATH = path.join(os.homedir(), ".config", "opencode", "plugins", "sgrep.ts");
|
|
9
|
+
// Legacy paths to clean up during uninstall
|
|
10
|
+
const LEGACY_TOOL_PATH = path.join(os.homedir(), ".config", "opencode", "tool", "sgrep.ts");
|
|
11
|
+
const LEGACY_PLUGIN_PATH = path.join(os.homedir(), ".config", "opencode", "plugin", "sgrep.ts");
|
|
12
|
+
// Combined plugin with tool definition and session hooks
|
|
13
|
+
const PLUGIN_DEFINITION = `
|
|
14
|
+
import { type Plugin, tool } from "@opencode-ai/plugin"
|
|
15
|
+
import { spawn, execSync } from "child_process"
|
|
16
|
+
import fs from "fs"
|
|
17
|
+
import path from "path"
|
|
18
|
+
import os from "os"
|
|
19
|
+
|
|
20
|
+
// Session state tracking for background processes
|
|
21
|
+
const sessionPids = new Map<string, number>()
|
|
22
|
+
|
|
23
|
+
function debugLog(message: string) {
|
|
24
|
+
if (process.env.SGREP_DEBUG !== "1" && process.env.SGREP_DEBUG !== "true") return
|
|
25
|
+
const logFile = process.env.SGREP_OPENCODE_LOG || path.join(os.tmpdir(), "sgrep-opencode.log")
|
|
26
|
+
try {
|
|
27
|
+
fs.appendFileSync(logFile, \`[\${new Date().toISOString()}] \${message}\\n\`)
|
|
28
|
+
} catch {}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function findSgrep(): string {
|
|
32
|
+
const isWindows = process.platform === "win32"
|
|
33
|
+
try {
|
|
34
|
+
const cmd = isWindows ? "where sgrep.cmd" : "which sgrep"
|
|
35
|
+
const result = execSync(cmd, { encoding: "utf8", timeout: 5000 }).trim().split(/\\r?\\n/)[0]
|
|
36
|
+
return result
|
|
37
|
+
} catch {
|
|
38
|
+
try {
|
|
39
|
+
const cmd = isWindows ? "where sgrep" : "which sgrep"
|
|
40
|
+
const result = execSync(cmd, { encoding: "utf8", timeout: 5000 }).trim().split(/\\r?\\n/)[0]
|
|
41
|
+
if (isWindows && !result.toLowerCase().endsWith(".cmd") && !result.toLowerCase().endsWith(".exe")) {
|
|
42
|
+
return result + ".cmd"
|
|
43
|
+
}
|
|
44
|
+
return result
|
|
45
|
+
} catch {
|
|
46
|
+
return "sgrep"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function startWatch(sessionId: string): void {
|
|
52
|
+
const pidFile = path.join(os.tmpdir(), \`sgrep-watch-pid-\${sessionId}.txt\`)
|
|
53
|
+
const logFile = path.join(os.tmpdir(), \`sgrep-watch-opencode-\${sessionId}.log\`)
|
|
54
|
+
|
|
55
|
+
// Check if already running
|
|
56
|
+
if (fs.existsSync(pidFile)) {
|
|
57
|
+
const existingPid = parseInt(fs.readFileSync(pidFile, "utf8").trim(), 10)
|
|
58
|
+
if (existingPid > 0) {
|
|
59
|
+
try {
|
|
60
|
+
process.kill(existingPid, 0)
|
|
61
|
+
debugLog(\`sgrep watch already running for session \${sessionId} with PID \${existingPid}\`)
|
|
62
|
+
sessionPids.set(sessionId, existingPid)
|
|
63
|
+
return
|
|
64
|
+
} catch {
|
|
65
|
+
fs.unlinkSync(pidFile)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const sgrepPath = findSgrep()
|
|
71
|
+
debugLog(\`Starting sgrep watch for session \${sessionId} using \${sgrepPath}\`)
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
const out = fs.openSync(logFile, "w")
|
|
75
|
+
const args = ["watch", "--pid-file", pidFile]
|
|
76
|
+
const isWindows = process.platform === "win32"
|
|
77
|
+
const isCmdScript = sgrepPath.toLowerCase().endsWith(".cmd") || sgrepPath.toLowerCase().endsWith(".bat")
|
|
78
|
+
|
|
79
|
+
let child
|
|
80
|
+
if (isWindows && isCmdScript) {
|
|
81
|
+
child = spawn("cmd.exe", ["/c", sgrepPath, ...args], {
|
|
82
|
+
detached: true,
|
|
83
|
+
stdio: ["ignore", out, out],
|
|
84
|
+
windowsHide: true,
|
|
85
|
+
})
|
|
86
|
+
} else {
|
|
87
|
+
child = spawn(sgrepPath, args, {
|
|
88
|
+
detached: true,
|
|
89
|
+
stdio: ["ignore", out, out],
|
|
90
|
+
...(isWindows ? { windowsHide: true } : {}),
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
child.unref()
|
|
95
|
+
debugLog(\`Spawned sgrep watch with wrapper PID \${child.pid}\`)
|
|
96
|
+
|
|
97
|
+
// Wait for PID file to be written
|
|
98
|
+
setTimeout(() => {
|
|
99
|
+
if (fs.existsSync(pidFile)) {
|
|
100
|
+
const pid = parseInt(fs.readFileSync(pidFile, "utf8").trim(), 10)
|
|
101
|
+
if (pid > 0) {
|
|
102
|
+
sessionPids.set(sessionId, pid)
|
|
103
|
+
debugLog(\`sgrep watch started with PID \${pid}\`)
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}, 500)
|
|
107
|
+
} catch (e) {
|
|
108
|
+
debugLog(\`Failed to start sgrep watch: \${e}\`)
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function stopWatch(sessionId: string): void {
|
|
113
|
+
const pidFile = path.join(os.tmpdir(), \`sgrep-watch-pid-\${sessionId}.txt\`)
|
|
114
|
+
|
|
115
|
+
// Try from our cache first
|
|
116
|
+
const cachedPid = sessionPids.get(sessionId)
|
|
117
|
+
if (cachedPid) {
|
|
118
|
+
try {
|
|
119
|
+
process.kill(cachedPid, "SIGTERM")
|
|
120
|
+
debugLog(\`Stopped sgrep watch PID \${cachedPid} from cache\`)
|
|
121
|
+
} catch {}
|
|
122
|
+
sessionPids.delete(sessionId)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Also check PID file
|
|
126
|
+
if (fs.existsSync(pidFile)) {
|
|
127
|
+
try {
|
|
128
|
+
const pid = parseInt(fs.readFileSync(pidFile, "utf8").trim(), 10)
|
|
129
|
+
if (pid > 0) {
|
|
130
|
+
try {
|
|
131
|
+
process.kill(pid, "SIGTERM")
|
|
132
|
+
debugLog(\`Stopped sgrep watch PID \${pid} from file\`)
|
|
133
|
+
} catch {}
|
|
134
|
+
}
|
|
135
|
+
fs.unlinkSync(pidFile)
|
|
136
|
+
} catch {}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const SKILL_DESCRIPTION = \`Semantic grep - search codebases by meaning using AI.
|
|
141
|
+
|
|
142
|
+
Use sgrep to search your local files semantically. Describe what you're looking for in natural language.
|
|
143
|
+
|
|
144
|
+
Examples:
|
|
145
|
+
sgrep "authentication middleware" # search in current directory
|
|
146
|
+
sgrep "database connection setup" ./src # search in specific directory
|
|
147
|
+
sgrep ask "how does the auth flow work?" # ask questions about code
|
|
148
|
+
sgrep enhance "fix the bug" # enhance vague prompts with context
|
|
149
|
+
|
|
150
|
+
Avoid overly vague queries like "function" - be specific about functionality.\`
|
|
151
|
+
|
|
152
|
+
export const SgrepPlugin: Plugin = async ({ $ }) => {
|
|
153
|
+
debugLog("sgrep plugin loaded")
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
// Session lifecycle hooks
|
|
157
|
+
event: async ({ event }) => {
|
|
158
|
+
const sessionId = (event as any).properties?.sessionId ||
|
|
159
|
+
(event as any).session_id ||
|
|
160
|
+
"default"
|
|
161
|
+
|
|
162
|
+
if (event.type === "session.created") {
|
|
163
|
+
debugLog(\`Session created: \${sessionId}\`)
|
|
164
|
+
startWatch(sessionId)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (event.type === "session.deleted") {
|
|
168
|
+
debugLog(\`Session deleted: \${sessionId}\`)
|
|
169
|
+
stopWatch(sessionId)
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
|
|
173
|
+
// Custom tool for semantic search
|
|
174
|
+
tool: {
|
|
175
|
+
sgrep: tool({
|
|
176
|
+
description: SKILL_DESCRIPTION,
|
|
177
|
+
args: {
|
|
178
|
+
query: tool.schema.string().describe("The semantic search query describing what you're looking for."),
|
|
179
|
+
maxResults: tool.schema.number().default(10).describe("Maximum number of results to return."),
|
|
180
|
+
askMode: tool.schema.boolean().default(false).describe("If true, get explanations instead of code snippets."),
|
|
181
|
+
},
|
|
182
|
+
async execute(args) {
|
|
183
|
+
const cmd = args.askMode ? "ask" : "search"
|
|
184
|
+
const result = await $\`sgrep \${cmd} -m \${args.maxResults} \${args.query}\`.text()
|
|
185
|
+
return result.trim()
|
|
186
|
+
},
|
|
187
|
+
}),
|
|
188
|
+
},
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
`;
|
|
192
|
+
async function installPlugin() {
|
|
193
|
+
console.log(chalk.cyan("Installing sgrep plugin for OpenCode..."));
|
|
194
|
+
console.log("");
|
|
195
|
+
try {
|
|
196
|
+
// Install the combined plugin (tool + session hooks)
|
|
197
|
+
fs.mkdirSync(path.dirname(PLUGIN_PATH), { recursive: true });
|
|
198
|
+
const existingPlugin = fs.existsSync(PLUGIN_PATH)
|
|
199
|
+
? fs.readFileSync(PLUGIN_PATH, "utf-8")
|
|
200
|
+
: "";
|
|
201
|
+
if (existingPlugin !== PLUGIN_DEFINITION) {
|
|
202
|
+
fs.writeFileSync(PLUGIN_PATH, PLUGIN_DEFINITION);
|
|
203
|
+
console.log(chalk.green(`Installed plugin: ${PLUGIN_PATH}`));
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
console.log(chalk.yellow("The sgrep plugin is already up to date"));
|
|
207
|
+
}
|
|
208
|
+
// Clean up legacy paths from previous installations
|
|
209
|
+
if (fs.existsSync(LEGACY_TOOL_PATH)) {
|
|
210
|
+
fs.unlinkSync(LEGACY_TOOL_PATH);
|
|
211
|
+
console.log(chalk.gray("Removed legacy tool file"));
|
|
212
|
+
}
|
|
213
|
+
if (fs.existsSync(LEGACY_PLUGIN_PATH)) {
|
|
214
|
+
fs.unlinkSync(LEGACY_PLUGIN_PATH);
|
|
215
|
+
console.log(chalk.gray("Removed legacy plugin file"));
|
|
216
|
+
}
|
|
217
|
+
console.log("");
|
|
218
|
+
console.log(chalk.green("Installation complete!"));
|
|
219
|
+
console.log("");
|
|
220
|
+
console.log("The sgrep plugin provides:");
|
|
221
|
+
console.log("- " + chalk.cyan("sgrep tool") + ": semantic code search via CLI");
|
|
222
|
+
console.log("- " + chalk.cyan("Session hooks") + ": sgrep watch starts/stops with your session");
|
|
223
|
+
console.log("");
|
|
224
|
+
console.log(chalk.gray("To uninstall: sgrep uninstall-opencode"));
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
228
|
+
console.error(chalk.red(`Error installing plugin: ${errorMessage}`));
|
|
229
|
+
process.exit(1);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
async function uninstallPlugin() {
|
|
233
|
+
console.log(chalk.cyan("Uninstalling sgrep plugin from OpenCode..."));
|
|
234
|
+
console.log("");
|
|
235
|
+
try {
|
|
236
|
+
let removed = false;
|
|
237
|
+
// Remove the plugin file
|
|
238
|
+
if (fs.existsSync(PLUGIN_PATH)) {
|
|
239
|
+
fs.unlinkSync(PLUGIN_PATH);
|
|
240
|
+
console.log(chalk.green("Removed sgrep plugin"));
|
|
241
|
+
removed = true;
|
|
242
|
+
}
|
|
243
|
+
// Clean up legacy paths
|
|
244
|
+
if (fs.existsSync(LEGACY_TOOL_PATH)) {
|
|
245
|
+
fs.unlinkSync(LEGACY_TOOL_PATH);
|
|
246
|
+
console.log(chalk.green("Removed legacy tool file"));
|
|
247
|
+
removed = true;
|
|
248
|
+
}
|
|
249
|
+
if (fs.existsSync(LEGACY_PLUGIN_PATH)) {
|
|
250
|
+
fs.unlinkSync(LEGACY_PLUGIN_PATH);
|
|
251
|
+
console.log(chalk.green("Removed legacy plugin file"));
|
|
252
|
+
removed = true;
|
|
253
|
+
}
|
|
254
|
+
if (!removed) {
|
|
255
|
+
console.log(chalk.yellow("The sgrep plugin was not installed"));
|
|
256
|
+
}
|
|
257
|
+
console.log("");
|
|
258
|
+
console.log(chalk.green("Uninstallation complete!"));
|
|
259
|
+
}
|
|
260
|
+
catch (error) {
|
|
261
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
262
|
+
console.error(chalk.red(`Error uninstalling plugin: ${errorMessage}`));
|
|
263
|
+
process.exit(1);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
export const installOpencode = new Command("install-opencode")
|
|
267
|
+
.description("Install the sgrep plugin for OpenCode (tool and session hooks)")
|
|
268
|
+
.action(async () => {
|
|
269
|
+
await installPlugin();
|
|
270
|
+
});
|
|
271
|
+
export const uninstallOpencode = new Command("uninstall-opencode")
|
|
272
|
+
.description("Uninstall the sgrep plugin from OpenCode")
|
|
273
|
+
.action(async () => {
|
|
274
|
+
await uninstallPlugin();
|
|
275
|
+
});
|
|
276
|
+
//# sourceMappingURL=opencode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../src/install/opencode.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "sgrep semantic search hooks - enhances prompts and manages index",
|
|
3
|
+
"hooks": {
|
|
4
|
+
"UserPromptSubmit": [
|
|
5
|
+
{
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/sgrep_enhance.js",
|
|
10
|
+
"timeout": 60
|
|
11
|
+
}
|
|
12
|
+
]
|
|
13
|
+
}
|
|
14
|
+
],
|
|
15
|
+
"SessionStart": [
|
|
16
|
+
{
|
|
17
|
+
"matcher": "startup|resume",
|
|
18
|
+
"hooks": [
|
|
19
|
+
{
|
|
20
|
+
"type": "command",
|
|
21
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/sgrep_watch.js",
|
|
22
|
+
"timeout": 10
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"SessionEnd": [
|
|
28
|
+
{
|
|
29
|
+
"hooks": [
|
|
30
|
+
{
|
|
31
|
+
"type": "command",
|
|
32
|
+
"command": "node ${CLAUDE_PLUGIN_ROOT}/hooks/sgrep_watch_kill.js",
|
|
33
|
+
"timeout": 10
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
}
|