bobs-workshop 0.3.3 → 3.1.0

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 (200) hide show
  1. package/LICENSE +2 -2
  2. package/README.md +199 -210
  3. package/bin/bobs-workshop.js +109 -0
  4. package/config/agents.json +27 -0
  5. package/dist/plugins/bobs-workshop.js +34 -0
  6. package/dist/tools/background-agent/cancel.d.ts +3 -0
  7. package/dist/tools/background-agent/cancel.d.ts.map +1 -0
  8. package/dist/tools/background-agent/cancel.js +52 -0
  9. package/dist/tools/background-agent/concurrency.d.ts +15 -0
  10. package/dist/tools/background-agent/concurrency.d.ts.map +1 -0
  11. package/dist/tools/background-agent/concurrency.js +61 -0
  12. package/dist/tools/background-agent/index.d.ts +8 -0
  13. package/dist/tools/background-agent/index.d.ts.map +1 -0
  14. package/dist/tools/background-agent/index.js +7 -0
  15. package/dist/tools/background-agent/launch.d.ts +6 -0
  16. package/dist/tools/background-agent/launch.d.ts.map +1 -0
  17. package/dist/tools/background-agent/launch.js +33 -0
  18. package/dist/tools/background-agent/list.d.ts +7 -0
  19. package/dist/tools/background-agent/list.d.ts.map +1 -0
  20. package/dist/tools/background-agent/list.js +40 -0
  21. package/dist/tools/background-agent/manager.d.ts +29 -0
  22. package/dist/tools/background-agent/manager.d.ts.map +1 -0
  23. package/dist/tools/background-agent/manager.js +377 -0
  24. package/dist/tools/background-agent/output.d.ts +3 -0
  25. package/dist/tools/background-agent/output.d.ts.map +1 -0
  26. package/dist/tools/background-agent/output.js +41 -0
  27. package/dist/tools/background-agent/types.d.ts +46 -0
  28. package/dist/tools/background-agent/types.d.ts.map +1 -0
  29. package/dist/tools/background-agent/types.js +1 -0
  30. package/dist/tools/index.d.ts +9 -0
  31. package/dist/tools/index.d.ts.map +1 -0
  32. package/dist/tools/index.js +8 -0
  33. package/dist/tools/manual/index.d.ts +3 -0
  34. package/dist/tools/manual/index.d.ts.map +1 -0
  35. package/dist/tools/manual/index.js +2 -0
  36. package/dist/tools/manual/manual-update.d.ts +4 -0
  37. package/dist/tools/manual/manual-update.d.ts.map +1 -0
  38. package/dist/tools/manual/manual-update.js +190 -0
  39. package/dist/tools/manual/verify-manual.d.ts +4 -0
  40. package/dist/tools/manual/verify-manual.d.ts.map +1 -0
  41. package/dist/tools/manual/verify-manual.js +46 -0
  42. package/package.json +34 -66
  43. package/postinstall.js +190 -0
  44. package/src/agents/alice.md +466 -0
  45. package/src/agents/bob-rev.md +493 -0
  46. package/src/agents/bob-send.md +277 -0
  47. package/src/agents/bob.md +442 -0
  48. package/src/agents/trace.md +451 -0
  49. package/src/plugins/bobs-workshop.ts +45 -0
  50. package/src/skills/api-patterns/SKILL.md +376 -0
  51. package/src/skills/architecture/SKILL.md +271 -0
  52. package/src/skills/bobs-workshop/performance/icon.svg +3 -0
  53. package/src/skills/brainstorming/SKILL.md +210 -0
  54. package/src/skills/clean-code/SKILL.md +151 -0
  55. package/src/skills/code-review-checklist/SKILL.md +220 -0
  56. package/src/skills/database-design/SKILL.md +271 -0
  57. package/src/skills/exploration/SKILL.md +257 -0
  58. package/src/skills/frontend-ui-ux/SKILL.md +78 -0
  59. package/src/skills/git-master/SKILL.md +1105 -0
  60. package/src/skills/performance/SKILL.md +144 -0
  61. package/src/skills/performance/icon.svg +3 -0
  62. package/src/skills/plan-writing/SKILL.md +225 -0
  63. package/src/skills/security/SKILL.md +410 -0
  64. package/src/skills/simplification/SKILL.md +238 -0
  65. package/src/skills/systematic-debugging/SKILL.md +175 -0
  66. package/src/skills/testing-patterns/SKILL.md +305 -0
  67. package/src/skills/verification/SKILL.md +286 -0
  68. package/src/tools/background-agent/cancel.ts +67 -0
  69. package/src/tools/background-agent/concurrency.ts +71 -0
  70. package/src/tools/background-agent/index.ts +7 -0
  71. package/src/tools/background-agent/launch.ts +39 -0
  72. package/src/tools/background-agent/list.ts +50 -0
  73. package/src/tools/background-agent/manager.ts +455 -0
  74. package/src/tools/background-agent/output.ts +57 -0
  75. package/src/tools/background-agent/types.ts +55 -0
  76. package/src/tools/index.ts +8 -0
  77. package/src/tools/manual/index.ts +2 -0
  78. package/src/tools/manual/manual-update.ts +197 -0
  79. package/src/tools/manual/verify-manual.ts +55 -0
  80. package/uninstall.js +64 -0
  81. package/Claude.md +0 -162
  82. package/bin/bobs-mcp-server.js +0 -11
  83. package/bin/bobs-mcp.js +0 -130
  84. package/dist/api/taskLogger.js +0 -106
  85. package/dist/api/taskLogger.js.map +0 -1
  86. package/dist/cli/checker.js +0 -401
  87. package/dist/cli/checker.js.map +0 -1
  88. package/dist/cli/cleanup.js +0 -131
  89. package/dist/cli/cleanup.js.map +0 -1
  90. package/dist/cli/debug.js +0 -157
  91. package/dist/cli/debug.js.map +0 -1
  92. package/dist/cli/health.js +0 -97
  93. package/dist/cli/health.js.map +0 -1
  94. package/dist/cli/setup.js +0 -81
  95. package/dist/cli/setup.js.map +0 -1
  96. package/dist/cli/workshop.js +0 -42
  97. package/dist/cli/workshop.js.map +0 -1
  98. package/dist/dashboard/server.js +0 -1203
  99. package/dist/dashboard/server.js.map +0 -1
  100. package/dist/index.js +0 -960
  101. package/dist/index.js.map +0 -1
  102. package/dist/prompts/architect.js +0 -221
  103. package/dist/prompts/architect.js.map +0 -1
  104. package/dist/prompts/debugger.js +0 -257
  105. package/dist/prompts/debugger.js.map +0 -1
  106. package/dist/prompts/engineer.js +0 -249
  107. package/dist/prompts/engineer.js.map +0 -1
  108. package/dist/prompts/orchestrator.js +0 -304
  109. package/dist/prompts/orchestrator.js.map +0 -1
  110. package/dist/prompts/reviewer.js +0 -289
  111. package/dist/prompts/reviewer.js.map +0 -1
  112. package/dist/services/activitySummarizer.js +0 -388
  113. package/dist/services/activitySummarizer.js.map +0 -1
  114. package/dist/services/changeValidator.js +0 -396
  115. package/dist/services/changeValidator.js.map +0 -1
  116. package/dist/services/claudeOrchestrator.js +0 -343
  117. package/dist/services/claudeOrchestrator.js.map +0 -1
  118. package/dist/services/fileMonitor.js +0 -250
  119. package/dist/services/fileMonitor.js.map +0 -1
  120. package/dist/services/implementationSummarizer.js +0 -306
  121. package/dist/services/implementationSummarizer.js.map +0 -1
  122. package/dist/services/liveMonitor.js +0 -315
  123. package/dist/services/liveMonitor.js.map +0 -1
  124. package/dist/services/mcpAuditLogger.js +0 -104
  125. package/dist/services/mcpAuditLogger.js.map +0 -1
  126. package/dist/services/mcpLogger.js +0 -223
  127. package/dist/services/mcpLogger.js.map +0 -1
  128. package/dist/services/tmuxManager.js +0 -541
  129. package/dist/services/tmuxManager.js.map +0 -1
  130. package/dist/tools/approvalTools.js +0 -244
  131. package/dist/tools/approvalTools.js.map +0 -1
  132. package/dist/tools/autoDebugger.js +0 -147
  133. package/dist/tools/autoDebugger.js.map +0 -1
  134. package/dist/tools/cleanupService.js +0 -221
  135. package/dist/tools/cleanupService.js.map +0 -1
  136. package/dist/tools/dashboardTools.js +0 -342
  137. package/dist/tools/dashboardTools.js.map +0 -1
  138. package/dist/tools/developmentNudges.js +0 -336
  139. package/dist/tools/developmentNudges.js.map +0 -1
  140. package/dist/tools/gitTools.js +0 -741
  141. package/dist/tools/gitTools.js.map +0 -1
  142. package/dist/tools/orchestratorTools.js +0 -832
  143. package/dist/tools/orchestratorTools.js.map +0 -1
  144. package/dist/tools/searchCache.js +0 -64
  145. package/dist/tools/searchCache.js.map +0 -1
  146. package/dist/tools/searchTools.js +0 -1107
  147. package/dist/tools/searchTools.js.map +0 -1
  148. package/dist/tools/semgrep-patterns.js +0 -296
  149. package/dist/tools/semgrep-patterns.js.map +0 -1
  150. package/dist/tools/specTools.js +0 -332
  151. package/dist/tools/specTools.js.map +0 -1
  152. package/dist/tools/structural/__tests__/orchestrator.test.js +0 -61
  153. package/dist/tools/structural/__tests__/orchestrator.test.js.map +0 -1
  154. package/dist/tools/structural/cache.js +0 -226
  155. package/dist/tools/structural/cache.js.map +0 -1
  156. package/dist/tools/structural/engines/python/index.js +0 -118
  157. package/dist/tools/structural/engines/python/index.js.map +0 -1
  158. package/dist/tools/structural/engines/typescript/__tests__/typescript-engine.test.js +0 -97
  159. package/dist/tools/structural/engines/typescript/__tests__/typescript-engine.test.js.map +0 -1
  160. package/dist/tools/structural/engines/typescript/analyzer.js +0 -433
  161. package/dist/tools/structural/engines/typescript/analyzer.js.map +0 -1
  162. package/dist/tools/structural/engines/typescript/index.js +0 -381
  163. package/dist/tools/structural/engines/typescript/index.js.map +0 -1
  164. package/dist/tools/structural/engines/typescript/utils.js +0 -279
  165. package/dist/tools/structural/engines/typescript/utils.js.map +0 -1
  166. package/dist/tools/structural/index.js +0 -248
  167. package/dist/tools/structural/index.js.map +0 -1
  168. package/dist/tools/structural/types.js +0 -18
  169. package/dist/tools/structural/types.js.map +0 -1
  170. package/dist/tools/tmuxTools.js +0 -100
  171. package/dist/tools/tmuxTools.js.map +0 -1
  172. package/dist/tools/workRecorder.js +0 -215
  173. package/dist/tools/workRecorder.js.map +0 -1
  174. package/dist/tools/worktreeTools.js +0 -705
  175. package/dist/tools/worktreeTools.js.map +0 -1
  176. package/dist/utils/__tests__/integration.test.js +0 -57
  177. package/dist/utils/__tests__/integration.test.js.map +0 -1
  178. package/dist/utils/__tests__/serverDetection.test.js +0 -151
  179. package/dist/utils/__tests__/serverDetection.test.js.map +0 -1
  180. package/dist/utils/errorHandling.js +0 -336
  181. package/dist/utils/errorHandling.js.map +0 -1
  182. package/dist/utils/processManager.js +0 -172
  183. package/dist/utils/processManager.js.map +0 -1
  184. package/dist/utils/reliability.js +0 -263
  185. package/dist/utils/reliability.js.map +0 -1
  186. package/dist/utils/responseFormatter.js +0 -250
  187. package/dist/utils/responseFormatter.js.map +0 -1
  188. package/dist/utils/serverDetection.js +0 -133
  189. package/dist/utils/serverDetection.js.map +0 -1
  190. package/dist/utils/specMigration.js +0 -105
  191. package/dist/utils/specMigration.js.map +0 -1
  192. package/dist/validation/schemas.js +0 -299
  193. package/dist/validation/schemas.js.map +0 -1
  194. package/public/.well-known/mcp/manifest.json +0 -473
  195. package/public/index.html +0 -3157
  196. package/public/index.html.backup +0 -2805
  197. package/public/index.html.backup2 +0 -1292
  198. package/scripts/cleanup-system-logs.ts +0 -121
  199. package/scripts/init-workspace.js +0 -63
  200. package/scripts/install-search-tools.js +0 -116
