@hailer/mcp 1.1.9 → 1.1.10
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/.mcp.json +2 -2
- package/.opencode/opencode.json +7 -0
- package/CHANGELOG.md +7 -0
- package/dist/cli.js +0 -0
- package/dist/mcp-server.js +16 -0
- package/package.json +1 -1
- package/.claude/.context-watchdog.json +0 -1
- package/.claude/.session-checked +0 -1
- package/.hailer-mcp-port +0 -1
- package/dist/CLAUDE.md +0 -370
- package/dist/lib/discussion-lock.d.ts +0 -42
- package/dist/lib/discussion-lock.js +0 -110
- package/dist/mcp/tools/bot-config/constants.d.ts +0 -23
- package/dist/mcp/tools/bot-config/constants.js +0 -94
- package/dist/mcp/tools/bot-config/core.d.ts +0 -253
- package/dist/mcp/tools/bot-config/core.js +0 -2456
- package/dist/mcp/tools/bot-config/index.d.ts +0 -10
- package/dist/mcp/tools/bot-config/index.js +0 -59
- package/dist/mcp/tools/bot-config/tools.d.ts +0 -7
- package/dist/mcp/tools/bot-config/tools.js +0 -15
- package/dist/mcp/tools/bot-config/types.d.ts +0 -50
- package/dist/mcp/tools/bot-config/types.js +0 -6
- package/dist/mcp/tools/bug-fixer-tools.d.ts +0 -45
- package/dist/mcp/tools/bug-fixer-tools.js +0 -1096
- package/dist/mcp/tools/document.d.ts +0 -11
- package/dist/mcp/tools/document.js +0 -741
- package/dist/mcp/tools/investigate.d.ts +0 -9
- package/dist/mcp/tools/investigate.js +0 -254
- package/inbox/failures.log +0 -1
- package/inbox/usage.jsonl +0 -3
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Investigation Tool - Spawn Claude Code agents to investigate local repos
|
|
3
|
-
*
|
|
4
|
-
* Uses `claude -p` (headless mode, subscription-based) to autonomously
|
|
5
|
-
* explore codebases, search for bugs, and analyze code.
|
|
6
|
-
*/
|
|
7
|
-
import { Tool } from '../tool-registry';
|
|
8
|
-
export declare const investigateRepoTool: Tool;
|
|
9
|
-
//# sourceMappingURL=investigate.d.ts.map
|
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Investigation Tool - Spawn Claude Code agents to investigate local repos
|
|
4
|
-
*
|
|
5
|
-
* Uses `claude -p` (headless mode, subscription-based) to autonomously
|
|
6
|
-
* explore codebases, search for bugs, and analyze code.
|
|
7
|
-
*/
|
|
8
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.investigateRepoTool = void 0;
|
|
10
|
-
const zod_1 = require("zod");
|
|
11
|
-
const child_process_1 = require("child_process");
|
|
12
|
-
const tool_registry_1 = require("../tool-registry");
|
|
13
|
-
const logger_1 = require("../../lib/logger");
|
|
14
|
-
const config_1 = require("../../config");
|
|
15
|
-
const logger = (0, logger_1.createLogger)({ component: 'investigate-tool' });
|
|
16
|
-
/**
|
|
17
|
-
* Resolve claude CLI path at module load
|
|
18
|
-
*/
|
|
19
|
-
const CLAUDE_BIN = (() => {
|
|
20
|
-
try {
|
|
21
|
-
return (0, child_process_1.execSync)('which claude', { encoding: 'utf-8' }).trim();
|
|
22
|
-
}
|
|
23
|
-
catch {
|
|
24
|
-
return 'claude'; // fallback to PATH lookup
|
|
25
|
-
}
|
|
26
|
-
})();
|
|
27
|
-
/**
|
|
28
|
-
* Parse DEV_AI_REPOS env var into a name->path map.
|
|
29
|
-
* Format: "name1:/path/one,name2:/path/two"
|
|
30
|
-
*/
|
|
31
|
-
function parseRepoPaths() {
|
|
32
|
-
const raw = config_1.environment.DEV_AI_REPOS;
|
|
33
|
-
const map = new Map();
|
|
34
|
-
if (!raw)
|
|
35
|
-
return map;
|
|
36
|
-
for (const entry of raw.split(',')) {
|
|
37
|
-
const colonIdx = entry.indexOf(':');
|
|
38
|
-
if (colonIdx === -1)
|
|
39
|
-
continue;
|
|
40
|
-
const name = entry.slice(0, colonIdx).trim();
|
|
41
|
-
const repoPath = entry.slice(colonIdx + 1).trim();
|
|
42
|
-
if (name && repoPath) {
|
|
43
|
-
map.set(name, repoPath);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
return map;
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Resolve a repo name to its local filesystem path.
|
|
50
|
-
*/
|
|
51
|
-
function resolveRepoPath(repoName) {
|
|
52
|
-
const repos = parseRepoPaths();
|
|
53
|
-
return repos.get(repoName) || null;
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Spawn `claude -p` in a repo directory and return its output.
|
|
57
|
-
*/
|
|
58
|
-
async function spawnInvestigation(prompt, cwd, maxTurns, repoName) {
|
|
59
|
-
const timeout = config_1.environment.DEV_AI_INVESTIGATION_TIMEOUT;
|
|
60
|
-
return new Promise((resolve, reject) => {
|
|
61
|
-
const proc = (0, child_process_1.spawn)(CLAUDE_BIN, [
|
|
62
|
-
'-p', prompt,
|
|
63
|
-
'--output-format', 'stream-json',
|
|
64
|
-
'--verbose',
|
|
65
|
-
'--allowedTools', 'Read,Glob,Grep,Bash,Task',
|
|
66
|
-
'--max-turns', String(maxTurns),
|
|
67
|
-
], {
|
|
68
|
-
cwd,
|
|
69
|
-
timeout,
|
|
70
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
71
|
-
env: {
|
|
72
|
-
...process.env,
|
|
73
|
-
// Strip MCP vars so investigation agent doesn't connect to our MCP server
|
|
74
|
-
MCP_SERVER_URL: undefined,
|
|
75
|
-
MCP_CLIENT_API_KEY: undefined,
|
|
76
|
-
MCP_CLIENT_ENABLED: undefined,
|
|
77
|
-
CLIENT_CONFIGS: undefined,
|
|
78
|
-
BOT_EMAIL: undefined,
|
|
79
|
-
BOT_PASSWORD: undefined,
|
|
80
|
-
BOT_API_BASE_URL: undefined,
|
|
81
|
-
ANTHROPIC_API_KEY: undefined,
|
|
82
|
-
},
|
|
83
|
-
});
|
|
84
|
-
let lineBuffer = '';
|
|
85
|
-
let resultText = '';
|
|
86
|
-
let stderr = '';
|
|
87
|
-
proc.stdout.on('data', (data) => {
|
|
88
|
-
lineBuffer += data.toString();
|
|
89
|
-
const lines = lineBuffer.split('\n');
|
|
90
|
-
lineBuffer = lines.pop() || ''; // Keep incomplete last line in buffer
|
|
91
|
-
for (const line of lines) {
|
|
92
|
-
const trimmed = line.trim();
|
|
93
|
-
if (!trimmed)
|
|
94
|
-
continue;
|
|
95
|
-
try {
|
|
96
|
-
const event = JSON.parse(trimmed);
|
|
97
|
-
if (event.type === 'system' && event.subtype === 'init') {
|
|
98
|
-
logger.debug(`[investigation:${repoName}] Agent initialized | tools: ${(event.tools || []).length} | model: ${event.model || 'unknown'}`);
|
|
99
|
-
}
|
|
100
|
-
else if (event.type === 'assistant' && event.message?.content) {
|
|
101
|
-
for (const block of event.message.content) {
|
|
102
|
-
if (block.type === 'tool_use') {
|
|
103
|
-
const inputStr = JSON.stringify(block.input || {});
|
|
104
|
-
logger.debug(`[investigation:${repoName}] Tool: ${block.name} ${inputStr.length > 200 ? inputStr.slice(0, 200) + '...' : inputStr}`);
|
|
105
|
-
}
|
|
106
|
-
else if (block.type === 'text') {
|
|
107
|
-
const text = (block.text || '').trim();
|
|
108
|
-
if (text) {
|
|
109
|
-
logger.debug(`[investigation:${repoName}] ${text.length > 300 ? text.slice(0, 300) + '...' : text}`);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
else if (event.type === 'tool') {
|
|
115
|
-
const content = typeof event.content === 'string' ? event.content : JSON.stringify(event.content || '');
|
|
116
|
-
logger.debug(`[investigation:${repoName}] Tool result (${event.tool_name}): ${content.length > 300 ? content.slice(0, 300) + '...' : content}`);
|
|
117
|
-
}
|
|
118
|
-
else if (event.type === 'result') {
|
|
119
|
-
resultText = event.result || '';
|
|
120
|
-
const cost = event.total_cost_usd ? `$${event.total_cost_usd.toFixed(4)}` : 'unknown';
|
|
121
|
-
const duration = event.duration_ms ? `${(event.duration_ms / 1000).toFixed(1)}s` : 'unknown';
|
|
122
|
-
logger.info(`[investigation:${repoName}] Complete | ${resultText.length} chars | ${duration} | cost: ${cost}`);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
catch {
|
|
126
|
-
// Non-JSON line
|
|
127
|
-
if (trimmed.length > 0) {
|
|
128
|
-
logger.debug(`[investigation:${repoName}] ${trimmed.length > 300 ? trimmed.slice(0, 300) + '...' : trimmed}`);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
proc.stderr.on('data', (data) => {
|
|
134
|
-
const chunk = data.toString();
|
|
135
|
-
stderr += chunk;
|
|
136
|
-
const trimmed = chunk.trim();
|
|
137
|
-
if (trimmed) {
|
|
138
|
-
logger.warn(`[investigation:${repoName}] ${trimmed.length > 500 ? trimmed.slice(0, 500) + '...' : trimmed}`);
|
|
139
|
-
}
|
|
140
|
-
});
|
|
141
|
-
proc.on('error', (err) => {
|
|
142
|
-
reject(new Error(`Failed to spawn claude: ${err.message}`));
|
|
143
|
-
});
|
|
144
|
-
proc.on('close', (code) => {
|
|
145
|
-
// Process any remaining data in lineBuffer
|
|
146
|
-
if (lineBuffer.trim()) {
|
|
147
|
-
try {
|
|
148
|
-
const event = JSON.parse(lineBuffer.trim());
|
|
149
|
-
if (event.type === 'result') {
|
|
150
|
-
resultText = event.result || '';
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
catch {
|
|
154
|
-
// ignore
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
if (code === 0) {
|
|
158
|
-
resolve(resultText || 'Investigation completed but returned no structured result.');
|
|
159
|
-
}
|
|
160
|
-
else {
|
|
161
|
-
const errDetail = stderr.trim() || `exit code ${code}`;
|
|
162
|
-
reject(new Error(`Investigation failed: ${errDetail}`));
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
}
|
|
167
|
-
const investigateRepoSchema = zod_1.z.object({
|
|
168
|
-
repoName: zod_1.z.string().describe('Target repo name (must match a configured repo). Available repos depend on DEV_AI_REPOS config.'),
|
|
169
|
-
prompt: zod_1.z.string().describe('What to investigate - bug description, search query, code question, etc.'),
|
|
170
|
-
maxTurns: zod_1.z.number().optional().default(30).describe('Max investigation depth (number of agentic turns). Default: 30.'),
|
|
171
|
-
});
|
|
172
|
-
exports.investigateRepoTool = {
|
|
173
|
-
name: 'investigate_repo',
|
|
174
|
-
group: tool_registry_1.ToolGroup.PLAYGROUND,
|
|
175
|
-
description: 'Spawn a Claude Code agent to investigate code in a local repo. ' +
|
|
176
|
-
'Uses claude -p (headless mode, subscription-based). ' +
|
|
177
|
-
'The agent can explore files, search code, analyze the codebase autonomously, ' +
|
|
178
|
-
'and spawn investigation teams for parallel exploration of complex issues. ' +
|
|
179
|
-
'Returns the investigation findings as text.',
|
|
180
|
-
schema: investigateRepoSchema,
|
|
181
|
-
async execute(args, _context) {
|
|
182
|
-
const repos = parseRepoPaths();
|
|
183
|
-
// If no repos configured, return helpful error
|
|
184
|
-
if (repos.size === 0) {
|
|
185
|
-
return {
|
|
186
|
-
content: [{
|
|
187
|
-
type: 'text',
|
|
188
|
-
text: 'No repos configured. Set DEV_AI_REPOS in .env.local (format: "name:/path,name2:/path2").',
|
|
189
|
-
}],
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
const repoPath = resolveRepoPath(args.repoName);
|
|
193
|
-
if (!repoPath) {
|
|
194
|
-
const available = Array.from(repos.keys()).join(', ');
|
|
195
|
-
return {
|
|
196
|
-
content: [{
|
|
197
|
-
type: 'text',
|
|
198
|
-
text: `Unknown repo: "${args.repoName}". Available repos: ${available}`,
|
|
199
|
-
}],
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
const enhancedPrompt = `You are a lead investigator. Use parallel agents to explore the codebase efficiently.
|
|
203
|
-
|
|
204
|
-
HOW TO USE PARALLEL AGENTS:
|
|
205
|
-
- Call multiple Task tools in a SINGLE response to run them in parallel
|
|
206
|
-
- Each Task call blocks until that agent finishes and returns its findings directly to you
|
|
207
|
-
- Use subagent_type: "Explore" with model: "haiku" — these are fast, read-only codebase search agents
|
|
208
|
-
- Do NOT use TeamCreate, SendMessage, or TaskCreate — just call Task directly
|
|
209
|
-
|
|
210
|
-
APPROACH:
|
|
211
|
-
1. In your FIRST response, call 2-3 Task tools simultaneously, each with a focused search prompt
|
|
212
|
-
2. You will receive all their findings in the next turn
|
|
213
|
-
3. If needed, do additional targeted searches yourself with Grep/Read
|
|
214
|
-
4. Write your FINAL REPORT
|
|
215
|
-
|
|
216
|
-
REPORT FORMAT:
|
|
217
|
-
- Root cause of the issue
|
|
218
|
-
- Affected files with paths and line numbers
|
|
219
|
-
- Suggested fix with specific code changes
|
|
220
|
-
|
|
221
|
-
INVESTIGATION TASK:
|
|
222
|
-
${args.prompt}`;
|
|
223
|
-
logger.info('Starting investigation', {
|
|
224
|
-
repo: args.repoName,
|
|
225
|
-
repoPath,
|
|
226
|
-
maxTurns: args.maxTurns,
|
|
227
|
-
promptLength: enhancedPrompt.length,
|
|
228
|
-
});
|
|
229
|
-
try {
|
|
230
|
-
const result = await spawnInvestigation(enhancedPrompt, repoPath, args.maxTurns, args.repoName);
|
|
231
|
-
logger.info('Investigation completed', {
|
|
232
|
-
repo: args.repoName,
|
|
233
|
-
resultLength: result.length,
|
|
234
|
-
});
|
|
235
|
-
return {
|
|
236
|
-
content: [{
|
|
237
|
-
type: 'text',
|
|
238
|
-
text: result || 'Investigation completed but returned no output.',
|
|
239
|
-
}],
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
catch (error) {
|
|
243
|
-
const errMsg = error instanceof Error ? error.message : String(error);
|
|
244
|
-
logger.error('Investigation failed', { repo: args.repoName, error: errMsg });
|
|
245
|
-
return {
|
|
246
|
-
content: [{
|
|
247
|
-
type: 'text',
|
|
248
|
-
text: `Investigation failed: ${errMsg}`,
|
|
249
|
-
}],
|
|
250
|
-
};
|
|
251
|
-
}
|
|
252
|
-
},
|
|
253
|
-
};
|
|
254
|
-
//# sourceMappingURL=investigate.js.map
|
package/inbox/failures.log
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
[2026-02-16T05:32:29.204Z] agent-giuseppe-app-builder | skill | hailer-mcp | \"Field '{fieldLabel}' expects Unix ms timestamp (number), got: '{value}'. Convert the date to milliseconds first.\"\n```\n\n**Important:**\n- Read th
|
package/inbox/usage.jsonl
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
{"ts":"2026-02-13T08:23:26.264Z","agent":"general-purpose","status":"unknown","project":"hailer-mcp","description":"Convert new agents to OpenCode"}
|
|
2
|
-
{"ts":"2026-02-16T05:26:20.980Z","agent":"agent-svetlana-code-review","status":"unknown","project":"hailer-mcp","description":"Check bot date handling code"}
|
|
3
|
-
{"ts":"2026-02-16T05:32:29.203Z","agent":"agent-giuseppe-app-builder","status":"error","project":"hailer-mcp","description":"Add date validation to bot+tools"}
|