adjustments based on gemini review

This commit is contained in:
trueheads
2025-12-11 09:14:41 -06:00
parent 4b1f4576ae
commit a602b1b519
3 changed files with 130 additions and 90 deletions

View File

@@ -404,7 +404,7 @@ class FeatureLoader {
status: status,
images: [],
imagePaths: [],
skipTests: true,
skipTests: false, // Auto-generated features should run tests by default
model: "sonnet",
thinkingLevel: "none",
summary: summary || description || '',

View File

@@ -461,8 +461,7 @@ Use the UpdateFeatureStatus tool to create features with ALL the fields above.`,
const currentQuery = query({ prompt, options });
execution.query = currentQuery;
let toolCallCount = 0;
let messageCount = 0;
const counters = { toolCallCount: 0, messageCount: 0 };
try {
for await (const msg of currentQuery) {
@@ -472,67 +471,11 @@ Use the UpdateFeatureStatus tool to create features with ALL the fields above.`,
}
if (msg.type === "assistant" && msg.message?.content) {
messageCount++;
for (const block of msg.message.content) {
if (block.type === "text") {
const preview = block.text.substring(0, 100).replace(/\n/g, " ");
console.log(`[SpecRegeneration] Feature gen message #${messageCount}: ${preview}...`);
sendToRenderer({
type: "spec_regeneration_progress",
content: block.text,
});
} else if (block.type === "tool_use") {
toolCallCount++;
const toolName = block.name;
const toolInput = block.input;
console.log(`[SpecRegeneration] Feature gen tool call #${toolCallCount}: ${toolName}`);
if (toolName === "mcp__automaker-tools__UpdateFeatureStatus" || toolName === "UpdateFeatureStatus") {
const featureId = toolInput?.featureId || "unknown";
const status = toolInput?.status || "unknown";
const summary = toolInput?.summary || "";
sendToRenderer({
type: "spec_regeneration_progress",
content: `\n[Feature Creation] Creating feature "${featureId}" with status "${status}"${summary ? `\n Summary: ${summary}` : ""}\n`,
});
} else {
sendToRenderer({
type: "spec_regeneration_progress",
content: `\n[Tool] Using ${toolName}...\n`,
});
}
sendToRenderer({
type: "spec_regeneration_tool",
tool: toolName,
input: toolInput,
});
}
}
this._handleAssistantMessage(msg, sendToRenderer, counters);
} else if (msg.type === "tool_result") {
const toolName = msg.toolName || "unknown";
const result = msg.content?.[0]?.text || JSON.stringify(msg.content);
const resultPreview = result.substring(0, 200).replace(/\n/g, " ");
console.log(`[SpecRegeneration] Feature gen tool result (${toolName}): ${resultPreview}...`);
if (toolName === "mcp__automaker-tools__UpdateFeatureStatus" || toolName === "UpdateFeatureStatus") {
sendToRenderer({
type: "spec_regeneration_progress",
content: `[Feature Creation] ${result}\n`,
});
} else {
sendToRenderer({
type: "spec_regeneration_progress",
content: `[Tool Result] ${toolName} completed successfully\n`,
});
}
this._handleToolResult(msg, sendToRenderer);
} else if (msg.type === "error") {
const errorMsg = msg.error?.message || JSON.stringify(msg.error);
console.error(`[SpecRegeneration] ERROR in feature generation stream: ${errorMsg}`);
sendToRenderer({
type: "spec_regeneration_error",
error: `Error during feature generation: ${errorMsg}`,
});
this._handleStreamError(msg, sendToRenderer);
}
}
} catch (streamError) {
@@ -544,7 +487,7 @@ Use the UpdateFeatureStatus tool to create features with ALL the fields above.`,
throw streamError;
}
console.log(`[SpecRegeneration] Feature generation completed - ${messageCount} messages, ${toolCallCount} tool calls`);
console.log(`[SpecRegeneration] Feature generation completed - ${counters.messageCount} messages, ${counters.toolCallCount} tool calls`);
execution.query = null;
execution.abortController = null;
@@ -1003,6 +946,94 @@ Use this general structure:
Begin by exploring the project structure.`;
}
/**
* Handle assistant message in feature generation stream
* @private
*/
_handleAssistantMessage(msg, sendToRenderer, counters) {
counters.messageCount++;
for (const block of msg.message.content) {
if (block.type === "text") {
const preview = block.text.substring(0, 100).replace(/\n/g, " ");
console.log(`[SpecRegeneration] Feature gen message #${counters.messageCount}: ${preview}...`);
sendToRenderer({
type: "spec_regeneration_progress",
content: block.text,
});
} else if (block.type === "tool_use") {
this._handleToolUse(block, sendToRenderer, counters);
}
}
}
/**
* Handle tool use block in feature generation stream
* @private
*/
_handleToolUse(block, sendToRenderer, counters) {
counters.toolCallCount++;
const toolName = block.name;
const toolInput = block.input;
console.log(`[SpecRegeneration] Feature gen tool call #${counters.toolCallCount}: ${toolName}`);
if (toolName === "mcp__automaker-tools__UpdateFeatureStatus" || toolName === "UpdateFeatureStatus") {
const featureId = toolInput?.featureId || "unknown";
const status = toolInput?.status || "unknown";
const summary = toolInput?.summary || "";
sendToRenderer({
type: "spec_regeneration_progress",
content: `\n[Feature Creation] Creating feature "${featureId}" with status "${status}"${summary ? `\n Summary: ${summary}` : ""}\n`,
});
} else {
sendToRenderer({
type: "spec_regeneration_progress",
content: `\n[Tool] Using ${toolName}...\n`,
});
}
sendToRenderer({
type: "spec_regeneration_tool",
tool: toolName,
input: toolInput,
});
}
/**
* Handle tool result in feature generation stream
* @private
*/
_handleToolResult(msg, sendToRenderer) {
const toolName = msg.toolName || "unknown";
const result = msg.content?.[0]?.text || JSON.stringify(msg.content);
const resultPreview = result.substring(0, 200).replace(/\n/g, " ");
console.log(`[SpecRegeneration] Feature gen tool result (${toolName}): ${resultPreview}...`);
if (toolName === "mcp__automaker-tools__UpdateFeatureStatus" || toolName === "UpdateFeatureStatus") {
sendToRenderer({
type: "spec_regeneration_progress",
content: `[Feature Creation] ${result}\n`,
});
} else {
sendToRenderer({
type: "spec_regeneration_progress",
content: `[Tool Result] ${toolName} completed successfully\n`,
});
}
}
/**
* Handle error in feature generation stream
* @private
*/
_handleStreamError(msg, sendToRenderer) {
const errorMsg = msg.error?.message || JSON.stringify(msg.error);
console.error(`[SpecRegeneration] ERROR in feature generation stream: ${errorMsg}`);
sendToRenderer({
type: "spec_regeneration_error",
error: `Error during feature generation: ${errorMsg}`,
});
}
/**
* Stop the current regeneration
*/

