@hailer/mcp 0.1.11 → 0.1.12

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.
Files changed (62) hide show
  1. package/.claude/settings.json +12 -0
  2. package/CLAUDE.md +37 -1
  3. package/ai-hub/dist/assets/index-8ce6041d.css +1 -0
  4. package/ai-hub/dist/assets/index-930f01ca.js +348 -0
  5. package/ai-hub/dist/index.html +15 -0
  6. package/ai-hub/dist/manifest.json +14 -0
  7. package/ai-hub/dist/vite.svg +1 -0
  8. package/dist/app.js +5 -0
  9. package/dist/client/agents/base.d.ts +5 -0
  10. package/dist/client/agents/base.js +9 -2
  11. package/dist/client/agents/definitions.js +85 -0
  12. package/dist/client/agents/orchestrator.d.ts +21 -0
  13. package/dist/client/agents/orchestrator.js +292 -1
  14. package/dist/client/bot-entrypoint.d.ts +7 -0
  15. package/dist/client/bot-entrypoint.js +103 -0
  16. package/dist/client/bot-runner.d.ts +35 -0
  17. package/dist/client/bot-runner.js +188 -0
  18. package/dist/client/factory.d.ts +4 -0
  19. package/dist/client/factory.js +10 -0
  20. package/dist/client/server.d.ts +8 -0
  21. package/dist/client/server.js +251 -0
  22. package/dist/client/types.d.ts +29 -0
  23. package/dist/client/types.js +4 -1
  24. package/dist/core.d.ts +3 -0
  25. package/dist/core.js +72 -0
  26. package/dist/mcp/hailer-clients.d.ts +4 -0
  27. package/dist/mcp/hailer-clients.js +16 -1
  28. package/dist/mcp/tools/app-scaffold.js +127 -5
  29. package/dist/mcp/tools/bot-config.d.ts +78 -0
  30. package/dist/mcp/tools/bot-config.js +442 -0
  31. package/dist/mcp-server.js +109 -1
  32. package/dist/modules/bug-reports/bug-config.d.ts +25 -0
  33. package/dist/modules/bug-reports/bug-config.js +187 -0
  34. package/dist/modules/bug-reports/bug-monitor.d.ts +108 -0
  35. package/dist/modules/bug-reports/bug-monitor.js +510 -0
  36. package/dist/modules/bug-reports/giuseppe-ai.d.ts +59 -0
  37. package/dist/modules/bug-reports/giuseppe-ai.js +335 -0
  38. package/dist/modules/bug-reports/giuseppe-bot.d.ts +109 -0
  39. package/dist/modules/bug-reports/giuseppe-bot.js +765 -0
  40. package/dist/modules/bug-reports/giuseppe-files.d.ts +52 -0
  41. package/dist/modules/bug-reports/giuseppe-files.js +338 -0
  42. package/dist/modules/bug-reports/giuseppe-git.d.ts +48 -0
  43. package/dist/modules/bug-reports/giuseppe-git.js +298 -0
  44. package/dist/modules/bug-reports/giuseppe-prompt.d.ts +5 -0
  45. package/dist/modules/bug-reports/giuseppe-prompt.js +94 -0
  46. package/dist/modules/bug-reports/index.d.ts +76 -0
  47. package/dist/modules/bug-reports/index.js +213 -0
  48. package/dist/modules/bug-reports/pending-classification-registry.d.ts +28 -0
  49. package/dist/modules/bug-reports/pending-classification-registry.js +50 -0
  50. package/dist/modules/bug-reports/pending-fix-registry.d.ts +30 -0
  51. package/dist/modules/bug-reports/pending-fix-registry.js +42 -0
  52. package/dist/modules/bug-reports/pending-registry.d.ts +27 -0
  53. package/dist/modules/bug-reports/pending-registry.js +49 -0
  54. package/dist/modules/bug-reports/types.d.ts +123 -0
  55. package/dist/modules/bug-reports/types.js +9 -0
  56. package/dist/services/bug-monitor.d.ts +23 -0
  57. package/dist/services/bug-monitor.js +275 -0
  58. package/lineup-manager/dist/assets/index-b30c809f.js +600 -0
  59. package/lineup-manager/dist/index.html +1 -1
  60. package/lineup-manager/dist/manifest.json +5 -5
  61. package/package.json +6 -2
  62. package/lineup-manager/dist/assets/index-e168f265.js +0 -600
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Giuseppe Files Module - File scanning, reading, and modification
3
+ */
4
+ import type { BugReport, AppRegistryEntry } from './types';
5
+ import type { FixPlan } from './giuseppe-ai';
6
+ export interface FileContent {
7
+ path: string;
8
+ content: string;
9
+ }
10
+ export interface ApplyResult {
11
+ success: boolean;
12
+ files: string[];
13
+ error?: string;
14
+ }
15
+ export interface ScannedApp {
16
+ path: string;
17
+ name: string;
18
+ appId?: string;
19
+ }
20
+ export declare class GiuseppeFiles {
21
+ private appsBasePath?;
22
+ constructor(appsBasePath?: string);
23
+ /**
24
+ * Check if file exists
25
+ */
26
+ fileExists(filePath: string): Promise<boolean>;
27
+ /**
28
+ * Scan for source file NAMES only (no content)
29
+ */
30
+ scanSourceFiles(projectPath: string): Promise<string[]>;
31
+ /**
32
+ * Read specific files by path
33
+ */
34
+ readSelectedFiles(projectPath: string, filePaths: string[]): Promise<FileContent[]>;
35
+ /**
36
+ * Find relevant files by searching for keywords from feedback/bug
37
+ */
38
+ findRelevantFiles(projectPath: string, feedback: string, bug: BugReport): Promise<string[]>;
39
+ /**
40
+ * Apply fixes to files
41
+ */
42
+ applyFixes(app: AppRegistryEntry, fixes: FixPlan['fix']['files']): Promise<ApplyResult>;
43
+ /**
44
+ * Scan apps directory for projects
45
+ */
46
+ scanAppsDirectory(): Promise<ScannedApp[]>;
47
+ /**
48
+ * Find app project by appId, appName, or bug title
49
+ */
50
+ findAppProject(bug: BugReport, appsRegistry: Map<string, AppRegistryEntry>): Promise<AppRegistryEntry | null>;
51
+ }
52
+ //# sourceMappingURL=giuseppe-files.d.ts.map
@@ -0,0 +1,338 @@
1
+ "use strict";
2
+ /**
3
+ * Giuseppe Files Module - File scanning, reading, and modification
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.GiuseppeFiles = void 0;
40
+ const child_process_1 = require("child_process");
41
+ const fs = __importStar(require("fs/promises"));
42
+ const path = __importStar(require("path"));
43
+ const logger_1 = require("../../lib/logger");
44
+ const logger = (0, logger_1.createLogger)({ component: 'giuseppe-files' });
45
+ /**
46
+ * Escape shell metacharacters to prevent command injection
47
+ */
48
+ function escapeShellArg(arg) {
49
+ return arg.replace(/["\$`\\!]/g, '\\$&');
50
+ }
51
+ class GiuseppeFiles {
52
+ appsBasePath;
53
+ constructor(appsBasePath) {
54
+ this.appsBasePath = appsBasePath;
55
+ }
56
+ /**
57
+ * Check if file exists
58
+ */
59
+ async fileExists(filePath) {
60
+ try {
61
+ await fs.access(filePath);
62
+ return true;
63
+ }
64
+ catch {
65
+ return false;
66
+ }
67
+ }
68
+ /**
69
+ * Scan for source file NAMES only (no content)
70
+ */
71
+ async scanSourceFiles(projectPath) {
72
+ const files = [];
73
+ const extensions = ['.tsx', '.ts', '.jsx', '.js', '.css', '.scss'];
74
+ const ignoreDirs = ['node_modules', 'dist', 'build', '.git', 'coverage', '.next', 'public'];
75
+ const scanDir = async (dir, depth = 0) => {
76
+ if (depth > 5)
77
+ return;
78
+ try {
79
+ const entries = await fs.readdir(dir, { withFileTypes: true });
80
+ for (const entry of entries) {
81
+ const fullPath = path.join(dir, entry.name);
82
+ const relativePath = path.relative(projectPath, fullPath);
83
+ if (entry.isDirectory()) {
84
+ if (!ignoreDirs.includes(entry.name) && !entry.name.startsWith('.')) {
85
+ await scanDir(fullPath, depth + 1);
86
+ }
87
+ }
88
+ else if (extensions.some(ext => entry.name.endsWith(ext))) {
89
+ // Skip test files
90
+ if (!entry.name.includes('.test.') && !entry.name.includes('.spec.')) {
91
+ files.push(relativePath);
92
+ }
93
+ }
94
+ }
95
+ }
96
+ catch {
97
+ // Skip unreadable directories
98
+ }
99
+ };
100
+ await scanDir(projectPath);
101
+ return files;
102
+ }
103
+ /**
104
+ * Read specific files by path
105
+ */
106
+ async readSelectedFiles(projectPath, filePaths) {
107
+ const files = [];
108
+ for (const filePath of filePaths) {
109
+ try {
110
+ const fullPath = path.join(projectPath, filePath);
111
+ const content = await fs.readFile(fullPath, 'utf-8');
112
+ files.push({ path: filePath, content });
113
+ logger.debug('Read file', { path: filePath, size: content.length });
114
+ }
115
+ catch (error) {
116
+ logger.warn('Could not read file', { path: filePath, error });
117
+ }
118
+ }
119
+ return files;
120
+ }
121
+ /**
122
+ * Find relevant files by searching for keywords from feedback/bug
123
+ */
124
+ async findRelevantFiles(projectPath, feedback, bug) {
125
+ const relevantFiles = new Set();
126
+ // Extract keywords from feedback and bug description
127
+ const text = `${feedback} ${bug.name} ${bug.description || ''} ${bug.stepsToReproduce || ''}`;
128
+ // Find component names (PascalCase words)
129
+ const componentMatches = text.match(/[A-Z][a-zA-Z]+(?:Tool|Button|Modal|Panel|Canvas|Toolbar|Card|Slot)?/g) || [];
130
+ // Find function/variable names (camelCase or specific keywords)
131
+ const functionMatches = text.match(/(?:handle|on|set|get|use)[A-Z][a-zA-Z]+|delete|remove|add|select|click|drag|drop|cursor/gi) || [];
132
+ const keywords = [...new Set([...componentMatches, ...functionMatches])];
133
+ // Search for each keyword using grep
134
+ for (const keyword of keywords.slice(0, 10)) { // Limit searches
135
+ try {
136
+ const escapedKeyword = escapeShellArg(keyword);
137
+ const result = (0, child_process_1.execSync)(`git grep -l "${escapedKeyword}" -- "*.tsx" "*.ts" 2>/dev/null || true`, { cwd: projectPath, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
138
+ result.trim().split('\n').filter(f => f).forEach(f => relevantFiles.add(f));
139
+ }
140
+ catch {
141
+ // Ignore grep errors
142
+ }
143
+ }
144
+ return Array.from(relevantFiles);
145
+ }
146
+ /**
147
+ * Apply fixes to files
148
+ */
149
+ async applyFixes(app, fixes) {
150
+ const modifiedFiles = [];
151
+ try {
152
+ for (const fix of fixes) {
153
+ const filePath = path.join(app.projectPath, fix.path);
154
+ if (fix.action === 'edit' && fix.search && fix.replace !== undefined) {
155
+ // Check file exists before reading
156
+ if (!await this.fileExists(filePath)) {
157
+ return {
158
+ success: false,
159
+ files: modifiedFiles,
160
+ error: `File not found: ${fix.path} - check the path is correct`
161
+ };
162
+ }
163
+ const content = await fs.readFile(filePath, 'utf-8');
164
+ // Try exact match first
165
+ if (content.includes(fix.search)) {
166
+ const newContent = content.replace(fix.search, fix.replace);
167
+ await fs.writeFile(filePath, newContent, 'utf-8');
168
+ modifiedFiles.push(fix.path);
169
+ }
170
+ else {
171
+ // Try normalized whitespace match
172
+ const normalizeWs = (s) => s.replace(/\s+/g, ' ').trim();
173
+ const normalizedContent = normalizeWs(content);
174
+ const normalizedSearch = normalizeWs(fix.search);
175
+ if (normalizedContent.includes(normalizedSearch)) {
176
+ // Find the actual line(s) to replace using line-by-line search
177
+ const searchLines = fix.search.split('\n').map(l => l.trim()).filter(l => l);
178
+ const contentLines = content.split('\n');
179
+ let found = false;
180
+ for (let i = 0; i <= contentLines.length - searchLines.length; i++) {
181
+ const candidateLines = contentLines.slice(i, i + searchLines.length);
182
+ if (candidateLines.every((line, j) => line.trim() === searchLines[j])) {
183
+ // Found match - replace these lines
184
+ const before = contentLines.slice(0, i);
185
+ const after = contentLines.slice(i + searchLines.length);
186
+ const replaceLines = fix.replace.split('\n');
187
+ const newContent = [...before, ...replaceLines, ...after].join('\n');
188
+ await fs.writeFile(filePath, newContent, 'utf-8');
189
+ modifiedFiles.push(fix.path);
190
+ found = true;
191
+ break;
192
+ }
193
+ }
194
+ if (!found) {
195
+ return {
196
+ success: false,
197
+ files: modifiedFiles,
198
+ error: `Search string not found in ${fix.path} (whitespace mismatch)`
199
+ };
200
+ }
201
+ }
202
+ else {
203
+ return {
204
+ success: false,
205
+ files: modifiedFiles,
206
+ error: `Search string not found in ${fix.path}`
207
+ };
208
+ }
209
+ }
210
+ }
211
+ else if (fix.action === 'create' && fix.content) {
212
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
213
+ await fs.writeFile(filePath, fix.content, 'utf-8');
214
+ modifiedFiles.push(fix.path);
215
+ }
216
+ else if (fix.action === 'delete') {
217
+ await fs.unlink(filePath);
218
+ modifiedFiles.push(fix.path);
219
+ }
220
+ }
221
+ return { success: true, files: modifiedFiles };
222
+ }
223
+ catch (error) {
224
+ return {
225
+ success: false,
226
+ files: modifiedFiles,
227
+ error: error instanceof Error ? error.message : String(error)
228
+ };
229
+ }
230
+ }
231
+ /**
232
+ * Scan apps directory for projects
233
+ */
234
+ async scanAppsDirectory() {
235
+ if (!this.appsBasePath) {
236
+ logger.warn('DEV_APPS_PATH not set - cannot scan for apps');
237
+ return [];
238
+ }
239
+ logger.debug('Scanning apps directory', { path: this.appsBasePath });
240
+ const results = [];
241
+ try {
242
+ const entries = await fs.readdir(this.appsBasePath, { withFileTypes: true });
243
+ for (const entry of entries) {
244
+ if (entry.isDirectory()) {
245
+ const projectPath = path.join(this.appsBasePath, entry.name);
246
+ const manifestPath = path.join(projectPath, 'manifest.json');
247
+ try {
248
+ const manifestContent = await fs.readFile(manifestPath, 'utf-8');
249
+ const manifest = JSON.parse(manifestContent);
250
+ results.push({
251
+ path: projectPath,
252
+ name: manifest.name || entry.name,
253
+ appId: manifest.appId
254
+ });
255
+ }
256
+ catch {
257
+ // No manifest, just use directory name
258
+ results.push({
259
+ path: projectPath,
260
+ name: entry.name
261
+ });
262
+ }
263
+ }
264
+ }
265
+ }
266
+ catch (error) {
267
+ logger.warn('Failed to scan apps directory', { error });
268
+ }
269
+ logger.debug('Found apps', { count: results.length, apps: results.map(a => a.name) });
270
+ return results;
271
+ }
272
+ /**
273
+ * Find app project by appId, appName, or bug title
274
+ */
275
+ async findAppProject(bug, appsRegistry) {
276
+ // 1. Check registry first
277
+ if (bug.appId && appsRegistry.has(bug.appId)) {
278
+ return appsRegistry.get(bug.appId);
279
+ }
280
+ // 2. Try to find by appId in apps directory
281
+ if (this.appsBasePath && bug.appId) {
282
+ const apps = await this.scanAppsDirectory();
283
+ for (const app of apps) {
284
+ if (app.appId === bug.appId) {
285
+ return {
286
+ projectPath: app.path,
287
+ name: app.name
288
+ };
289
+ }
290
+ }
291
+ }
292
+ // 3. Try to find by app name
293
+ if (this.appsBasePath && bug.appName) {
294
+ const apps = await this.scanAppsDirectory();
295
+ for (const app of apps) {
296
+ if (app.name.toLowerCase().includes(bug.appName.toLowerCase())) {
297
+ return {
298
+ projectPath: app.path,
299
+ name: app.name
300
+ };
301
+ }
302
+ }
303
+ }
304
+ // 4. Try to extract app name from bug title (e.g., "Bug Report - Lineup Manager")
305
+ if (this.appsBasePath) {
306
+ const apps = await this.scanAppsDirectory();
307
+ const bugTitle = bug.name.toLowerCase();
308
+ for (const app of apps) {
309
+ const appNameLower = app.name.toLowerCase();
310
+ // Check if app name appears in bug title
311
+ if (bugTitle.includes(appNameLower) ||
312
+ bugTitle.includes(appNameLower.replace(/-/g, ' ')) ||
313
+ bugTitle.includes(appNameLower.replace(/_/g, ' '))) {
314
+ logger.info('Found app from bug title', { bugTitle: bug.name, appName: app.name });
315
+ return {
316
+ projectPath: app.path,
317
+ name: app.name
318
+ };
319
+ }
320
+ }
321
+ // Also try matching directory name directly
322
+ for (const app of apps) {
323
+ const dirName = app.path.split('/').pop()?.toLowerCase() || '';
324
+ if (bugTitle.includes(dirName) ||
325
+ bugTitle.includes(dirName.replace(/-/g, ' '))) {
326
+ logger.info('Found app from directory name', { bugTitle: bug.name, dirName });
327
+ return {
328
+ projectPath: app.path,
329
+ name: app.name
330
+ };
331
+ }
332
+ }
333
+ }
334
+ return null;
335
+ }
336
+ }
337
+ exports.GiuseppeFiles = GiuseppeFiles;
338
+ //# sourceMappingURL=giuseppe-files.js.map
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Giuseppe Git Module - Git operations for committing, reverting, tagging
3
+ */
4
+ import type { BugReport, AppRegistryEntry } from './types';
5
+ export declare class GiuseppeGit {
6
+ /**
7
+ * Get source files using git ls-files (fast and accurate)
8
+ */
9
+ getSourceFilesFromGit(projectPath: string): Promise<string[]>;
10
+ /**
11
+ * Commit changes to git
12
+ */
13
+ commitChanges(app: AppRegistryEntry, bug: BugReport): Promise<{
14
+ success: boolean;
15
+ hash?: string;
16
+ }>;
17
+ /**
18
+ * Revert changes using git checkout
19
+ */
20
+ revertChanges(app: AppRegistryEntry, files: string[]): Promise<void>;
21
+ /**
22
+ * Get latest version from git tags (e.g., v1.0.1 -> 1.0.1)
23
+ * Returns null if no version tags found
24
+ */
25
+ getLatestVersionFromTags(projectPath: string): string | null;
26
+ /**
27
+ * Create and push a version tag after successful publish
28
+ */
29
+ createVersionTag(projectPath: string, version: string): boolean;
30
+ /**
31
+ * Bump patch version in manifest.json (bug fixes always bump patch)
32
+ * Uses git tags to determine latest version, falls back to manifest
33
+ * 1.0.0 -> 1.0.1 -> 1.0.2 etc.
34
+ */
35
+ bumpPatchVersion(projectPath: string): Promise<{
36
+ oldVersion: string;
37
+ newVersion: string;
38
+ } | null>;
39
+ /**
40
+ * Push to git remote
41
+ */
42
+ push(projectPath: string): Promise<boolean>;
43
+ /**
44
+ * Stage and commit version bump
45
+ */
46
+ commitVersionBump(projectPath: string, version: string): Promise<boolean>;
47
+ }
48
+ //# sourceMappingURL=giuseppe-git.d.ts.map