bobs-workshop 0.3.3 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +2 -2
- package/README.md +199 -210
- package/bin/bobs-workshop.js +109 -0
- package/config/agents.json +27 -0
- package/dist/plugins/bobs-workshop.js +34 -0
- package/dist/tools/background-agent/cancel.d.ts +3 -0
- package/dist/tools/background-agent/cancel.d.ts.map +1 -0
- package/dist/tools/background-agent/cancel.js +52 -0
- package/dist/tools/background-agent/concurrency.d.ts +15 -0
- package/dist/tools/background-agent/concurrency.d.ts.map +1 -0
- package/dist/tools/background-agent/concurrency.js +61 -0
- package/dist/tools/background-agent/index.d.ts +8 -0
- package/dist/tools/background-agent/index.d.ts.map +1 -0
- package/dist/tools/background-agent/index.js +7 -0
- package/dist/tools/background-agent/launch.d.ts +6 -0
- package/dist/tools/background-agent/launch.d.ts.map +1 -0
- package/dist/tools/background-agent/launch.js +33 -0
- package/dist/tools/background-agent/list.d.ts +7 -0
- package/dist/tools/background-agent/list.d.ts.map +1 -0
- package/dist/tools/background-agent/list.js +40 -0
- package/dist/tools/background-agent/manager.d.ts +29 -0
- package/dist/tools/background-agent/manager.d.ts.map +1 -0
- package/dist/tools/background-agent/manager.js +388 -0
- package/dist/tools/background-agent/output.d.ts +3 -0
- package/dist/tools/background-agent/output.d.ts.map +1 -0
- package/dist/tools/background-agent/output.js +41 -0
- package/dist/tools/background-agent/types.d.ts +46 -0
- package/dist/tools/background-agent/types.d.ts.map +1 -0
- package/dist/tools/background-agent/types.js +1 -0
- package/dist/tools/index.d.ts +9 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +8 -0
- package/dist/tools/manual/index.d.ts +3 -0
- package/dist/tools/manual/index.d.ts.map +1 -0
- package/dist/tools/manual/index.js +2 -0
- package/dist/tools/manual/manual-update.d.ts +4 -0
- package/dist/tools/manual/manual-update.d.ts.map +1 -0
- package/dist/tools/manual/manual-update.js +190 -0
- package/dist/tools/manual/verify-manual.d.ts +4 -0
- package/dist/tools/manual/verify-manual.d.ts.map +1 -0
- package/dist/tools/manual/verify-manual.js +51 -0
- package/package.json +34 -66
- package/postinstall.js +193 -0
- package/src/agents/alice.md +466 -0
- package/src/agents/bob-rev.md +493 -0
- package/src/agents/bob-send.md +277 -0
- package/src/agents/bob.md +442 -0
- package/src/agents/trace.md +451 -0
- package/src/plugins/bobs-workshop.ts +45 -0
- package/src/skills/api-patterns/SKILL.md +376 -0
- package/src/skills/architecture/SKILL.md +271 -0
- package/src/skills/bobs-workshop/performance/icon.svg +3 -0
- package/src/skills/brainstorming/SKILL.md +210 -0
- package/src/skills/clean-code/SKILL.md +151 -0
- package/src/skills/code-review-checklist/SKILL.md +220 -0
- package/src/skills/database-design/SKILL.md +271 -0
- package/src/skills/exploration/SKILL.md +257 -0
- package/src/skills/frontend-ui-ux/SKILL.md +78 -0
- package/src/skills/git-master/SKILL.md +1105 -0
- package/src/skills/performance/SKILL.md +144 -0
- package/src/skills/performance/icon.svg +3 -0
- package/src/skills/plan-writing/SKILL.md +225 -0
- package/src/skills/security/SKILL.md +410 -0
- package/src/skills/simplification/SKILL.md +238 -0
- package/src/skills/systematic-debugging/SKILL.md +175 -0
- package/src/skills/testing-patterns/SKILL.md +305 -0
- package/src/skills/verification/SKILL.md +286 -0
- package/src/tools/background-agent/cancel.ts +67 -0
- package/src/tools/background-agent/concurrency.ts +71 -0
- package/src/tools/background-agent/index.ts +7 -0
- package/src/tools/background-agent/launch.ts +39 -0
- package/src/tools/background-agent/list.ts +50 -0
- package/src/tools/background-agent/manager.ts +466 -0
- package/src/tools/background-agent/output.ts +57 -0
- package/src/tools/background-agent/types.ts +55 -0
- package/src/tools/index.ts +8 -0
- package/src/tools/manual/index.ts +2 -0
- package/src/tools/manual/manual-update.ts +197 -0
- package/src/tools/manual/verify-manual.ts +60 -0
- package/uninstall.js +64 -0
- package/Claude.md +0 -162
- package/bin/bobs-mcp-server.js +0 -11
- package/bin/bobs-mcp.js +0 -130
- package/dist/api/taskLogger.js +0 -106
- package/dist/api/taskLogger.js.map +0 -1
- package/dist/cli/checker.js +0 -401
- package/dist/cli/checker.js.map +0 -1
- package/dist/cli/cleanup.js +0 -131
- package/dist/cli/cleanup.js.map +0 -1
- package/dist/cli/debug.js +0 -157
- package/dist/cli/debug.js.map +0 -1
- package/dist/cli/health.js +0 -97
- package/dist/cli/health.js.map +0 -1
- package/dist/cli/setup.js +0 -81
- package/dist/cli/setup.js.map +0 -1
- package/dist/cli/workshop.js +0 -42
- package/dist/cli/workshop.js.map +0 -1
- package/dist/dashboard/server.js +0 -1203
- package/dist/dashboard/server.js.map +0 -1
- package/dist/index.js +0 -960
- package/dist/index.js.map +0 -1
- package/dist/prompts/architect.js +0 -221
- package/dist/prompts/architect.js.map +0 -1
- package/dist/prompts/debugger.js +0 -257
- package/dist/prompts/debugger.js.map +0 -1
- package/dist/prompts/engineer.js +0 -249
- package/dist/prompts/engineer.js.map +0 -1
- package/dist/prompts/orchestrator.js +0 -304
- package/dist/prompts/orchestrator.js.map +0 -1
- package/dist/prompts/reviewer.js +0 -289
- package/dist/prompts/reviewer.js.map +0 -1
- package/dist/services/activitySummarizer.js +0 -388
- package/dist/services/activitySummarizer.js.map +0 -1
- package/dist/services/changeValidator.js +0 -396
- package/dist/services/changeValidator.js.map +0 -1
- package/dist/services/claudeOrchestrator.js +0 -343
- package/dist/services/claudeOrchestrator.js.map +0 -1
- package/dist/services/fileMonitor.js +0 -250
- package/dist/services/fileMonitor.js.map +0 -1
- package/dist/services/implementationSummarizer.js +0 -306
- package/dist/services/implementationSummarizer.js.map +0 -1
- package/dist/services/liveMonitor.js +0 -315
- package/dist/services/liveMonitor.js.map +0 -1
- package/dist/services/mcpAuditLogger.js +0 -104
- package/dist/services/mcpAuditLogger.js.map +0 -1
- package/dist/services/mcpLogger.js +0 -223
- package/dist/services/mcpLogger.js.map +0 -1
- package/dist/services/tmuxManager.js +0 -541
- package/dist/services/tmuxManager.js.map +0 -1
- package/dist/tools/approvalTools.js +0 -244
- package/dist/tools/approvalTools.js.map +0 -1
- package/dist/tools/autoDebugger.js +0 -147
- package/dist/tools/autoDebugger.js.map +0 -1
- package/dist/tools/cleanupService.js +0 -221
- package/dist/tools/cleanupService.js.map +0 -1
- package/dist/tools/dashboardTools.js +0 -342
- package/dist/tools/dashboardTools.js.map +0 -1
- package/dist/tools/developmentNudges.js +0 -336
- package/dist/tools/developmentNudges.js.map +0 -1
- package/dist/tools/gitTools.js +0 -741
- package/dist/tools/gitTools.js.map +0 -1
- package/dist/tools/orchestratorTools.js +0 -832
- package/dist/tools/orchestratorTools.js.map +0 -1
- package/dist/tools/searchCache.js +0 -64
- package/dist/tools/searchCache.js.map +0 -1
- package/dist/tools/searchTools.js +0 -1107
- package/dist/tools/searchTools.js.map +0 -1
- package/dist/tools/semgrep-patterns.js +0 -296
- package/dist/tools/semgrep-patterns.js.map +0 -1
- package/dist/tools/specTools.js +0 -332
- package/dist/tools/specTools.js.map +0 -1
- package/dist/tools/structural/__tests__/orchestrator.test.js +0 -61
- package/dist/tools/structural/__tests__/orchestrator.test.js.map +0 -1
- package/dist/tools/structural/cache.js +0 -226
- package/dist/tools/structural/cache.js.map +0 -1
- package/dist/tools/structural/engines/python/index.js +0 -118
- package/dist/tools/structural/engines/python/index.js.map +0 -1
- package/dist/tools/structural/engines/typescript/__tests__/typescript-engine.test.js +0 -97
- package/dist/tools/structural/engines/typescript/__tests__/typescript-engine.test.js.map +0 -1
- package/dist/tools/structural/engines/typescript/analyzer.js +0 -433
- package/dist/tools/structural/engines/typescript/analyzer.js.map +0 -1
- package/dist/tools/structural/engines/typescript/index.js +0 -381
- package/dist/tools/structural/engines/typescript/index.js.map +0 -1
- package/dist/tools/structural/engines/typescript/utils.js +0 -279
- package/dist/tools/structural/engines/typescript/utils.js.map +0 -1
- package/dist/tools/structural/index.js +0 -248
- package/dist/tools/structural/index.js.map +0 -1
- package/dist/tools/structural/types.js +0 -18
- package/dist/tools/structural/types.js.map +0 -1
- package/dist/tools/tmuxTools.js +0 -100
- package/dist/tools/tmuxTools.js.map +0 -1
- package/dist/tools/workRecorder.js +0 -215
- package/dist/tools/workRecorder.js.map +0 -1
- package/dist/tools/worktreeTools.js +0 -705
- package/dist/tools/worktreeTools.js.map +0 -1
- package/dist/utils/__tests__/integration.test.js +0 -57
- package/dist/utils/__tests__/integration.test.js.map +0 -1
- package/dist/utils/__tests__/serverDetection.test.js +0 -151
- package/dist/utils/__tests__/serverDetection.test.js.map +0 -1
- package/dist/utils/errorHandling.js +0 -336
- package/dist/utils/errorHandling.js.map +0 -1
- package/dist/utils/processManager.js +0 -172
- package/dist/utils/processManager.js.map +0 -1
- package/dist/utils/reliability.js +0 -263
- package/dist/utils/reliability.js.map +0 -1
- package/dist/utils/responseFormatter.js +0 -250
- package/dist/utils/responseFormatter.js.map +0 -1
- package/dist/utils/serverDetection.js +0 -133
- package/dist/utils/serverDetection.js.map +0 -1
- package/dist/utils/specMigration.js +0 -105
- package/dist/utils/specMigration.js.map +0 -1
- package/dist/validation/schemas.js +0 -299
- package/dist/validation/schemas.js.map +0 -1
- package/public/.well-known/mcp/manifest.json +0 -473
- package/public/index.html +0 -3157
- package/public/index.html.backup +0 -2805
- package/public/index.html.backup2 +0 -1292
- package/scripts/cleanup-system-logs.ts +0 -121
- package/scripts/init-workspace.js +0 -63
- package/scripts/install-search-tools.js +0 -116
|
@@ -1,832 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { specCreateHandler, specGetHandler, specListHandler } from "./specTools.js";
|
|
3
|
-
import { dashboardLaunchHandler, dashboardUpdateHandler } from "./dashboardTools.js";
|
|
4
|
-
import { mcpLogger } from "../services/mcpLogger.js";
|
|
5
|
-
import { validateGate1, validateGate2, validateGate3, validateEnhancedStateTransition } from "../validation/schemas.js";
|
|
6
|
-
export const WorkshopInput = z.object({
|
|
7
|
-
problem: z.string().describe("Problem statement or task description"),
|
|
8
|
-
mode: z.enum(["architect", "engineer", "debugger", "reviewer"]).optional().describe("Preferred mode (optional - will be auto-determined)"),
|
|
9
|
-
spec_id: z.string().optional().describe("Continue existing SPEC (optional)"),
|
|
10
|
-
clarifications: z.record(z.string()).optional().describe("Answers to previous clarifying questions"),
|
|
11
|
-
user_approval: z.boolean().optional().describe("User approval for spec or implementation"),
|
|
12
|
-
user_satisfaction: z.boolean().optional().describe("User satisfaction with completed work")
|
|
13
|
-
});
|
|
14
|
-
export const WorkshopOutput = z.object({
|
|
15
|
-
spec_id: z.string(),
|
|
16
|
-
action: z.enum(["clarify", "route", "continue", "await_approval", "proceed", "complete"]),
|
|
17
|
-
clarify_questions: z.array(z.string()).optional(),
|
|
18
|
-
next_mode: z.string().optional(),
|
|
19
|
-
dashboard_url: z.string().optional(),
|
|
20
|
-
prompt_context: z.string().optional(),
|
|
21
|
-
workflow_step: z.enum([
|
|
22
|
-
"questioning", "spec_review", "approved", "implementation",
|
|
23
|
-
"user_review", "completed", "routed_to_architect", "routed_to_engineer",
|
|
24
|
-
"routed_to_debugger", "routed_to_reviewer"
|
|
25
|
-
]).optional(),
|
|
26
|
-
requires_user_input: z.boolean().optional(),
|
|
27
|
-
approval_message: z.string().optional(),
|
|
28
|
-
confidence_score: z.number().optional().describe("Confidence level in problem understanding (0-1)")
|
|
29
|
-
});
|
|
30
|
-
export async function workshopHandler(input) {
|
|
31
|
-
console.log("bob.workshop orchestrator called with:", input);
|
|
32
|
-
const validated = WorkshopInput.parse(input);
|
|
33
|
-
// Step 1: Analyze the problem statement
|
|
34
|
-
const analysis = analyzeProblem(validated.problem, validated.clarifications);
|
|
35
|
-
// Step 2: Handle existing SPEC continuation
|
|
36
|
-
if (validated.spec_id) {
|
|
37
|
-
return await continueExistingSpec(validated.spec_id, analysis, validated.mode);
|
|
38
|
-
}
|
|
39
|
-
// Step 3: Check for existing related SPECs
|
|
40
|
-
const existingSpecs = await findRelatedSpecs(validated.problem);
|
|
41
|
-
// Step 4: Decide if we need clarification (enhanced threshold and logic)
|
|
42
|
-
if (analysis.confidence < 0.95 && !validated.clarifications && analysis.questions.length > 0) {
|
|
43
|
-
return {
|
|
44
|
-
spec_id: "",
|
|
45
|
-
action: "clarify",
|
|
46
|
-
clarify_questions: analysis.questions,
|
|
47
|
-
next_mode: analysis.suggestedMode,
|
|
48
|
-
dashboard_url: undefined,
|
|
49
|
-
prompt_context: undefined,
|
|
50
|
-
workflow_step: "questioning",
|
|
51
|
-
requires_user_input: true,
|
|
52
|
-
approval_message: `I need to ask ${analysis.questions.length} clarifying question${analysis.questions.length > 1 ? 's' : ''} before proceeding. Please provide answers to ensure accurate implementation.`,
|
|
53
|
-
confidence_score: analysis.confidence
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
// Step 5: Create new SPEC for new features with parallel dashboard update
|
|
57
|
-
let specId = "";
|
|
58
|
-
if (analysis.category === "feature" || analysis.category === "research") {
|
|
59
|
-
// Create SPEC and send dashboard update in parallel
|
|
60
|
-
const [newSpec] = await Promise.allSettled([
|
|
61
|
-
specCreateHandler({
|
|
62
|
-
title: extractTitle(validated.problem),
|
|
63
|
-
author: "AI Orchestrator",
|
|
64
|
-
category: mapCategoryToSpecCategory(analysis.category),
|
|
65
|
-
priority: mapComplexityToPriority(analysis.complexity),
|
|
66
|
-
tags: extractTags(validated.problem),
|
|
67
|
-
initial_state: "draft"
|
|
68
|
-
}),
|
|
69
|
-
sendDashboardUpdate("", "orchestrator_started", {
|
|
70
|
-
action: "spec_creation",
|
|
71
|
-
problem: validated.problem,
|
|
72
|
-
analysis: {
|
|
73
|
-
category: analysis.category,
|
|
74
|
-
complexity: analysis.complexity,
|
|
75
|
-
confidence: analysis.confidence
|
|
76
|
-
}
|
|
77
|
-
})
|
|
78
|
-
]);
|
|
79
|
-
if (newSpec.status === 'fulfilled') {
|
|
80
|
-
specId = newSpec.value.spec_id;
|
|
81
|
-
// Send spec creation notification
|
|
82
|
-
await sendDashboardUpdate(specId, "spec_created", {
|
|
83
|
-
title: extractTitle(validated.problem),
|
|
84
|
-
category: analysis.category,
|
|
85
|
-
complexity: analysis.complexity
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
throw new Error(`Failed to create SPEC: ${newSpec.reason}`);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
else if (existingSpecs.length > 0) {
|
|
93
|
-
// Use most recent existing SPEC for non-feature work
|
|
94
|
-
specId = existingSpecs[0].spec_id;
|
|
95
|
-
// Notify about continuing existing SPEC
|
|
96
|
-
await sendDashboardUpdate(specId, "spec_continued", {
|
|
97
|
-
problem: validated.problem,
|
|
98
|
-
analysis: {
|
|
99
|
-
category: analysis.category,
|
|
100
|
-
complexity: analysis.complexity
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
// Step 6: Launch dashboard for new feature work with parallel notification
|
|
105
|
-
let dashboardUrl = "";
|
|
106
|
-
if (analysis.category === "feature" && analysis.suggestedMode === "architect") {
|
|
107
|
-
const [dashboardResult] = await Promise.allSettled([
|
|
108
|
-
dashboardLaunchHandler(),
|
|
109
|
-
sendDashboardUpdate(specId, "dashboard_launch_requested", {
|
|
110
|
-
mode: analysis.suggestedMode,
|
|
111
|
-
reason: "new feature development"
|
|
112
|
-
})
|
|
113
|
-
]);
|
|
114
|
-
if (dashboardResult.status === 'fulfilled') {
|
|
115
|
-
dashboardUrl = "http://localhost:4577";
|
|
116
|
-
// Notify dashboard is ready
|
|
117
|
-
await sendDashboardUpdate(specId, "dashboard_launched", {
|
|
118
|
-
url: dashboardUrl,
|
|
119
|
-
status: dashboardResult.value?.status || "launched"
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
// Step 7: Determine final mode (respect explicit preference)
|
|
124
|
-
const finalMode = validated.mode || analysis.suggestedMode;
|
|
125
|
-
// Log role transition from orchestrator to target mode
|
|
126
|
-
await mcpLogger.logRoleTransition('orchestrator', finalMode, specId, `Problem classified as ${analysis.category} (confidence: ${Math.round(analysis.confidence * 100)}%)`);
|
|
127
|
-
// Step 8: Create context for the target mode
|
|
128
|
-
const promptContext = await createModeContext(finalMode, validated.problem, specId, analysis);
|
|
129
|
-
// Step 9: Send final mode switching notification in parallel with return
|
|
130
|
-
const result = {
|
|
131
|
-
spec_id: specId,
|
|
132
|
-
action: "route",
|
|
133
|
-
clarify_questions: undefined,
|
|
134
|
-
next_mode: finalMode,
|
|
135
|
-
dashboard_url: dashboardUrl || undefined,
|
|
136
|
-
prompt_context: promptContext,
|
|
137
|
-
workflow_step: `routed_to_${finalMode}`,
|
|
138
|
-
requires_user_input: false,
|
|
139
|
-
approval_message: undefined,
|
|
140
|
-
confidence_score: analysis.confidence
|
|
141
|
-
};
|
|
142
|
-
// Send mode switching notification without blocking return
|
|
143
|
-
sendDashboardUpdate(specId, "orchestrator_mode_switch", {
|
|
144
|
-
target_mode: finalMode,
|
|
145
|
-
workflow_step: `switching_to_${finalMode}`,
|
|
146
|
-
dashboard_available: !!dashboardUrl,
|
|
147
|
-
execution_note: `YOU are now switching to ${finalMode} mode - execute ${finalMode.toUpperCase()}_PROMPT steps directly`
|
|
148
|
-
}).catch(error => {
|
|
149
|
-
console.log('Dashboard mode switch notification failed (non-blocking):', error);
|
|
150
|
-
});
|
|
151
|
-
return result;
|
|
152
|
-
}
|
|
153
|
-
function analyzeProblem(problem, clarifications) {
|
|
154
|
-
const lowerProblem = problem.toLowerCase();
|
|
155
|
-
// Simple keyword-based analysis (can be enhanced with more sophisticated NLP)
|
|
156
|
-
let category = "feature";
|
|
157
|
-
let suggestedMode = "architect";
|
|
158
|
-
let confidence = 0.8; // Base confidence
|
|
159
|
-
const questions = [];
|
|
160
|
-
// Detect category and mode with priority order (most specific first)
|
|
161
|
-
if (lowerProblem.includes("review") || lowerProblem.includes("audit") || lowerProblem.includes("check") || lowerProblem.includes("vulnerabilities")) {
|
|
162
|
-
category = "review";
|
|
163
|
-
suggestedMode = "reviewer";
|
|
164
|
-
confidence += 0.2;
|
|
165
|
-
}
|
|
166
|
-
else if (lowerProblem.includes("bug") || lowerProblem.includes("fix") || lowerProblem.includes("error") || lowerProblem.includes("broken")) {
|
|
167
|
-
category = "bug";
|
|
168
|
-
suggestedMode = "debugger";
|
|
169
|
-
confidence += 0.2;
|
|
170
|
-
}
|
|
171
|
-
else if (lowerProblem.includes("implement") || lowerProblem.includes("develop") || (lowerProblem.includes("according") && lowerProblem.includes("spec"))) {
|
|
172
|
-
category = "implementation";
|
|
173
|
-
suggestedMode = "engineer";
|
|
174
|
-
confidence += 0.2;
|
|
175
|
-
}
|
|
176
|
-
else if (lowerProblem.includes("add") || lowerProblem.includes("create") || lowerProblem.includes("build") || lowerProblem.includes("new") || lowerProblem.includes("dashboard") || lowerProblem.includes("feature") || lowerProblem.includes("library") || lowerProblem.includes("make me")) {
|
|
177
|
-
category = "feature";
|
|
178
|
-
suggestedMode = "architect";
|
|
179
|
-
confidence += 0.15;
|
|
180
|
-
}
|
|
181
|
-
// Assess complexity
|
|
182
|
-
let complexity = "medium";
|
|
183
|
-
if (lowerProblem.length < 50 || lowerProblem.split(" ").length < 8) {
|
|
184
|
-
complexity = "simple";
|
|
185
|
-
confidence -= 0.1;
|
|
186
|
-
}
|
|
187
|
-
else if (lowerProblem.length > 200 || lowerProblem.includes("system") || lowerProblem.includes("architecture")) {
|
|
188
|
-
complexity = "complex";
|
|
189
|
-
confidence += 0.05;
|
|
190
|
-
}
|
|
191
|
-
// Final category adjustment based on strong indicators (only for ambiguous cases)
|
|
192
|
-
if (category === "feature" && (lowerProblem.includes("dashboard") || lowerProblem.includes("comprehensive") || lowerProblem.includes("components"))) {
|
|
193
|
-
confidence = 0.9; // High confidence for clear feature descriptions
|
|
194
|
-
}
|
|
195
|
-
// Enhanced question generation with more sophisticated probing
|
|
196
|
-
if (!clarifications) {
|
|
197
|
-
// Feature category questions
|
|
198
|
-
if (category === "feature") {
|
|
199
|
-
// Core architecture questions
|
|
200
|
-
if (!lowerProblem.includes("user") && !lowerProblem.includes("api") && !lowerProblem.includes("frontend") && !lowerProblem.includes("backend")) {
|
|
201
|
-
questions.push("Is this a user-facing feature, internal API, or full-stack component?");
|
|
202
|
-
confidence -= 0.08;
|
|
203
|
-
}
|
|
204
|
-
// Data persistence questions
|
|
205
|
-
if (!lowerProblem.includes("database") && !lowerProblem.includes("storage") && !lowerProblem.includes("persist") && complexity !== "simple") {
|
|
206
|
-
questions.push("Does this feature need to store/persist data? If so, what type of data?");
|
|
207
|
-
confidence -= 0.06;
|
|
208
|
-
}
|
|
209
|
-
// Security and access control
|
|
210
|
-
if (!lowerProblem.includes("authentication") && !lowerProblem.includes("permission") && !lowerProblem.includes("role") && lowerProblem.includes("user")) {
|
|
211
|
-
questions.push("What are the authentication and authorization requirements? Who can access this feature?");
|
|
212
|
-
confidence -= 0.06;
|
|
213
|
-
}
|
|
214
|
-
// Integration and dependencies
|
|
215
|
-
if (!lowerProblem.includes("integrate") && !lowerProblem.includes("external") && !lowerProblem.includes("api") && complexity === "complex") {
|
|
216
|
-
questions.push("Does this feature integrate with external services or existing systems?");
|
|
217
|
-
confidence -= 0.04;
|
|
218
|
-
}
|
|
219
|
-
// Performance and scale
|
|
220
|
-
if (!lowerProblem.includes("performance") && !lowerProblem.includes("scale") && !lowerProblem.includes("users") && complexity !== "simple") {
|
|
221
|
-
questions.push("What are the expected performance requirements and user scale?");
|
|
222
|
-
confidence -= 0.04;
|
|
223
|
-
}
|
|
224
|
-
// UI/UX considerations
|
|
225
|
-
if (lowerProblem.includes("user") && !lowerProblem.includes("interface") && !lowerProblem.includes("ui") && !lowerProblem.includes("design")) {
|
|
226
|
-
questions.push("Do you have specific UI/UX requirements or design preferences?");
|
|
227
|
-
confidence -= 0.03;
|
|
228
|
-
}
|
|
229
|
-
// Testing strategy
|
|
230
|
-
if (!lowerProblem.includes("test") && !lowerProblem.includes("quality") && complexity !== "simple") {
|
|
231
|
-
questions.push("What level of testing is required (unit, integration, e2e)?");
|
|
232
|
-
confidence -= 0.03;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
else if (category === "bug") {
|
|
236
|
-
// Reproduction steps
|
|
237
|
-
if (!lowerProblem.includes("reproduce") && !lowerProblem.includes("steps") && !lowerProblem.includes("when")) {
|
|
238
|
-
questions.push("Can you provide detailed steps to reproduce this issue?");
|
|
239
|
-
confidence -= 0.08;
|
|
240
|
-
}
|
|
241
|
-
// Expected vs actual behavior
|
|
242
|
-
if (!lowerProblem.includes("expect") && !lowerProblem.includes("should") && !lowerProblem.includes("supposed")) {
|
|
243
|
-
questions.push("What is the expected behavior vs. what you're actually seeing?");
|
|
244
|
-
confidence -= 0.07;
|
|
245
|
-
}
|
|
246
|
-
// Environment and context
|
|
247
|
-
if (!lowerProblem.includes("environment") && !lowerProblem.includes("browser") && !lowerProblem.includes("version")) {
|
|
248
|
-
questions.push("In what environment does this occur (browser, OS, version, etc.)?");
|
|
249
|
-
confidence -= 0.06;
|
|
250
|
-
}
|
|
251
|
-
// Frequency and impact
|
|
252
|
-
if (!lowerProblem.includes("always") && !lowerProblem.includes("sometimes") && !lowerProblem.includes("critical")) {
|
|
253
|
-
questions.push("How frequently does this occur and what's the business impact?");
|
|
254
|
-
confidence -= 0.05;
|
|
255
|
-
}
|
|
256
|
-
// Error messages and logs
|
|
257
|
-
if (!lowerProblem.includes("error") && !lowerProblem.includes("log") && !lowerProblem.includes("message")) {
|
|
258
|
-
questions.push("Are there any error messages, console logs, or stack traces?");
|
|
259
|
-
confidence -= 0.05;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
else if (category === "implementation") {
|
|
263
|
-
// Existing specifications
|
|
264
|
-
if (!lowerProblem.includes("spec") && !lowerProblem.includes("requirement") && !lowerProblem.includes("design")) {
|
|
265
|
-
questions.push("Do you have existing specifications, designs, or requirements documents?");
|
|
266
|
-
confidence -= 0.07;
|
|
267
|
-
}
|
|
268
|
-
// Technical constraints
|
|
269
|
-
if (!lowerProblem.includes("constraint") && !lowerProblem.includes("limitation") && !lowerProblem.includes("technology")) {
|
|
270
|
-
questions.push("Are there any technical constraints or preferred technologies to use?");
|
|
271
|
-
confidence -= 0.06;
|
|
272
|
-
}
|
|
273
|
-
// Timeline and priority
|
|
274
|
-
if (!lowerProblem.includes("deadline") && !lowerProblem.includes("urgent") && !lowerProblem.includes("priority")) {
|
|
275
|
-
questions.push("What's the timeline and priority level for this implementation?");
|
|
276
|
-
confidence -= 0.04;
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
else if (category === "review") {
|
|
280
|
-
// Scope of review
|
|
281
|
-
if (!lowerProblem.includes("component") && !lowerProblem.includes("module") && !lowerProblem.includes("file")) {
|
|
282
|
-
questions.push("What specific components, modules, or files should be reviewed?");
|
|
283
|
-
confidence -= 0.08;
|
|
284
|
-
}
|
|
285
|
-
// Review focus areas
|
|
286
|
-
if (!lowerProblem.includes("security") && !lowerProblem.includes("performance") && !lowerProblem.includes("quality")) {
|
|
287
|
-
questions.push("What should the review focus on: security, performance, code quality, or all?");
|
|
288
|
-
confidence -= 0.06;
|
|
289
|
-
}
|
|
290
|
-
// Standards and guidelines
|
|
291
|
-
if (!lowerProblem.includes("standard") && !lowerProblem.includes("guideline") && !lowerProblem.includes("compliance")) {
|
|
292
|
-
questions.push("Are there specific coding standards or compliance requirements to check against?");
|
|
293
|
-
confidence -= 0.05;
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
else if (category === "research") {
|
|
297
|
-
// Research scope
|
|
298
|
-
if (!lowerProblem.includes("scope") && !lowerProblem.includes("depth") && !lowerProblem.includes("focus")) {
|
|
299
|
-
questions.push("What's the scope and depth of research needed? Any specific focus areas?");
|
|
300
|
-
confidence -= 0.07;
|
|
301
|
-
}
|
|
302
|
-
// Deliverables
|
|
303
|
-
if (!lowerProblem.includes("report") && !lowerProblem.includes("document") && !lowerProblem.includes("summary")) {
|
|
304
|
-
questions.push("What deliverables are expected: summary, detailed report, recommendations?");
|
|
305
|
-
confidence -= 0.06;
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
// Universal questions for ambiguous or short descriptions
|
|
309
|
-
if (problem.length < 30) {
|
|
310
|
-
questions.push("Could you provide more details about what you're trying to accomplish?");
|
|
311
|
-
confidence -= 0.1;
|
|
312
|
-
}
|
|
313
|
-
if (complexity === "simple" && questions.length === 0 && confidence < 0.9) {
|
|
314
|
-
questions.push("Are there any specific requirements or constraints I should be aware of?");
|
|
315
|
-
confidence -= 0.05;
|
|
316
|
-
}
|
|
317
|
-
// Limit to maximum 3 most important questions to avoid overwhelming user
|
|
318
|
-
if (questions.length > 3) {
|
|
319
|
-
questions.splice(3);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
return {
|
|
323
|
-
confidence: Math.max(0.5, Math.min(1.0, confidence)),
|
|
324
|
-
category,
|
|
325
|
-
complexity,
|
|
326
|
-
suggestedMode,
|
|
327
|
-
questions
|
|
328
|
-
};
|
|
329
|
-
}
|
|
330
|
-
async function continueExistingSpec(specId, analysis, preferredMode) {
|
|
331
|
-
try {
|
|
332
|
-
const spec = await specGetHandler({ spec_id: specId });
|
|
333
|
-
const mode = preferredMode || analysis.suggestedMode;
|
|
334
|
-
// Log role transition for existing spec continuation
|
|
335
|
-
await mcpLogger.logRoleTransition('orchestrator', mode, specId, `Continuing existing SPEC work, transitioning to ${mode} mode`);
|
|
336
|
-
const promptContext = await createModeContext(mode, "", specId, analysis);
|
|
337
|
-
// Send dashboard notification about continuing existing SPEC
|
|
338
|
-
sendDashboardUpdate(specId, "spec_continuation", {
|
|
339
|
-
mode,
|
|
340
|
-
analysis: {
|
|
341
|
-
category: analysis.category,
|
|
342
|
-
complexity: analysis.complexity,
|
|
343
|
-
confidence: analysis.confidence
|
|
344
|
-
},
|
|
345
|
-
spec_title: spec.title
|
|
346
|
-
}).catch(error => {
|
|
347
|
-
console.log('Dashboard continuation notification failed (non-blocking):', error);
|
|
348
|
-
});
|
|
349
|
-
return {
|
|
350
|
-
spec_id: specId,
|
|
351
|
-
action: "continue",
|
|
352
|
-
clarify_questions: undefined,
|
|
353
|
-
next_mode: mode,
|
|
354
|
-
dashboard_url: undefined,
|
|
355
|
-
prompt_context: promptContext,
|
|
356
|
-
workflow_step: `continuing_with_${mode}`
|
|
357
|
-
};
|
|
358
|
-
}
|
|
359
|
-
catch (error) {
|
|
360
|
-
throw new Error(`Cannot continue SPEC ${specId}: ${error}`);
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
async function findRelatedSpecs(problem) {
|
|
364
|
-
try {
|
|
365
|
-
const allSpecs = await specListHandler({});
|
|
366
|
-
const keywords = extractKeywords(problem);
|
|
367
|
-
return allSpecs.specs.filter((spec) => {
|
|
368
|
-
const specText = (spec.title + " " + spec.category).toLowerCase();
|
|
369
|
-
return keywords.some(keyword => specText.includes(keyword));
|
|
370
|
-
}).slice(0, 3); // Return top 3 matches
|
|
371
|
-
}
|
|
372
|
-
catch (error) {
|
|
373
|
-
return [];
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
function extractTitle(problem) {
|
|
377
|
-
// Extract a concise title from the problem statement
|
|
378
|
-
const words = problem.split(" ").slice(0, 8);
|
|
379
|
-
return words.join(" ").replace(/[^\w\s-]/g, "").trim();
|
|
380
|
-
}
|
|
381
|
-
function extractKeywords(text) {
|
|
382
|
-
const stopWords = ["the", "a", "an", "and", "or", "but", "in", "on", "at", "to", "for", "of", "with", "by"];
|
|
383
|
-
return text.toLowerCase()
|
|
384
|
-
.split(/\s+/)
|
|
385
|
-
.filter(word => word.length > 2 && !stopWords.includes(word))
|
|
386
|
-
.slice(0, 5);
|
|
387
|
-
}
|
|
388
|
-
function extractTags(problem) {
|
|
389
|
-
const lowerProblem = problem.toLowerCase();
|
|
390
|
-
const tags = [];
|
|
391
|
-
// Common technology/domain tags
|
|
392
|
-
const tagMap = {
|
|
393
|
-
"react": ["frontend", "react"],
|
|
394
|
-
"api": ["backend", "api"],
|
|
395
|
-
"database": ["backend", "database"],
|
|
396
|
-
"auth": ["security", "authentication"],
|
|
397
|
-
"user": ["frontend", "ux"],
|
|
398
|
-
"mobile": ["mobile", "responsive"],
|
|
399
|
-
"test": ["testing", "qa"],
|
|
400
|
-
"performance": ["performance", "optimization"]
|
|
401
|
-
};
|
|
402
|
-
Object.entries(tagMap).forEach(([keyword, tagList]) => {
|
|
403
|
-
if (lowerProblem.includes(keyword)) {
|
|
404
|
-
tags.push(...tagList);
|
|
405
|
-
}
|
|
406
|
-
});
|
|
407
|
-
return [...new Set(tags)]; // Remove duplicates
|
|
408
|
-
}
|
|
409
|
-
function mapCategoryToSpecCategory(category) {
|
|
410
|
-
const mapping = {
|
|
411
|
-
"feature": "fullstack",
|
|
412
|
-
"bug": "general",
|
|
413
|
-
"review": "general",
|
|
414
|
-
"implementation": "backend",
|
|
415
|
-
"research": "general"
|
|
416
|
-
};
|
|
417
|
-
return mapping[category];
|
|
418
|
-
}
|
|
419
|
-
function mapComplexityToPriority(complexity) {
|
|
420
|
-
const mapping = {
|
|
421
|
-
"simple": "low",
|
|
422
|
-
"medium": "medium",
|
|
423
|
-
"complex": "high"
|
|
424
|
-
};
|
|
425
|
-
return mapping[complexity];
|
|
426
|
-
}
|
|
427
|
-
async function createModeContext(mode, problem, specId, analysis) {
|
|
428
|
-
let context = `MODE SWITCH DIRECTIVE:\n`;
|
|
429
|
-
context += `⚠️ YOU are now switching to ${mode.toUpperCase()} mode.\n`;
|
|
430
|
-
context += `⚠️ Read the ${mode.toUpperCase()}_PROMPT and execute those steps directly.\n`;
|
|
431
|
-
context += `⚠️ There is NO delegation - YOU ARE the ${mode} executing these tasks.\n\n`;
|
|
432
|
-
context += `CONTEXT PROVIDED BY ORCHESTRATOR:\n`;
|
|
433
|
-
context += `- Problem: ${problem}\n`;
|
|
434
|
-
context += `- SPEC ID: ${specId}\n`;
|
|
435
|
-
context += `- Category: ${analysis.category}\n`;
|
|
436
|
-
context += `- Complexity: ${analysis.complexity}\n`;
|
|
437
|
-
context += `- Confidence: ${(analysis.confidence * 100).toFixed(1)}%\n\n`;
|
|
438
|
-
// Add mode-specific first steps
|
|
439
|
-
switch (mode) {
|
|
440
|
-
case "architect":
|
|
441
|
-
context += `YOUR FIRST STEPS AS ARCHITECT:\n`;
|
|
442
|
-
context += `1. Call bob.code.search with phase: "architect" to research existing codebase patterns\n`;
|
|
443
|
-
context += `2. Call bob.workflow.start to create manual + worktree + launch dashboard\n`;
|
|
444
|
-
context += `3. Use bob.manual.update to build all required SPEC sections\n`;
|
|
445
|
-
context += `4. Focus on technical architecture and implementation plan\n`;
|
|
446
|
-
break;
|
|
447
|
-
case "engineer":
|
|
448
|
-
context += `YOUR FIRST STEPS AS ENGINEER:\n`;
|
|
449
|
-
context += `1. Call bob.manual.get to load the SPEC for implementation guidance\n`;
|
|
450
|
-
context += `2. Extract implementation plan and update your TODO list\n`;
|
|
451
|
-
context += `3. Use bob.code.search with phase: "engineer" to find affected files\n`;
|
|
452
|
-
context += `4. Follow implementation plan and log progress with bob.manual.update\n`;
|
|
453
|
-
break;
|
|
454
|
-
case "debugger":
|
|
455
|
-
context += `YOUR FIRST STEPS AS DEBUGGER:\n`;
|
|
456
|
-
context += `1. Call bob.code.search with phase: "debugger" to analyze the issue\n`;
|
|
457
|
-
context += `2. Research existing codebase for similar patterns and bugs\n`;
|
|
458
|
-
context += `3. Apply minimal, safe fixes with user validation\n`;
|
|
459
|
-
context += `4. Document findings with bob.manual.update (debug_log parameter)\n`;
|
|
460
|
-
break;
|
|
461
|
-
case "reviewer":
|
|
462
|
-
context += `YOUR FIRST STEPS AS REVIEWER:\n`;
|
|
463
|
-
context += `1. Call bob.code.search with phase: "reviewer" for vulnerability detection\n`;
|
|
464
|
-
context += `2. Analyze security, performance, and quality issues\n`;
|
|
465
|
-
context += `3. Create review manual with improvement recommendations\n`;
|
|
466
|
-
context += `4. Provide severity-based findings and validation requirements\n`;
|
|
467
|
-
break;
|
|
468
|
-
}
|
|
469
|
-
return context;
|
|
470
|
-
}
|
|
471
|
-
// Helper function to format role directive for Claude (Option A: Enhanced Tool Response)
|
|
472
|
-
// Based on proven pattern from workflows-mcp-server (350+ GitHub stars)
|
|
473
|
-
export function formatRoleDirective(mode, context) {
|
|
474
|
-
const roleMap = {
|
|
475
|
-
architect: {
|
|
476
|
-
emoji: '📐',
|
|
477
|
-
actions: [
|
|
478
|
-
'Call bob.code.search({ query: "...", phase: "architect" }) to research existing patterns',
|
|
479
|
-
'Build manual sections: executive_summary, product_specifications, architecture_analysis, implementation_plan, testing',
|
|
480
|
-
'Call bob.approval.request(spec_id, "spec_approval", ...) when ready for user review'
|
|
481
|
-
]
|
|
482
|
-
},
|
|
483
|
-
debugger: {
|
|
484
|
-
emoji: '🐛',
|
|
485
|
-
actions: [
|
|
486
|
-
'Call bob.code.search({ query: "...", phase: "debugger" }) - MANDATORY before diagnosis',
|
|
487
|
-
'Reproduce and analyze the issue systematically',
|
|
488
|
-
'Apply minimal, safe fix that addresses root cause',
|
|
489
|
-
'Update bob.manual.update with debug_log documenting findings'
|
|
490
|
-
]
|
|
491
|
-
},
|
|
492
|
-
engineer: {
|
|
493
|
-
emoji: '⚙️',
|
|
494
|
-
actions: [
|
|
495
|
-
'Call bob.manual.get(spec_id) to load the implementation plan',
|
|
496
|
-
'Create worktree if needed using bob.workflow.start',
|
|
497
|
-
'Implement tasks from plan sequentially (database → backend → frontend → integration)',
|
|
498
|
-
'Run tests and call bob.workflow.deploy when complete'
|
|
499
|
-
]
|
|
500
|
-
},
|
|
501
|
-
reviewer: {
|
|
502
|
-
emoji: '🔍',
|
|
503
|
-
actions: [
|
|
504
|
-
'Load context and code to review',
|
|
505
|
-
'Perform security, performance, and quality audit',
|
|
506
|
-
'Document findings in bob.manual.update with severity levels',
|
|
507
|
-
'Provide actionable recommendations'
|
|
508
|
-
]
|
|
509
|
-
}
|
|
510
|
-
};
|
|
511
|
-
const role = roleMap[mode];
|
|
512
|
-
if (!role) {
|
|
513
|
-
return `Role ${mode} not recognized. Please use architect, engineer, debugger, or reviewer.`;
|
|
514
|
-
}
|
|
515
|
-
const problemText = context.problem ? context.problem.substring(0, 100) : 'See spec for details';
|
|
516
|
-
const specText = context.spec_id || 'Will be created';
|
|
517
|
-
const confidenceText = context.confidence ? Math.round(context.confidence * 100) : 0;
|
|
518
|
-
return `
|
|
519
|
-
${role.emoji} ROLE ASSIGNMENT: ${mode.toUpperCase()}
|
|
520
|
-
|
|
521
|
-
YOU are now executing as the ${mode.toUpperCase()} role. This is not routing to another agent - YOU must perform these actions:
|
|
522
|
-
|
|
523
|
-
IMMEDIATE ACTIONS REQUIRED:
|
|
524
|
-
${role.actions.map((a, i) => `${i + 1}. ${a}`).join('\n')}
|
|
525
|
-
|
|
526
|
-
CONTEXT:
|
|
527
|
-
- Spec ID: ${specText}
|
|
528
|
-
- Problem: ${problemText}
|
|
529
|
-
- Confidence: ${confidenceText}%
|
|
530
|
-
|
|
531
|
-
⚠️ DO NOT wait for another agent. YOU are the ${mode}. Start with step 1 now.
|
|
532
|
-
`.trim();
|
|
533
|
-
}
|
|
534
|
-
// Helper function to send dashboard updates without blocking main workflow
|
|
535
|
-
async function sendDashboardUpdate(specId, event, data) {
|
|
536
|
-
try {
|
|
537
|
-
await dashboardUpdateHandler({
|
|
538
|
-
spec_id: specId,
|
|
539
|
-
event,
|
|
540
|
-
data
|
|
541
|
-
});
|
|
542
|
-
}
|
|
543
|
-
catch (error) {
|
|
544
|
-
// Don't let dashboard update failures break the main workflow
|
|
545
|
-
console.log(`Dashboard update failed (non-blocking): [${specId}] ${event}`, error instanceof Error ? error.message : String(error));
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
// Search enforcement functions for Debugger
|
|
549
|
-
function countSearchToolUsage(specId) {
|
|
550
|
-
let searchCount = 0;
|
|
551
|
-
// Check active operations for search tool calls
|
|
552
|
-
const activeOps = mcpLogger.getActiveOperationsForSpec(specId);
|
|
553
|
-
for (const operationId of activeOps) {
|
|
554
|
-
const operation = mcpLogger.activeOperations.get(operationId);
|
|
555
|
-
if (operation && operation.details.tool_name === 'bob.code.search') {
|
|
556
|
-
searchCount++;
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
// Also check completed tool calls in the log buffer (for recent completions)
|
|
560
|
-
const logBuffer = mcpLogger.logBuffer || [];
|
|
561
|
-
for (const entry of logBuffer) {
|
|
562
|
-
if (entry.data &&
|
|
563
|
-
entry.data.tool_name === 'bob.code.search' &&
|
|
564
|
-
entry.data.spec_id === specId &&
|
|
565
|
-
entry.data.event_type === 'tool_call_completed') {
|
|
566
|
-
searchCount++;
|
|
567
|
-
}
|
|
568
|
-
}
|
|
569
|
-
return searchCount;
|
|
570
|
-
}
|
|
571
|
-
export function validateDebuggerSearchUsage(specId, operation) {
|
|
572
|
-
// Only enforce for debug operations (commits and debug_log updates)
|
|
573
|
-
const debugOperations = ['debug_log', 'commit', 'fix_implementation'];
|
|
574
|
-
if (!debugOperations.some(op => operation.toLowerCase().includes(op))) {
|
|
575
|
-
return { valid: true };
|
|
576
|
-
}
|
|
577
|
-
const searchCount = countSearchToolUsage(specId);
|
|
578
|
-
if (searchCount < 1) {
|
|
579
|
-
return {
|
|
580
|
-
valid: false,
|
|
581
|
-
error: `Debugger must call bob.code.search at least once before ${operation}. Current search calls: ${searchCount}. Please perform search to understand the codebase before proceeding.`
|
|
582
|
-
};
|
|
583
|
-
}
|
|
584
|
-
return { valid: true };
|
|
585
|
-
}
|
|
586
|
-
// 3-Gate Approval System Implementation
|
|
587
|
-
export async function processApprovalGate(specId, gateNumber, context) {
|
|
588
|
-
try {
|
|
589
|
-
let approved = false;
|
|
590
|
-
let nextStep = "";
|
|
591
|
-
let message = "";
|
|
592
|
-
let blockingReason;
|
|
593
|
-
switch (gateNumber) {
|
|
594
|
-
case 1: // Q&A Clarification Gate
|
|
595
|
-
approved = validateGate1(context.confidence || 0, context.questions || []);
|
|
596
|
-
if (approved) {
|
|
597
|
-
nextStep = "spec_review";
|
|
598
|
-
message = "Confidence threshold met (≥95%). Proceeding to architecture planning.";
|
|
599
|
-
// Validate state transition
|
|
600
|
-
await validateEnhancedStateTransition({ from: "questioning", to: "spec_review", spec_id: specId }, { confidence_threshold: true });
|
|
601
|
-
}
|
|
602
|
-
else {
|
|
603
|
-
nextStep = "questioning";
|
|
604
|
-
blockingReason = `Confidence too low (${Math.round((context.confidence || 0) * 100)}%) or questions remain`;
|
|
605
|
-
message = `Gate 1 blocked: ${blockingReason}. Please provide clarifications.`;
|
|
606
|
-
}
|
|
607
|
-
break;
|
|
608
|
-
case 2: // Spec Approval Gate
|
|
609
|
-
approved = validateGate2(context.userApproval || false, context.sectionsComplete || []);
|
|
610
|
-
if (approved) {
|
|
611
|
-
nextStep = "approved";
|
|
612
|
-
message = "Specification approved. Ready for implementation.";
|
|
613
|
-
// Validate state transition
|
|
614
|
-
await validateEnhancedStateTransition({ from: "spec_review", to: "approved", spec_id: specId }, { confidence_threshold: true, user_approval: true });
|
|
615
|
-
}
|
|
616
|
-
else {
|
|
617
|
-
nextStep = "spec_review";
|
|
618
|
-
blockingReason = "Specification not approved or missing required sections";
|
|
619
|
-
message = `Gate 2 blocked: ${blockingReason}. Please complete spec and get approval.`;
|
|
620
|
-
}
|
|
621
|
-
break;
|
|
622
|
-
case 3: // Implementation Approval Gate (with mandatory Reviewer)
|
|
623
|
-
approved = validateGate3(context.testsPass || false, context.reviewerComplete || false, context.userApproval || false);
|
|
624
|
-
if (approved) {
|
|
625
|
-
nextStep = "completed";
|
|
626
|
-
message = "Implementation approved after testing and review. Ready for deployment.";
|
|
627
|
-
// Validate state transition
|
|
628
|
-
await validateEnhancedStateTransition({ from: "user_review", to: "completed", spec_id: specId }, {
|
|
629
|
-
confidence_threshold: true,
|
|
630
|
-
reviewer_completed: true,
|
|
631
|
-
user_approval: true
|
|
632
|
-
});
|
|
633
|
-
}
|
|
634
|
-
else {
|
|
635
|
-
nextStep = "user_review";
|
|
636
|
-
const reasons = [];
|
|
637
|
-
if (!context.testsPass)
|
|
638
|
-
reasons.push("tests not passing");
|
|
639
|
-
if (!context.reviewerComplete)
|
|
640
|
-
reasons.push("reviewer not completed");
|
|
641
|
-
if (!context.userApproval)
|
|
642
|
-
reasons.push("user approval pending");
|
|
643
|
-
blockingReason = reasons.join(", ");
|
|
644
|
-
message = `Gate 3 blocked: ${blockingReason}. Please address issues before proceeding.`;
|
|
645
|
-
}
|
|
646
|
-
break;
|
|
647
|
-
}
|
|
648
|
-
// Log gate processing
|
|
649
|
-
await mcpLogger.info(`Gate ${gateNumber} processed for ${specId}`, {
|
|
650
|
-
approved,
|
|
651
|
-
nextStep,
|
|
652
|
-
blockingReason,
|
|
653
|
-
gateNumber,
|
|
654
|
-
spec_id: specId
|
|
655
|
-
});
|
|
656
|
-
return { approved, nextStep, message, blockingReason };
|
|
657
|
-
}
|
|
658
|
-
catch (error) {
|
|
659
|
-
const errorMessage = `Gate ${gateNumber} validation failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
660
|
-
await mcpLogger.error(errorMessage, { specId, gateNumber, error });
|
|
661
|
-
return {
|
|
662
|
-
approved: false,
|
|
663
|
-
nextStep: "error",
|
|
664
|
-
message: errorMessage,
|
|
665
|
-
blockingReason: "Validation error"
|
|
666
|
-
};
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
// Enhanced workflow router with 3-gate integration
|
|
670
|
-
export async function routeWithApprovalGates(specId, currentState, context) {
|
|
671
|
-
// Determine which gate to process based on current state
|
|
672
|
-
let gateNumber = null;
|
|
673
|
-
if (currentState === "questioning" && context.confidence >= 0.95) {
|
|
674
|
-
gateNumber = 1;
|
|
675
|
-
}
|
|
676
|
-
else if (currentState === "spec_review" && context.requestingApproval) {
|
|
677
|
-
gateNumber = 2;
|
|
678
|
-
}
|
|
679
|
-
else if (currentState === "implementation" && context.implementationComplete) {
|
|
680
|
-
gateNumber = 3;
|
|
681
|
-
}
|
|
682
|
-
if (gateNumber) {
|
|
683
|
-
const gateResult = await processApprovalGate(specId, gateNumber, context);
|
|
684
|
-
if (gateResult.approved) {
|
|
685
|
-
return {
|
|
686
|
-
action: "proceed",
|
|
687
|
-
nextMode: getNextMode(gateResult.nextStep),
|
|
688
|
-
gateResult
|
|
689
|
-
};
|
|
690
|
-
}
|
|
691
|
-
else {
|
|
692
|
-
return {
|
|
693
|
-
action: "await_approval",
|
|
694
|
-
gateResult
|
|
695
|
-
};
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
// No gate processing needed, continue with normal routing
|
|
699
|
-
return {
|
|
700
|
-
action: "route",
|
|
701
|
-
nextMode: context.suggestedMode
|
|
702
|
-
};
|
|
703
|
-
}
|
|
704
|
-
function getNextMode(nextStep) {
|
|
705
|
-
const modeMap = {
|
|
706
|
-
"spec_review": "architect",
|
|
707
|
-
"approved": "engineer",
|
|
708
|
-
"user_review": "reviewer",
|
|
709
|
-
"completed": "none"
|
|
710
|
-
};
|
|
711
|
-
return modeMap[nextStep] || "architect";
|
|
712
|
-
}
|
|
713
|
-
// Mandatory Reviewer Integration (TASK-006)
|
|
714
|
-
export async function enforceReviewerBeforeGate3(specId, context) {
|
|
715
|
-
// Check if implementation is complete and ready for Gate 3
|
|
716
|
-
if (!context.implementationComplete) {
|
|
717
|
-
return {
|
|
718
|
-
requiresReviewer: false,
|
|
719
|
-
reviewerComplete: false,
|
|
720
|
-
nextAction: "continue_implementation"
|
|
721
|
-
};
|
|
722
|
-
}
|
|
723
|
-
// Check if tests are passing (required before reviewer)
|
|
724
|
-
if (!context.testsPass) {
|
|
725
|
-
return {
|
|
726
|
-
requiresReviewer: false,
|
|
727
|
-
reviewerComplete: false,
|
|
728
|
-
nextAction: "fix_tests_first"
|
|
729
|
-
};
|
|
730
|
-
}
|
|
731
|
-
// Check if reviewer has already completed their work
|
|
732
|
-
const reviewerComplete = await checkReviewerCompletion(specId);
|
|
733
|
-
if (!reviewerComplete) {
|
|
734
|
-
// Auto-route to Reviewer with context
|
|
735
|
-
await mcpLogger.info(`Auto-routing to Reviewer before Gate 3 for ${specId}`, {
|
|
736
|
-
spec_id: specId,
|
|
737
|
-
reason: "mandatory_review_before_gate3",
|
|
738
|
-
tests_passing: context.testsPass
|
|
739
|
-
});
|
|
740
|
-
// Send dashboard update
|
|
741
|
-
await sendDashboardUpdate(specId, "auto_routing_reviewer", {
|
|
742
|
-
reason: "Gate 3 requires review",
|
|
743
|
-
tests_status: "passing"
|
|
744
|
-
});
|
|
745
|
-
return {
|
|
746
|
-
requiresReviewer: true,
|
|
747
|
-
reviewerComplete: false,
|
|
748
|
-
nextAction: "route_to_reviewer"
|
|
749
|
-
};
|
|
750
|
-
}
|
|
751
|
-
// Reviewer is complete, ready for Gate 3
|
|
752
|
-
return {
|
|
753
|
-
requiresReviewer: false,
|
|
754
|
-
reviewerComplete: true,
|
|
755
|
-
nextAction: "proceed_to_gate3"
|
|
756
|
-
};
|
|
757
|
-
}
|
|
758
|
-
async function checkReviewerCompletion(specId) {
|
|
759
|
-
try {
|
|
760
|
-
// Check for reviewer completion in the spec logs
|
|
761
|
-
const spec = await specGetHandler({ spec_id: specId });
|
|
762
|
-
// Look for reviewer completion in execution logs
|
|
763
|
-
const reviewerLogs = spec.execution_logs?.filter((log) => log.engineer?.includes("REVIEWER") || log.action?.includes("review")) || [];
|
|
764
|
-
// Also check debug logs for review findings
|
|
765
|
-
const reviewFindings = spec.debug_logs?.filter((log) => log.issue?.includes("review") || log.root_cause?.includes("review")) || [];
|
|
766
|
-
return reviewerLogs.length > 0 || reviewFindings.length > 0;
|
|
767
|
-
}
|
|
768
|
-
catch (error) {
|
|
769
|
-
await mcpLogger.warning(`Failed to check reviewer completion for ${specId}`, { error });
|
|
770
|
-
// Default to requiring review if we can't determine completion
|
|
771
|
-
return false;
|
|
772
|
-
}
|
|
773
|
-
}
|
|
774
|
-
// Enhanced implementation complete handler with reviewer enforcement
|
|
775
|
-
export async function handleImplementationComplete(specId, context) {
|
|
776
|
-
// Step 1: Check if tests are passing
|
|
777
|
-
if (!context.testsPass) {
|
|
778
|
-
return {
|
|
779
|
-
action: "fix_tests",
|
|
780
|
-
message: "Tests must pass before proceeding to review and approval. Please fix failing tests.",
|
|
781
|
-
};
|
|
782
|
-
}
|
|
783
|
-
// Step 2: Start dev server (moved from workflow.start)
|
|
784
|
-
if (!context.devServerStarted) {
|
|
785
|
-
await mcpLogger.info(`Starting dev server after tests pass for ${specId}`, { spec_id: specId });
|
|
786
|
-
// This would integrate with the server startup logic that was removed from workflow.start
|
|
787
|
-
await sendDashboardUpdate(specId, "starting_preview_server", {
|
|
788
|
-
reason: "tests_passed",
|
|
789
|
-
next_step: "review_and_approval"
|
|
790
|
-
});
|
|
791
|
-
return {
|
|
792
|
-
action: "start_server",
|
|
793
|
-
message: "Tests passed! Starting preview server before review and approval.",
|
|
794
|
-
};
|
|
795
|
-
}
|
|
796
|
-
// Step 3: Enforce mandatory reviewer
|
|
797
|
-
const reviewerCheck = await enforceReviewerBeforeGate3(specId, context);
|
|
798
|
-
if (reviewerCheck.requiresReviewer) {
|
|
799
|
-
return {
|
|
800
|
-
action: "route",
|
|
801
|
-
nextMode: "reviewer",
|
|
802
|
-
message: "Implementation complete and tests passing. Routing to Reviewer for mandatory review before final approval.",
|
|
803
|
-
};
|
|
804
|
-
}
|
|
805
|
-
if (reviewerCheck.nextAction === "fix_tests_first") {
|
|
806
|
-
return {
|
|
807
|
-
action: "fix_tests",
|
|
808
|
-
message: "Please ensure all tests are passing before proceeding to review.",
|
|
809
|
-
};
|
|
810
|
-
}
|
|
811
|
-
// Step 4: Process Gate 3 (all requirements met)
|
|
812
|
-
const gateResult = await processApprovalGate(specId, 3, {
|
|
813
|
-
...context,
|
|
814
|
-
reviewerComplete: reviewerCheck.reviewerComplete
|
|
815
|
-
});
|
|
816
|
-
if (gateResult.approved) {
|
|
817
|
-
return {
|
|
818
|
-
action: "complete",
|
|
819
|
-
message: "Implementation approved! Ready for deployment.",
|
|
820
|
-
gateResult
|
|
821
|
-
};
|
|
822
|
-
}
|
|
823
|
-
else {
|
|
824
|
-
return {
|
|
825
|
-
action: "await_approval",
|
|
826
|
-
message: gateResult.message,
|
|
827
|
-
requiresApproval: true,
|
|
828
|
-
gateResult
|
|
829
|
-
};
|
|
830
|
-
}
|
|
831
|
-
}
|
|
832
|
-
//# sourceMappingURL=orchestratorTools.js.map
|