View File

@@ -19,6 +19,12 @@ import { Checkbox } from "@/components/ui/checkbox";
import { XmlSyntaxEditor } from "@/components/ui/xml-syntax-editor";
import type { SpecRegenerationEvent } from "@/types/electron";
// Delay before reloading spec file to ensure it's written to disk
const SPEC_FILE_WRITE_DELAY = 500;
// Interval for polling backend status during generation
const STATUS_CHECK_INTERVAL_MS = 2000;
export function SpecView() {
const { currentProject, appSpec, setAppSpec } = useAppStore();
const [isLoading, setIsLoading] = useState(true);
@@ -40,6 +46,9 @@ export function SpecView() {
// Generate features only state
const [isGeneratingFeatures, setIsGeneratingFeatures] = useState(false);
// Logs state (kept for internal tracking, but UI removed)
const [logs, setLogs] = useState<string>("");
const logsRef = useRef<string>("");
// Phase tracking and status
const [currentPhase, setCurrentPhase] = useState<string>("");
@@ -246,7 +255,7 @@ export function SpecView() {
loadSpec();
}
}
}, 2000);
}, STATUS_CHECK_INTERVAL_MS);
}
}
} catch (error) {
@@ -310,7 +319,7 @@ export function SpecView() {
} catch (error) {
console.error("[SpecView] Periodic status check error:", error);
}
}, 2000); // Check every 2 seconds (more frequent)
}, STATUS_CHECK_INTERVAL_MS);
return () => {
clearInterval(intervalId);
@@ -342,7 +351,7 @@ export function SpecView() {
// Small delay to ensure spec file is written
setTimeout(() => {
loadSpec();
}, 500);
}, SPEC_FILE_WRITE_DELAY);
}
}
@@ -357,7 +366,7 @@ export function SpecView() {
stateRestoredRef.current = false;
setTimeout(() => {
loadSpec();
}, 500);
}, SPEC_FILE_WRITE_DELAY);
}
// Append progress to logs
@@ -399,37 +408,37 @@ export function SpecView() {
logsRef.current = completionLog;
setLogs(completionLog);
// Check if this is the final completion
const isFinalCompletion = event.message?.includes("All tasks completed") ||
event.message === "All tasks completed!" ||
event.message === "All tasks completed";
// --- Completion Detection Logic ---
// Check 1: Message explicitly indicates all tasks are done
const isFinalCompletionMessage = event.message?.includes("All tasks completed") ||
event.message === "All tasks completed!" ||
event.message === "All tasks completed";
// Check if we've already seen a completion phase in logs (including the message we just added)
const hasSeenCompletePhase = logsRef.current.includes("[Phase: complete]");
// Check 2: We've seen a [Phase: complete] marker in the logs
const hasCompletePhase = logsRef.current.includes("[Phase: complete]");
// Check recent logs for feature activity
// Check 3: Feature generation has finished (no recent activity and not actively generating)
const recentLogs = logsRef.current.slice(-2000);
const hasRecentFeatureActivity = recentLogs.includes("Feature Creation") ||
recentLogs.includes("Creating feature") ||
recentLogs.includes("UpdateFeatureStatus");
recentLogs.includes("Creating feature") ||
recentLogs.includes("UpdateFeatureStatus");
const isStillGeneratingFeatures = !isFinalCompletionMessage &&
!hasCompletePhase &&
(event.message?.includes("Features are being generated") ||
event.message?.includes("features are being generated"));
const isFeatureGenerationComplete = currentPhase === "feature_generation" &&
!hasRecentFeatureActivity &&
!isStillGeneratingFeatures;
// Check if we're still generating features (only for intermediate completion)
const isGeneratingFeatures = !isFinalCompletion &&
!hasSeenCompletePhase &&
(event.message?.includes("Features are being generated") ||
event.message?.includes("features are being generated"));
// If we're in feature_generation but no recent activity and we see completion, we're done
const shouldComplete = isFinalCompletion ||
hasSeenCompletePhase ||
(currentPhase === "feature_generation" && !hasRecentFeatureActivity && !isGeneratingFeatures);
// Determine if we should mark everything as complete
const shouldComplete = isFinalCompletionMessage || hasCompletePhase || isFeatureGenerationComplete;
if (shouldComplete) {
// Fully complete - clear all states immediately
console.log("[SpecView] Final completion detected - clearing state", {
isFinalCompletion,
hasSeenCompletePhase,
shouldComplete,
isFinalCompletionMessage,
hasCompletePhase,
isFeatureGenerationComplete,
hasRecentFeatureActivity,
currentPhase,
message: event.message
@@ -452,7 +461,7 @@ export function SpecView() {
setIsRegenerating(true);
setCurrentPhase("feature_generation");
console.log("[SpecView] Spec complete, continuing with feature generation", {
isGeneratingFeatures,
isStillGeneratingFeatures,
hasRecentFeatureActivity,
currentPhase
});