4937d57453
* auto-claude: subtask-1-1 - Extend RoadmapGenerationStatus type with startedAt and lastActivityAt * auto-claude: subtask-1-2 - Add IPC channels for progress persistence: ROADMAP_PROGRESS_SAVE, ROADMAP_PROGRESS_LOAD, ROADMAP_PROGRESS_CLEAR * auto-claude: subtask-1-3 - Add GENERATION_PROGRESS constant to AUTO_BUILD_PATHS * auto-claude: subtask-2-1 - Add IPC handlers for roadmap progress persistence Add three IPC handlers in roadmap-handlers.ts: - ROADMAP_PROGRESS_SAVE: Persist progress state to generation_progress.json - ROADMAP_PROGRESS_LOAD: Load persisted progress state from disk - ROADMAP_PROGRESS_CLEAR: Delete the progress file on completion/error/stop Follows existing patterns with snake_case JSON files and camelCase frontend. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * auto-claude: subtask-2-2 - Update agent-queue.ts to persist progress updates * auto-claude: subtask-3-1 - Add preload API methods for progress persistence Add saveRoadmapProgress, loadRoadmapProgress, and clearRoadmapProgress methods to RoadmapAPI interface and implementation. These methods use the IPC channels defined in subtask-1-2 to enable the renderer process to persist and restore roadmap generation state. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * auto-claude: subtask-4-1 - Update loadRoadmap function to load persisted prog - Update loadRoadmap to load persisted progress via loadRoadmapProgress API - Restore startedAt and lastActivityAt timestamps when is_running is true - Add fallback with current timestamps when no persisted progress found - Add roadmap progress persistence methods to ElectronAPI interface - Add browser mock implementations for progress persistence methods Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * auto-claude: subtask-4-2 - Update setGenerationStatus action to include times Updated setGenerationStatus action in roadmap-store.ts to automatically manage timestamp fields: - Sets startedAt when transitioning from idle to active phase - Updates lastActivityAt on every status change during generation - Clears both timestamps when generation stops (idle/complete/error) - Preserves existing startedAt during active generation phases Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * auto-claude: subtask-5-1 - Add elapsed time display with formatElapsedTime utility - Add formatElapsedTime utility function for MM:SS and H:MM:SS formatting - Add elapsedTime state with useEffect interval for real-time updates - Display elapsed time with Clock icon next to progress indicator - Calculate elapsed time from RoadmapGenerationStatus.startedAt field - Use useCallback for memoized calculation function - Clean up interval on phase change or component unmount - Reset elapsed time when returning to idle phase Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * auto-claude: subtask-5-2 - Add last activity timestamp display with formatTimeAgo utility - Added formatTimeAgo utility function that formats timestamps into human-readable relative time strings (e.g., "just now", "5s ago", "2m ago", "1h ago") - Added lastActivityDisplay state with useEffect interval to update every 5 seconds - Display last activity timestamp next to elapsed time in progress bar section - Added tooltip explaining "Last progress update received" - Uses muted styling to differentiate from elapsed time Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * auto-claude: subtask-5-3 - Add heartbeat animation indicator that pulses subtly - Add HeartbeatIndicator component with subtle scale pulse (1.05x) animation - Show "Processing" status with animated dot to indicate process is alive - Respect useReducedMotion preference by disabling animation when enabled - Integrate indicator into progress bar section next to percentage display Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * auto-claude: subtask-6-1 - Add translation keys for roadmap progress UI text: - Add roadmapProgress section with elapsedTime, lastActivity, staleWarning keys - Add staleWarningTooltip with interpolation for minutes - Add French translations for all new keys Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * auto-claude: subtask-6-2 - Update RoadmapGenerationProgress to use translation keys - Add useTranslation hook from react-i18next - Convert hardcoded phase labels and descriptions to translation keys - Convert step labels to translation keys - Translate button text, tooltips, and progress labels - Add translation keys to en/common.json and fr/common.json - Pass translation function to child components Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: preserve persisted timestamps when restoring roadmap progress state - Fix startedAt being overwritten with current time on reload by using status.startedAt ?? now when starting generation - Fix lastActivityAt always being overwritten by using status.lastActivityAt ?? now to preserve passed timestamps - Add documentation comment for SAVE/CLEAR IPC handlers explaining their purpose for API completeness Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: align IPC progress types and add validation - Add PersistedRoadmapProgress type for IPC transport with string timestamps - Update loadRoadmapProgress return type to use PersistedRoadmapProgress - Remove unused isRunning field from persisted progress - Add validation for JSON structure before using parsed data Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: validate phase value against allowed values when loading progress Add validation to ensure the phase field from persisted progress file matches one of the expected values (idle, analyzing, discovering, generating, complete, error). Prevents TypeError in frontend component when corrupted or manually edited files contain invalid phase values. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: align progress persistence types and add date validation - Update saveRoadmapProgress to use PersistedRoadmapProgress type - Derive isRunning from phase instead of requiring it as parameter - Add date validation when parsing persisted timestamps to handle corrupted date strings gracefully (returns current time as fallback) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * test: increase subprocess-spawn test timeout for Windows CI Increase timeout from 15s to 30s for all subprocess spawn integration tests. Dynamic imports are slower on Windows CI, causing intermittent timeouts. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
120 lines
4.5 KiB
TypeScript
120 lines
4.5 KiB
TypeScript
import { IPC_CHANNELS } from '../../../shared/constants';
|
|
import type {
|
|
Roadmap,
|
|
RoadmapFeatureStatus,
|
|
RoadmapGenerationStatus,
|
|
PersistedRoadmapProgress,
|
|
Task,
|
|
IPCResult
|
|
} from '../../../shared/types';
|
|
import { createIpcListener, invokeIpc, sendIpc, IpcListenerCleanup } from './ipc-utils';
|
|
|
|
/**
|
|
* Roadmap API operations
|
|
*/
|
|
export interface RoadmapAPI {
|
|
// Operations
|
|
getRoadmap: (projectId: string) => Promise<IPCResult<Roadmap | null>>;
|
|
getRoadmapStatus: (projectId: string) => Promise<IPCResult<{ isRunning: boolean }>>;
|
|
saveRoadmap: (projectId: string, roadmap: Roadmap) => Promise<IPCResult>;
|
|
generateRoadmap: (projectId: string, enableCompetitorAnalysis?: boolean, refreshCompetitorAnalysis?: boolean) => void;
|
|
refreshRoadmap: (projectId: string, enableCompetitorAnalysis?: boolean, refreshCompetitorAnalysis?: boolean) => void;
|
|
stopRoadmap: (projectId: string) => Promise<IPCResult>;
|
|
updateFeatureStatus: (
|
|
projectId: string,
|
|
featureId: string,
|
|
status: RoadmapFeatureStatus
|
|
) => Promise<IPCResult>;
|
|
convertFeatureToSpec: (
|
|
projectId: string,
|
|
featureId: string
|
|
) => Promise<IPCResult<Task>>;
|
|
|
|
// Progress persistence
|
|
saveRoadmapProgress: (projectId: string, progress: PersistedRoadmapProgress) => Promise<IPCResult>;
|
|
loadRoadmapProgress: (projectId: string) => Promise<IPCResult<PersistedRoadmapProgress | null>>;
|
|
clearRoadmapProgress: (projectId: string) => Promise<IPCResult>;
|
|
|
|
// Event Listeners
|
|
onRoadmapProgress: (
|
|
callback: (projectId: string, status: RoadmapGenerationStatus) => void
|
|
) => IpcListenerCleanup;
|
|
onRoadmapComplete: (
|
|
callback: (projectId: string, roadmap: Roadmap) => void
|
|
) => IpcListenerCleanup;
|
|
onRoadmapError: (
|
|
callback: (projectId: string, error: string) => void
|
|
) => IpcListenerCleanup;
|
|
onRoadmapStopped: (
|
|
callback: (projectId: string) => void
|
|
) => IpcListenerCleanup;
|
|
}
|
|
|
|
/**
|
|
* Creates the Roadmap API implementation
|
|
*/
|
|
export const createRoadmapAPI = (): RoadmapAPI => ({
|
|
// Operations
|
|
getRoadmap: (projectId: string): Promise<IPCResult<Roadmap | null>> =>
|
|
invokeIpc(IPC_CHANNELS.ROADMAP_GET, projectId),
|
|
|
|
getRoadmapStatus: (projectId: string): Promise<IPCResult<{ isRunning: boolean }>> =>
|
|
invokeIpc(IPC_CHANNELS.ROADMAP_GET_STATUS, projectId),
|
|
|
|
saveRoadmap: (projectId: string, roadmap: Roadmap): Promise<IPCResult> =>
|
|
invokeIpc(IPC_CHANNELS.ROADMAP_SAVE, projectId, roadmap),
|
|
|
|
generateRoadmap: (projectId: string, enableCompetitorAnalysis?: boolean, refreshCompetitorAnalysis?: boolean): void =>
|
|
sendIpc(IPC_CHANNELS.ROADMAP_GENERATE, projectId, enableCompetitorAnalysis, refreshCompetitorAnalysis),
|
|
|
|
refreshRoadmap: (projectId: string, enableCompetitorAnalysis?: boolean, refreshCompetitorAnalysis?: boolean): void =>
|
|
sendIpc(IPC_CHANNELS.ROADMAP_REFRESH, projectId, enableCompetitorAnalysis, refreshCompetitorAnalysis),
|
|
|
|
stopRoadmap: (projectId: string): Promise<IPCResult> =>
|
|
invokeIpc(IPC_CHANNELS.ROADMAP_STOP, projectId),
|
|
|
|
updateFeatureStatus: (
|
|
projectId: string,
|
|
featureId: string,
|
|
status: RoadmapFeatureStatus
|
|
): Promise<IPCResult> =>
|
|
invokeIpc(IPC_CHANNELS.ROADMAP_UPDATE_FEATURE, projectId, featureId, status),
|
|
|
|
convertFeatureToSpec: (
|
|
projectId: string,
|
|
featureId: string
|
|
): Promise<IPCResult<Task>> =>
|
|
invokeIpc(IPC_CHANNELS.ROADMAP_CONVERT_TO_SPEC, projectId, featureId),
|
|
|
|
// Progress persistence
|
|
saveRoadmapProgress: (projectId: string, progress: PersistedRoadmapProgress): Promise<IPCResult> =>
|
|
invokeIpc(IPC_CHANNELS.ROADMAP_PROGRESS_SAVE, projectId, progress),
|
|
|
|
loadRoadmapProgress: (projectId: string): Promise<IPCResult<PersistedRoadmapProgress | null>> =>
|
|
invokeIpc(IPC_CHANNELS.ROADMAP_PROGRESS_LOAD, projectId),
|
|
|
|
clearRoadmapProgress: (projectId: string): Promise<IPCResult> =>
|
|
invokeIpc(IPC_CHANNELS.ROADMAP_PROGRESS_CLEAR, projectId),
|
|
|
|
// Event Listeners
|
|
onRoadmapProgress: (
|
|
callback: (projectId: string, status: RoadmapGenerationStatus) => void
|
|
): IpcListenerCleanup =>
|
|
createIpcListener(IPC_CHANNELS.ROADMAP_PROGRESS, callback),
|
|
|
|
onRoadmapComplete: (
|
|
callback: (projectId: string, roadmap: Roadmap) => void
|
|
): IpcListenerCleanup =>
|
|
createIpcListener(IPC_CHANNELS.ROADMAP_COMPLETE, callback),
|
|
|
|
onRoadmapError: (
|
|
callback: (projectId: string, error: string) => void
|
|
): IpcListenerCleanup =>
|
|
createIpcListener(IPC_CHANNELS.ROADMAP_ERROR, callback),
|
|
|
|
onRoadmapStopped: (
|
|
callback: (projectId: string) => void
|
|
): IpcListenerCleanup =>
|
|
createIpcListener(IPC_CHANNELS.ROADMAP_STOPPED, callback)
|
|
});
|