@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.
Files changed (271) hide show
  1. package/CHANGELOG.md +0 -7
  2. package/{.claude → dist}/CLAUDE.md +2 -2
  3. package/dist/app.js +18 -5
  4. package/dist/bot/bot-config.d.ts +10 -1
  5. package/dist/bot/bot-config.js +64 -3
  6. package/dist/bot/bot-manager.d.ts +2 -0
  7. package/dist/bot/bot-manager.js +9 -2
  8. package/dist/bot/bot.d.ts +33 -0
  9. package/dist/bot/bot.js +461 -160
  10. package/dist/bot/services/message-classifier.js +17 -0
  11. package/dist/bot/services/permission-guard.d.ts +52 -0
  12. package/dist/bot/services/permission-guard.js +149 -0
  13. package/dist/bot/services/types.d.ts +5 -0
  14. package/dist/bot/services/typing-indicator.d.ts +6 -1
  15. package/dist/bot/services/typing-indicator.js +19 -3
  16. package/dist/cli.js +0 -0
  17. package/dist/config.d.ts +6 -1
  18. package/dist/config.js +43 -0
  19. package/dist/core.js +3 -6
  20. package/dist/lib/discussion-lock.d.ts +42 -0
  21. package/dist/lib/discussion-lock.js +110 -0
  22. package/dist/mcp/UserContextCache.d.ts +5 -0
  23. package/dist/mcp/UserContextCache.js +51 -19
  24. package/dist/mcp/hailer-clients.d.ts +19 -1
  25. package/dist/mcp/hailer-clients.js +158 -24
  26. package/dist/mcp/session-store.d.ts +68 -0
  27. package/dist/mcp/session-store.js +169 -0
  28. package/dist/mcp/signal-handler.js +2 -0
  29. package/dist/mcp/tool-registry.d.ts +17 -4
  30. package/dist/mcp/tool-registry.js +37 -7
  31. package/dist/mcp/tools/activity.js +99 -7
  32. package/dist/mcp/tools/app-scaffold.js +304 -336
  33. package/dist/mcp/tools/bot-config/constants.d.ts +23 -0
  34. package/dist/mcp/tools/bot-config/constants.js +94 -0
  35. package/dist/mcp/tools/bot-config/core.d.ts +253 -0
  36. package/dist/mcp/tools/bot-config/core.js +2456 -0
  37. package/dist/mcp/tools/bot-config/index.d.ts +10 -0
  38. package/dist/mcp/tools/bot-config/index.js +59 -0
  39. package/dist/mcp/tools/bot-config/tools.d.ts +7 -0
  40. package/dist/mcp/tools/bot-config/tools.js +15 -0
  41. package/dist/mcp/tools/bot-config/types.d.ts +50 -0
  42. package/dist/mcp/tools/bot-config/types.js +6 -0
  43. package/dist/mcp/tools/bug-fixer-tools.d.ts +45 -0
  44. package/dist/mcp/tools/bug-fixer-tools.js +1096 -0
  45. package/dist/mcp/tools/company.d.ts +9 -0
  46. package/dist/mcp/tools/company.js +88 -0
  47. package/dist/mcp/tools/discussion.js +68 -0
  48. package/dist/mcp/tools/document.d.ts +11 -0
  49. package/dist/mcp/tools/document.js +741 -0
  50. package/dist/mcp/tools/investigate.d.ts +9 -0
  51. package/dist/mcp/tools/investigate.js +254 -0
  52. package/dist/mcp/tools/workflow-permissions.d.ts +15 -0
  53. package/dist/mcp/tools/workflow-permissions.js +204 -0
  54. package/dist/mcp/tools/workflow.js +57 -18
  55. package/dist/mcp/utils/index.d.ts +2 -0
  56. package/dist/mcp/utils/index.js +12 -1
  57. package/dist/mcp/utils/role-utils.d.ts +74 -0
  58. package/dist/mcp/utils/role-utils.js +151 -0
  59. package/dist/mcp/utils/types.d.ts +43 -1
  60. package/dist/mcp/utils/types.js +14 -0
  61. package/dist/mcp/webhook-handler.d.ts +4 -0
  62. package/dist/mcp/webhook-handler.js +8 -0
  63. package/dist/mcp-server.d.ts +23 -2
  64. package/dist/mcp-server.js +639 -127
  65. package/dist/plugins/vipunen/client.d.ts +150 -0
  66. package/dist/plugins/vipunen/client.js +535 -0
  67. package/dist/plugins/vipunen/config/schema-config.json +19 -0
  68. package/dist/plugins/vipunen/config/schema-doc.json +22 -0
  69. package/dist/plugins/vipunen/index.d.ts +41 -0
  70. package/dist/plugins/vipunen/index.js +88 -0
  71. package/dist/plugins/vipunen/tools.d.ts +26 -0
  72. package/dist/plugins/vipunen/tools.js +501 -0
  73. package/dist/stdio-server.d.ts +14 -0
  74. package/dist/stdio-server.js +101 -0
  75. package/package.json +2 -1
  76. package/.claude/agents/agent-ada-skill-builder.md +0 -94
  77. package/.claude/agents/agent-alejandro-function-fields.md +0 -342
  78. package/.claude/agents/agent-bjorn-config-audit.md +0 -103
  79. package/.claude/agents/agent-builder-agent-creator.md +0 -130
  80. package/.claude/agents/agent-code-simplifier.md +0 -53
  81. package/.claude/agents/agent-dmitri-activity-crud.md +0 -159
  82. package/.claude/agents/agent-giuseppe-app-builder.md +0 -247
  83. package/.claude/agents/agent-gunther-mcp-tools.md +0 -39
  84. package/.claude/agents/agent-helga-workflow-config.md +0 -204
  85. package/.claude/agents/agent-igor-activity-mover-automation.md +0 -125
  86. package/.claude/agents/agent-ingrid-doc-templates.md +0 -261
  87. package/.claude/agents/agent-ivan-monolith.md +0 -154
  88. package/.claude/agents/agent-kenji-data-reader.md +0 -86
  89. package/.claude/agents/agent-lars-code-inspector.md +0 -102
  90. package/.claude/agents/agent-marco-mockup-builder.md +0 -110
  91. package/.claude/agents/agent-marcus-api-documenter.md +0 -323
  92. package/.claude/agents/agent-marketplace-publisher.md +0 -280
  93. package/.claude/agents/agent-marketplace-reviewer.md +0 -309
  94. package/.claude/agents/agent-permissions-handler.md +0 -208
  95. package/.claude/agents/agent-simple-writer.md +0 -48
  96. package/.claude/agents/agent-svetlana-code-review.md +0 -171
  97. package/.claude/agents/agent-tanya-test-runner.md +0 -333
  98. package/.claude/agents/agent-ui-designer.md +0 -100
  99. package/.claude/agents/agent-viktor-sql-insights.md +0 -212
  100. package/.claude/agents/agent-web-search.md +0 -55
  101. package/.claude/agents/agent-yevgeni-discussions.md +0 -45
  102. package/.claude/agents/agent-zara-zapier.md +0 -159
  103. package/.claude/commands/app-squad.md +0 -135
  104. package/.claude/commands/audit-squad.md +0 -158
  105. package/.claude/commands/autoplan.md +0 -563
  106. package/.claude/commands/cleanup-squad.md +0 -98
  107. package/.claude/commands/config-squad.md +0 -106
  108. package/.claude/commands/crud-squad.md +0 -87
  109. package/.claude/commands/data-squad.md +0 -97
  110. package/.claude/commands/debug-squad.md +0 -303
  111. package/.claude/commands/doc-squad.md +0 -65
  112. package/.claude/commands/handoff.md +0 -137
  113. package/.claude/commands/health.md +0 -49
  114. package/.claude/commands/help.md +0 -29
  115. package/.claude/commands/help:agents.md +0 -151
  116. package/.claude/commands/help:commands.md +0 -78
  117. package/.claude/commands/help:faq.md +0 -79
  118. package/.claude/commands/help:plugins.md +0 -50
  119. package/.claude/commands/help:skills.md +0 -93
  120. package/.claude/commands/help:tools.md +0 -75
  121. package/.claude/commands/hotfix-squad.md +0 -112
  122. package/.claude/commands/integration-squad.md +0 -82
  123. package/.claude/commands/janitor-squad.md +0 -167
  124. package/.claude/commands/learn-auto.md +0 -120
  125. package/.claude/commands/learn.md +0 -120
  126. package/.claude/commands/mcp-list.md +0 -27
  127. package/.claude/commands/onboard-squad.md +0 -140
  128. package/.claude/commands/plan-workspace.md +0 -732
  129. package/.claude/commands/prd.md +0 -130
  130. package/.claude/commands/project-status.md +0 -82
  131. package/.claude/commands/publish.md +0 -138
  132. package/.claude/commands/recap.md +0 -69
  133. package/.claude/commands/restore.md +0 -64
  134. package/.claude/commands/review-squad.md +0 -152
  135. package/.claude/commands/save.md +0 -24
  136. package/.claude/commands/stats.md +0 -19
  137. package/.claude/commands/swarm.md +0 -210
  138. package/.claude/commands/tool-builder.md +0 -39
  139. package/.claude/commands/ws-pull.md +0 -44
  140. package/.claude/hooks/_shared-memory.cjs +0 -305
  141. package/.claude/hooks/_utils.cjs +0 -108
  142. package/.claude/hooks/agent-failure-detector.cjs +0 -383
  143. package/.claude/hooks/agent-usage-logger.cjs +0 -204
  144. package/.claude/hooks/app-edit-guard.cjs +0 -494
  145. package/.claude/hooks/auto-learn.cjs +0 -304
  146. package/.claude/hooks/bash-guard.cjs +0 -272
  147. package/.claude/hooks/builder-mode-manager.cjs +0 -354
  148. package/.claude/hooks/bulk-activity-guard.cjs +0 -271
  149. package/.claude/hooks/context-watchdog.cjs +0 -230
  150. package/.claude/hooks/delegation-reminder.cjs +0 -465
  151. package/.claude/hooks/design-system-lint.cjs +0 -271
  152. package/.claude/hooks/post-scaffold-hook.cjs +0 -181
  153. package/.claude/hooks/prompt-guard.cjs +0 -354
  154. package/.claude/hooks/publish-template-guard.cjs +0 -147
  155. package/.claude/hooks/session-start.cjs +0 -35
  156. package/.claude/hooks/shared-memory-writer.cjs +0 -147
  157. package/.claude/hooks/skill-injector.cjs +0 -140
  158. package/.claude/hooks/skill-usage-logger.cjs +0 -258
  159. package/.claude/hooks/src-edit-guard.cjs +0 -240
  160. package/.claude/hooks/sync-marketplace-agents.cjs +0 -346
  161. package/.claude/settings.json +0 -257
  162. package/.claude/skills/SDK-activity-patterns/SKILL.md +0 -428
  163. package/.claude/skills/SDK-document-templates/SKILL.md +0 -1033
  164. package/.claude/skills/SDK-function-fields/SKILL.md +0 -542
  165. package/.claude/skills/SDK-generate-skill/SKILL.md +0 -92
  166. package/.claude/skills/SDK-init-skill/SKILL.md +0 -127
  167. package/.claude/skills/SDK-insight-queries/SKILL.md +0 -787
  168. package/.claude/skills/SDK-ws-config-skill/SKILL.md +0 -1139
  169. package/.claude/skills/agent-structure/SKILL.md +0 -98
  170. package/.claude/skills/api-documentation-patterns/SKILL.md +0 -474
  171. package/.claude/skills/chrome-mcp-reference/SKILL.md +0 -370
  172. package/.claude/skills/delegation-routing/SKILL.md +0 -202
  173. package/.claude/skills/frontend-design/SKILL.md +0 -254
  174. package/.claude/skills/hailer-activity-mover/SKILL.md +0 -213
  175. package/.claude/skills/hailer-api-client/SKILL.md +0 -518
  176. package/.claude/skills/hailer-app-builder/SKILL.md +0 -1434
  177. package/.claude/skills/hailer-apps-pictures/SKILL.md +0 -269
  178. package/.claude/skills/hailer-design-system/SKILL.md +0 -235
  179. package/.claude/skills/hailer-monolith-automations/SKILL.md +0 -686
  180. package/.claude/skills/hailer-permissions-system/SKILL.md +0 -121
  181. package/.claude/skills/hailer-project-protocol/SKILL.md +0 -488
  182. package/.claude/skills/hailer-rest-api/SKILL.md +0 -61
  183. package/.claude/skills/hailer-rest-api/hailer-activities.md +0 -184
  184. package/.claude/skills/hailer-rest-api/hailer-admin.md +0 -473
  185. package/.claude/skills/hailer-rest-api/hailer-calendar.md +0 -256
  186. package/.claude/skills/hailer-rest-api/hailer-feed.md +0 -249
  187. package/.claude/skills/hailer-rest-api/hailer-insights.md +0 -195
  188. package/.claude/skills/hailer-rest-api/hailer-messaging.md +0 -276
  189. package/.claude/skills/hailer-rest-api/hailer-workflows.md +0 -283
  190. package/.claude/skills/insight-join-patterns/SKILL.md +0 -174
  191. package/.claude/skills/integration-patterns/SKILL.md +0 -421
  192. package/.claude/skills/json-only-output/SKILL.md +0 -72
  193. package/.claude/skills/lsp-setup/SKILL.md +0 -160
  194. package/.claude/skills/mcp-direct-tools/SKILL.md +0 -153
  195. package/.claude/skills/optional-parameters/SKILL.md +0 -72
  196. package/.claude/skills/publish-hailer-app/SKILL.md +0 -244
  197. package/.claude/skills/testing-patterns/SKILL.md +0 -630
  198. package/.claude/skills/tool-builder/SKILL.md +0 -250
  199. package/.claude/skills/tool-parameter-usage/SKILL.md +0 -126
  200. package/.claude/skills/tool-response-verification/SKILL.md +0 -92
  201. package/.claude/skills/zapier-hailer-patterns/SKILL.md +0 -581
  202. package/.mcp.json +0 -13
  203. package/.opencode/agent/agent-ada-skill-builder.md +0 -35
  204. package/.opencode/agent/agent-alejandro-function-fields.md +0 -39
  205. package/.opencode/agent/agent-bjorn-config-audit.md +0 -36
  206. package/.opencode/agent/agent-builder-agent-creator.md +0 -39
  207. package/.opencode/agent/agent-code-simplifier.md +0 -31
  208. package/.opencode/agent/agent-dmitri-activity-crud.md +0 -40
  209. package/.opencode/agent/agent-giuseppe-app-builder.md +0 -37
  210. package/.opencode/agent/agent-gunther-mcp-tools.md +0 -39
  211. package/.opencode/agent/agent-helga-workflow-config.md +0 -203
  212. package/.opencode/agent/agent-igor-activity-mover-automation.md +0 -46
  213. package/.opencode/agent/agent-ingrid-doc-templates.md +0 -39
  214. package/.opencode/agent/agent-ivan-monolith.md +0 -46
  215. package/.opencode/agent/agent-kenji-data-reader.md +0 -53
  216. package/.opencode/agent/agent-lars-code-inspector.md +0 -28
  217. package/.opencode/agent/agent-marco-mockup-builder.md +0 -42
  218. package/.opencode/agent/agent-marcus-api-documenter.md +0 -53
  219. package/.opencode/agent/agent-marketplace-publisher.md +0 -44
  220. package/.opencode/agent/agent-marketplace-reviewer.md +0 -42
  221. package/.opencode/agent/agent-permissions-handler.md +0 -50
  222. package/.opencode/agent/agent-simple-writer.md +0 -45
  223. package/.opencode/agent/agent-svetlana-code-review.md +0 -39
  224. package/.opencode/agent/agent-tanya-test-runner.md +0 -57
  225. package/.opencode/agent/agent-ui-designer.md +0 -56
  226. package/.opencode/agent/agent-viktor-sql-insights.md +0 -34
  227. package/.opencode/agent/agent-web-search.md +0 -42
  228. package/.opencode/agent/agent-yevgeni-discussions.md +0 -37
  229. package/.opencode/agent/agent-zara-zapier.md +0 -53
  230. package/.opencode/commands/app-squad.md +0 -135
  231. package/.opencode/commands/audit-squad.md +0 -158
  232. package/.opencode/commands/autoplan.md +0 -563
  233. package/.opencode/commands/cleanup-squad.md +0 -98
  234. package/.opencode/commands/config-squad.md +0 -106
  235. package/.opencode/commands/crud-squad.md +0 -87
  236. package/.opencode/commands/data-squad.md +0 -97
  237. package/.opencode/commands/debug-squad.md +0 -303
  238. package/.opencode/commands/doc-squad.md +0 -65
  239. package/.opencode/commands/handoff.md +0 -137
  240. package/.opencode/commands/health.md +0 -49
  241. package/.opencode/commands/help-agents.md +0 -151
  242. package/.opencode/commands/help-commands.md +0 -32
  243. package/.opencode/commands/help-faq.md +0 -29
  244. package/.opencode/commands/help-plugins.md +0 -28
  245. package/.opencode/commands/help-skills.md +0 -7
  246. package/.opencode/commands/help-tools.md +0 -40
  247. package/.opencode/commands/help.md +0 -28
  248. package/.opencode/commands/hotfix-squad.md +0 -112
  249. package/.opencode/commands/integration-squad.md +0 -82
  250. package/.opencode/commands/janitor-squad.md +0 -167
  251. package/.opencode/commands/learn-auto.md +0 -120
  252. package/.opencode/commands/learn.md +0 -120
  253. package/.opencode/commands/mcp-list.md +0 -27
  254. package/.opencode/commands/onboard-squad.md +0 -140
  255. package/.opencode/commands/plan-workspace.md +0 -732
  256. package/.opencode/commands/prd.md +0 -131
  257. package/.opencode/commands/project-status.md +0 -82
  258. package/.opencode/commands/publish.md +0 -138
  259. package/.opencode/commands/recap.md +0 -69
  260. package/.opencode/commands/restore.md +0 -64
  261. package/.opencode/commands/review-squad.md +0 -152
  262. package/.opencode/commands/save.md +0 -24
  263. package/.opencode/commands/stats.md +0 -19
  264. package/.opencode/commands/swarm.md +0 -210
  265. package/.opencode/commands/tool-builder.md +0 -39
  266. package/.opencode/commands/ws-pull.md +0 -44
  267. package/.opencode/opencode.json +0 -28
  268. package/SESSION-HANDOFF.md +0 -68
  269. package/inbox/2026-03-04-bot-config-patterns.md +0 -24
  270. package/scripts/postinstall.cjs +0 -64
  271. 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