@stackmemoryai/stackmemory 1.2.1 → 1.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.
- package/dist/src/cli/commands/skills.js +123 -1
- package/dist/src/hooks/graphiti-hooks.js +149 -0
- package/dist/src/hooks/session-summary.js +30 -0
- package/dist/src/integrations/graphiti/linear-graphiti-bridge.js +115 -0
- package/dist/src/integrations/greptile/client.js +101 -0
- package/dist/src/integrations/greptile/config.js +14 -0
- package/dist/src/integrations/greptile/index.js +11 -0
- package/dist/src/integrations/greptile/types.js +4 -0
- package/dist/src/integrations/linear/webhook.js +16 -0
- package/dist/src/integrations/mcp/handlers/greptile-handlers.js +456 -0
- package/dist/src/integrations/mcp/server.js +27 -0
- package/dist/src/skills/claude-skills.js +46 -1
- package/dist/src/skills/parallel-agent-skill.js +514 -0
- package/package.json +1 -1
- package/scripts/gepa/.before-optimize.md +140 -159
- package/scripts/gepa/config.json +7 -1
- package/scripts/gepa/evals/fixtures/api-endpoint.ts +31 -0
- package/scripts/gepa/evals/fixtures/brittle-integration.ts +38 -0
- package/scripts/gepa/evals/fixtures/fts5-triggers.sql +23 -0
- package/scripts/gepa/evals/fixtures/leaky-service.ts +70 -0
- package/scripts/gepa/evals/fixtures/mcp-dispatch-stub.ts +39 -0
- package/scripts/gepa/evals/fixtures/pr-diff.txt +24 -0
- package/scripts/gepa/evals/fixtures/unsafe-webhook.ts +34 -0
- package/scripts/gepa/evals/fixtures/unwrapped-db-op.ts +42 -0
- package/scripts/gepa/evals/stackmemory-tasks.jsonl +8 -0
- package/scripts/gepa/generations/gen-000/baseline.md +172 -159
- package/scripts/gepa/generations/gen-001/baseline.md +172 -159
- package/scripts/gepa/generations/gen-001/variant-a.md +156 -146
- package/scripts/gepa/generations/gen-001/variant-b.md +199 -170
- package/scripts/gepa/generations/gen-001/variant-c.md +127 -46
- package/scripts/gepa/generations/gen-001/variant-d.md +160 -107
- package/scripts/gepa/hooks/reflect.js +44 -5
- package/scripts/gepa/optimize.js +281 -39
- package/scripts/gepa/results/eval-1-baseline.json +187 -10
- package/scripts/gepa/results/eval-1-variant-a.json +188 -11
- package/scripts/gepa/results/eval-1-variant-b.json +188 -11
- package/scripts/gepa/results/eval-1-variant-c.json +168 -11
- package/scripts/gepa/results/eval-1-variant-d.json +169 -12
- package/scripts/gepa/state.json +18 -18
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
import { fileURLToPath as __fileURLToPath } from 'url';
|
|
2
|
+
import { dirname as __pathDirname } from 'path';
|
|
3
|
+
const __filename = __fileURLToPath(import.meta.url);
|
|
4
|
+
const __dirname = __pathDirname(__filename);
|
|
5
|
+
import { DEFAULT_GREPTILE_CONFIG } from "../../greptile/config.js";
|
|
6
|
+
import { GreptileClient, GreptileClientError } from "../../greptile/client.js";
|
|
7
|
+
import { logger } from "../../../core/monitoring/logger.js";
|
|
8
|
+
class GreptileHandlers {
|
|
9
|
+
config;
|
|
10
|
+
client = null;
|
|
11
|
+
constructor(deps) {
|
|
12
|
+
this.config = { ...DEFAULT_GREPTILE_CONFIG, ...deps?.config };
|
|
13
|
+
if (this.config.enabled && this.config.apiKey) {
|
|
14
|
+
try {
|
|
15
|
+
this.client = new GreptileClient(this.config);
|
|
16
|
+
} catch {
|
|
17
|
+
this.client = null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
getToolDefinitions() {
|
|
22
|
+
return [
|
|
23
|
+
{
|
|
24
|
+
name: "greptile_pr_comments",
|
|
25
|
+
description: "Get PR review comments from Greptile. Returns unaddressed comments with suggestedCode for auto-fix workflows.",
|
|
26
|
+
inputSchema: {
|
|
27
|
+
type: "object",
|
|
28
|
+
properties: {
|
|
29
|
+
name: {
|
|
30
|
+
type: "string",
|
|
31
|
+
description: 'Repository full name (e.g., "owner/repo")'
|
|
32
|
+
},
|
|
33
|
+
remote: {
|
|
34
|
+
type: "string",
|
|
35
|
+
enum: ["github", "gitlab", "azure", "bitbucket"],
|
|
36
|
+
description: "Remote provider"
|
|
37
|
+
},
|
|
38
|
+
defaultBranch: {
|
|
39
|
+
type: "string",
|
|
40
|
+
description: 'Default branch (e.g., "main")'
|
|
41
|
+
},
|
|
42
|
+
prNumber: {
|
|
43
|
+
type: "number",
|
|
44
|
+
description: "Pull request number"
|
|
45
|
+
},
|
|
46
|
+
greptileGenerated: {
|
|
47
|
+
type: "boolean",
|
|
48
|
+
description: "Filter for only Greptile review comments"
|
|
49
|
+
},
|
|
50
|
+
addressed: {
|
|
51
|
+
type: "boolean",
|
|
52
|
+
description: "Filter by comment addressed status"
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
required: ["name", "remote", "defaultBranch", "prNumber"]
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: "greptile_pr_details",
|
|
60
|
+
description: "Get detailed PR information including metadata, statistics, and review analysis from Greptile.",
|
|
61
|
+
inputSchema: {
|
|
62
|
+
type: "object",
|
|
63
|
+
properties: {
|
|
64
|
+
name: {
|
|
65
|
+
type: "string",
|
|
66
|
+
description: 'Repository full name (e.g., "owner/repo")'
|
|
67
|
+
},
|
|
68
|
+
remote: {
|
|
69
|
+
type: "string",
|
|
70
|
+
enum: ["github", "gitlab", "azure", "bitbucket"],
|
|
71
|
+
description: "Remote provider"
|
|
72
|
+
},
|
|
73
|
+
defaultBranch: {
|
|
74
|
+
type: "string",
|
|
75
|
+
description: "Default branch"
|
|
76
|
+
},
|
|
77
|
+
prNumber: {
|
|
78
|
+
type: "number",
|
|
79
|
+
description: "Pull request number"
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
required: ["name", "remote", "defaultBranch", "prNumber"]
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: "greptile_list_prs",
|
|
87
|
+
description: "List pull requests. Filter by repository, branch, author, or state.",
|
|
88
|
+
inputSchema: {
|
|
89
|
+
type: "object",
|
|
90
|
+
properties: {
|
|
91
|
+
name: {
|
|
92
|
+
type: "string",
|
|
93
|
+
description: 'Repository full name (e.g., "owner/repo")'
|
|
94
|
+
},
|
|
95
|
+
remote: {
|
|
96
|
+
type: "string",
|
|
97
|
+
enum: ["github", "gitlab", "azure", "bitbucket"],
|
|
98
|
+
description: "Remote provider"
|
|
99
|
+
},
|
|
100
|
+
defaultBranch: {
|
|
101
|
+
type: "string",
|
|
102
|
+
description: "Default branch"
|
|
103
|
+
},
|
|
104
|
+
sourceBranch: {
|
|
105
|
+
type: "string",
|
|
106
|
+
description: "Filter by source branch name"
|
|
107
|
+
},
|
|
108
|
+
authorLogin: {
|
|
109
|
+
type: "string",
|
|
110
|
+
description: "Filter by PR author username"
|
|
111
|
+
},
|
|
112
|
+
state: {
|
|
113
|
+
type: "string",
|
|
114
|
+
enum: ["open", "closed", "merged"],
|
|
115
|
+
description: "Filter by PR state"
|
|
116
|
+
},
|
|
117
|
+
limit: {
|
|
118
|
+
type: "number",
|
|
119
|
+
description: "Max results (default 20)"
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
name: "greptile_trigger_review",
|
|
126
|
+
description: "Trigger a Greptile code review for a pull request.",
|
|
127
|
+
inputSchema: {
|
|
128
|
+
type: "object",
|
|
129
|
+
properties: {
|
|
130
|
+
name: {
|
|
131
|
+
type: "string",
|
|
132
|
+
description: 'Repository full name (e.g., "owner/repo")'
|
|
133
|
+
},
|
|
134
|
+
remote: {
|
|
135
|
+
type: "string",
|
|
136
|
+
enum: ["github", "gitlab", "azure", "bitbucket"],
|
|
137
|
+
description: "Remote provider"
|
|
138
|
+
},
|
|
139
|
+
defaultBranch: {
|
|
140
|
+
type: "string",
|
|
141
|
+
description: "Default branch"
|
|
142
|
+
},
|
|
143
|
+
prNumber: {
|
|
144
|
+
type: "number",
|
|
145
|
+
description: "Pull request number"
|
|
146
|
+
},
|
|
147
|
+
branch: {
|
|
148
|
+
type: "string",
|
|
149
|
+
description: "Current working branch"
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
required: ["name", "remote", "prNumber"]
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
name: "greptile_search_patterns",
|
|
157
|
+
description: "Search custom coding patterns and instructions in Greptile.",
|
|
158
|
+
inputSchema: {
|
|
159
|
+
type: "object",
|
|
160
|
+
properties: {
|
|
161
|
+
query: {
|
|
162
|
+
type: "string",
|
|
163
|
+
description: "Search query for pattern content"
|
|
164
|
+
},
|
|
165
|
+
limit: {
|
|
166
|
+
type: "number",
|
|
167
|
+
description: "Max results (default 10)"
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
required: ["query"]
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
name: "greptile_create_pattern",
|
|
175
|
+
description: "Create a new custom coding pattern or instruction in Greptile.",
|
|
176
|
+
inputSchema: {
|
|
177
|
+
type: "object",
|
|
178
|
+
properties: {
|
|
179
|
+
body: {
|
|
180
|
+
type: "string",
|
|
181
|
+
description: "Pattern content"
|
|
182
|
+
},
|
|
183
|
+
type: {
|
|
184
|
+
type: "string",
|
|
185
|
+
enum: ["CUSTOM_INSTRUCTION", "PATTERN"],
|
|
186
|
+
description: "Context type (default: CUSTOM_INSTRUCTION)"
|
|
187
|
+
},
|
|
188
|
+
scopes: {
|
|
189
|
+
type: "object",
|
|
190
|
+
description: "Boolean expression defining where this pattern applies"
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
required: ["body"]
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
name: "greptile_status",
|
|
198
|
+
description: "Check Greptile integration connection status.",
|
|
199
|
+
inputSchema: {
|
|
200
|
+
type: "object",
|
|
201
|
+
properties: {}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
];
|
|
205
|
+
}
|
|
206
|
+
async handleListPRComments(args) {
|
|
207
|
+
if (!this.client) return this.disabledResponse();
|
|
208
|
+
try {
|
|
209
|
+
const toolArgs = {
|
|
210
|
+
name: args.name,
|
|
211
|
+
remote: args.remote,
|
|
212
|
+
defaultBranch: args.defaultBranch,
|
|
213
|
+
prNumber: args.prNumber
|
|
214
|
+
};
|
|
215
|
+
if (args.greptileGenerated !== void 0)
|
|
216
|
+
toolArgs.greptileGenerated = args.greptileGenerated;
|
|
217
|
+
if (args.addressed !== void 0) toolArgs.addressed = args.addressed;
|
|
218
|
+
const result = await this.client.callTool(
|
|
219
|
+
"list_merge_request_comments",
|
|
220
|
+
toolArgs
|
|
221
|
+
);
|
|
222
|
+
let actionableCount = 0;
|
|
223
|
+
if (Array.isArray(result)) {
|
|
224
|
+
actionableCount = result.filter(
|
|
225
|
+
(c) => !c.addressed && (c.suggestedCode || typeof c.body === "string" && c.body.includes("```suggestion"))
|
|
226
|
+
).length;
|
|
227
|
+
}
|
|
228
|
+
return {
|
|
229
|
+
content: [
|
|
230
|
+
{
|
|
231
|
+
type: "text",
|
|
232
|
+
text: typeof result === "string" ? result : JSON.stringify(result, null, 2)
|
|
233
|
+
}
|
|
234
|
+
],
|
|
235
|
+
metadata: { actionableCount, tool: "list_merge_request_comments" }
|
|
236
|
+
};
|
|
237
|
+
} catch (error) {
|
|
238
|
+
return this.handleError("listPRComments", error);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
async handleGetMergeRequest(args) {
|
|
242
|
+
if (!this.client) return this.disabledResponse();
|
|
243
|
+
try {
|
|
244
|
+
const result = await this.client.callTool("get_merge_request", {
|
|
245
|
+
name: args.name,
|
|
246
|
+
remote: args.remote,
|
|
247
|
+
defaultBranch: args.defaultBranch,
|
|
248
|
+
prNumber: args.prNumber
|
|
249
|
+
});
|
|
250
|
+
return {
|
|
251
|
+
content: [
|
|
252
|
+
{
|
|
253
|
+
type: "text",
|
|
254
|
+
text: typeof result === "string" ? result : JSON.stringify(result, null, 2)
|
|
255
|
+
}
|
|
256
|
+
],
|
|
257
|
+
metadata: { tool: "get_merge_request" }
|
|
258
|
+
};
|
|
259
|
+
} catch (error) {
|
|
260
|
+
return this.handleError("getMergeRequest", error);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
async handleListPullRequests(args) {
|
|
264
|
+
if (!this.client) return this.disabledResponse();
|
|
265
|
+
try {
|
|
266
|
+
const toolArgs = {};
|
|
267
|
+
if (args.name) toolArgs.name = args.name;
|
|
268
|
+
if (args.remote) toolArgs.remote = args.remote;
|
|
269
|
+
if (args.defaultBranch) toolArgs.defaultBranch = args.defaultBranch;
|
|
270
|
+
if (args.sourceBranch) toolArgs.sourceBranch = args.sourceBranch;
|
|
271
|
+
if (args.authorLogin) toolArgs.authorLogin = args.authorLogin;
|
|
272
|
+
if (args.state) toolArgs.state = args.state;
|
|
273
|
+
if (args.limit) toolArgs.limit = args.limit;
|
|
274
|
+
const result = await this.client.callTool("list_pull_requests", toolArgs);
|
|
275
|
+
return {
|
|
276
|
+
content: [
|
|
277
|
+
{
|
|
278
|
+
type: "text",
|
|
279
|
+
text: typeof result === "string" ? result : JSON.stringify(result, null, 2)
|
|
280
|
+
}
|
|
281
|
+
],
|
|
282
|
+
metadata: { tool: "list_pull_requests" }
|
|
283
|
+
};
|
|
284
|
+
} catch (error) {
|
|
285
|
+
return this.handleError("listPullRequests", error);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
async handleTriggerCodeReview(args) {
|
|
289
|
+
if (!this.client) return this.disabledResponse();
|
|
290
|
+
try {
|
|
291
|
+
const toolArgs = {
|
|
292
|
+
name: args.name,
|
|
293
|
+
remote: args.remote,
|
|
294
|
+
prNumber: args.prNumber
|
|
295
|
+
};
|
|
296
|
+
if (args.defaultBranch) toolArgs.defaultBranch = args.defaultBranch;
|
|
297
|
+
if (args.branch) toolArgs.branch = args.branch;
|
|
298
|
+
const result = await this.client.callTool(
|
|
299
|
+
"trigger_code_review",
|
|
300
|
+
toolArgs
|
|
301
|
+
);
|
|
302
|
+
return {
|
|
303
|
+
content: [
|
|
304
|
+
{
|
|
305
|
+
type: "text",
|
|
306
|
+
text: typeof result === "string" ? result : JSON.stringify(result, null, 2)
|
|
307
|
+
}
|
|
308
|
+
],
|
|
309
|
+
metadata: { tool: "trigger_code_review" }
|
|
310
|
+
};
|
|
311
|
+
} catch (error) {
|
|
312
|
+
return this.handleError("triggerCodeReview", error);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
async handleSearchPatterns(args) {
|
|
316
|
+
if (!this.client) return this.disabledResponse();
|
|
317
|
+
try {
|
|
318
|
+
const toolArgs = { query: args.query };
|
|
319
|
+
if (args.limit) toolArgs.limit = args.limit;
|
|
320
|
+
const result = await this.client.callTool(
|
|
321
|
+
"search_custom_context",
|
|
322
|
+
toolArgs
|
|
323
|
+
);
|
|
324
|
+
return {
|
|
325
|
+
content: [
|
|
326
|
+
{
|
|
327
|
+
type: "text",
|
|
328
|
+
text: typeof result === "string" ? result : JSON.stringify(result, null, 2)
|
|
329
|
+
}
|
|
330
|
+
],
|
|
331
|
+
metadata: { tool: "search_custom_context" }
|
|
332
|
+
};
|
|
333
|
+
} catch (error) {
|
|
334
|
+
return this.handleError("searchPatterns", error);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
async handleCreatePattern(args) {
|
|
338
|
+
if (!this.client) return this.disabledResponse();
|
|
339
|
+
try {
|
|
340
|
+
const toolArgs = { body: args.body };
|
|
341
|
+
if (args.type) toolArgs.type = args.type;
|
|
342
|
+
if (args.scopes) toolArgs.scopes = args.scopes;
|
|
343
|
+
const result = await this.client.callTool(
|
|
344
|
+
"create_custom_context",
|
|
345
|
+
toolArgs
|
|
346
|
+
);
|
|
347
|
+
return {
|
|
348
|
+
content: [
|
|
349
|
+
{
|
|
350
|
+
type: "text",
|
|
351
|
+
text: typeof result === "string" ? result : JSON.stringify(result, null, 2)
|
|
352
|
+
}
|
|
353
|
+
],
|
|
354
|
+
metadata: { tool: "create_custom_context" }
|
|
355
|
+
};
|
|
356
|
+
} catch (error) {
|
|
357
|
+
return this.handleError("createPattern", error);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
async handleStatus() {
|
|
361
|
+
if (!this.client) {
|
|
362
|
+
return {
|
|
363
|
+
content: [
|
|
364
|
+
{
|
|
365
|
+
type: "text",
|
|
366
|
+
text: JSON.stringify(
|
|
367
|
+
{
|
|
368
|
+
connected: false,
|
|
369
|
+
message: "Greptile integration disabled (GREPTILE_API_KEY not set)"
|
|
370
|
+
},
|
|
371
|
+
null,
|
|
372
|
+
2
|
|
373
|
+
)
|
|
374
|
+
}
|
|
375
|
+
],
|
|
376
|
+
metadata: { connected: false }
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
try {
|
|
380
|
+
await this.client.callTool("list_pull_requests", { limit: 1 });
|
|
381
|
+
return {
|
|
382
|
+
content: [
|
|
383
|
+
{
|
|
384
|
+
type: "text",
|
|
385
|
+
text: JSON.stringify(
|
|
386
|
+
{
|
|
387
|
+
connected: true,
|
|
388
|
+
endpoint: this.config.mcpEndpoint
|
|
389
|
+
},
|
|
390
|
+
null,
|
|
391
|
+
2
|
|
392
|
+
)
|
|
393
|
+
}
|
|
394
|
+
],
|
|
395
|
+
metadata: { connected: true }
|
|
396
|
+
};
|
|
397
|
+
} catch (error) {
|
|
398
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
399
|
+
return {
|
|
400
|
+
content: [
|
|
401
|
+
{
|
|
402
|
+
type: "text",
|
|
403
|
+
text: JSON.stringify(
|
|
404
|
+
{
|
|
405
|
+
connected: false,
|
|
406
|
+
error: msg,
|
|
407
|
+
endpoint: this.config.mcpEndpoint
|
|
408
|
+
},
|
|
409
|
+
null,
|
|
410
|
+
2
|
|
411
|
+
)
|
|
412
|
+
}
|
|
413
|
+
],
|
|
414
|
+
metadata: { connected: false, error: msg }
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
disabledResponse() {
|
|
419
|
+
return {
|
|
420
|
+
content: [
|
|
421
|
+
{
|
|
422
|
+
type: "text",
|
|
423
|
+
text: "Greptile integration disabled (GREPTILE_API_KEY not set)"
|
|
424
|
+
}
|
|
425
|
+
]
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
handleError(operation, error) {
|
|
429
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
430
|
+
const isConnectionError = msg.includes("ECONNREFUSED") || msg.includes("fetch failed") || msg.includes("network") || error instanceof GreptileClientError;
|
|
431
|
+
logger.debug(`Greptile ${operation} failed`, { error: msg });
|
|
432
|
+
if (isConnectionError) {
|
|
433
|
+
return {
|
|
434
|
+
content: [
|
|
435
|
+
{
|
|
436
|
+
type: "text",
|
|
437
|
+
text: `Greptile unavailable (${operation}). The service may be temporarily unreachable.`
|
|
438
|
+
}
|
|
439
|
+
],
|
|
440
|
+
metadata: { error: true, unavailable: true, operation }
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
return {
|
|
444
|
+
content: [
|
|
445
|
+
{
|
|
446
|
+
type: "text",
|
|
447
|
+
text: `Greptile ${operation} error: ${msg}`
|
|
448
|
+
}
|
|
449
|
+
],
|
|
450
|
+
metadata: { error: true, operation, message: msg }
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
export {
|
|
455
|
+
GreptileHandlers
|
|
456
|
+
};
|
|
@@ -30,6 +30,7 @@ import { TraceDetector } from "../../core/trace/trace-detector.js";
|
|
|
30
30
|
import { LLMContextRetrieval } from "../../core/retrieval/index.js";
|
|
31
31
|
import { DiscoveryHandlers } from "./handlers/discovery-handlers.js";
|
|
32
32
|
import { DiffMemHandlers } from "./handlers/diffmem-handlers.js";
|
|
33
|
+
import { GreptileHandlers } from "./handlers/greptile-handlers.js";
|
|
33
34
|
import { GraphitiClient } from "../graphiti/client.js";
|
|
34
35
|
import { fuzzyEdit } from "../../utils/fuzzy-edit.js";
|
|
35
36
|
import { v4 as uuidv4 } from "uuid";
|
|
@@ -64,6 +65,7 @@ class LocalStackMemoryMCP {
|
|
|
64
65
|
contextRetrieval;
|
|
65
66
|
discoveryHandlers;
|
|
66
67
|
diffMemHandlers;
|
|
68
|
+
greptileHandlers;
|
|
67
69
|
providerHandlers = null;
|
|
68
70
|
graphitiClient = null;
|
|
69
71
|
pendingPlans = /* @__PURE__ */ new Map();
|
|
@@ -138,6 +140,7 @@ class LocalStackMemoryMCP {
|
|
|
138
140
|
projectRoot: this.projectRoot
|
|
139
141
|
});
|
|
140
142
|
this.diffMemHandlers = new DiffMemHandlers();
|
|
143
|
+
this.greptileHandlers = new GreptileHandlers();
|
|
141
144
|
this.initProviderHandlers();
|
|
142
145
|
if (process.env.GRAPHITI_ENDPOINT) {
|
|
143
146
|
this.graphitiClient = new GraphitiClient({
|
|
@@ -1129,6 +1132,8 @@ ${summary}...`, 0.8);
|
|
|
1129
1132
|
}
|
|
1130
1133
|
}
|
|
1131
1134
|
] : [],
|
|
1135
|
+
// Greptile tools (only active when GREPTILE_API_KEY is set)
|
|
1136
|
+
...process.env.GREPTILE_API_KEY ? this.greptileHandlers.getToolDefinitions() : [],
|
|
1132
1137
|
// Provider tools (only active when STACKMEMORY_MULTI_PROVIDER=true)
|
|
1133
1138
|
...isFeatureEnabled("multiProvider") ? [
|
|
1134
1139
|
{
|
|
@@ -1377,6 +1382,28 @@ ${summary}...`, 0.8);
|
|
|
1377
1382
|
case "diffmem_status":
|
|
1378
1383
|
result = await this.diffMemHandlers.handleStatus();
|
|
1379
1384
|
break;
|
|
1385
|
+
// Greptile handlers
|
|
1386
|
+
case "greptile_pr_comments":
|
|
1387
|
+
result = await this.greptileHandlers.handleListPRComments(args);
|
|
1388
|
+
break;
|
|
1389
|
+
case "greptile_pr_details":
|
|
1390
|
+
result = await this.greptileHandlers.handleGetMergeRequest(args);
|
|
1391
|
+
break;
|
|
1392
|
+
case "greptile_list_prs":
|
|
1393
|
+
result = await this.greptileHandlers.handleListPullRequests(args);
|
|
1394
|
+
break;
|
|
1395
|
+
case "greptile_trigger_review":
|
|
1396
|
+
result = await this.greptileHandlers.handleTriggerCodeReview(args);
|
|
1397
|
+
break;
|
|
1398
|
+
case "greptile_search_patterns":
|
|
1399
|
+
result = await this.greptileHandlers.handleSearchPatterns(args);
|
|
1400
|
+
break;
|
|
1401
|
+
case "greptile_create_pattern":
|
|
1402
|
+
result = await this.greptileHandlers.handleCreatePattern(args);
|
|
1403
|
+
break;
|
|
1404
|
+
case "greptile_status":
|
|
1405
|
+
result = await this.greptileHandlers.handleStatus();
|
|
1406
|
+
break;
|
|
1380
1407
|
case "sm_edit":
|
|
1381
1408
|
result = await this.handleSmEdit(args);
|
|
1382
1409
|
break;
|
|
@@ -948,6 +948,25 @@ class ClaudeSkillsManager {
|
|
|
948
948
|
};
|
|
949
949
|
}
|
|
950
950
|
}
|
|
951
|
+
case "agent": {
|
|
952
|
+
const { ParallelAgentSkill } = await import("./parallel-agent-skill.js");
|
|
953
|
+
const agentSkill = new ParallelAgentSkill(this.context);
|
|
954
|
+
const sub = args[0];
|
|
955
|
+
const agentOpts = { timeout: options?.timeout };
|
|
956
|
+
switch (sub) {
|
|
957
|
+
case "research":
|
|
958
|
+
return agentSkill.research(args.slice(1).join(" "), agentOpts);
|
|
959
|
+
case "maintain":
|
|
960
|
+
return agentSkill.maintain(args.slice(1).join(" "), agentOpts);
|
|
961
|
+
case "spec-run":
|
|
962
|
+
return agentSkill.specRun(args[1], agentOpts);
|
|
963
|
+
default:
|
|
964
|
+
return {
|
|
965
|
+
success: false,
|
|
966
|
+
message: `Unknown: agent ${sub}. Use: research|maintain|spec-run`
|
|
967
|
+
};
|
|
968
|
+
}
|
|
969
|
+
}
|
|
951
970
|
case "linear-run": {
|
|
952
971
|
if (!this.linearTaskRunner) {
|
|
953
972
|
return {
|
|
@@ -983,7 +1002,15 @@ class ClaudeSkillsManager {
|
|
|
983
1002
|
}
|
|
984
1003
|
}
|
|
985
1004
|
getAvailableSkills() {
|
|
986
|
-
const skills = [
|
|
1005
|
+
const skills = [
|
|
1006
|
+
"handoff",
|
|
1007
|
+
"checkpoint",
|
|
1008
|
+
"dig",
|
|
1009
|
+
"dashboard",
|
|
1010
|
+
"api",
|
|
1011
|
+
"spec",
|
|
1012
|
+
"agent"
|
|
1013
|
+
];
|
|
987
1014
|
if (this.repoIngestionSkill) {
|
|
988
1015
|
skills.push("repo");
|
|
989
1016
|
}
|
|
@@ -1145,6 +1172,24 @@ Examples:
|
|
|
1145
1172
|
/spec dev-spec
|
|
1146
1173
|
/spec update prompt-plan "Initialize repository and tooling"
|
|
1147
1174
|
/spec validate prompt-plan
|
|
1175
|
+
`;
|
|
1176
|
+
case "agent":
|
|
1177
|
+
return `
|
|
1178
|
+
/agent research "How does the FTS5 search work?"
|
|
1179
|
+
/agent maintain "Fix the deprecation warning in webhook.ts"
|
|
1180
|
+
/agent spec-run docs/specs/my-feature.md
|
|
1181
|
+
|
|
1182
|
+
Parallel agent skill (Willison patterns) \u2014 spawn isolated Claude agents:
|
|
1183
|
+
research \u2014 Explore codebase, save findings as a frame (read-only)
|
|
1184
|
+
maintain \u2014 Low-stakes fix, produces a .patch file
|
|
1185
|
+
spec-run \u2014 Implement a spec on a branch, validate with lint+test+build
|
|
1186
|
+
|
|
1187
|
+
Options:
|
|
1188
|
+
--timeout <ms> Agent timeout in milliseconds (default: 300000)
|
|
1189
|
+
|
|
1190
|
+
Each agent runs in a disposable /tmp workspace (git clone --depth=1).
|
|
1191
|
+
Patches: git apply .stackmemory/patches/<file>.patch
|
|
1192
|
+
Spec branches: cd /tmp/sm-spec-* && git log --oneline
|
|
1148
1193
|
`;
|
|
1149
1194
|
case "linear-run":
|
|
1150
1195
|
return `
|