@hailer/mcp 1.1.12 → 1.1.13
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/CHANGELOG.md +0 -7
- package/{.claude → dist}/CLAUDE.md +2 -2
- package/dist/app.js +18 -5
- package/dist/bot/bot-config.d.ts +10 -1
- package/dist/bot/bot-config.js +64 -3
- package/dist/bot/bot-manager.d.ts +2 -0
- package/dist/bot/bot-manager.js +9 -2
- package/dist/bot/bot.d.ts +33 -0
- package/dist/bot/bot.js +461 -160
- package/dist/bot/services/message-classifier.js +17 -0
- package/dist/bot/services/permission-guard.d.ts +52 -0
- package/dist/bot/services/permission-guard.js +149 -0
- package/dist/bot/services/types.d.ts +5 -0
- package/dist/bot/services/typing-indicator.d.ts +6 -1
- package/dist/bot/services/typing-indicator.js +19 -3
- package/dist/cli.js +0 -0
- package/dist/config.d.ts +6 -1
- package/dist/config.js +43 -0
- package/dist/core.js +3 -6
- package/dist/lib/discussion-lock.d.ts +42 -0
- package/dist/lib/discussion-lock.js +110 -0
- package/dist/mcp/UserContextCache.d.ts +5 -0
- package/dist/mcp/UserContextCache.js +51 -19
- package/dist/mcp/hailer-clients.d.ts +19 -1
- package/dist/mcp/hailer-clients.js +158 -24
- package/dist/mcp/session-store.d.ts +68 -0
- package/dist/mcp/session-store.js +169 -0
- package/dist/mcp/signal-handler.js +2 -0
- package/dist/mcp/tool-registry.d.ts +17 -4
- package/dist/mcp/tool-registry.js +37 -7
- package/dist/mcp/tools/activity.js +99 -7
- package/dist/mcp/tools/app-scaffold.js +304 -336
- package/dist/mcp/tools/bot-config/constants.d.ts +23 -0
- package/dist/mcp/tools/bot-config/constants.js +94 -0
- package/dist/mcp/tools/bot-config/core.d.ts +253 -0
- package/dist/mcp/tools/bot-config/core.js +2456 -0
- package/dist/mcp/tools/bot-config/index.d.ts +10 -0
- package/dist/mcp/tools/bot-config/index.js +59 -0
- package/dist/mcp/tools/bot-config/tools.d.ts +7 -0
- package/dist/mcp/tools/bot-config/tools.js +15 -0
- package/dist/mcp/tools/bot-config/types.d.ts +50 -0
- package/dist/mcp/tools/bot-config/types.js +6 -0
- package/dist/mcp/tools/bug-fixer-tools.d.ts +45 -0
- package/dist/mcp/tools/bug-fixer-tools.js +1096 -0
- package/dist/mcp/tools/company.d.ts +9 -0
- package/dist/mcp/tools/company.js +88 -0
- package/dist/mcp/tools/discussion.js +68 -0
- package/dist/mcp/tools/document.d.ts +11 -0
- package/dist/mcp/tools/document.js +741 -0
- package/dist/mcp/tools/investigate.d.ts +9 -0
- package/dist/mcp/tools/investigate.js +254 -0
- package/dist/mcp/tools/workflow-permissions.d.ts +15 -0
- package/dist/mcp/tools/workflow-permissions.js +204 -0
- package/dist/mcp/tools/workflow.js +57 -18
- package/dist/mcp/utils/index.d.ts +2 -0
- package/dist/mcp/utils/index.js +12 -1
- package/dist/mcp/utils/role-utils.d.ts +74 -0
- package/dist/mcp/utils/role-utils.js +151 -0
- package/dist/mcp/utils/types.d.ts +43 -1
- package/dist/mcp/utils/types.js +14 -0
- package/dist/mcp/webhook-handler.d.ts +4 -0
- package/dist/mcp/webhook-handler.js +8 -0
- package/dist/mcp-server.d.ts +23 -2
- package/dist/mcp-server.js +639 -127
- package/dist/plugins/vipunen/client.d.ts +150 -0
- package/dist/plugins/vipunen/client.js +535 -0
- package/dist/plugins/vipunen/config/schema-config.json +19 -0
- package/dist/plugins/vipunen/config/schema-doc.json +22 -0
- package/dist/plugins/vipunen/index.d.ts +41 -0
- package/dist/plugins/vipunen/index.js +88 -0
- package/dist/plugins/vipunen/tools.d.ts +26 -0
- package/dist/plugins/vipunen/tools.js +501 -0
- package/dist/stdio-server.d.ts +14 -0
- package/dist/stdio-server.js +101 -0
- package/package.json +2 -1
- package/.claude/agents/agent-ada-skill-builder.md +0 -94
- package/.claude/agents/agent-alejandro-function-fields.md +0 -342
- package/.claude/agents/agent-bjorn-config-audit.md +0 -103
- package/.claude/agents/agent-builder-agent-creator.md +0 -130
- package/.claude/agents/agent-code-simplifier.md +0 -53
- package/.claude/agents/agent-dmitri-activity-crud.md +0 -159
- package/.claude/agents/agent-giuseppe-app-builder.md +0 -247
- package/.claude/agents/agent-gunther-mcp-tools.md +0 -39
- package/.claude/agents/agent-helga-workflow-config.md +0 -204
- package/.claude/agents/agent-igor-activity-mover-automation.md +0 -125
- package/.claude/agents/agent-ingrid-doc-templates.md +0 -261
- package/.claude/agents/agent-ivan-monolith.md +0 -154
- package/.claude/agents/agent-kenji-data-reader.md +0 -86
- package/.claude/agents/agent-lars-code-inspector.md +0 -102
- package/.claude/agents/agent-marco-mockup-builder.md +0 -110
- package/.claude/agents/agent-marcus-api-documenter.md +0 -323
- package/.claude/agents/agent-marketplace-publisher.md +0 -280
- package/.claude/agents/agent-marketplace-reviewer.md +0 -309
- package/.claude/agents/agent-permissions-handler.md +0 -208
- package/.claude/agents/agent-simple-writer.md +0 -48
- package/.claude/agents/agent-svetlana-code-review.md +0 -171
- package/.claude/agents/agent-tanya-test-runner.md +0 -333
- package/.claude/agents/agent-ui-designer.md +0 -100
- package/.claude/agents/agent-viktor-sql-insights.md +0 -212
- package/.claude/agents/agent-web-search.md +0 -55
- package/.claude/agents/agent-yevgeni-discussions.md +0 -45
- package/.claude/agents/agent-zara-zapier.md +0 -159
- package/.claude/commands/app-squad.md +0 -135
- package/.claude/commands/audit-squad.md +0 -158
- package/.claude/commands/autoplan.md +0 -563
- package/.claude/commands/cleanup-squad.md +0 -98
- package/.claude/commands/config-squad.md +0 -106
- package/.claude/commands/crud-squad.md +0 -87
- package/.claude/commands/data-squad.md +0 -97
- package/.claude/commands/debug-squad.md +0 -303
- package/.claude/commands/doc-squad.md +0 -65
- package/.claude/commands/handoff.md +0 -137
- package/.claude/commands/health.md +0 -49
- package/.claude/commands/help.md +0 -29
- package/.claude/commands/help:agents.md +0 -151
- package/.claude/commands/help:commands.md +0 -78
- package/.claude/commands/help:faq.md +0 -79
- package/.claude/commands/help:plugins.md +0 -50
- package/.claude/commands/help:skills.md +0 -93
- package/.claude/commands/help:tools.md +0 -75
- package/.claude/commands/hotfix-squad.md +0 -112
- package/.claude/commands/integration-squad.md +0 -82
- package/.claude/commands/janitor-squad.md +0 -167
- package/.claude/commands/learn-auto.md +0 -120
- package/.claude/commands/learn.md +0 -120
- package/.claude/commands/mcp-list.md +0 -27
- package/.claude/commands/onboard-squad.md +0 -140
- package/.claude/commands/plan-workspace.md +0 -732
- package/.claude/commands/prd.md +0 -130
- package/.claude/commands/project-status.md +0 -82
- package/.claude/commands/publish.md +0 -138
- package/.claude/commands/recap.md +0 -69
- package/.claude/commands/restore.md +0 -64
- package/.claude/commands/review-squad.md +0 -152
- package/.claude/commands/save.md +0 -24
- package/.claude/commands/stats.md +0 -19
- package/.claude/commands/swarm.md +0 -210
- package/.claude/commands/tool-builder.md +0 -39
- package/.claude/commands/ws-pull.md +0 -44
- package/.claude/hooks/_shared-memory.cjs +0 -305
- package/.claude/hooks/_utils.cjs +0 -108
- package/.claude/hooks/agent-failure-detector.cjs +0 -383
- package/.claude/hooks/agent-usage-logger.cjs +0 -204
- package/.claude/hooks/app-edit-guard.cjs +0 -494
- package/.claude/hooks/auto-learn.cjs +0 -304
- package/.claude/hooks/bash-guard.cjs +0 -272
- package/.claude/hooks/builder-mode-manager.cjs +0 -354
- package/.claude/hooks/bulk-activity-guard.cjs +0 -271
- package/.claude/hooks/context-watchdog.cjs +0 -230
- package/.claude/hooks/delegation-reminder.cjs +0 -465
- package/.claude/hooks/design-system-lint.cjs +0 -271
- package/.claude/hooks/post-scaffold-hook.cjs +0 -181
- package/.claude/hooks/prompt-guard.cjs +0 -354
- package/.claude/hooks/publish-template-guard.cjs +0 -147
- package/.claude/hooks/session-start.cjs +0 -35
- package/.claude/hooks/shared-memory-writer.cjs +0 -147
- package/.claude/hooks/skill-injector.cjs +0 -140
- package/.claude/hooks/skill-usage-logger.cjs +0 -258
- package/.claude/hooks/src-edit-guard.cjs +0 -240
- package/.claude/hooks/sync-marketplace-agents.cjs +0 -346
- package/.claude/settings.json +0 -257
- package/.claude/skills/SDK-activity-patterns/SKILL.md +0 -428
- package/.claude/skills/SDK-document-templates/SKILL.md +0 -1033
- package/.claude/skills/SDK-function-fields/SKILL.md +0 -542
- package/.claude/skills/SDK-generate-skill/SKILL.md +0 -92
- package/.claude/skills/SDK-init-skill/SKILL.md +0 -127
- package/.claude/skills/SDK-insight-queries/SKILL.md +0 -787
- package/.claude/skills/SDK-ws-config-skill/SKILL.md +0 -1139
- package/.claude/skills/agent-structure/SKILL.md +0 -98
- package/.claude/skills/api-documentation-patterns/SKILL.md +0 -474
- package/.claude/skills/chrome-mcp-reference/SKILL.md +0 -370
- package/.claude/skills/delegation-routing/SKILL.md +0 -202
- package/.claude/skills/frontend-design/SKILL.md +0 -254
- package/.claude/skills/hailer-activity-mover/SKILL.md +0 -213
- package/.claude/skills/hailer-api-client/SKILL.md +0 -518
- package/.claude/skills/hailer-app-builder/SKILL.md +0 -1434
- package/.claude/skills/hailer-apps-pictures/SKILL.md +0 -269
- package/.claude/skills/hailer-design-system/SKILL.md +0 -235
- package/.claude/skills/hailer-monolith-automations/SKILL.md +0 -686
- package/.claude/skills/hailer-permissions-system/SKILL.md +0 -121
- package/.claude/skills/hailer-project-protocol/SKILL.md +0 -488
- package/.claude/skills/hailer-rest-api/SKILL.md +0 -61
- package/.claude/skills/hailer-rest-api/hailer-activities.md +0 -184
- package/.claude/skills/hailer-rest-api/hailer-admin.md +0 -473
- package/.claude/skills/hailer-rest-api/hailer-calendar.md +0 -256
- package/.claude/skills/hailer-rest-api/hailer-feed.md +0 -249
- package/.claude/skills/hailer-rest-api/hailer-insights.md +0 -195
- package/.claude/skills/hailer-rest-api/hailer-messaging.md +0 -276
- package/.claude/skills/hailer-rest-api/hailer-workflows.md +0 -283
- package/.claude/skills/insight-join-patterns/SKILL.md +0 -174
- package/.claude/skills/integration-patterns/SKILL.md +0 -421
- package/.claude/skills/json-only-output/SKILL.md +0 -72
- package/.claude/skills/lsp-setup/SKILL.md +0 -160
- package/.claude/skills/mcp-direct-tools/SKILL.md +0 -153
- package/.claude/skills/optional-parameters/SKILL.md +0 -72
- package/.claude/skills/publish-hailer-app/SKILL.md +0 -244
- package/.claude/skills/testing-patterns/SKILL.md +0 -630
- package/.claude/skills/tool-builder/SKILL.md +0 -250
- package/.claude/skills/tool-parameter-usage/SKILL.md +0 -126
- package/.claude/skills/tool-response-verification/SKILL.md +0 -92
- package/.claude/skills/zapier-hailer-patterns/SKILL.md +0 -581
- package/.mcp.json +0 -13
- package/.opencode/agent/agent-ada-skill-builder.md +0 -35
- package/.opencode/agent/agent-alejandro-function-fields.md +0 -39
- package/.opencode/agent/agent-bjorn-config-audit.md +0 -36
- package/.opencode/agent/agent-builder-agent-creator.md +0 -39
- package/.opencode/agent/agent-code-simplifier.md +0 -31
- package/.opencode/agent/agent-dmitri-activity-crud.md +0 -40
- package/.opencode/agent/agent-giuseppe-app-builder.md +0 -37
- package/.opencode/agent/agent-gunther-mcp-tools.md +0 -39
- package/.opencode/agent/agent-helga-workflow-config.md +0 -203
- package/.opencode/agent/agent-igor-activity-mover-automation.md +0 -46
- package/.opencode/agent/agent-ingrid-doc-templates.md +0 -39
- package/.opencode/agent/agent-ivan-monolith.md +0 -46
- package/.opencode/agent/agent-kenji-data-reader.md +0 -53
- package/.opencode/agent/agent-lars-code-inspector.md +0 -28
- package/.opencode/agent/agent-marco-mockup-builder.md +0 -42
- package/.opencode/agent/agent-marcus-api-documenter.md +0 -53
- package/.opencode/agent/agent-marketplace-publisher.md +0 -44
- package/.opencode/agent/agent-marketplace-reviewer.md +0 -42
- package/.opencode/agent/agent-permissions-handler.md +0 -50
- package/.opencode/agent/agent-simple-writer.md +0 -45
- package/.opencode/agent/agent-svetlana-code-review.md +0 -39
- package/.opencode/agent/agent-tanya-test-runner.md +0 -57
- package/.opencode/agent/agent-ui-designer.md +0 -56
- package/.opencode/agent/agent-viktor-sql-insights.md +0 -34
- package/.opencode/agent/agent-web-search.md +0 -42
- package/.opencode/agent/agent-yevgeni-discussions.md +0 -37
- package/.opencode/agent/agent-zara-zapier.md +0 -53
- package/.opencode/commands/app-squad.md +0 -135
- package/.opencode/commands/audit-squad.md +0 -158
- package/.opencode/commands/autoplan.md +0 -563
- package/.opencode/commands/cleanup-squad.md +0 -98
- package/.opencode/commands/config-squad.md +0 -106
- package/.opencode/commands/crud-squad.md +0 -87
- package/.opencode/commands/data-squad.md +0 -97
- package/.opencode/commands/debug-squad.md +0 -303
- package/.opencode/commands/doc-squad.md +0 -65
- package/.opencode/commands/handoff.md +0 -137
- package/.opencode/commands/health.md +0 -49
- package/.opencode/commands/help-agents.md +0 -151
- package/.opencode/commands/help-commands.md +0 -32
- package/.opencode/commands/help-faq.md +0 -29
- package/.opencode/commands/help-plugins.md +0 -28
- package/.opencode/commands/help-skills.md +0 -7
- package/.opencode/commands/help-tools.md +0 -40
- package/.opencode/commands/help.md +0 -28
- package/.opencode/commands/hotfix-squad.md +0 -112
- package/.opencode/commands/integration-squad.md +0 -82
- package/.opencode/commands/janitor-squad.md +0 -167
- package/.opencode/commands/learn-auto.md +0 -120
- package/.opencode/commands/learn.md +0 -120
- package/.opencode/commands/mcp-list.md +0 -27
- package/.opencode/commands/onboard-squad.md +0 -140
- package/.opencode/commands/plan-workspace.md +0 -732
- package/.opencode/commands/prd.md +0 -131
- package/.opencode/commands/project-status.md +0 -82
- package/.opencode/commands/publish.md +0 -138
- package/.opencode/commands/recap.md +0 -69
- package/.opencode/commands/restore.md +0 -64
- package/.opencode/commands/review-squad.md +0 -152
- package/.opencode/commands/save.md +0 -24
- package/.opencode/commands/stats.md +0 -19
- package/.opencode/commands/swarm.md +0 -210
- package/.opencode/commands/tool-builder.md +0 -39
- package/.opencode/commands/ws-pull.md +0 -44
- package/.opencode/opencode.json +0 -28
- package/SESSION-HANDOFF.md +0 -68
- package/inbox/2026-03-04-bot-config-patterns.md +0 -24
- package/scripts/postinstall.cjs +0 -64
- package/scripts/test-hal-tools.ts +0 -154
|
@@ -0,0 +1,1096 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Bug Fixer MCP Tools
|
|
4
|
+
*
|
|
5
|
+
* Bug-fixing tools for Bug Fixer specialist daemon.
|
|
6
|
+
* These tools handle file operations, git, and build commands.
|
|
7
|
+
*/
|
|
8
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
+
if (k2 === undefined) k2 = k;
|
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
}) : (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
}));
|
|
19
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
20
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
21
|
+
}) : function(o, v) {
|
|
22
|
+
o["default"] = v;
|
|
23
|
+
});
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.bugFixerTools = exports.markBugFixedTool = exports.markBugDeclinedTool = exports.bugFixerRetryFixTool = exports.bugFixerPublishFixTool = exports.bugFixerMarkDeclinedTool = exports.bugFixerStartFixTool = exports.bugFixerAnalyzeBugTool = exports.bugFixerPublishAppTool = exports.bugFixerGitRevertTool = exports.bugFixerGitPushTool = exports.bugFixerGitCommitTool = exports.bugFixerGitPullTool = exports.bugFixerGitStatusTool = exports.bugFixerRunBuildTool = exports.bugFixerApplyFixTool = exports.bugFixerWriteFileTool = exports.bugFixerReadFileTool = exports.bugFixerListFilesTool = exports.bugFixerFindAppTool = void 0;
|
|
43
|
+
const zod_1 = require("zod");
|
|
44
|
+
const child_process_1 = require("child_process");
|
|
45
|
+
const fs = __importStar(require("fs/promises"));
|
|
46
|
+
const path = __importStar(require("path"));
|
|
47
|
+
const tool_registry_1 = require("../tool-registry");
|
|
48
|
+
const logger_1 = require("../../lib/logger");
|
|
49
|
+
const config_1 = require("../../config");
|
|
50
|
+
const pending_classification_1 = require("../../agents/bug-fixer/registries/pending-classification");
|
|
51
|
+
const pending_fix_1 = require("../../agents/bug-fixer/registries/pending-fix");
|
|
52
|
+
const logger = (0, logger_1.createLogger)({ component: "bug-fixer-tools" });
|
|
53
|
+
// Parse all configured app paths
|
|
54
|
+
function getAppPaths() {
|
|
55
|
+
const paths = [];
|
|
56
|
+
// Multiple paths (comma-separated)
|
|
57
|
+
if (config_1.environment.DEV_APPS_PATHS) {
|
|
58
|
+
paths.push(...config_1.environment.DEV_APPS_PATHS.split(',').map(p => p.trim()).filter(p => p.length > 0));
|
|
59
|
+
}
|
|
60
|
+
// Single path (fallback)
|
|
61
|
+
if (config_1.environment.DEV_APPS_PATH && !paths.includes(config_1.environment.DEV_APPS_PATH)) {
|
|
62
|
+
paths.push(config_1.environment.DEV_APPS_PATH);
|
|
63
|
+
}
|
|
64
|
+
// Default to cwd if nothing configured
|
|
65
|
+
if (paths.length === 0) {
|
|
66
|
+
paths.push(process.cwd());
|
|
67
|
+
}
|
|
68
|
+
return paths;
|
|
69
|
+
}
|
|
70
|
+
// Cache for scanned apps
|
|
71
|
+
let appsCache = null;
|
|
72
|
+
// Helper to scan for apps across all configured directories
|
|
73
|
+
async function scanApps() {
|
|
74
|
+
// Return cached if available
|
|
75
|
+
if (appsCache)
|
|
76
|
+
return appsCache;
|
|
77
|
+
const apps = [];
|
|
78
|
+
const appPaths = getAppPaths();
|
|
79
|
+
for (const basePath of appPaths) {
|
|
80
|
+
try {
|
|
81
|
+
const entries = await fs.readdir(basePath, { withFileTypes: true });
|
|
82
|
+
for (const entry of entries) {
|
|
83
|
+
if (entry.isDirectory() && !entry.name.startsWith(".") && !["node_modules", "dist"].includes(entry.name)) {
|
|
84
|
+
const appPath = path.join(basePath, entry.name);
|
|
85
|
+
// Try to read manifest for appId
|
|
86
|
+
let manifest = null;
|
|
87
|
+
try {
|
|
88
|
+
const content = await fs.readFile(path.join(appPath, "manifest.json"), "utf-8");
|
|
89
|
+
manifest = JSON.parse(content);
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
try {
|
|
93
|
+
const content = await fs.readFile(path.join(appPath, "public", "manifest.json"), "utf-8");
|
|
94
|
+
manifest = JSON.parse(content);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// Not a Hailer app
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (manifest) {
|
|
101
|
+
apps.push({
|
|
102
|
+
name: manifest.name || entry.name,
|
|
103
|
+
path: appPath,
|
|
104
|
+
appId: manifest.appId
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
catch (e) {
|
|
111
|
+
logger.warn("Failed to scan apps directory", { path: basePath, error: e });
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Cache results
|
|
115
|
+
appsCache = apps;
|
|
116
|
+
logger.info("Scanned apps for bug fixer tools", {
|
|
117
|
+
paths: appPaths,
|
|
118
|
+
found: apps.map(a => ({ name: a.name, appId: a.appId?.substring(0, 8) || "none" }))
|
|
119
|
+
});
|
|
120
|
+
return apps;
|
|
121
|
+
}
|
|
122
|
+
// Find App Tool
|
|
123
|
+
exports.bugFixerFindAppTool = {
|
|
124
|
+
name: "bug_fixer_find_app",
|
|
125
|
+
group: tool_registry_1.ToolGroup.BOT_INTERNAL,
|
|
126
|
+
description: "Find a Hailer app project by name or from bug title",
|
|
127
|
+
schema: zod_1.z.object({
|
|
128
|
+
searchTerm: zod_1.z.string().describe("App name or bug title to search for").optional(),
|
|
129
|
+
name: zod_1.z.string().describe("Alias for searchTerm - app name to search for").optional(),
|
|
130
|
+
appName: zod_1.z.string().describe("Alias for searchTerm - app name to search for").optional()
|
|
131
|
+
}).refine(data => data.searchTerm || data.name || data.appName, {
|
|
132
|
+
message: "Either searchTerm, name, or appName is required"
|
|
133
|
+
}),
|
|
134
|
+
async execute(args, _context) {
|
|
135
|
+
// Accept searchTerm, name, or appName
|
|
136
|
+
const searchTerm = (args.searchTerm || args.name || args.appName || '').toLowerCase();
|
|
137
|
+
const apps = await scanApps();
|
|
138
|
+
for (const app of apps) {
|
|
139
|
+
if (app.name.toLowerCase().includes(searchTerm) ||
|
|
140
|
+
searchTerm.includes(app.name.toLowerCase())) {
|
|
141
|
+
return {
|
|
142
|
+
content: [{ type: "text", text: JSON.stringify({ found: true, name: app.name, path: app.path }) }]
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
content: [{ type: "text", text: JSON.stringify({ found: false, availableApps: apps.map(a => a.name) }) }]
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
// List Files Tool
|
|
152
|
+
exports.bugFixerListFilesTool = {
|
|
153
|
+
name: "bug_fixer_list_files",
|
|
154
|
+
group: tool_registry_1.ToolGroup.BOT_INTERNAL,
|
|
155
|
+
description: "List source files in a Hailer app project",
|
|
156
|
+
schema: zod_1.z.object({
|
|
157
|
+
appPath: zod_1.z.string().describe("Path to the app project").optional(),
|
|
158
|
+
app: zod_1.z.string().describe("Alias for appPath - path to the app project").optional()
|
|
159
|
+
}).refine(data => data.appPath || data.app, {
|
|
160
|
+
message: "Either appPath or app is required"
|
|
161
|
+
}),
|
|
162
|
+
async execute(args, _context) {
|
|
163
|
+
// Accept either appPath or app
|
|
164
|
+
const appPath = args.appPath || args.app || '';
|
|
165
|
+
const files = [];
|
|
166
|
+
const extensions = [".tsx", ".ts", ".jsx", ".js"];
|
|
167
|
+
const ignoreDirs = ["node_modules", "dist", "build", ".git"];
|
|
168
|
+
const scan = async (dir, depth = 0) => {
|
|
169
|
+
if (depth > 5)
|
|
170
|
+
return;
|
|
171
|
+
try {
|
|
172
|
+
const entries = await fs.readdir(dir, { withFileTypes: true });
|
|
173
|
+
for (const entry of entries) {
|
|
174
|
+
const fullPath = path.join(dir, entry.name);
|
|
175
|
+
const relativePath = path.relative(appPath, fullPath);
|
|
176
|
+
if (entry.isDirectory()) {
|
|
177
|
+
if (!ignoreDirs.includes(entry.name) && !entry.name.startsWith(".")) {
|
|
178
|
+
await scan(fullPath, depth + 1);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else if (extensions.some(ext => entry.name.endsWith(ext))) {
|
|
182
|
+
if (!entry.name.includes(".test.") && !entry.name.includes(".spec.")) {
|
|
183
|
+
files.push(relativePath);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
catch { /* skip */ }
|
|
189
|
+
};
|
|
190
|
+
await scan(appPath);
|
|
191
|
+
return {
|
|
192
|
+
content: [{ type: "text", text: JSON.stringify({ files: files.slice(0, 50), total: files.length }) }]
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
// Read File Tool
|
|
197
|
+
exports.bugFixerReadFileTool = {
|
|
198
|
+
name: "bug_fixer_read_file",
|
|
199
|
+
group: tool_registry_1.ToolGroup.BOT_INTERNAL,
|
|
200
|
+
description: "Read a source file from the app",
|
|
201
|
+
schema: zod_1.z.object({
|
|
202
|
+
appPath: zod_1.z.string().describe("Path to the app project"),
|
|
203
|
+
filePath: zod_1.z.string().describe("Relative path to the file")
|
|
204
|
+
}),
|
|
205
|
+
async execute(args, _context) {
|
|
206
|
+
try {
|
|
207
|
+
const fullPath = path.join(args.appPath, args.filePath);
|
|
208
|
+
const content = await fs.readFile(fullPath, "utf-8");
|
|
209
|
+
return {
|
|
210
|
+
content: [{ type: "text", text: JSON.stringify({ content }) }]
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
catch (e) {
|
|
214
|
+
return {
|
|
215
|
+
content: [{ type: "text", text: JSON.stringify({ error: e.message }) }]
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
// Write File Tool
|
|
221
|
+
exports.bugFixerWriteFileTool = {
|
|
222
|
+
name: "bug_fixer_write_file",
|
|
223
|
+
group: tool_registry_1.ToolGroup.BOT_INTERNAL,
|
|
224
|
+
description: "Write/update a source file in the app",
|
|
225
|
+
schema: zod_1.z.object({
|
|
226
|
+
appPath: zod_1.z.string().describe("Path to the app project"),
|
|
227
|
+
filePath: zod_1.z.string().describe("Relative path to the file"),
|
|
228
|
+
content: zod_1.z.string().describe("New file content")
|
|
229
|
+
}),
|
|
230
|
+
async execute(args, _context) {
|
|
231
|
+
try {
|
|
232
|
+
const fullPath = path.join(args.appPath, args.filePath);
|
|
233
|
+
await fs.mkdir(path.dirname(fullPath), { recursive: true });
|
|
234
|
+
await fs.writeFile(fullPath, args.content, "utf-8");
|
|
235
|
+
logger.info("Bug Fixer wrote file", { filePath: args.filePath });
|
|
236
|
+
return {
|
|
237
|
+
content: [{ type: "text", text: JSON.stringify({ success: true, path: args.filePath }) }]
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
catch (e) {
|
|
241
|
+
return {
|
|
242
|
+
content: [{ type: "text", text: JSON.stringify({ error: e.message }) }]
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
// Apply Fix Tool (search/replace pattern - calls existing bot logic)
|
|
248
|
+
const fixFileSchema = zod_1.z.object({
|
|
249
|
+
path: zod_1.z.string().describe("Relative file path (e.g., 'src/App.tsx')"),
|
|
250
|
+
action: zod_1.z.enum(["edit", "create", "delete"]).describe("Action: edit (search/replace), create (new file), delete"),
|
|
251
|
+
search: zod_1.z.string().optional().describe("For 'edit': the exact code snippet to find"),
|
|
252
|
+
replace: zod_1.z.string().optional().describe("For 'edit': the code to replace it with"),
|
|
253
|
+
content: zod_1.z.string().optional().describe("For 'create': the full file content")
|
|
254
|
+
});
|
|
255
|
+
exports.bugFixerApplyFixTool = {
|
|
256
|
+
name: "bug_fixer_apply_fix",
|
|
257
|
+
group: tool_registry_1.ToolGroup.BOT_INTERNAL,
|
|
258
|
+
description: `Apply code fixes using search/replace pattern. More token-efficient than rewriting entire files.
|
|
259
|
+
|
|
260
|
+
**For 'edit' action:** Provide search (code to find) and replace (code to replace with).
|
|
261
|
+
**For 'create' action:** Provide content (full file content).
|
|
262
|
+
**For 'delete' action:** Just provide path.
|
|
263
|
+
|
|
264
|
+
Example:
|
|
265
|
+
\`\`\`json
|
|
266
|
+
{
|
|
267
|
+
"appPath": "lineup-manager",
|
|
268
|
+
"fixes": [{
|
|
269
|
+
"path": "src/App.tsx",
|
|
270
|
+
"action": "edit",
|
|
271
|
+
"search": "const handleDragEnd = () => {\\n // old code\\n}",
|
|
272
|
+
"replace": "const handleDragEnd = () => {\\n // fixed code\\n}"
|
|
273
|
+
}]
|
|
274
|
+
}
|
|
275
|
+
\`\`\``,
|
|
276
|
+
schema: zod_1.z.object({
|
|
277
|
+
appPath: zod_1.z.string().describe("App folder name or path (e.g., 'lineup-manager')"),
|
|
278
|
+
fixes: zod_1.z.array(fixFileSchema).describe("Array of file operations to apply")
|
|
279
|
+
}),
|
|
280
|
+
async execute(args, _context) {
|
|
281
|
+
try {
|
|
282
|
+
// Resolve app path - try absolute first, then search in configured directories
|
|
283
|
+
let appFullPath = args.appPath;
|
|
284
|
+
if (!path.isAbsolute(args.appPath)) {
|
|
285
|
+
// Try to find in scanned apps
|
|
286
|
+
const apps = await scanApps();
|
|
287
|
+
const matchedApp = apps.find(a => a.name.toLowerCase() === args.appPath.toLowerCase() ||
|
|
288
|
+
a.path.endsWith(`/${args.appPath}`));
|
|
289
|
+
if (matchedApp) {
|
|
290
|
+
appFullPath = matchedApp.path;
|
|
291
|
+
}
|
|
292
|
+
else {
|
|
293
|
+
// Fallback: try first configured path
|
|
294
|
+
const basePaths = getAppPaths();
|
|
295
|
+
appFullPath = path.join(basePaths[0], args.appPath);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
// Check app exists
|
|
299
|
+
try {
|
|
300
|
+
await fs.access(appFullPath);
|
|
301
|
+
}
|
|
302
|
+
catch {
|
|
303
|
+
return {
|
|
304
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
305
|
+
success: false,
|
|
306
|
+
error: `App not found at: ${appFullPath}`
|
|
307
|
+
}) }]
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
const modifiedFiles = [];
|
|
311
|
+
const errors = [];
|
|
312
|
+
for (const fix of args.fixes) {
|
|
313
|
+
const filePath = path.join(appFullPath, fix.path);
|
|
314
|
+
try {
|
|
315
|
+
if (fix.action === 'edit' && fix.search && fix.replace !== undefined) {
|
|
316
|
+
// Read file
|
|
317
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
318
|
+
// Try exact match first
|
|
319
|
+
if (content.includes(fix.search)) {
|
|
320
|
+
const newContent = content.replace(fix.search, fix.replace);
|
|
321
|
+
await fs.writeFile(filePath, newContent, 'utf-8');
|
|
322
|
+
modifiedFiles.push(fix.path);
|
|
323
|
+
logger.info("Bug Fixer applied fix (exact match)", { path: fix.path });
|
|
324
|
+
}
|
|
325
|
+
else {
|
|
326
|
+
// Try normalized whitespace match
|
|
327
|
+
const normalizeWs = (s) => s.replace(/\s+/g, ' ').trim();
|
|
328
|
+
const normalizedContent = normalizeWs(content);
|
|
329
|
+
const normalizedSearch = normalizeWs(fix.search);
|
|
330
|
+
if (normalizedContent.includes(normalizedSearch)) {
|
|
331
|
+
// Line-by-line search
|
|
332
|
+
const searchLines = fix.search.split('\n').map((l) => l.trim()).filter((l) => l);
|
|
333
|
+
const contentLines = content.split('\n');
|
|
334
|
+
let found = false;
|
|
335
|
+
for (let i = 0; i <= contentLines.length - searchLines.length; i++) {
|
|
336
|
+
const candidateLines = contentLines.slice(i, i + searchLines.length);
|
|
337
|
+
if (candidateLines.every((line, j) => line.trim() === searchLines[j])) {
|
|
338
|
+
const before = contentLines.slice(0, i);
|
|
339
|
+
const after = contentLines.slice(i + searchLines.length);
|
|
340
|
+
const replaceLines = fix.replace.split('\n');
|
|
341
|
+
const newContent = [...before, ...replaceLines, ...after].join('\n');
|
|
342
|
+
await fs.writeFile(filePath, newContent, 'utf-8');
|
|
343
|
+
modifiedFiles.push(fix.path);
|
|
344
|
+
found = true;
|
|
345
|
+
logger.info("Bug Fixer applied fix (normalized match)", { path: fix.path });
|
|
346
|
+
break;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
if (!found) {
|
|
350
|
+
errors.push(`${fix.path}: Search string not found (whitespace mismatch)`);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
errors.push(`${fix.path}: Search string not found`);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
else if (fix.action === 'create' && fix.content) {
|
|
359
|
+
await fs.mkdir(path.dirname(filePath), { recursive: true });
|
|
360
|
+
await fs.writeFile(filePath, fix.content, 'utf-8');
|
|
361
|
+
modifiedFiles.push(fix.path);
|
|
362
|
+
logger.info("Bug Fixer created file", { path: fix.path });
|
|
363
|
+
}
|
|
364
|
+
else if (fix.action === 'delete') {
|
|
365
|
+
await fs.unlink(filePath);
|
|
366
|
+
modifiedFiles.push(fix.path);
|
|
367
|
+
logger.info("Bug Fixer deleted file", { path: fix.path });
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
errors.push(`${fix.path}: Invalid action or missing required fields`);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
catch (e) {
|
|
374
|
+
errors.push(`${fix.path}: ${e.message}`);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
if (errors.length > 0) {
|
|
378
|
+
return {
|
|
379
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
380
|
+
success: false,
|
|
381
|
+
modifiedFiles,
|
|
382
|
+
errors,
|
|
383
|
+
hint: "Check that 'search' exactly matches the code in the file (including whitespace)"
|
|
384
|
+
}) }]
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
return {
|
|
388
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
389
|
+
success: true,
|
|
390
|
+
modifiedFiles,
|
|
391
|
+
message: `Applied ${modifiedFiles.length} fix(es). Run bug_fixer_run_build to verify.`
|
|
392
|
+
}) }]
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
catch (e) {
|
|
396
|
+
return {
|
|
397
|
+
content: [{ type: "text", text: JSON.stringify({ success: false, error: e.message }) }]
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
};
|
|
402
|
+
// Run Build Tool
|
|
403
|
+
exports.bugFixerRunBuildTool = {
|
|
404
|
+
name: "bug_fixer_run_build",
|
|
405
|
+
group: tool_registry_1.ToolGroup.BOT_INTERNAL,
|
|
406
|
+
description: "Run TypeScript build to check for errors",
|
|
407
|
+
schema: zod_1.z.object({
|
|
408
|
+
appPath: zod_1.z.string().describe("Path to the app project")
|
|
409
|
+
}),
|
|
410
|
+
async execute(args, _context) {
|
|
411
|
+
try {
|
|
412
|
+
const output = (0, child_process_1.execSync)("npm run build 2>&1", { cwd: args.appPath, encoding: "utf-8", timeout: 60000 });
|
|
413
|
+
return {
|
|
414
|
+
content: [{ type: "text", text: JSON.stringify({ success: true, output: output.slice(-2000) }) }]
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
catch (e) {
|
|
418
|
+
return {
|
|
419
|
+
content: [{ type: "text", text: JSON.stringify({ success: false, error: (e.stdout || e.stderr || e.message).slice(-2000) }) }]
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
};
|
|
424
|
+
// Git Status Tool
|
|
425
|
+
exports.bugFixerGitStatusTool = {
|
|
426
|
+
name: "bug_fixer_git_status",
|
|
427
|
+
group: tool_registry_1.ToolGroup.BOT_INTERNAL,
|
|
428
|
+
description: "Check git status - branch, changes, sync with remote",
|
|
429
|
+
schema: zod_1.z.object({
|
|
430
|
+
appPath: zod_1.z.string().describe("Path to the app project")
|
|
431
|
+
}),
|
|
432
|
+
async execute(args, _context) {
|
|
433
|
+
try {
|
|
434
|
+
const status = (0, child_process_1.execSync)("git status --short", { cwd: args.appPath, encoding: "utf-8" });
|
|
435
|
+
const branch = (0, child_process_1.execSync)("git branch --show-current", { cwd: args.appPath, encoding: "utf-8" }).trim();
|
|
436
|
+
let behind = 0, ahead = 0;
|
|
437
|
+
try {
|
|
438
|
+
const revList = (0, child_process_1.execSync)("git rev-list --left-right --count HEAD...@{upstream} 2>/dev/null", { cwd: args.appPath, encoding: "utf-8" }).trim().split(/\s+/);
|
|
439
|
+
ahead = parseInt(revList[0]) || 0;
|
|
440
|
+
behind = parseInt(revList[1]) || 0;
|
|
441
|
+
}
|
|
442
|
+
catch { /* no upstream */ }
|
|
443
|
+
return {
|
|
444
|
+
content: [{ type: "text", text: JSON.stringify({ branch, status: status || "clean", ahead, behind }) }]
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
catch (e) {
|
|
448
|
+
return {
|
|
449
|
+
content: [{ type: "text", text: JSON.stringify({ error: e.message }) }]
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
};
|
|
454
|
+
// Git Pull Tool
|
|
455
|
+
exports.bugFixerGitPullTool = {
|
|
456
|
+
name: "bug_fixer_git_pull",
|
|
457
|
+
group: tool_registry_1.ToolGroup.BOT_INTERNAL,
|
|
458
|
+
description: "Pull latest changes from remote",
|
|
459
|
+
schema: zod_1.z.object({
|
|
460
|
+
appPath: zod_1.z.string().describe("Path to the app project")
|
|
461
|
+
}),
|
|
462
|
+
async execute(args, _context) {
|
|
463
|
+
try {
|
|
464
|
+
const output = (0, child_process_1.execSync)("git pull", { cwd: args.appPath, encoding: "utf-8" });
|
|
465
|
+
return {
|
|
466
|
+
content: [{ type: "text", text: JSON.stringify({ success: true, output }) }]
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
catch (e) {
|
|
470
|
+
return {
|
|
471
|
+
content: [{ type: "text", text: JSON.stringify({ success: false, error: e.stderr || e.message }) }]
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
// Git Commit Tool
|
|
477
|
+
exports.bugFixerGitCommitTool = {
|
|
478
|
+
name: "bug_fixer_git_commit",
|
|
479
|
+
group: tool_registry_1.ToolGroup.BOT_INTERNAL,
|
|
480
|
+
description: "Stage all changes and commit",
|
|
481
|
+
schema: zod_1.z.object({
|
|
482
|
+
appPath: zod_1.z.string().describe("Path to the app project"),
|
|
483
|
+
message: zod_1.z.string().describe("Commit message")
|
|
484
|
+
}),
|
|
485
|
+
async execute(args, _context) {
|
|
486
|
+
try {
|
|
487
|
+
(0, child_process_1.execSync)("git add -A", { cwd: args.appPath });
|
|
488
|
+
(0, child_process_1.execSync)(`git commit -m "${args.message.replace(/"/g, '\\"')}"`, { cwd: args.appPath });
|
|
489
|
+
const hash = (0, child_process_1.execSync)("git rev-parse --short HEAD", { cwd: args.appPath, encoding: "utf-8" }).trim();
|
|
490
|
+
logger.info("Bug Fixer committed", { hash, message: args.message });
|
|
491
|
+
return {
|
|
492
|
+
content: [{ type: "text", text: JSON.stringify({ success: true, hash }) }]
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
catch (e) {
|
|
496
|
+
return {
|
|
497
|
+
content: [{ type: "text", text: JSON.stringify({ success: false, error: e.stderr || e.stdout || e.message }) }]
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
};
|
|
502
|
+
// Git Push Tool
|
|
503
|
+
exports.bugFixerGitPushTool = {
|
|
504
|
+
name: "bug_fixer_git_push",
|
|
505
|
+
group: tool_registry_1.ToolGroup.BOT_INTERNAL,
|
|
506
|
+
description: "Push commits to remote",
|
|
507
|
+
schema: zod_1.z.object({
|
|
508
|
+
appPath: zod_1.z.string().describe("Path to the app project")
|
|
509
|
+
}),
|
|
510
|
+
async execute(args, _context) {
|
|
511
|
+
try {
|
|
512
|
+
(0, child_process_1.execSync)("git push", { cwd: args.appPath, encoding: "utf-8", stdio: "pipe" });
|
|
513
|
+
return {
|
|
514
|
+
content: [{ type: "text", text: JSON.stringify({ success: true }) }]
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
catch (e) {
|
|
518
|
+
return {
|
|
519
|
+
content: [{ type: "text", text: JSON.stringify({ success: false, error: e.stderr || e.message }) }]
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
// Git Revert Tool
|
|
525
|
+
exports.bugFixerGitRevertTool = {
|
|
526
|
+
name: "bug_fixer_git_revert",
|
|
527
|
+
group: tool_registry_1.ToolGroup.BOT_INTERNAL,
|
|
528
|
+
description: "Discard all uncommitted changes",
|
|
529
|
+
schema: zod_1.z.object({
|
|
530
|
+
appPath: zod_1.z.string().describe("Path to the app project")
|
|
531
|
+
}),
|
|
532
|
+
async execute(args, _context) {
|
|
533
|
+
try {
|
|
534
|
+
(0, child_process_1.execSync)("git checkout -- .", { cwd: args.appPath });
|
|
535
|
+
return {
|
|
536
|
+
content: [{ type: "text", text: JSON.stringify({ success: true }) }]
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
catch (e) {
|
|
540
|
+
return {
|
|
541
|
+
content: [{ type: "text", text: JSON.stringify({ success: false, error: e.message }) }]
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
};
|
|
546
|
+
// Publish App Tool
|
|
547
|
+
exports.bugFixerPublishAppTool = {
|
|
548
|
+
name: "bug_fixer_publish_app",
|
|
549
|
+
group: tool_registry_1.ToolGroup.BOT_INTERNAL,
|
|
550
|
+
description: "Publish app to Hailer production - ALWAYS ASK USER FIRST",
|
|
551
|
+
schema: zod_1.z.object({
|
|
552
|
+
appPath: zod_1.z.string().describe("Path to the app project")
|
|
553
|
+
}),
|
|
554
|
+
async execute(args, context) {
|
|
555
|
+
try {
|
|
556
|
+
const { publishHailerAppTool } = await Promise.resolve().then(() => __importStar(require("./app-scaffold")));
|
|
557
|
+
const result = await publishHailerAppTool.execute({ projectDirectory: args.appPath }, context);
|
|
558
|
+
return result;
|
|
559
|
+
}
|
|
560
|
+
catch (e) {
|
|
561
|
+
return {
|
|
562
|
+
content: [{ type: "text", text: JSON.stringify({ success: false, error: e.message }) }]
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
};
|
|
567
|
+
// ============================================================================
|
|
568
|
+
// HIGH-LEVEL WORKFLOW TOOLS (LLM-driven workflow control)
|
|
569
|
+
// ============================================================================
|
|
570
|
+
/**
|
|
571
|
+
* Analyze Bug Tool - Read bug report and get classification info
|
|
572
|
+
* The LLM uses this to understand the bug and decide next steps
|
|
573
|
+
*/
|
|
574
|
+
exports.bugFixerAnalyzeBugTool = {
|
|
575
|
+
name: "bug_fixer_analyze_bug",
|
|
576
|
+
group: tool_registry_1.ToolGroup.BOT_INTERNAL,
|
|
577
|
+
description: `Read a bug report and get classification information.
|
|
578
|
+
Returns the bug details and classification if already analyzed.
|
|
579
|
+
Use this to understand the current state of a bug discussion.`,
|
|
580
|
+
schema: zod_1.z.object({
|
|
581
|
+
discussionId: zod_1.z.string().describe("The discussion ID for the bug report").optional(),
|
|
582
|
+
activityId: zod_1.z.string().describe("Alias - the bug activity ID (will look up discussion)").optional()
|
|
583
|
+
}).refine(data => data.discussionId || data.activityId, {
|
|
584
|
+
message: "Either discussionId or activityId is required"
|
|
585
|
+
}),
|
|
586
|
+
async execute(args, context) {
|
|
587
|
+
try {
|
|
588
|
+
// Accept either discussionId or look up from activityId
|
|
589
|
+
let discussionId = args.discussionId;
|
|
590
|
+
if (!discussionId && args.activityId) {
|
|
591
|
+
// Try to find discussionId from pending registries by activityId
|
|
592
|
+
const allPending = pending_classification_1.pendingClassificationRegistry.getAll();
|
|
593
|
+
for (const pending of allPending) {
|
|
594
|
+
if (pending.bugId === args.activityId) {
|
|
595
|
+
discussionId = pending.discussionId;
|
|
596
|
+
break;
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
// If still not found, fetch activity to get discussion
|
|
600
|
+
if (!discussionId) {
|
|
601
|
+
const activity = await context.hailer.fetchActivityById(args.activityId);
|
|
602
|
+
if (activity?.discussion) {
|
|
603
|
+
discussionId = activity.discussion;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
if (!discussionId) {
|
|
608
|
+
return {
|
|
609
|
+
content: [{
|
|
610
|
+
type: "text",
|
|
611
|
+
text: JSON.stringify({
|
|
612
|
+
status: "error",
|
|
613
|
+
message: "Could not find discussion for the given ID"
|
|
614
|
+
})
|
|
615
|
+
}]
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
// Check if we have pending classification info
|
|
619
|
+
const pending = pending_classification_1.pendingClassificationRegistry.get(discussionId);
|
|
620
|
+
if (pending) {
|
|
621
|
+
return {
|
|
622
|
+
content: [{
|
|
623
|
+
type: "text",
|
|
624
|
+
text: JSON.stringify({
|
|
625
|
+
status: "pending_confirmation",
|
|
626
|
+
bugId: pending.bugId,
|
|
627
|
+
bugName: pending.bugName,
|
|
628
|
+
appId: pending.appId,
|
|
629
|
+
appName: pending.appName,
|
|
630
|
+
classification: pending.classification,
|
|
631
|
+
reason: pending.reason,
|
|
632
|
+
description: pending.bug.description,
|
|
633
|
+
stepsToReproduce: pending.bug.stepsToReproduce,
|
|
634
|
+
message: "Bug has been classified. Waiting for user to confirm whether to proceed with fix."
|
|
635
|
+
})
|
|
636
|
+
}]
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
// Check if we have a pending fix
|
|
640
|
+
const pendingFix = pending_fix_1.pendingFixRegistry.get(args.discussionId);
|
|
641
|
+
if (pendingFix) {
|
|
642
|
+
return {
|
|
643
|
+
content: [{
|
|
644
|
+
type: "text",
|
|
645
|
+
text: JSON.stringify({
|
|
646
|
+
status: pendingFix.state === "awaiting_test" ? "fix_applied" : "awaiting_explanation",
|
|
647
|
+
bugId: pendingFix.bugId,
|
|
648
|
+
appId: pendingFix.appId,
|
|
649
|
+
fixSummary: pendingFix.fixSummary,
|
|
650
|
+
filesModified: pendingFix.filesModified,
|
|
651
|
+
message: pendingFix.state === "awaiting_test"
|
|
652
|
+
? "Fix has been applied. Waiting for user to test and approve."
|
|
653
|
+
: "Fix was rejected. Waiting for user to explain what's wrong."
|
|
654
|
+
})
|
|
655
|
+
}]
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
return {
|
|
659
|
+
content: [{
|
|
660
|
+
type: "text",
|
|
661
|
+
text: JSON.stringify({
|
|
662
|
+
status: "not_found",
|
|
663
|
+
message: "No pending bug found for this discussion. The bug may have already been processed."
|
|
664
|
+
})
|
|
665
|
+
}]
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
catch (e) {
|
|
669
|
+
return {
|
|
670
|
+
content: [{ type: "text", text: JSON.stringify({ error: e.message }) }]
|
|
671
|
+
};
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
};
|
|
675
|
+
/**
|
|
676
|
+
* Start Fix Tool - Begin the bug fix process
|
|
677
|
+
* This triggers the full fix workflow: find app → analyze → apply fix → build
|
|
678
|
+
*/
|
|
679
|
+
exports.bugFixerStartFixTool = {
|
|
680
|
+
name: "bug_fixer_start_fix",
|
|
681
|
+
group: tool_registry_1.ToolGroup.BOT_INTERNAL,
|
|
682
|
+
description: `Start the bug fix process. Call this when the user confirms they want you to fix the bug.
|
|
683
|
+
This will: find the app, analyze the code, generate and apply a fix, and run the build.
|
|
684
|
+
The user should test the fix afterward.`,
|
|
685
|
+
schema: zod_1.z.object({
|
|
686
|
+
discussionId: zod_1.z.string().describe("The discussion ID for the bug report")
|
|
687
|
+
}),
|
|
688
|
+
async execute(args, _context) {
|
|
689
|
+
try {
|
|
690
|
+
const pending = pending_classification_1.pendingClassificationRegistry.get(args.discussionId);
|
|
691
|
+
if (!pending) {
|
|
692
|
+
return {
|
|
693
|
+
content: [{
|
|
694
|
+
type: "text",
|
|
695
|
+
text: JSON.stringify({
|
|
696
|
+
success: false,
|
|
697
|
+
error: "No pending bug classification found for this discussion. Cannot start fix."
|
|
698
|
+
})
|
|
699
|
+
}]
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
// Trigger the fix via the registry callback
|
|
703
|
+
const triggered = await pending_classification_1.pendingClassificationRegistry.triggerFixIt(args.discussionId);
|
|
704
|
+
if (triggered) {
|
|
705
|
+
return {
|
|
706
|
+
content: [{
|
|
707
|
+
type: "text",
|
|
708
|
+
text: JSON.stringify({
|
|
709
|
+
success: true,
|
|
710
|
+
message: "Fix process started. The bot will analyze and apply the fix, then notify the user to test."
|
|
711
|
+
})
|
|
712
|
+
}]
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
else {
|
|
716
|
+
return {
|
|
717
|
+
content: [{
|
|
718
|
+
type: "text",
|
|
719
|
+
text: JSON.stringify({
|
|
720
|
+
success: false,
|
|
721
|
+
error: "Failed to trigger fix process. The callback may not be registered."
|
|
722
|
+
})
|
|
723
|
+
}]
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
catch (e) {
|
|
728
|
+
return {
|
|
729
|
+
content: [{ type: "text", text: JSON.stringify({ success: false, error: e.message }) }]
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
};
|
|
734
|
+
/**
|
|
735
|
+
* Mark Declined Tool - Mark bug as not-a-bug and close it
|
|
736
|
+
*/
|
|
737
|
+
exports.bugFixerMarkDeclinedTool = {
|
|
738
|
+
name: "bug_fixer_mark_declined",
|
|
739
|
+
group: tool_registry_1.ToolGroup.BOT_INTERNAL,
|
|
740
|
+
description: `Mark a bug report as "not a bug" and move it to the Declined phase.
|
|
741
|
+
Call this when the user confirms it's actually a feature request or not a real bug.`,
|
|
742
|
+
schema: zod_1.z.object({
|
|
743
|
+
discussionId: zod_1.z.string().describe("The discussion ID for the bug report")
|
|
744
|
+
}),
|
|
745
|
+
async execute(args, _context) {
|
|
746
|
+
try {
|
|
747
|
+
const pending = pending_classification_1.pendingClassificationRegistry.get(args.discussionId);
|
|
748
|
+
if (!pending) {
|
|
749
|
+
return {
|
|
750
|
+
content: [{
|
|
751
|
+
type: "text",
|
|
752
|
+
text: JSON.stringify({
|
|
753
|
+
success: false,
|
|
754
|
+
error: "No pending bug classification found for this discussion."
|
|
755
|
+
})
|
|
756
|
+
}]
|
|
757
|
+
};
|
|
758
|
+
}
|
|
759
|
+
// Trigger the not-a-bug action via the registry callback
|
|
760
|
+
const triggered = await pending_classification_1.pendingClassificationRegistry.triggerNotABug(args.discussionId);
|
|
761
|
+
if (triggered) {
|
|
762
|
+
return {
|
|
763
|
+
content: [{
|
|
764
|
+
type: "text",
|
|
765
|
+
text: JSON.stringify({
|
|
766
|
+
success: true,
|
|
767
|
+
bugId: pending.bugId,
|
|
768
|
+
message: "Bug marked as declined (not a bug). Moved to Declined phase."
|
|
769
|
+
})
|
|
770
|
+
}]
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
else {
|
|
774
|
+
return {
|
|
775
|
+
content: [{
|
|
776
|
+
type: "text",
|
|
777
|
+
text: JSON.stringify({
|
|
778
|
+
success: false,
|
|
779
|
+
error: "Failed to decline bug. The callback may not be registered."
|
|
780
|
+
})
|
|
781
|
+
}]
|
|
782
|
+
};
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
catch (e) {
|
|
786
|
+
return {
|
|
787
|
+
content: [{ type: "text", text: JSON.stringify({ success: false, error: e.message }) }]
|
|
788
|
+
};
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
};
|
|
792
|
+
/**
|
|
793
|
+
* Publish Fix Tool - Publish the fix to production
|
|
794
|
+
*/
|
|
795
|
+
exports.bugFixerPublishFixTool = {
|
|
796
|
+
name: "bug_fixer_publish_fix",
|
|
797
|
+
group: tool_registry_1.ToolGroup.BOT_INTERNAL,
|
|
798
|
+
description: `Publish a tested fix to production and mark the bug as Fixed.
|
|
799
|
+
Call this ONLY after the user has tested the fix and approved it.`,
|
|
800
|
+
schema: zod_1.z.object({
|
|
801
|
+
discussionId: zod_1.z.string().describe("The discussion ID for the bug report")
|
|
802
|
+
}),
|
|
803
|
+
async execute(args, _context) {
|
|
804
|
+
try {
|
|
805
|
+
// Trigger approval via the registry callback
|
|
806
|
+
const triggered = await pending_fix_1.pendingFixRegistry.triggerApproval(args.discussionId);
|
|
807
|
+
if (triggered) {
|
|
808
|
+
return {
|
|
809
|
+
content: [{
|
|
810
|
+
type: "text",
|
|
811
|
+
text: JSON.stringify({
|
|
812
|
+
success: true,
|
|
813
|
+
message: "Fix is being published to production. This may take a moment."
|
|
814
|
+
})
|
|
815
|
+
}]
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
else {
|
|
819
|
+
// Get more info about why it failed
|
|
820
|
+
const pending = pending_fix_1.pendingFixRegistry.get(args.discussionId);
|
|
821
|
+
if (!pending) {
|
|
822
|
+
return {
|
|
823
|
+
content: [{
|
|
824
|
+
type: "text",
|
|
825
|
+
text: JSON.stringify({
|
|
826
|
+
success: false,
|
|
827
|
+
error: "No pending fix found for this discussion. Cannot publish."
|
|
828
|
+
})
|
|
829
|
+
}]
|
|
830
|
+
};
|
|
831
|
+
}
|
|
832
|
+
if (pending.state !== "awaiting_test") {
|
|
833
|
+
return {
|
|
834
|
+
content: [{
|
|
835
|
+
type: "text",
|
|
836
|
+
text: JSON.stringify({
|
|
837
|
+
success: false,
|
|
838
|
+
error: `Cannot publish - fix is in state '${pending.state}'. User must test and approve first.`
|
|
839
|
+
})
|
|
840
|
+
}]
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
return {
|
|
844
|
+
content: [{
|
|
845
|
+
type: "text",
|
|
846
|
+
text: JSON.stringify({
|
|
847
|
+
success: false,
|
|
848
|
+
error: "Failed to trigger publish. The approval callback may not be registered."
|
|
849
|
+
})
|
|
850
|
+
}]
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
catch (e) {
|
|
855
|
+
return {
|
|
856
|
+
content: [{ type: "text", text: JSON.stringify({ success: false, error: e.message }) }]
|
|
857
|
+
};
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
};
|
|
861
|
+
/**
|
|
862
|
+
* Retry Fix Tool - Retry a fix with additional context/explanation
|
|
863
|
+
*/
|
|
864
|
+
exports.bugFixerRetryFixTool = {
|
|
865
|
+
name: "bug_fixer_retry_fix",
|
|
866
|
+
group: tool_registry_1.ToolGroup.BOT_INTERNAL,
|
|
867
|
+
description: `Retry fixing a bug with additional context from the user.
|
|
868
|
+
Call this when the user explains why the previous fix didn't work.`,
|
|
869
|
+
schema: zod_1.z.object({
|
|
870
|
+
discussionId: zod_1.z.string().describe("The discussion ID for the bug report"),
|
|
871
|
+
explanation: zod_1.z.string().describe("User's explanation of what's still broken or wrong")
|
|
872
|
+
}),
|
|
873
|
+
async execute(args, _context) {
|
|
874
|
+
try {
|
|
875
|
+
const pending = pending_fix_1.pendingFixRegistry.get(args.discussionId);
|
|
876
|
+
if (!pending) {
|
|
877
|
+
return {
|
|
878
|
+
content: [{
|
|
879
|
+
type: "text",
|
|
880
|
+
text: JSON.stringify({
|
|
881
|
+
success: false,
|
|
882
|
+
error: "No pending fix found for this discussion."
|
|
883
|
+
})
|
|
884
|
+
}]
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
// Trigger retry via the registry callback
|
|
888
|
+
const triggered = await pending_fix_1.pendingFixRegistry.triggerRetry(args.discussionId, args.explanation);
|
|
889
|
+
if (triggered) {
|
|
890
|
+
return {
|
|
891
|
+
content: [{
|
|
892
|
+
type: "text",
|
|
893
|
+
text: JSON.stringify({
|
|
894
|
+
success: true,
|
|
895
|
+
message: "Retry started with user feedback. The bot will generate a new fix."
|
|
896
|
+
})
|
|
897
|
+
}]
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
else {
|
|
901
|
+
return {
|
|
902
|
+
content: [{
|
|
903
|
+
type: "text",
|
|
904
|
+
text: JSON.stringify({
|
|
905
|
+
success: false,
|
|
906
|
+
error: "Failed to trigger retry. The callback may not be registered."
|
|
907
|
+
})
|
|
908
|
+
}]
|
|
909
|
+
};
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
catch (e) {
|
|
913
|
+
return {
|
|
914
|
+
content: [{ type: "text", text: JSON.stringify({ success: false, error: e.message }) }]
|
|
915
|
+
};
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
};
|
|
919
|
+
// Mark Bug Declined Tool - handles everything automatically
|
|
920
|
+
exports.markBugDeclinedTool = {
|
|
921
|
+
name: "mark_bug_declined",
|
|
922
|
+
group: tool_registry_1.ToolGroup.BOT_INTERNAL,
|
|
923
|
+
description: "Mark a bug as declined (not a bug / won't fix). Automatically sets phase to Declined, status to 'Won't Fix', and leaves the discussion.",
|
|
924
|
+
schema: zod_1.z.object({
|
|
925
|
+
bugId: zod_1.z.string().describe("The bug activity ID"),
|
|
926
|
+
workflowId: zod_1.z.string().describe("The workflow ID for the Bug Reports workflow"),
|
|
927
|
+
discussionId: zod_1.z.string().describe("The discussion ID to leave after marking declined"),
|
|
928
|
+
reason: zod_1.z.string().optional().describe("Optional reason for declining"),
|
|
929
|
+
}),
|
|
930
|
+
async execute(args, context) {
|
|
931
|
+
const { bugId, workflowId, discussionId, reason } = args;
|
|
932
|
+
const { hailer } = context;
|
|
933
|
+
try {
|
|
934
|
+
// 1. Get workflow phases from cached init data (reliable method used by list_workflow_phases)
|
|
935
|
+
const workflowData = context.init.processes?.find((p) => p._id === workflowId);
|
|
936
|
+
if (!workflowData) {
|
|
937
|
+
return {
|
|
938
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
939
|
+
success: false,
|
|
940
|
+
error: `Workflow ${workflowId} not found`
|
|
941
|
+
}) }]
|
|
942
|
+
};
|
|
943
|
+
}
|
|
944
|
+
const phases = workflowData.phases || {};
|
|
945
|
+
const declinedPhase = Object.entries(phases).find(([_, phase]) => phase.name?.toLowerCase() === 'declined');
|
|
946
|
+
if (!declinedPhase) {
|
|
947
|
+
return {
|
|
948
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
949
|
+
success: false,
|
|
950
|
+
error: "Could not find 'Declined' phase in workflow",
|
|
951
|
+
availablePhases: Object.values(phases).map((p) => p.name)
|
|
952
|
+
}) }]
|
|
953
|
+
};
|
|
954
|
+
}
|
|
955
|
+
const [declinedPhaseId, declinedPhaseData] = declinedPhase;
|
|
956
|
+
// 2. Get workflow schema to find status field ID
|
|
957
|
+
const schema = await hailer.getWorkflowSchema(workflowId, declinedPhaseId);
|
|
958
|
+
const statusField = Object.entries(schema.fields || {}).find(([_, f]) => f.key === 'status' || f.label?.toLowerCase() === 'status');
|
|
959
|
+
// 3. Update activity with phase AND status
|
|
960
|
+
const updateData = {
|
|
961
|
+
_id: bugId,
|
|
962
|
+
phaseId: declinedPhaseId,
|
|
963
|
+
};
|
|
964
|
+
if (statusField) {
|
|
965
|
+
updateData.fields = { [statusField[0]]: "Won't Fix" };
|
|
966
|
+
}
|
|
967
|
+
await hailer.updateActivities([updateData]);
|
|
968
|
+
// 4. Leave the discussion
|
|
969
|
+
try {
|
|
970
|
+
await hailer.leaveDiscussion(discussionId);
|
|
971
|
+
}
|
|
972
|
+
catch (e) {
|
|
973
|
+
// Ignore leave errors - might already be out
|
|
974
|
+
}
|
|
975
|
+
return {
|
|
976
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
977
|
+
success: true,
|
|
978
|
+
phase: "Declined",
|
|
979
|
+
status: "Won't Fix",
|
|
980
|
+
leftDiscussion: true,
|
|
981
|
+
reason: reason || "Not a bug"
|
|
982
|
+
}) }]
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
catch (error) {
|
|
986
|
+
return {
|
|
987
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
988
|
+
success: false,
|
|
989
|
+
error: error instanceof Error ? error.message : String(error)
|
|
990
|
+
}) }]
|
|
991
|
+
};
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
};
|
|
995
|
+
// Mark Bug Fixed Tool - handles everything automatically
|
|
996
|
+
exports.markBugFixedTool = {
|
|
997
|
+
name: "mark_bug_fixed",
|
|
998
|
+
group: tool_registry_1.ToolGroup.BOT_INTERNAL,
|
|
999
|
+
description: "Mark a bug as fixed. Automatically sets phase to Fixed, status to 'Fixed', and leaves the discussion. Only use AFTER fix is published and user confirmed it works!",
|
|
1000
|
+
schema: zod_1.z.object({
|
|
1001
|
+
bugId: zod_1.z.string().describe("The bug activity ID"),
|
|
1002
|
+
workflowId: zod_1.z.string().describe("The workflow ID for the Bug Reports workflow"),
|
|
1003
|
+
discussionId: zod_1.z.string().describe("The discussion ID to leave after marking fixed"),
|
|
1004
|
+
fixSummary: zod_1.z.string().optional().describe("Optional summary of what was fixed"),
|
|
1005
|
+
}),
|
|
1006
|
+
async execute(args, context) {
|
|
1007
|
+
const { bugId, workflowId, discussionId, fixSummary } = args;
|
|
1008
|
+
const { hailer } = context;
|
|
1009
|
+
try {
|
|
1010
|
+
// 1. Get workflow phases from cached init data (reliable method used by list_workflow_phases)
|
|
1011
|
+
const workflowData = context.init.processes?.find((p) => p._id === workflowId);
|
|
1012
|
+
if (!workflowData) {
|
|
1013
|
+
return {
|
|
1014
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
1015
|
+
success: false,
|
|
1016
|
+
error: `Workflow ${workflowId} not found`
|
|
1017
|
+
}) }]
|
|
1018
|
+
};
|
|
1019
|
+
}
|
|
1020
|
+
const phases = workflowData.phases || {};
|
|
1021
|
+
const fixedPhase = Object.entries(phases).find(([_, phase]) => phase.name?.toLowerCase() === 'fixed');
|
|
1022
|
+
if (!fixedPhase) {
|
|
1023
|
+
return {
|
|
1024
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
1025
|
+
success: false,
|
|
1026
|
+
error: "Could not find 'Fixed' phase in workflow",
|
|
1027
|
+
availablePhases: Object.values(phases).map((p) => p.name)
|
|
1028
|
+
}) }]
|
|
1029
|
+
};
|
|
1030
|
+
}
|
|
1031
|
+
const [fixedPhaseId, fixedPhaseData] = fixedPhase;
|
|
1032
|
+
// 2. Get workflow schema to find status field ID
|
|
1033
|
+
const schema = await hailer.getWorkflowSchema(workflowId, fixedPhaseId);
|
|
1034
|
+
const statusField = Object.entries(schema.fields || {}).find(([_, f]) => f.key === 'status' || f.label?.toLowerCase() === 'status');
|
|
1035
|
+
// 3. Update activity with phase AND status
|
|
1036
|
+
const updateData = {
|
|
1037
|
+
_id: bugId,
|
|
1038
|
+
phaseId: fixedPhaseId,
|
|
1039
|
+
};
|
|
1040
|
+
if (statusField) {
|
|
1041
|
+
updateData.fields = { [statusField[0]]: "Fixed" };
|
|
1042
|
+
}
|
|
1043
|
+
await hailer.updateActivities([updateData]);
|
|
1044
|
+
// 4. Leave the discussion
|
|
1045
|
+
try {
|
|
1046
|
+
await hailer.leaveDiscussion(discussionId);
|
|
1047
|
+
}
|
|
1048
|
+
catch (e) {
|
|
1049
|
+
// Ignore leave errors - might already be out
|
|
1050
|
+
}
|
|
1051
|
+
return {
|
|
1052
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
1053
|
+
success: true,
|
|
1054
|
+
phase: "Fixed",
|
|
1055
|
+
status: "Fixed",
|
|
1056
|
+
leftDiscussion: true,
|
|
1057
|
+
fixSummary: fixSummary || "Bug fixed"
|
|
1058
|
+
}) }]
|
|
1059
|
+
};
|
|
1060
|
+
}
|
|
1061
|
+
catch (error) {
|
|
1062
|
+
return {
|
|
1063
|
+
content: [{ type: "text", text: JSON.stringify({
|
|
1064
|
+
success: false,
|
|
1065
|
+
error: error instanceof Error ? error.message : String(error)
|
|
1066
|
+
}) }]
|
|
1067
|
+
};
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
};
|
|
1071
|
+
// Export all tools
|
|
1072
|
+
exports.bugFixerTools = [
|
|
1073
|
+
// Low-level tools
|
|
1074
|
+
exports.bugFixerFindAppTool,
|
|
1075
|
+
exports.bugFixerListFilesTool,
|
|
1076
|
+
exports.bugFixerReadFileTool,
|
|
1077
|
+
exports.bugFixerWriteFileTool,
|
|
1078
|
+
exports.bugFixerApplyFixTool,
|
|
1079
|
+
exports.bugFixerRunBuildTool,
|
|
1080
|
+
exports.bugFixerGitStatusTool,
|
|
1081
|
+
exports.bugFixerGitPullTool,
|
|
1082
|
+
exports.bugFixerGitCommitTool,
|
|
1083
|
+
exports.bugFixerGitPushTool,
|
|
1084
|
+
exports.bugFixerGitRevertTool,
|
|
1085
|
+
exports.bugFixerPublishAppTool,
|
|
1086
|
+
// High-level workflow tools (LLM-driven)
|
|
1087
|
+
exports.bugFixerAnalyzeBugTool,
|
|
1088
|
+
exports.bugFixerStartFixTool,
|
|
1089
|
+
exports.bugFixerMarkDeclinedTool,
|
|
1090
|
+
exports.bugFixerPublishFixTool,
|
|
1091
|
+
exports.bugFixerRetryFixTool,
|
|
1092
|
+
// Standalone phase/status tools (no registry dependency)
|
|
1093
|
+
exports.markBugDeclinedTool,
|
|
1094
|
+
exports.markBugFixedTool,
|
|
1095
|
+
];
|
|
1096
|
+
//# sourceMappingURL=bug-fixer-tools.js.map
|