package/dist/index.js DELETED
@@ -1,960 +0,0 @@
1
- #!/usr/bin/env node
2
- // src/index.ts
3
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
4
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
- import { ListResourcesRequestSchema, ReadResourceRequestSchema } from "@modelcontextprotocol/sdk/types.js";
6
- import { z } from "zod";
7
- import { fileURLToPath } from "url";
8
- import path from "path";
9
- import fs from "fs-extra";
10
- // Import all tool handlers
11
- import { specCreateHandler, specUpdateHandler, specGetHandler, specListHandler } from "./tools/specTools.js";
12
- import { worktreeCreateHandler } from "./tools/worktreeTools.js";
13
- import { stopDevServer } from "./utils/processManager.js";
14
- import { hybridSearchHandler } from "./tools/searchTools.js";
15
- import { dashboardLaunchHandler } from "./tools/dashboardTools.js";
16
- import { workshopHandler, formatRoleDirective } from "./tools/orchestratorTools.js";
17
- // REMOVED: Approval tools imports - use structured outputs instead
18
- import { getGitStatus, autoCommitChanges, autoMergeAndCleanup, findWorktreeForSpec } from "./tools/gitTools.js";
19
- import { autoDebugError, shouldInvokeDebugger } from "./tools/autoDebugger.js";
20
- import { cleanupService } from "./tools/cleanupService.js";
21
- import { changeValidator } from "./services/changeValidator.js";
22
- import { implementationSummarizer } from "./services/implementationSummarizer.js";
23
- import { mcpLogger } from "./services/mcpLogger.js";
24
- import { formatConciseResponse } from "./utils/responseFormatter.js";
25
- import { withTimeout, createCircuitBreaker, globalHealthChecker } from "./utils/reliability.js";
26
- import { withErrorHandling, globalErrorCollector } from "./utils/errorHandling.js";
27
- // Import all prompts
28
- import { ARCHITECT_PROMPT } from "./prompts/architect.js";
29
- import { ENGINEER_PROMPT } from "./prompts/engineer.js";
30
- import { DEBUGGER_PROMPT } from "./prompts/debugger.js";
31
- import { REVIEWER_PROMPT } from "./prompts/reviewer.js";
32
- // Global circuit breakers for external operations
33
- const fileSystemCircuitBreaker = createCircuitBreaker({
34
- threshold: 5,
35
- timeout: 15000,
36
- resetTimeout: 30000
37
- });
38
- // Helper function to determine appropriate timeout for different tools
39
- function getToolTimeout(toolName) {
40
- // Longer timeouts for complex operations
41
- if (toolName.includes('search') || toolName.includes('hybrid')) {
42
- return 45000; // 45 seconds for search operations
43
- }
44
- if (toolName.includes('workflow') || toolName.includes('create')) {
45
- return 60000; // 60 seconds for workflow operations
46
- }
47
- return 20000; // 20 seconds default
48
- }
49
- // Initialize health checks for system components
50
- async function initializeHealthChecks() {
51
- // MCP server health check
52
- globalHealthChecker.register('mcp_server', async () => {
53
- try {
54
- // Basic functionality check
55
- return process.uptime() > 0;
56
- }
57
- catch {
58
- return false;
59
- }
60
- });
61
- // File system health check
62
- globalHealthChecker.register('file_system', async () => {
63
- try {
64
- const fs = await import('fs-extra');
65
- const path = await import('path');
66
- const testPath = path.resolve(process.cwd(), '.bob');
67
- await fs.ensureDir(testPath);
68
- return true;
69
- }
70
- catch {
71
- return false;
72
- }
73
- });
74
- // Dashboard service check
75
- globalHealthChecker.register('dashboard', async () => {
76
- try {
77
- // Check if we can create the dashboard server
78
- const { createDashboardServer } = await import('./dashboard/server.js');
79
- const app = createDashboardServer();
80
- return app !== null;
81
- }
82
- catch {
83
- return false;
84
- }
85
- });
86
- console.log("Health checks initialized");
87
- }
88
- // Graceful shutdown handler
89
- async function gracefulShutdown(server) {
90
- console.log("Initiating graceful shutdown...");
91
- try {
92
- // Stop auto-cleanup service
93
- const { cleanupService } = await import('./tools/cleanupService.js');
94
- cleanupService.stopAutoCleanup();
95
- console.log("Auto-cleanup service stopped");
96
- // Perform final cleanup
97
- await cleanupService.performCleanup({
98
- maxWorktreeAge: 7,
99
- cleanTempFiles: true,
100
- stopOrphanedRecorders: true,
101
- forceCleanup: false
102
- });
103
- console.log("Final cleanup completed");
104
- // Log shutdown statistics
105
- const errorStats = globalErrorCollector.getStats();
106
- console.log("Error statistics:", errorStats);
107
- console.log("Graceful shutdown completed");
108
- }
109
- catch (error) {
110
- console.error("Error during shutdown:", error);
111
- }
112
- }
113
- // Enhanced CLI output formatting for modern terminal experience
114
- function generateToolStatusMessage(toolName, args, status, duration, result, error) {
115
- const toolCategory = getToolCategory(toolName);
116
- const categoryIcon = getCategoryIcon(toolCategory);
117
- const statusIcon = getStatusIcon(status);
118
- const toolDisplayName = getToolDisplayName(toolName);
119
- switch (status) {
120
- case 'started':
121
- return `${categoryIcon} [${toolCategory.toUpperCase()}] ${toolDisplayName} → ⏳ Starting...`;
122
- case 'completed':
123
- const durationText = formatDuration(duration || 0);
124
- const summary = extractResultSummary(toolName, result);
125
- return `${categoryIcon} [${toolCategory.toUpperCase()}] ${toolDisplayName} → ${statusIcon} ${summary} (${durationText})`;
126
- case 'error':
127
- const errorDuration = formatDuration(duration || 0);
128
- return `${categoryIcon} [${toolCategory.toUpperCase()}] ${toolDisplayName} → ❌ Failed: ${error} (${errorDuration})`;
129
- default:
130
- return `${categoryIcon} [${toolCategory.toUpperCase()}] ${toolDisplayName}`;
131
- }
132
- }
133
- function getToolCategory(toolName) {
134
- if (toolName.includes('manual'))
135
- return 'manual';
136
- if (toolName.includes('search'))
137
- return 'search';
138
- if (toolName.includes('workflow'))
139
- return 'workflow';
140
- if (toolName.includes('dashboard'))
141
- return 'dashboard';
142
- if (toolName.includes('worktree'))
143
- return 'worktree';
144
- if (toolName.includes('validate'))
145
- return 'validation';
146
- if (toolName.includes('summarize'))
147
- return 'analysis';
148
- if (toolName.includes('health'))
149
- return 'system';
150
- if (toolName.includes('cleanup'))
151
- return 'maintenance';
152
- if (toolName.includes('workshop'))
153
- return 'orchestration';
154
- return 'tool';
155
- }
156
- function getCategoryIcon(category) {
157
- const icons = {
158
- 'manual': '📋',
159
- 'search': '🔍',
160
- 'workflow': '🔄',
161
- 'dashboard': '💻',
162
- 'worktree': '🌳',
163
- 'validation': '✅',
164
- 'analysis': '📊',
165
- 'system': '🛠️',
166
- 'maintenance': '🧹',
167
- 'session': '📺',
168
- 'orchestration': '🎯',
169
- 'tool': '⚙️'
170
- };
171
- return icons[category] || '⚙️';
172
- }
173
- function getStatusIcon(status) {
174
- const icons = {
175
- 'completed': '✅',
176
- 'error': '❌',
177
- 'started': '⏳',
178
- 'success': '✅'
179
- };
180
- return icons[status] || '📄';
181
- }
182
- function getToolDisplayName(toolName) {
183
- return toolName.replace('bob.', '').replace(/\./g, '.');
184
- }
185
- function formatDuration(ms) {
186
- if (ms < 1000)
187
- return `${ms}ms`;
188
- if (ms < 60000)
189
- return `${(ms / 1000).toFixed(1)}s`;
190
- return `${Math.floor(ms / 60000)}m ${Math.floor((ms % 60000) / 1000)}s`;
191
- }
192
- function extractResultSummary(toolName, result) {
193
- if (!result)
194
- return 'Completed';
195
- // Custom summaries based on tool type
196
- if (toolName.includes('manual')) {
197
- if (result.spec_id) {
198
- const action = toolName.includes('create') ? 'Created' : 'Updated';
199
- return `${action} ${result.spec_id.split('-').pop() || 'manual'}`;
200
- }
201
- return 'Manual operation completed';
202
- }
203
- if (toolName.includes('search')) {
204
- if (result.stats?.totalResults !== undefined) {
205
- const count = result.stats.totalResults;
206
- return `${count} result${count !== 1 ? 's' : ''} found`;
207
- }
208
- if (result.lexicalHits && result.semanticHits) {
209
- const total = result.lexicalHits.length + result.semanticHits.length;
210
- return `${total} result${total !== 1 ? 's' : ''} found`;
211
- }
212
- return 'Search completed';
213
- }
214
- if (toolName.includes('workflow')) {
215
- if (toolName.includes('start') && result.manual?.spec_id) {
216
- return `Workflow started for ${result.manual.spec_id.split('-').pop()}`;
217
- }
218
- if (toolName.includes('deploy')) {
219
- return 'Deployment completed';
220
- }
221
- return 'Workflow operation completed';
222
- }
223
- if (toolName.includes('health')) {
224
- const status = result.status || result.overall_healthy;
225
- return status === 'healthy' || status === true ? 'System healthy' : 'Issues detected';
226
- }
227
- if (toolName.includes('validate')) {
228
- if (result.overall_compliance) {
229
- return `Validation: ${result.overall_compliance}`;
230
- }
231
- return 'Validation completed';
232
- }
233
- return 'Operation completed';
234
- }
235
- async function bootstrap() {
236
- const server = new McpServer({
237
- name: "bobs-workshop",
238
- version: "0.2.0"
239
- }, {
240
- capabilities: {
241
- resources: {},
242
- prompts: {},
243
- tools: {},
244
- logging: {}
245
- }
246
- });
247
- // Initialize MCP logging with error handling
248
- try {
249
- mcpLogger.initialize(server.server);
250
- console.log("MCP logging initialized successfully");
251
- }
252
- catch (error) {
253
- console.error("Failed to initialize MCP logging:", error);
254
- // Continue without logging rather than failing completely
255
- }
256
- // Initialize health checks
257
- await initializeHealthChecks();
258
- // Send startup observation to reinforce policy awareness
259
- try {
260
- await mcpLogger.info("👋 Welcome to Bob's Workshop! Please review mcp://bobs-workshop/policy before invoking any tools.");
261
- }
262
- catch (error) {
263
- console.log("Note: Could not send startup observation, but continuing normally");
264
- }
265
- // Enhanced tool call wrapper with reliability features and modern CLI output
266
- const withToolLogging = (toolName, handler) => {
267
- return withErrorHandling(async (args, extra) => {
268
- const startTime = Date.now();
269
- const specId = (args && typeof args === 'object' && 'spec_id' in args) ? args.spec_id : undefined;
270
- // Start logical operation for tool call
271
- const operationId = await mcpLogger.startLogicalOperation('tool_call', specId, `🔧 Executing ${toolName}`);
272
- // Generate enhanced status message for Claude Code terminal
273
- const statusMessage = generateToolStatusMessage(toolName, args, 'started');
274
- console.log(statusMessage);
275
- await mcpLogger.logToolCall(toolName, args, specId);
276
- try {
277
- // Apply timeout to tool operations (30 seconds for most tools)
278
- const timeoutMs = getToolTimeout(toolName);
279
- const result = await withTimeout(() => handler(args, extra), { timeout: timeoutMs });
280
- const duration = Date.now() - startTime;
281
- // Add success sub-event
282
- await mcpLogger.addSubEvent(operationId, {
283
- timestamp: new Date().toISOString(),
284
- event: 'tool_success',
285
- details: { tool_name: toolName, duration_ms: duration }
286
- });
287
- // Generate success status message
288
- const successMessage = generateToolStatusMessage(toolName, args, 'completed', duration, result);
289
- console.log(successMessage);
290
- await mcpLogger.logToolSuccess(toolName, duration, specId);
291
- await mcpLogger.completeLogicalOperation(operationId, true);
292
- // Return enhanced result with status summary
293
- return {
294
- ...result,
295
- _meta: {
296
- tool: toolName,
297
- duration_ms: duration,
298
- status: 'success',
299
- summary: extractResultSummary(toolName, result)
300
- }
301
- };
302
- }
303
- catch (error) {
304
- const duration = Date.now() - startTime;
305
- const errorMsg = error instanceof Error ? error.message : String(error);
306
- // Add error sub-event
307
- await mcpLogger.addSubEvent(operationId, {
308
- timestamp: new Date().toISOString(),
309
- event: 'tool_error',
310
- details: { tool_name: toolName, error: errorMsg }
311
- });
312
- // Generate error status message
313
- const errorMessage = generateToolStatusMessage(toolName, args, 'error', duration, null, errorMsg);
314
- console.log(errorMessage);
315
- await mcpLogger.logToolError(toolName, errorMsg, duration, specId);
316
- await mcpLogger.completeLogicalOperation(operationId, false);
317
- // Auto-debug if we have a spec_id and this is a critical error
318
- if (specId && shouldInvokeDebugger(error)) {
319
- try {
320
- await autoDebugError({
321
- spec_id: specId,
322
- operation: `MCP tool execution: ${toolName}`,
323
- error: error,
324
- context: { args, toolName, duration }
325
- });
326
- console.log(`[AUTO-DEBUG] Created debug log for ${toolName} error in spec ${specId}`);
327
- }
328
- catch (debugError) {
329
- console.log(`[AUTO-DEBUG] Failed to create debug log: ${debugError}`);
330
- }
331
- }
332
- throw error;
333
- }
334
- }, `MCP tool: ${toolName}`, (args) => ({
335
- tool_name: toolName,
336
- spec_id: (args && typeof args === 'object' && 'spec_id' in args) ? args.spec_id : undefined
337
- }));
338
- };
339
- // Configure path resolution for manifest (works in both dev and global install)
340
- const __filename = fileURLToPath(import.meta.url);
341
- const __dirname = path.dirname(__filename);
342
- const getManifestPath = () => {
343
- // Resolve manifest path relative to compiled dist directory
344
- // When installed globally: /opt/homebrew/lib/node_modules/bobs-mcp/dist/index.js
345
- // Manifest at: /opt/homebrew/lib/node_modules/bobs-mcp/public/.well-known/mcp/manifest.json
346
- return path.resolve(__dirname, "../public/.well-known/mcp/manifest.json");
347
- };
348
- // Register MCP resource endpoints to expose manifest.json
349
- // This allows Claude Code to read llm_guidance configuration for tool selection
350
- server.server.setRequestHandler(ListResourcesRequestSchema, async () => {
351
- return {
352
- resources: [
353
- {
354
- uri: "mcp://bobs-workshop/manifest",
355
- name: "Bob's MCP Manifest",
356
- description: "MCP server manifest with tool definitions and LLM guidance for optimal tool selection",
357
- mimeType: "application/json"
358
- },
359
- {
360
- uri: "mcp://bobs-workshop/policy",
361
- name: "Bob's Workshop Policy",
362
- description: "Runtime behavioral rules and best practices for using Bob's Workshop",
363
- mimeType: "text/markdown"
364
- }
365
- ]
366
- };
367
- });
368
- server.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
369
- if (request.params.uri === "mcp://bobs-workshop/manifest") {
370
- try {
371
- const manifestPath = getManifestPath();
372
- // Check if manifest file exists
373
- if (!await fs.pathExists(manifestPath)) {
374
- console.error(`[MANIFEST ERROR] Manifest not found at: ${manifestPath}`);
375
- throw new Error(`Manifest file not found at ${manifestPath}`);
376
- }
377
- const manifest = await fs.readFile(manifestPath, "utf-8");
378
- console.log(`[MANIFEST] Served manifest from ${manifestPath}`);
379
- return {
380
- contents: [{
381
- uri: request.params.uri,
382
- mimeType: "application/json",
383
- text: manifest
384
- }]
385
- };
386
- }
387
- catch (error) {
388
- console.error(`[MANIFEST ERROR] Failed to read manifest:`, error);
389
- throw new Error(`Failed to read manifest: ${error instanceof Error ? error.message : String(error)}`);
390
- }
391
- }
392
- if (request.params.uri === "mcp://bobs-workshop/policy") {
393
- const policyContent = `# Bob's Workshop – Usage Policy
394
-
395
- ## 1. Code Search Best Practices
396
-
397
- **Understanding Search Modes:**
398
-
399
- **Lexical Mode** (pattern matching via ripgrep):
400
- - ✅ Single terms: \`bob.code.search({ query: "mcpLogger", mode: "lexical" })\`
401
- - ✅ Regex patterns: \`bob.code.search({ query: "mcpLogger\\\\.(log|info)", mode: "lexical" })\`
402
- - ✅ Multi-word: Automatically interpreted with smart cascade (see below)
403
-
404
- **Multi-Word Query Smart Cascade:**
405
- When you use multi-word queries like "pdf export", the tool automatically tries patterns in order:
406
- 1. **Method call** (2 words, identifiers): \`object\\.(method)\`
407
- 2. **Ordered proximity** (3+ words or fallback): \`word1.*word2.*word3\`
408
- 3. **OR pattern** (last resort if #2 returns 0): \`\\b(word1|word2|word3)\\b\`
409
-
410
- The tool will inform you which pattern was used and return results automatically.
411
-
412
- **Semantic Mode** (conceptual via semgrep):
413
- - ✅ Multi-word concepts: \`bob.code.search({ query: "authentication error handling", mode: "auto" })\`
414
- - Automatically selected for 3+ word queries in architect/debugger/reviewer phases
415
- - Best for understanding architecture, security, patterns
416
-
417
- **Auto Mode** (recommended - intelligent routing):
418
- - Automatically chooses lexical or semantic based on query and phase
419
- - 3+ words + semantic-enabled phase → semantic mode
420
- - Otherwise → lexical mode with smart cascade
421
-
422
- **Examples:**
423
- \`\`\`javascript
424
- // Method call (auto-detects)
425
- bob.code.search({ query: "mcpLogger info", mode: "lexical" })
426
- // → Tries: mcpLogger\\.(info) → Results found ✅
427
-
428
- // Concept search (ordered proximity)
429
- bob.code.search({ query: "pdf export", mode: "lexical" })
430
- // → Tries: pdf.*export → 355 results ✅
431
- // → Note: Skipped OR pattern (would return 1,665 noisy results)
432
-
433
- // Semantic routing (auto mode)
434
- bob.code.search({ query: "authentication flow security", mode: "auto", phase: "architect" })
435
- // → Routes to semantic search
436
- \`\`\`
437
-
438
- ## 2. Tool Preference Hierarchy
439
-
440
- **Search Strategy:**
441
- 1. **Start with \`bob.code.search\`** (auto mode) - smart cascade handles multi-word
442
- 2. **Use Glob** for finding specific files by name/pattern
443
- 3. **Use Read** when you know the exact file path
444
- 4. **Use Grep** only for exact string matching (when bob.code.search doesn't fit)
445
-
446
- **Manual Updates:**
447
- - ❌ DO NOT create separate markdown files
448
- - ✅ ALWAYS use \`bob.manual.update\` with execution_log/debug_log
449
-
450
- **Git Operations:**
451
- - ❌ DO NOT use manual git commands
452
- - ✅ ALWAYS use \`bob.workflow.start\` and \`bob.workflow.deploy\`
453
-
454
- ## 3. Workflow Sequence
455
- Follow the mode progression:
456
- Orchestrator → Architect → Engineer → Debugger → Reviewer
457
-
458
- ## 4. Manual as Single Source of Truth
459
- - All specifications, logs, and progress MUST be in SPEC files
460
- - DO NOT create separate markdown files
461
- - Use \`bob.manual.update\` with execution_log or debug_log
462
-
463
- ## 5. Mode-Specific Responsibilities
464
- **Architect**: Creates executive_summary, product_specifications, architecture_analysis, implementation_plan, testing
465
- **Engineer**: Updates execution_logs
466
- **Debugger**: Updates debug_logs
467
- **Reviewer**: Creates own review manual
468
-
469
- ## 6. Before Acting
470
- 1. Review this policy
471
- 2. Use \`bob.code.search\` to locate information
472
- 3. Log updates with \`bob.manual.update\`
473
- `;
474
- console.log(`[POLICY] Served policy resource`);
475
- return {
476
- contents: [{
477
- uri: request.params.uri,
478
- mimeType: "text/markdown",
479
- text: policyContent
480
- }]
481
- };
482
- }
483
- throw new Error(`Unknown resource URI: ${request.params.uri}`);
484
- });
485
- console.log("[MANIFEST] Resource endpoints registered successfully");
486
- // Register orchestrator tool (main entry point)
487
- server.registerTool("bob.workshop", {
488
- title: "🔧 Intelligent workflow orchestrator for all development tasks",
489
- description: "🔧 Main entry point for all development workflows. Analyzes problems, asks clarifying questions when needed, and assigns you a role (Architect, Engineer, Debugger, Reviewer). When this tool returns, YOU will assume the assigned role and execute the provided actions immediately. This is not external routing - you are the agent.",
490
- inputSchema: {
491
- problem: z.string().min(5).describe("Problem statement or task description (e.g. 'Add JWT authentication', 'Fix login bug', 'Review user service')"),
492
- mode: z.enum(["architect", "engineer", "debugger", "reviewer"]).optional().describe("Preferred mode (optional - will be auto-determined based on problem)"),
493
- spec_id: z.string().optional().describe("Continue work on existing manual (optional)"),
494
- clarifications: z.record(z.string()).optional().describe("Answers to previous clarifying questions")
495
- }
496
- }, withToolLogging("bob.workshop", async ({ problem, mode, spec_id, clarifications }) => {
497
- console.log("bob.workshop orchestrator called with:", { problem, mode, spec_id, clarifications });
498
- const result = await workshopHandler({ problem, mode, spec_id, clarifications });
499
- // Format response with role directive if routing to a mode (BACKEND-002 & BACKEND-003)
500
- // This implements Option A: Enhanced Tool Response pattern from workflows-mcp-server
501
- let responseText;
502
- if ((result.action === 'route' || result.action === 'continue') && result.next_mode) {
503
- const directive = formatRoleDirective(result.next_mode, {
504
- spec_id: result.spec_id,
505
- problem: problem,
506
- confidence: 'confidence_score' in result ? result.confidence_score : undefined
507
- });
508
- responseText = `${directive}\n\n---\n\nContext (JSON):\n${JSON.stringify(result, null, 2)}`;
509
- }
510
- else {
511
- // For clarify, await_approval, etc. - just return JSON (no directive)
512
- responseText = JSON.stringify(result, null, 2);
513
- }
514
- return { content: [{ type: "text", text: responseText }] };
515
- }));
516
- // Register Manual management tools (new workshop terminology)
517
- server.registerTool("bob.manual.create", {
518
- title: "🔧 Start a new feature manual for this project",
519
- description: "🔧 Start a new feature manual for this project. Use this when building new apps, features, or components. This creates the manual that drives planning, coding, debugging, and review.",
520
- inputSchema: {
521
- title: z.string().describe("Title of the feature/app to build (e.g. 'Sudoku PWA', 'User Authentication')"),
522
- author: z.string().optional().describe("Author of the manual"),
523
- category: z.string().optional().describe("Category: frontend, backend, fullstack, devtools, etc."),
524
- priority: z.string().optional().describe("Priority: low, medium, high, critical"),
525
- tags: z.array(z.string()).optional().describe("Tags for organization (e.g. ['pwa', 'mobile', 'game'])")
526
- }
527
- }, withToolLogging("bob.manual.create", async ({ title, author, category, priority, tags }) => {
528
- console.log("bob.manual.create MCP tool called with:", { title, author, category, priority, tags });
529
- const result = await specCreateHandler({ title, author, category, priority, tags, initial_state: "draft" });
530
- const conciseText = await formatConciseResponse("bob.manual.create", result);
531
- return { content: [{ type: "text", text: conciseText }] };
532
- }));
533
- server.registerTool("bob.manual.update", {
534
- title: "🔧 Update details or logs in a manual",
535
- description: "🔧 Update details or logs in a manual (implementation notes, debug entries, etc.). Use this to add progress updates, execution logs, or debug information to an existing manual.",
536
- inputSchema: {
537
- spec_id: z.string().describe("Manual ID to update"),
538
- section: z.enum(["executive_summary", "product_specifications", "architecture_analysis", "implementation_plan", "testing", "risk_assessment", "review"]).optional().describe("Section to update"),
539
- content: z.string().optional().describe("Content to add to the section"),
540
- execution_log: z.object({
541
- timestamp: z.string(),
542
- engineer: z.string(),
543
- action: z.string(),
544
- task_id: z.string(),
545
- files_changed: z.array(z.string()),
546
- commit_hash: z.string(),
547
- note: z.string()
548
- }).optional().describe("Execution log entry"),
549
- debug_log: z.object({
550
- timestamp: z.string(),
551
- issue: z.string(),
552
- root_cause: z.string(),
553
- fix: z.string(),
554
- confidence: z.string()
555
- }).optional().describe("Debug log entry"),
556
- state: z.enum(["draft", "ready", "engineered", "done"]).optional().describe("Manual state to set explicitly")
557
- }
558
- }, withToolLogging("bob.manual.update", async ({ spec_id, section, content, execution_log, debug_log, state }) => {
559
- const result = await specUpdateHandler({ spec_id, section, content, execution_log, debug_log, state });
560
- // Detect mode based on what type of update this is
561
- let mode = 'unknown';
562
- if (execution_log)
563
- mode = 'engineer';
564
- else if (debug_log)
565
- mode = 'debugger';
566
- else if (section === 'architecture_analysis' || section === 'product_specifications')
567
- mode = 'architect';
568
- else if (section === 'review')
569
- mode = 'reviewer';
570
- const conciseText = await formatConciseResponse("bob.manual.update", result);
571
- return { content: [{ type: "text", text: conciseText }] };
572
- }));
573
- server.registerTool("bob.manual.get", {
574
- title: "🔧 Retrieve a specific manual",
575
- description: "🔧 Retrieve a specific manual with all its details, logs, and current status. Use this to review existing manuals before making updates or continuing work.",
576
- inputSchema: {
577
- spec_id: z.string().describe("Manual ID to retrieve")
578
- }
579
- }, withToolLogging("bob.manual.get", async ({ spec_id }) => {
580
- const result = await specGetHandler({ spec_id });
581
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
582
- }));
583
- server.registerTool("bob.manual.list", {
584
- title: "🔧 List all project manuals",
585
- description: "🔧 List all project manuals with their current status. Use this to see what features/components are planned, in progress, or completed.",
586
- inputSchema: {
587
- filter: z.string().optional().describe("Optional filter by title or category")
588
- }
589
- }, async ({ filter }) => {
590
- const result = await specListHandler({ filter });
591
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
592
- });
593
- // REMOVED: Legacy bob.spec.* tools - use bob.manual.* instead
594
- // REMOVED: Individual worktree and git tools - use bob.workflow.* instead
595
- // The following tools have been consolidated into bob.workflow.start and bob.workflow.deploy:
596
- // - bob.worktree.list (use bob.worktree.debug with action: "status" instead)
597
- // - bob.git.commit (automated by bob.workflow.deploy)
598
- // - bob.git.merge (automated by bob.workflow.deploy)
599
- // Advanced worktree maintenance tool (kept for debugging)
600
- server.registerTool("bob.worktree.debug", {
601
- title: "🔧 Debug and maintain worktrees",
602
- description: "🔧 Comprehensive worktree maintenance tool. Handles repair (fix orphaned worktrees), cleanup (remove stale worktrees), validate (check worktree status), and status (detailed report). Essential for fail-safe worktree management.",
603
- inputSchema: {
604
- action: z.enum(["repair", "cleanup", "validate", "status"]).describe("Debug action: 'status' = report all worktrees, 'validate' = check manual worktree, 'repair' = fix orphaned worktrees, 'cleanup' = remove stale worktrees"),
605
- spec_id: z.string().optional().describe("Optional manual ID for validate/repair actions"),
606
- max_age_days: z.number().optional().default(7).describe("Max age in days for cleanup action (default: 7)")
607
- }
608
- }, withToolLogging("bob.worktree.debug", async ({ action, spec_id, max_age_days = 7 }) => {
609
- const { worktreeDebugHandler } = await import("./tools/worktreeTools.js");
610
- const result = await worktreeDebugHandler({ action, spec_id, max_age_days });
611
- const conciseText = await formatConciseResponse("bob.worktree.debug", result);
612
- return { content: [{ type: "text", text: conciseText }] };
613
- }));
614
- // REMOVED: Old search tools - use bob.code.search instead
615
- server.registerTool("bob.code.search", {
616
- title: "🔧 Unified lexical + semantic + structural search",
617
- description: "🔧 Hybrid search combining ripgrep (lexical), semgrep (semantic), and AST-based (structural) for comprehensive code search. Primary search tool with phase-aware execution and normalized outputs.",
618
- inputSchema: {
619
- query: z.string().describe("Search query to find in codebase. Structural queries like 'find references to X', 'show dependencies' use AST analysis."),
620
- mode: z.enum(["lexical", "semantic", "structural", "auto"]).optional().default("auto").describe("Search mode: lexical (ripgrep), semantic (semgrep), structural (AST-based), or auto (intelligent routing)"),
621
- phase: z.enum(["architect", "engineer", "debugger", "reviewer"]).optional().describe("Caller phase for phase-aware Semgrep rule selection"),
622
- path: z.string().optional().describe("Root path or subdirectory to search (optional)"),
623
- includeHidden: z.boolean().optional().default(false).describe("Include hidden/ignored files (equivalent to rg -uuu)"),
624
- followGitIgnore: z.boolean().optional().default(true).describe("Respect .gitignore rules (default: true)"),
625
- fileTypes: z.array(z.string()).optional().describe("File types to include (e.g., ['ts', 'tsx', 'py'])"),
626
- maxHits: z.number().optional().default(30).describe("Maximum total results to return (default: 30 for token efficiency)"),
627
- perFileLimit: z.number().optional().default(5).describe("Maximum matches per file (default: 5 to prevent single-file domination)"),
628
- contextLines: z.number().optional().default(2).describe("Context lines before/after matches"),
629
- timeoutMs: z.number().optional().default(4000).describe("Timeout in milliseconds"),
630
- verbose: z.boolean().optional().default(false).describe("Include full lexicalHits/semanticHits arrays for debugging (increases token usage)")
631
- }
632
- }, async ({ query, mode, phase, path, includeHidden, followGitIgnore, fileTypes, maxHits, perFileLimit, contextLines, timeoutMs, verbose }) => {
633
- const result = await hybridSearchHandler({
634
- query,
635
- mode: mode || "auto",
636
- phase,
637
- path,
638
- includeHidden: includeHidden || false,
639
- followGitIgnore: followGitIgnore !== false,
640
- fileTypes,
641
- maxHits: maxHits || 30,
642
- perFileLimit: perFileLimit || 5,
643
- contextLines: contextLines || 2,
644
- timeoutMs: timeoutMs || 4000,
645
- verbose: verbose || false
646
- });
647
- // Keep search results verbose since Claude needs to see the content
648
- // But add concise summary to _meta for status messages
649
- const enhancedResult = {
650
- ...result,
651
- _meta: {
652
- ...(result._meta || {}),
653
- summary: formatConciseResponse("bob.code.search", result)
654
- }
655
- };
656
- return {
657
- content: [{
658
- type: "text",
659
- text: JSON.stringify(enhancedResult, null, 2)
660
- }]
661
- };
662
- });
663
- // Register dashboard tools
664
- server.registerTool("bob.dashboard.launch", {
665
- title: "🔧 Open the visual workshop management interface",
666
- description: "🔧 Launch the visual workshop dashboard for tracking manuals, worktrees, and logs on port 4577. Orchestrator should launch this when starting new feature development. Architect MUST launch this when working on new manuals. Returns status: 'launched', 'already_running', or 'already_running_external'. Process exits cleanly without hanging."
667
- }, async () => {
668
- const result = await dashboardLaunchHandler();
669
- return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
670
- });
671
- // REMOVED: bob.dashboard.update tool - use bob.manual.update with execution_log/debug_log instead
672
- // REMOVED: Approval tools - use structured outputs with approval_required flag instead
673
- // Register Simplified Workflow tools (bundled git + worktree operations)
674
- server.registerTool("bob.workflow.start", {
675
- title: "🔧 Start new feature development workflow",
676
- description: "🔧 Architect workflow: Create manual + worktree + launch dashboard. Bundles manual creation, git worktree setup, and dashboard launch for streamlined feature development start.",
677
- inputSchema: {
678
- title: z.string().describe("Title of the feature/app to build"),
679
- author: z.string().optional().describe("Author of the manual"),
680
- category: z.string().optional().describe("Category: frontend, backend, fullstack, devtools, etc."),
681
- priority: z.string().optional().describe("Priority: low, medium, high, critical"),
682
- tags: z.array(z.string()).optional().describe("Tags for organization"),
683
- branch_name: z.string().optional().describe("Custom branch name (auto-generated if not provided)")
684
- }
685
- }, withToolLogging("bob.workflow.start", async ({ title, author, category, priority, tags, branch_name }) => {
686
- console.log("bob.workflow.start called with:", { title, author, category, priority, tags, branch_name });
687
- // Create manual
688
- const manual = await specCreateHandler({ title, author, category, priority, tags, initial_state: "draft" });
689
- // Create worktree with auto-generated branch name if not provided
690
- const branchName = branch_name || `feature/${title.toLowerCase().replace(/[^a-z0-9]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '')}`;
691
- const worktree = await worktreeCreateHandler({ spec_id: manual.spec_id, branch: branchName });
692
- // Launch dashboard
693
- const dashboard = await dashboardLaunchHandler();
694
- // Log workflow initialization via execution log (dashboard reads from SPEC file)
695
- await specUpdateHandler({
696
- spec_id: manual.spec_id,
697
- execution_log: {
698
- timestamp: new Date().toISOString(),
699
- engineer: "architect",
700
- action: "planning: milestone_completed",
701
- task_id: "WORKFLOW_INIT",
702
- files_changed: [`manual: ${manual.spec_id}`, `worktree: ${branchName}`, "dashboard: launched"],
703
- commit_hash: "pending",
704
- note: "[planning] 🎯 Milestone: Feature development workflow started. Deliverables: manual: " + manual.spec_id + ", worktree: " + branchName + ", dashboard: launched. Next: complete requirements analysis, create implementation plan, start development"
705
- }
706
- });
707
- // NOTE: Dev server startup moved to post-test phase in Engineer workflow
708
- // This prevents early resource conflicts and aligns with 3-gate approval system
709
- const workflowResult = {
710
- manual: manual,
711
- worktree: worktree,
712
- dashboard: dashboard,
713
- workflow_status: "started",
714
- work_recording: "active",
715
- note: "Dev server will be started after implementation and testing"
716
- };
717
- const conciseText = await formatConciseResponse("bob.workflow.start", workflowResult);
718
- return {
719
- content: [{
720
- type: "text",
721
- text: conciseText
722
- }]
723
- };
724
- }));
725
- server.registerTool("bob.workflow.deploy", {
726
- title: "🔧 Complete implementation and deploy to main",
727
- description: "🔧 Engineer workflow: Commit changes + merge to main + cleanup worktree. Bundles git operations for streamlined feature completion and deployment.",
728
- inputSchema: {
729
- spec_id: z.string().describe("Manual ID for the completed implementation"),
730
- action_description: z.string().describe("Brief description of what was implemented"),
731
- files_changed: z.array(z.string()).optional().describe("List of files changed (auto-detected if not provided)"),
732
- target_branch: z.string().optional().default("main").describe("Target branch to merge into")
733
- }
734
- }, withToolLogging("bob.workflow.deploy", async ({ spec_id, action_description, files_changed, target_branch = "main" }) => {
735
- console.log("bob.workflow.deploy called with:", { spec_id, action_description, files_changed, target_branch });
736
- // Get git status and auto-detect changed files if not provided
737
- const gitStatus = await getGitStatus();
738
- const changedFiles = files_changed || [...gitStatus.staged_files, ...gitStatus.unstaged_files, ...gitStatus.untracked_files];
739
- // NEW: Stop any running dev server before deployment
740
- let serverCleanupInfo = null;
741
- try {
742
- console.log(`Stopping dev server for manual ${spec_id}...`);
743
- const serverStopped = await stopDevServer(spec_id);
744
- if (serverStopped) {
745
- serverCleanupInfo = { server_stopped: true };
746
- console.log(`Dev server stopped successfully for manual ${spec_id}`);
747
- // Log server cleanup
748
- await specUpdateHandler({
749
- spec_id,
750
- execution_log: {
751
- timestamp: new Date().toISOString(),
752
- engineer: "system",
753
- action: "server_stopped",
754
- task_id: "auto-server-cleanup",
755
- files_changed: [],
756
- commit_hash: "pending",
757
- note: `Auto-stopped dev server before deployment`
758
- }
759
- });
760
- }
761
- else {
762
- serverCleanupInfo = { server_stopped: false, reason: "no_server_running" };
763
- console.log(`No running server found for manual ${spec_id}`);
764
- }
765
- }
766
- catch (serverError) {
767
- console.warn('Server cleanup failed (non-critical):', serverError);
768
- serverCleanupInfo = { server_stopped: false, error: String(serverError) };
769
- }
770
- // Find worktree path for this spec
771
- const worktreePath = await findWorktreeForSpec(spec_id);
772
- console.log(`Found worktree path: ${worktreePath}`);
773
- // Commit changes
774
- const commit = await autoCommitChanges({
775
- spec_id,
776
- files_changed: changedFiles,
777
- action_description,
778
- worktree_path: worktreePath || undefined
779
- });
780
- // Merge and cleanup
781
- const merge = await autoMergeAndCleanup({
782
- spec_id,
783
- target_branch,
784
- cleanup_worktree: true
785
- });
786
- // Record completion milestone (dashboard reads from SPEC file)
787
- await specUpdateHandler({
788
- spec_id: spec_id,
789
- execution_log: {
790
- timestamp: new Date().toISOString(),
791
- engineer: "engineer",
792
- action: "implementation: workflow_deployment_completed",
793
- task_id: "WORKFLOW_DEPLOY",
794
- files_changed: changedFiles,
795
- commit_hash: commit.commit_hash,
796
- note: `🚀 Successfully deployed implementation: ${action_description}. Committed ${changedFiles.length} files and merged to ${target_branch}. Commit: ${commit.commit_hash}`
797
- }
798
- });
799
- const deployResult = {
800
- commit: commit,
801
- merge: merge,
802
- server_cleanup: serverCleanupInfo,
803
- workflow_status: "deployed",
804
- work_recording: "completed"
805
- };
806
- const conciseText = await formatConciseResponse("bob.workflow.deploy", deployResult);
807
- return {
808
- content: [{
809
- type: "text",
810
- text: conciseText
811
- }]
812
- };
813
- }));
814
- // Health check tool migrated to CLI: use "bobs health"
815
- // Register change validation tool
816
- server.registerTool("bob.validate.changes", {
817
- title: "🔍 Validate implementation changes against manual",
818
- description: "🔍 Validate recent file changes against manual expectations. Analyzes actual diffs, checks compliance, and provides human-readable summaries of what was implemented.",
819
- inputSchema: {
820
- spec_id: z.string().describe("Manual ID to validate changes against")
821
- }
822
- }, withToolLogging("bob.validate.changes", async ({ spec_id }) => {
823
- console.log("bob.validate.changes called with:", { spec_id });
824
- if (!spec_id) {
825
- throw new Error("spec_id is required");
826
- }
827
- const validationResult = await changeValidator.validateChangesForSpec(spec_id);
828
- // Update manual with validation results
829
- await changeValidator.updateSpecWithValidation(validationResult);
830
- return { content: [{ type: "text", text: JSON.stringify(validationResult, null, 2) }] };
831
- }));
832
- // Register implementation summarizer tool
833
- server.registerTool("bob.summarize.implementation", {
834
- title: "📊 Generate implementation summary from chokidar observations",
835
- description: "📊 Analyze file changes observed by chokidar and generate comprehensive implementation summaries with compliance analysis, git commits, and actionable insights. Updates the manual's implementation logs.",
836
- inputSchema: {
837
- spec_id: z.string().describe("Manual ID to generate implementation summary for"),
838
- lookback_hours: z.number().optional().default(24).describe("Hours to look back for changes (default: 24)")
839
- }
840
- }, withToolLogging("bob.summarize.implementation", async ({ spec_id, lookback_hours = 24 }) => {
841
- console.log("bob.summarize.implementation called with:", { spec_id, lookback_hours });
842
- if (!spec_id) {
843
- throw new Error("spec_id is required");
844
- }
845
- const summary = await implementationSummarizer.generateSummaryForSpec(spec_id, lookback_hours);
846
- // Update manual with summary
847
- await implementationSummarizer.updateSpecWithSummary(summary);
848
- return { content: [{ type: "text", text: JSON.stringify(summary, null, 2) }] };
849
- }));
850
- // Cleanup tools migrated to CLI: use "bobs cleanup" and "bobs cleanup --stats"
851
- // Debug tool - no parameters
852
- server.registerTool("bob.debug", {
853
- title: "🔧 Debug Bob's Workshop server state",
854
- description: "🔧 Debug tool with no parameters. Use this to check Bob's Workshop internal state and troubleshoot issues.",
855
- }, async () => {
856
- console.log("bob.debug called successfully");
857
- return {
858
- content: [
859
- {
860
- type: "text",
861
- text: "Debug tool works!",
862
- },
863
- ],
864
- };
865
- });
866
- // Register prompts
867
- server.registerPrompt("Architect", { description: "Requirements analysis and technical planning specialist" }, async () => ({
868
- messages: [{ role: "user", content: [{ type: "text", text: ARCHITECT_PROMPT }] }]
869
- }));
870
- server.registerPrompt("Engineer", { description: "Implementation specialist following engineering best practices" }, async () => ({
871
- messages: [{ role: "user", content: [{ type: "text", text: ENGINEER_PROMPT }] }]
872
- }));
873
- server.registerPrompt("Debugger", { description: "Issue diagnosis and resolution specialist" }, async () => ({
874
- messages: [{ role: "user", content: [{ type: "text", text: DEBUGGER_PROMPT }] }]
875
- }));
876
- server.registerPrompt("Reviewer", { description: "Quality assurance and security audit specialist" }, async () => ({
877
- messages: [{ role: "user", content: [{ type: "text", text: REVIEWER_PROMPT }] }]
878
- }));
879
- server.registerPrompt("help", { description: "Get guidance on using Bob's Workshop effectively" }, async () => {
880
- const helpContent = `You are connected to Bob's Workshop MCP.
881
-
882
- Before taking any actions:
883
- 1. Review \`mcp://bobs-workshop/policy\` for behavioral rules
884
- 2. Use \`bob.code.search\` to locate information
885
- 3. Log updates with \`bob.manual.update\`
886
- 4. Follow the workflow sequence: Orchestrator → Architect → Engineer → Debugger → Reviewer
887
-
888
- ## Quick Reference
889
-
890
- **Multi-Word Search - Smart Cascade:**
891
-
892
- The tool automatically interprets your query:
893
-
894
- **Method Calls** (2 words, identifiers):
895
- \`\`\`javascript
896
- { query: "mcpLogger info", mode: "lexical" }
897
- // → Auto-tries: mcpLogger\\.(info)
898
- // → Finds: await mcpLogger.info(...) calls
899
- \`\`\`
900
-
901
- **Concept Search** (3+ words or fallback):
902
- \`\`\`javascript
903
- { query: "pdf export", mode: "lexical" }
904
- // → Auto-tries: pdf.*export
905
- // → Finds: 355 results about PDF export
906
- // → Skips noisy OR pattern (would be 1,665 results)
907
- \`\`\`
908
-
909
- **How It Works:**
910
- 1. Tries method call pattern (if 2 identifiers)
911
- 2. Tries ordered proximity (word1.*word2.*word3)
912
- 3. Falls back to OR only if needed
913
-
914
- The tool tells you which pattern matched in the results.
915
-
916
- **Tool Preference:**
917
- - ✅ bob.code.search (handles multi-word automatically)
918
- - ❌ Grep, Glob (for general search)
919
-
920
- Need more details? Read the full policy at \`mcp://bobs-workshop/policy\`.`;
921
- return {
922
- messages: [{ role: "user", content: [{ type: "text", text: helpContent }] }]
923
- };
924
- });
925
- // Start auto-cleanup service
926
- cleanupService.startAutoCleanup(30); // Every 30 minutes
927
- console.log("Auto-cleanup service started (30-minute intervals)");
928
- // Set up graceful shutdown handlers
929
- const signals = ['SIGTERM', 'SIGINT', 'SIGUSR2'];
930
- signals.forEach(signal => {
931
- process.on(signal, async () => {
932
- console.log(`Received ${signal}, initiating graceful shutdown`);
933
- await gracefulShutdown(server);
934
- process.exit(0);
935
- });
936
- });
937
- // Handle uncaught exceptions and rejections
938
- process.on('uncaughtException', async (error) => {
939
- console.error('Uncaught Exception:', error);
940
- globalErrorCollector.add(await import('./utils/errorHandling.js').then(m => m.enhanceError(error, m.createErrorContext('uncaught_exception'))));
941
- await gracefulShutdown(server);
942
- process.exit(1);
943
- });
944
- process.on('unhandledRejection', async (reason, promise) => {
945
- console.error('Unhandled Rejection at:', promise, 'reason:', reason);
946
- const error = reason instanceof Error ? reason : new Error(String(reason));
947
- globalErrorCollector.add(await import('./utils/errorHandling.js').then(m => m.enhanceError(error, m.createErrorContext('unhandled_rejection'))));
948
- await gracefulShutdown(server);
949
- process.exit(1);
950
- });
951
- console.log("Starting Bob MCP server with enhanced reliability...");
952
- const transport = new StdioServerTransport();
953
- await server.connect(transport);
954
- console.log("Bob MCP server started successfully");
955
- }
956
- bootstrap().catch(err => {
957
- console.error("Failed to start Bob MCP:", err);
958
- process.exit(1);
959
- });
960
- //# sourceMappingURL=index.js.map