mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-01-30 06:12:03 +00:00
feat: enhance board background settings and introduce animated borders
- Added default background settings to streamline background management across components. - Implemented animated border styles for in-progress cards to improve visual feedback. - Refactored BoardBackgroundModal and BoardView components to utilize the new default settings, ensuring consistent background behavior. - Updated KanbanCard to support animated borders, enhancing the user experience during task progress. - Improved Sidebar component by optimizing the fetching of running agents count with a more efficient use of hooks.
This commit is contained in:
@@ -1397,6 +1397,39 @@
|
||||
.text-running-indicator {
|
||||
color: var(--running-indicator-text);
|
||||
}
|
||||
|
||||
/* Animated border for in-progress cards */
|
||||
@keyframes border-rotate {
|
||||
0% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
50% {
|
||||
background-position: 100% 50%;
|
||||
}
|
||||
100% {
|
||||
background-position: 0% 50%;
|
||||
}
|
||||
}
|
||||
|
||||
.animated-border-wrapper {
|
||||
position: relative;
|
||||
border-radius: 0.75rem;
|
||||
padding: 2px;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
var(--running-indicator),
|
||||
color-mix(in oklch, var(--running-indicator), transparent 50%),
|
||||
var(--running-indicator),
|
||||
color-mix(in oklch, var(--running-indicator), transparent 50%),
|
||||
var(--running-indicator)
|
||||
);
|
||||
background-size: 200% 100%;
|
||||
animation: border-rotate 3s ease infinite;
|
||||
}
|
||||
|
||||
.animated-border-wrapper > * {
|
||||
border-radius: calc(0.75rem - 2px);
|
||||
}
|
||||
}
|
||||
|
||||
/* Retro Overrides for Utilities */
|
||||
|
||||
@@ -14,7 +14,7 @@ import { Slider } from "@/components/ui/slider";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useAppStore } from "@/store/app-store";
|
||||
import { useAppStore, defaultBackgroundSettings } from "@/store/app-store";
|
||||
import { getHttpApiClient } from "@/lib/http-api-client";
|
||||
import { toast } from "sonner";
|
||||
|
||||
@@ -55,27 +55,9 @@ export function BoardBackgroundModal({
|
||||
const [previewImage, setPreviewImage] = useState<string | null>(null);
|
||||
|
||||
// Get current background settings (live from store)
|
||||
const backgroundSettings = currentProject
|
||||
? boardBackgroundByProject[currentProject.path] || {
|
||||
imagePath: null,
|
||||
cardOpacity: 100,
|
||||
columnOpacity: 100,
|
||||
columnBorderEnabled: true,
|
||||
cardGlassmorphism: true,
|
||||
cardBorderEnabled: true,
|
||||
cardBorderOpacity: 100,
|
||||
hideScrollbar: false,
|
||||
}
|
||||
: {
|
||||
imagePath: null,
|
||||
cardOpacity: 100,
|
||||
columnOpacity: 100,
|
||||
columnBorderEnabled: true,
|
||||
cardGlassmorphism: true,
|
||||
cardBorderEnabled: true,
|
||||
cardBorderOpacity: 100,
|
||||
hideScrollbar: false,
|
||||
};
|
||||
const backgroundSettings =
|
||||
(currentProject && boardBackgroundByProject[currentProject.path]) ||
|
||||
defaultBackgroundSettings;
|
||||
|
||||
const cardOpacity = backgroundSettings.cardOpacity;
|
||||
const columnOpacity = backgroundSettings.columnOpacity;
|
||||
@@ -84,6 +66,7 @@ export function BoardBackgroundModal({
|
||||
const cardBorderEnabled = backgroundSettings.cardBorderEnabled;
|
||||
const cardBorderOpacity = backgroundSettings.cardBorderOpacity;
|
||||
const hideScrollbar = backgroundSettings.hideScrollbar;
|
||||
const imageVersion = backgroundSettings.imageVersion;
|
||||
|
||||
// Update preview image when background settings change
|
||||
useEffect(() => {
|
||||
@@ -91,8 +74,8 @@ export function BoardBackgroundModal({
|
||||
const serverUrl =
|
||||
process.env.NEXT_PUBLIC_SERVER_URL || "http://localhost:3008";
|
||||
// Add cache-busting query parameter to force browser to reload image
|
||||
const cacheBuster = backgroundSettings.imageVersion
|
||||
? `&v=${backgroundSettings.imageVersion}`
|
||||
const cacheBuster = imageVersion
|
||||
? `&v=${imageVersion}`
|
||||
: `&v=${Date.now()}`;
|
||||
const imagePath = `${serverUrl}/api/fs/image?path=${encodeURIComponent(
|
||||
backgroundSettings.imagePath
|
||||
@@ -101,11 +84,7 @@ export function BoardBackgroundModal({
|
||||
} else {
|
||||
setPreviewImage(null);
|
||||
}
|
||||
}, [
|
||||
currentProject,
|
||||
backgroundSettings.imagePath,
|
||||
backgroundSettings.imageVersion,
|
||||
]);
|
||||
}, [currentProject, backgroundSettings.imagePath, imageVersion]);
|
||||
|
||||
const fileToBase64 = (file: File): Promise<string> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
@@ -332,35 +332,32 @@ export function Sidebar() {
|
||||
};
|
||||
}, [setCurrentView]);
|
||||
|
||||
// Fetch running agents count and update every 2 seconds
|
||||
useEffect(() => {
|
||||
const fetchRunningAgentsCount = async () => {
|
||||
try {
|
||||
const api = getElectronAPI();
|
||||
if (api.runningAgents) {
|
||||
const result = await api.runningAgents.getAll();
|
||||
if (result.success && result.runningAgents) {
|
||||
setRunningAgentsCount(result.runningAgents.length);
|
||||
}
|
||||
// Fetch running agents count function - used for initial load and event-driven updates
|
||||
const fetchRunningAgentsCount = useCallback(async () => {
|
||||
try {
|
||||
const api = getElectronAPI();
|
||||
if (api.runningAgents) {
|
||||
const result = await api.runningAgents.getAll();
|
||||
if (result.success && result.runningAgents) {
|
||||
setRunningAgentsCount(result.runningAgents.length);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[Sidebar] Error fetching running agents count:", error);
|
||||
}
|
||||
};
|
||||
|
||||
// Initial fetch
|
||||
fetchRunningAgentsCount();
|
||||
|
||||
// Set up interval to refresh every 2 seconds
|
||||
const interval = setInterval(fetchRunningAgentsCount, 2000);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
} catch (error) {
|
||||
console.error("[Sidebar] Error fetching running agents count:", error);
|
||||
}
|
||||
}, []);
|
||||
|
||||
// Subscribe to auto-mode events to update running agents count in real-time
|
||||
useEffect(() => {
|
||||
const api = getElectronAPI();
|
||||
if (!api.autoMode) return;
|
||||
if (!api.autoMode) {
|
||||
// If autoMode is not available, still fetch initial count
|
||||
fetchRunningAgentsCount();
|
||||
return;
|
||||
}
|
||||
|
||||
// Initial fetch on mount
|
||||
fetchRunningAgentsCount();
|
||||
|
||||
const unsubscribe = api.autoMode.onEvent((event) => {
|
||||
// When a feature starts, completes, or errors, refresh the count
|
||||
@@ -369,21 +366,6 @@ export function Sidebar() {
|
||||
event.type === "auto_mode_error" ||
|
||||
event.type === "auto_mode_feature_start"
|
||||
) {
|
||||
const fetchRunningAgentsCount = async () => {
|
||||
try {
|
||||
if (api.runningAgents) {
|
||||
const result = await api.runningAgents.getAll();
|
||||
if (result.success && result.runningAgents) {
|
||||
setRunningAgentsCount(result.runningAgents.length);
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(
|
||||
"[Sidebar] Error fetching running agents count:",
|
||||
error
|
||||
);
|
||||
}
|
||||
};
|
||||
fetchRunningAgentsCount();
|
||||
}
|
||||
});
|
||||
@@ -391,7 +373,7 @@ export function Sidebar() {
|
||||
return () => {
|
||||
unsubscribe();
|
||||
};
|
||||
}, []);
|
||||
}, [fetchRunningAgentsCount]);
|
||||
|
||||
// Handle creating initial spec for new project
|
||||
const handleCreateInitialSpec = useCallback(async () => {
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
AgentModel,
|
||||
ThinkingLevel,
|
||||
AIProfile,
|
||||
defaultBackgroundSettings,
|
||||
} from "@/store/app-store";
|
||||
import { getElectronAPI } from "@/lib/electron";
|
||||
import { cn, modelSupportsThinking } from "@/lib/utils";
|
||||
@@ -1554,25 +1555,6 @@ export function BoardView() {
|
||||
}
|
||||
});
|
||||
|
||||
// Sort waiting_approval column: justFinished features (within 2 minutes) go to the top
|
||||
map.waiting_approval.sort((a, b) => {
|
||||
// Helper to check if feature is "just finished" (within 2 minutes)
|
||||
const isJustFinished = (feature: Feature) => {
|
||||
if (!feature.justFinishedAt) return false;
|
||||
const finishedTime = new Date(feature.justFinishedAt).getTime();
|
||||
const now = Date.now();
|
||||
const twoMinutes = 2 * 60 * 1000; // 2 minutes in milliseconds
|
||||
return now - finishedTime < twoMinutes;
|
||||
};
|
||||
|
||||
const aJustFinished = isJustFinished(a);
|
||||
const bJustFinished = isJustFinished(b);
|
||||
// Features with justFinishedAt within 2 minutes should appear first
|
||||
if (aJustFinished && !bJustFinished) return -1;
|
||||
if (!aJustFinished && bJustFinished) return 1;
|
||||
return 0; // Keep original order for features with same justFinished status
|
||||
});
|
||||
|
||||
return map;
|
||||
}, [features, runningAutoTasks, searchQuery]);
|
||||
|
||||
@@ -1975,27 +1957,9 @@ export function BoardView() {
|
||||
{/* Kanban Columns */}
|
||||
{(() => {
|
||||
// Get background settings for current project
|
||||
const backgroundSettings = currentProject
|
||||
? boardBackgroundByProject[currentProject.path] || {
|
||||
imagePath: null,
|
||||
cardOpacity: 100,
|
||||
columnOpacity: 100,
|
||||
columnBorderEnabled: true,
|
||||
cardGlassmorphism: true,
|
||||
cardBorderEnabled: true,
|
||||
cardBorderOpacity: 100,
|
||||
hideScrollbar: false,
|
||||
}
|
||||
: {
|
||||
imagePath: null,
|
||||
cardOpacity: 100,
|
||||
columnOpacity: 100,
|
||||
columnBorderEnabled: true,
|
||||
cardGlassmorphism: true,
|
||||
cardBorderEnabled: true,
|
||||
cardBorderOpacity: 100,
|
||||
hideScrollbar: false,
|
||||
};
|
||||
const backgroundSettings =
|
||||
(currentProject && boardBackgroundByProject[currentProject.path]) ||
|
||||
defaultBackgroundSettings;
|
||||
|
||||
// Build background image style if image exists
|
||||
const backgroundImageStyle = backgroundSettings.imagePath
|
||||
|
||||
@@ -309,26 +309,30 @@ export const KanbanCard = memo(function KanbanCard({
|
||||
).borderColor = `color-mix(in oklch, var(--border) ${cardBorderOpacity}%, transparent)`;
|
||||
}
|
||||
|
||||
return (
|
||||
const cardElement = (
|
||||
<Card
|
||||
ref={setNodeRef}
|
||||
style={borderStyle}
|
||||
style={isCurrentAutoTask ? style : borderStyle}
|
||||
className={cn(
|
||||
"cursor-grab active:cursor-grabbing transition-all relative kanban-card-content select-none",
|
||||
// Apply border class when border is enabled and opacity is 100%
|
||||
// When opacity is not 100%, we use inline styles for border color
|
||||
cardBorderEnabled && cardBorderOpacity === 100 && "border-border",
|
||||
// Skip border classes when animated border is active (isCurrentAutoTask)
|
||||
!isCurrentAutoTask &&
|
||||
cardBorderEnabled &&
|
||||
cardBorderOpacity === 100 &&
|
||||
"border-border",
|
||||
// When border is enabled but opacity is not 100%, we still need border width
|
||||
cardBorderEnabled && cardBorderOpacity !== 100 && "border",
|
||||
!isCurrentAutoTask &&
|
||||
cardBorderEnabled &&
|
||||
cardBorderOpacity !== 100 &&
|
||||
"border",
|
||||
// Remove default background when using opacity overlay
|
||||
!isDragging && "bg-transparent",
|
||||
// Remove default backdrop-blur-sm from Card component when glassmorphism is disabled
|
||||
!glassmorphism && "backdrop-blur-[0px]!",
|
||||
isDragging && "scale-105 shadow-lg",
|
||||
// Special border styles for running/error states override the border opacity
|
||||
// These need to be applied with higher specificity
|
||||
isCurrentAutoTask &&
|
||||
"border-running-indicator border-2 shadow-running-indicator/50 shadow-lg animate-pulse",
|
||||
// Error state border (only when not in progress)
|
||||
feature.error &&
|
||||
!isCurrentAutoTask &&
|
||||
"border-red-500 border-2 shadow-red-500/30 shadow-lg",
|
||||
@@ -1056,4 +1060,11 @@ export const KanbanCard = memo(function KanbanCard({
|
||||
</Dialog>
|
||||
</Card>
|
||||
);
|
||||
|
||||
// Wrap with animated border when in progress
|
||||
if (isCurrentAutoTask) {
|
||||
return <div className="animated-border-wrapper">{cardElement}</div>;
|
||||
}
|
||||
|
||||
return cardElement;
|
||||
});
|
||||
|
||||
@@ -388,6 +388,28 @@ export interface AppState {
|
||||
previewTheme: ThemeMode | null;
|
||||
}
|
||||
|
||||
// Default background settings for board backgrounds
|
||||
export const defaultBackgroundSettings: {
|
||||
imagePath: string | null;
|
||||
imageVersion?: number;
|
||||
cardOpacity: number;
|
||||
columnOpacity: number;
|
||||
columnBorderEnabled: boolean;
|
||||
cardGlassmorphism: boolean;
|
||||
cardBorderEnabled: boolean;
|
||||
cardBorderOpacity: number;
|
||||
hideScrollbar: boolean;
|
||||
} = {
|
||||
imagePath: null,
|
||||
cardOpacity: 100,
|
||||
columnOpacity: 100,
|
||||
columnBorderEnabled: true,
|
||||
cardGlassmorphism: true,
|
||||
cardBorderEnabled: true,
|
||||
cardBorderOpacity: 100,
|
||||
hideScrollbar: false,
|
||||
};
|
||||
|
||||
export interface AutoModeActivity {
|
||||
id: string;
|
||||
featureId: string;
|
||||
@@ -1345,16 +1367,7 @@ export const useAppStore = create<AppState & AppActions>()(
|
||||
|
||||
setCardOpacity: (projectPath, opacity) => {
|
||||
const current = get().boardBackgroundByProject;
|
||||
const existing = current[projectPath] || {
|
||||
imagePath: null,
|
||||
cardOpacity: 100,
|
||||
columnOpacity: 100,
|
||||
columnBorderEnabled: true,
|
||||
cardGlassmorphism: true,
|
||||
cardBorderEnabled: true,
|
||||
cardBorderOpacity: 100,
|
||||
hideScrollbar: false,
|
||||
};
|
||||
const existing = current[projectPath] || defaultBackgroundSettings;
|
||||
set({
|
||||
boardBackgroundByProject: {
|
||||
...current,
|
||||
@@ -1368,16 +1381,7 @@ export const useAppStore = create<AppState & AppActions>()(
|
||||
|
||||
setColumnOpacity: (projectPath, opacity) => {
|
||||
const current = get().boardBackgroundByProject;
|
||||
const existing = current[projectPath] || {
|
||||
imagePath: null,
|
||||
cardOpacity: 100,
|
||||
columnOpacity: 100,
|
||||
columnBorderEnabled: true,
|
||||
cardGlassmorphism: true,
|
||||
cardBorderEnabled: true,
|
||||
cardBorderOpacity: 100,
|
||||
hideScrollbar: false,
|
||||
};
|
||||
const existing = current[projectPath] || defaultBackgroundSettings;
|
||||
set({
|
||||
boardBackgroundByProject: {
|
||||
...current,
|
||||
@@ -1391,32 +1395,12 @@ export const useAppStore = create<AppState & AppActions>()(
|
||||
|
||||
getBoardBackground: (projectPath) => {
|
||||
const settings = get().boardBackgroundByProject[projectPath];
|
||||
return (
|
||||
settings || {
|
||||
imagePath: null,
|
||||
cardOpacity: 100,
|
||||
columnOpacity: 100,
|
||||
columnBorderEnabled: true,
|
||||
cardGlassmorphism: true,
|
||||
cardBorderEnabled: true,
|
||||
cardBorderOpacity: 100,
|
||||
hideScrollbar: false,
|
||||
}
|
||||
);
|
||||
return settings || defaultBackgroundSettings;
|
||||
},
|
||||
|
||||
setColumnBorderEnabled: (projectPath, enabled) => {
|
||||
const current = get().boardBackgroundByProject;
|
||||
const existing = current[projectPath] || {
|
||||
imagePath: null,
|
||||
cardOpacity: 100,
|
||||
columnOpacity: 100,
|
||||
columnBorderEnabled: true,
|
||||
cardGlassmorphism: true,
|
||||
cardBorderEnabled: true,
|
||||
cardBorderOpacity: 100,
|
||||
hideScrollbar: false,
|
||||
};
|
||||
const existing = current[projectPath] || defaultBackgroundSettings;
|
||||
set({
|
||||
boardBackgroundByProject: {
|
||||
...current,
|
||||
@@ -1430,16 +1414,7 @@ export const useAppStore = create<AppState & AppActions>()(
|
||||
|
||||
setCardGlassmorphism: (projectPath, enabled) => {
|
||||
const current = get().boardBackgroundByProject;
|
||||
const existing = current[projectPath] || {
|
||||
imagePath: null,
|
||||
cardOpacity: 100,
|
||||
columnOpacity: 100,
|
||||
columnBorderEnabled: true,
|
||||
cardGlassmorphism: true,
|
||||
cardBorderEnabled: true,
|
||||
cardBorderOpacity: 100,
|
||||
hideScrollbar: false,
|
||||
};
|
||||
const existing = current[projectPath] || defaultBackgroundSettings;
|
||||
set({
|
||||
boardBackgroundByProject: {
|
||||
...current,
|
||||
@@ -1453,16 +1428,7 @@ export const useAppStore = create<AppState & AppActions>()(
|
||||
|
||||
setCardBorderEnabled: (projectPath, enabled) => {
|
||||
const current = get().boardBackgroundByProject;
|
||||
const existing = current[projectPath] || {
|
||||
imagePath: null,
|
||||
cardOpacity: 100,
|
||||
columnOpacity: 100,
|
||||
columnBorderEnabled: true,
|
||||
cardGlassmorphism: true,
|
||||
cardBorderEnabled: true,
|
||||
cardBorderOpacity: 100,
|
||||
hideScrollbar: false,
|
||||
};
|
||||
const existing = current[projectPath] || defaultBackgroundSettings;
|
||||
set({
|
||||
boardBackgroundByProject: {
|
||||
...current,
|
||||
@@ -1476,16 +1442,7 @@ export const useAppStore = create<AppState & AppActions>()(
|
||||
|
||||
setCardBorderOpacity: (projectPath, opacity) => {
|
||||
const current = get().boardBackgroundByProject;
|
||||
const existing = current[projectPath] || {
|
||||
imagePath: null,
|
||||
cardOpacity: 100,
|
||||
columnOpacity: 100,
|
||||
columnBorderEnabled: true,
|
||||
cardGlassmorphism: true,
|
||||
cardBorderEnabled: true,
|
||||
cardBorderOpacity: 100,
|
||||
hideScrollbar: false,
|
||||
};
|
||||
const existing = current[projectPath] || defaultBackgroundSettings;
|
||||
set({
|
||||
boardBackgroundByProject: {
|
||||
...current,
|
||||
@@ -1499,16 +1456,7 @@ export const useAppStore = create<AppState & AppActions>()(
|
||||
|
||||
setHideScrollbar: (projectPath, hide) => {
|
||||
const current = get().boardBackgroundByProject;
|
||||
const existing = current[projectPath] || {
|
||||
imagePath: null,
|
||||
cardOpacity: 100,
|
||||
columnOpacity: 100,
|
||||
columnBorderEnabled: true,
|
||||
cardGlassmorphism: true,
|
||||
cardBorderEnabled: true,
|
||||
cardBorderOpacity: 100,
|
||||
hideScrollbar: false,
|
||||
};
|
||||
const existing = current[projectPath] || defaultBackgroundSettings;
|
||||
set({
|
||||
boardBackgroundByProject: {
|
||||
...current,
|
||||
@@ -1522,16 +1470,7 @@ export const useAppStore = create<AppState & AppActions>()(
|
||||
|
||||
clearBoardBackground: (projectPath) => {
|
||||
const current = get().boardBackgroundByProject;
|
||||
const existing = current[projectPath] || {
|
||||
imagePath: null,
|
||||
cardOpacity: 100,
|
||||
columnOpacity: 100,
|
||||
columnBorderEnabled: true,
|
||||
cardGlassmorphism: true,
|
||||
cardBorderEnabled: true,
|
||||
cardBorderOpacity: 100,
|
||||
hideScrollbar: false,
|
||||
};
|
||||
const existing = current[projectPath] || defaultBackgroundSettings;
|
||||
set({
|
||||
boardBackgroundByProject: {
|
||||
...current,
|
||||
|
||||
@@ -25,8 +25,9 @@ const execAsync = promisify(exec);
|
||||
|
||||
interface Feature {
|
||||
id: string;
|
||||
title: string;
|
||||
category: string;
|
||||
description: string;
|
||||
steps?: string[];
|
||||
status: string;
|
||||
priority?: number;
|
||||
spec?: string;
|
||||
@@ -636,7 +637,9 @@ Address the follow-up instructions above. Review the previous work and make the
|
||||
// Load feature for commit message
|
||||
const feature = await this.loadFeature(projectPath, featureId);
|
||||
const commitMessage = feature
|
||||
? `feat: ${feature.title}\n\nImplemented by Automaker auto-mode`
|
||||
? `feat: ${this.extractTitleFromDescription(
|
||||
feature.description
|
||||
)}\n\nImplemented by Automaker auto-mode`
|
||||
: `feat: Feature ${featureId}`;
|
||||
|
||||
// Stage and commit
|
||||
@@ -930,11 +933,56 @@ Format your response as a structured markdown document.`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract a title from feature description (first line or truncated)
|
||||
*/
|
||||
private extractTitleFromDescription(description: string): string {
|
||||
if (!description || !description.trim()) {
|
||||
return "Untitled Feature";
|
||||
}
|
||||
|
||||
// Get first line, or first 60 characters if no newline
|
||||
const firstLine = description.split("\n")[0].trim();
|
||||
if (firstLine.length <= 60) {
|
||||
return firstLine;
|
||||
}
|
||||
|
||||
// Truncate to 60 characters and add ellipsis
|
||||
return firstLine.substring(0, 57) + "...";
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract image paths from feature's imagePaths array
|
||||
* Handles both string paths and objects with path property
|
||||
*/
|
||||
private extractImagePaths(
|
||||
imagePaths:
|
||||
| Array<string | { path: string; [key: string]: unknown }>
|
||||
| undefined,
|
||||
projectPath: string
|
||||
): string[] {
|
||||
if (!imagePaths || imagePaths.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return imagePaths
|
||||
.map((imgPath) => {
|
||||
const pathStr = typeof imgPath === "string" ? imgPath : imgPath.path;
|
||||
// Resolve relative paths to absolute paths
|
||||
return path.isAbsolute(pathStr)
|
||||
? pathStr
|
||||
: path.join(projectPath, pathStr);
|
||||
})
|
||||
.filter((p) => p); // Filter out any empty paths
|
||||
}
|
||||
|
||||
private buildFeaturePrompt(feature: Feature): string {
|
||||
const title = this.extractTitleFromDescription(feature.description);
|
||||
|
||||
let prompt = `## Feature Implementation Task
|
||||
|
||||
**Feature ID:** ${feature.id}
|
||||
**Title:** ${feature.title}
|
||||
**Title:** ${title}
|
||||
**Description:** ${feature.description}
|
||||
`;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user