Skip to content

Conversation

@JoshuaRileyDev
Copy link
Contributor

@JoshuaRileyDev JoshuaRileyDev commented Dec 27, 2025

Summary

Fixes a bug where the logs tab continued to show phases as "Running" even after a task was stopped and moved to the planning board.

Problem

When a user stopped a task in progress:

  • ✅ Task status changed to 'backlog'
  • ✅ Execution progress reset to 'idle'
  • ✅ Task moved to planning board in UI
  • But the logs tab still showed "Running" badge for active phases

Root Cause

The phase logs are stored in task_logs.json files (separate from task status). When a task was stopped:

  1. The main task status was updated to 'backlog'
  2. The execution progress was reset to 'idle'
  3. But the task_logs.json files were not updated
  4. Phases with status: 'active' in the log files continued to display as "Running"

Solution

Backend Changes

task-log-service.ts

  • Added markActivePhasesStopped() method to update phase status in log files
  • Updates both main and worktree task_logs.json files
  • Marks all active phases as stopped when task is interrupted
  • Emits logs-changed event to update UI immediately

execution-handlers.ts

  • Updated TASK_STOP handler to call markActivePhasesStopped()
  • Wrapped in try-catch to ensure task stopping works even if log update fails
  • Prevents any errors in log updates from breaking core stop functionality

Type System Changes

task.ts

  • Extended TaskLogPhaseStatus to include 'stopped' as a valid status
  • More semantically correct than using 'failed' for user-initiated stops

UI Changes

TaskLogs.tsx

  • Added "Stopped" badge with muted gray styling
  • Shows alert triangle icon to indicate interruption
  • Distinct from "Failed" (red/error) and "Running" (blue/active)
  • Added phase section styling for stopped status

Testing

Tested the following scenarios:

  1. ✅ Starting a task and immediately stopping it
  2. ✅ Stopping a task during different phases (planning, coding, validation)
  3. ✅ Verifying logs tab updates immediately when task is stopped
  4. ✅ Ensuring stop button works even if log files are missing/corrupted
  5. ✅ Checking both main and worktree log files are updated

Files Changed

  • apps/frontend/src/main/task-log-service.ts - Added phase status update methods
  • apps/frontend/src/main/ipc-handlers/task/execution-handlers.ts - Call markActivePhasesStopped on task stop
  • apps/frontend/src/shared/types/task.ts - Extended TaskLogPhaseStatus type
  • apps/frontend/src/renderer/components/task-detail/TaskLogs.tsx - Added Stopped badge and styling

Screenshots

Before: Logs tab showed "Running" even after task was stopped
After: Logs tab correctly shows "Stopped" when task is stopped

Breaking Changes

None - this is purely a bug fix. The new 'stopped' status is backward compatible.

Related Issues

Fixes issue where logs tab displays incorrect running status after stopping a task.

Summary by CodeRabbit

  • New Features

    • Added a "Stopped" phase status with dedicated visuals and badge.
    • Task log phase statuses are now localized in English and French.
  • Bug Fixes

    • Running phases are now marked as stopped when a task is interrupted.
    • Improved resilience so log-update errors won’t prevent a task from stopping.

✏️ Tip: You can customize this high-level summary in your review settings.

When a task is stopped, the task status changes to 'backlog' and execution
progress resets to 'idle', but the task_logs.json files were not being updated.
This caused the logs tab to continue showing "Running" badges for phases that
were still marked as 'active' in the log files.

Changes:
- Add markActivePhasesStopped() method to TaskLogService
- Update both main and worktree task_logs.json files
- Mark active phases as 'failed' (interrupted) when task is stopped
- Call this method in TASK_STOP handler before sending status change event
- Emit logs-changed event to update UI immediately

Fixes issue where logs tab shows task as running after it's been stopped.
…log update fails

The stop button wasn't working because an error in the phase log update code
was preventing the task from stopping. Now the log update is wrapped in a
try-catch block so the task will always stop, even if updating the logs fails.

This ensures the critical stop functionality works while still attempting to
update the phase logs when possible.
Replace dynamic require() call with static import at the top of the file.
This is cleaner and avoids potential module resolution issues.
…ases

When a task is stopped by the user, phases are now marked as 'stopped' instead
of 'failed'. This is more semantically correct and clearer to users.

Changes:
- Add 'stopped' to TaskLogPhaseStatus type
- Update task-log-service to mark phases as 'stopped' when task is stopped
- Add 'Stopped' badge in TaskLogs UI with muted styling
- Add stopped status styling for phase sections

The 'stopped' status uses muted colors to distinguish it from errors ('failed')
while still indicating the phase didn't complete normally.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 27, 2025

📝 Walkthrough

Walkthrough

Adds a new 'stopped' phase status, updates TaskLogService to mark active phases stopped with atomic file writes and emit refreshed logs, invokes that service during task-stop handling (errors swallowed), and updates UI and i18n to render the new stopped state.

Changes

Cohort / File(s) Summary
Type definitions
apps/frontend/src/shared/types/task.ts
Extend TaskLogPhaseStatus to include 'stopped'.
Task log service
apps/frontend/src/main/task-log-service.ts
Add markActivePhasesStopped(specId, projectPath, specsRelPath), private updateLogFilePhaseStatus() and isValidSpecId(); import writeFileSync, renameSync, unlinkSync; export taskLogService; perform atomic file updates and emit refreshed logs.
Task execution handler
apps/frontend/src/main/ipc-handlers/task/execution-handlers.ts
Import and call taskLogService.markActivePhasesStopped() during task stop handling; call wrapped in try-catch to avoid aborting stop flow on logging errors.
UI rendering & i18n
apps/frontend/src/renderer/components/task-detail/TaskLogs.tsx, apps/frontend/src/shared/i18n/index.ts, apps/frontend/src/shared/i18n/locales/en/taskLogs.json, apps/frontend/src/shared/i18n/locales/fr/taskLogs.json
Add taskLogs namespace and locale files; use t(...) for phase statuses; render new 'stopped' status with translated label and muted styling.

Sequence Diagram(s)

sequenceDiagram
    participant Handler as Task Stop Handler
    participant Service as TaskLogService
    participant FS as File System
    participant Cache as Log Loader
    participant Emitter as Event Emitter
    participant UI as TaskLogs UI

    Handler->>Service: markActivePhasesStopped(specId, projectPath, specsRelPath)
    alt update succeeds
        Service->>FS: read main log file
        Service->>Service: mark active phases as 'stopped' + set completed_at
        Service->>FS: write updated main log file (atomic: temp -> rename)
        Service->>FS: read worktree log file
        Service->>Service: mark active phases as 'stopped' + set completed_at
        Service->>FS: write updated worktree log file (atomic)
        Service->>Cache: reload logs
        Service->>Emitter: emit updated logs
        Emitter->>UI: deliver updated logs
        UI->>UI: render phases with 'stopped' status (localized, muted styling)
    else error during update
        Service-->>Handler: swallow/log error (no throw)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • AlexMadera
  • MikeeBuilds

Poem

🐰 I nudged the phases into sleepy stops,

Quieted logs with tiny hops,
"Stopped" now rests where running played,
Translated tags and files are laid,
Hooray — the task can take a nap! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix: Update phase logs when task is stopped' directly and clearly summarizes the main change: updating phase logs to reflect the stopped status when a task is stopped.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 52d4c36 and 7d2ae82.

📒 Files selected for processing (1)
  • apps/frontend/src/main/ipc-handlers/task/execution-handlers.ts
🧰 Additional context used
📓 Path-based instructions (2)
apps/frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/frontend/src/**/*.{ts,tsx}: Always use translation keys with useTranslation() for all user-facing text in React/TypeScript frontend components - use format namespace:section.key (e.g., navigation:items.githubPRs)
Never use hardcoded strings in JSX/TSX files for user-facing text - always reference translation keys from apps/frontend/src/shared/i18n/locales/

Files:

  • apps/frontend/src/main/ipc-handlers/task/execution-handlers.ts
apps/frontend/**/*.{ts,tsx}

⚙️ CodeRabbit configuration file

apps/frontend/**/*.{ts,tsx}: Review React patterns and TypeScript type safety.
Check for proper state management and component composition.

Files:

  • apps/frontend/src/main/ipc-handlers/task/execution-handlers.ts
🧬 Code graph analysis (1)
apps/frontend/src/main/ipc-handlers/task/execution-handlers.ts (2)
apps/frontend/src/shared/constants/config.ts (1)
  • getSpecsDir (104-107)
apps/frontend/src/main/task-log-service.ts (1)
  • taskLogService (482-482)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Cursor Bugbot
  • GitHub Check: CodeQL (python)
  • GitHub Check: CodeQL (javascript-typescript)
🔇 Additional comments (2)
apps/frontend/src/main/ipc-handlers/task/execution-handlers.ts (2)

12-12: LGTM: Import statement is correct.

The import of taskLogService singleton is properly structured and follows the existing pattern in this file.


189-201: LGTM: Excellent error handling and correct implementation.

The integration with taskLogService.markActivePhasesStopped() is well-implemented:

  • Resilient error handling: The try-catch ensures task stopping succeeds even if log updates fail, which is the correct behavior since stopping the task is the primary operation.
  • Proper sequence: Logs are updated after killing the task and unwatching files, but before notifying the UI, ensuring consistent state when the renderer receives the status change.
  • Correct parameters: The call uses the appropriate task.specId, project.path, and computed specsBaseDir matching the method signature.
  • Safe null checks: Guards against missing task or project data.

The error logging on Line 200 provides good observability without impacting the user experience.


Comment @coderabbitai help to get the list of available commands and usage tips.

@AndyMik90 AndyMik90 self-assigned this Dec 27, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 40d04d7 and bc9cf39.

📒 Files selected for processing (4)
  • apps/frontend/src/main/ipc-handlers/task/execution-handlers.ts
  • apps/frontend/src/main/task-log-service.ts
  • apps/frontend/src/renderer/components/task-detail/TaskLogs.tsx
  • apps/frontend/src/shared/types/task.ts
🧰 Additional context used
📓 Path-based instructions (2)
apps/frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/frontend/src/**/*.{ts,tsx}: Always use translation keys with useTranslation() for all user-facing text in React/TypeScript frontend components - use format namespace:section.key (e.g., navigation:items.githubPRs)
Never use hardcoded strings in JSX/TSX files for user-facing text - always reference translation keys from apps/frontend/src/shared/i18n/locales/

Files:

  • apps/frontend/src/shared/types/task.ts
  • apps/frontend/src/renderer/components/task-detail/TaskLogs.tsx
  • apps/frontend/src/main/task-log-service.ts
  • apps/frontend/src/main/ipc-handlers/task/execution-handlers.ts
apps/frontend/**/*.{ts,tsx}

⚙️ CodeRabbit configuration file

apps/frontend/**/*.{ts,tsx}: Review React patterns and TypeScript type safety.
Check for proper state management and component composition.

Files:

  • apps/frontend/src/shared/types/task.ts
  • apps/frontend/src/renderer/components/task-detail/TaskLogs.tsx
  • apps/frontend/src/main/task-log-service.ts
  • apps/frontend/src/main/ipc-handlers/task/execution-handlers.ts
🧬 Code graph analysis (3)
apps/frontend/src/renderer/components/task-detail/TaskLogs.tsx (1)
.design-system/src/components/Badge.tsx (1)
  • Badge (9-27)
apps/frontend/src/main/task-log-service.ts (1)
apps/frontend/src/shared/types/task.ts (2)
  • TaskLogs (87-96)
  • TaskLogPhase (60-60)
apps/frontend/src/main/ipc-handlers/task/execution-handlers.ts (2)
apps/frontend/src/shared/constants/config.ts (1)
  • getSpecsDir (102-105)
apps/frontend/src/main/task-log-service.ts (1)
  • taskLogService (447-447)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: CodeQL (javascript-typescript)
  • GitHub Check: CodeQL (python)
🔇 Additional comments (8)
apps/frontend/src/main/ipc-handlers/task/execution-handlers.ts (2)

12-12: LGTM: Correct singleton import.

The import correctly uses the singleton instance exported from task-log-service.ts.


188-200: LGTM: Robust error handling for log updates.

The try-catch wrapper ensures task stopping succeeds even if log file updates fail. The error is appropriately logged while allowing the core stop operation to proceed.

apps/frontend/src/shared/types/task.ts (1)

61-61: LGTM: Type extension enables stopped phase status.

The addition of 'stopped' to TaskLogPhaseStatus appropriately distinguishes user-initiated stops from failures, supporting the new functionality across the UI and backend.

apps/frontend/src/renderer/components/task-detail/TaskLogs.tsx (1)

242-242: LGTM: Consistent styling for stopped status.

The conditional styling for the stopped phase status appropriately uses muted colors to visually distinguish it from active, completed, and failed states.

apps/frontend/src/main/task-log-service.ts (4)

2-2: LGTM: Import addition for file writing.

The writeFileSync import is appropriately added to support the new log update functionality.


380-410: LGTM: Well-structured method with appropriate error handling.

The markActivePhasesStopped method correctly:

  • Resolves both main and worktree log file paths
  • Updates log files via the helper method
  • Reloads and emits updated logs to listeners
  • Handles missing worktree directories gracefully

The error handling in the caller (execution-handlers.ts) ensures non-critical log update failures don't block task stopping.


412-443: LGTM: Atomic update with proper error handling.

The updateLogFilePhaseStatus helper appropriately:

  • Checks file existence before attempting updates
  • Only writes when changes are made
  • Sets both status and completed_at timestamp
  • Catches and logs errors without throwing

Note: The read-modify-write pattern has an inherent race condition risk, but this is acceptable here since log updates are non-critical and failures are logged.


446-447: LGTM: Singleton export for service access.

The singleton export enables centralized access to the task log service, which is correctly imported and used in execution-handlers.ts.

JoshuaRileyDev and others added 2 commits December 27, 2025 17:15
- Create taskLogs namespace with status translations (EN/FR)
- Update TaskLogs.tsx to use translation keys instead of hardcoded strings
- Register taskLogs namespace in i18n configuration
- Fix CodeQL race condition warning in task-log-service.ts by removing redundant existsSync check

Translation keys added:
- status.pending
- status.active (Running)
- status.completed (Complete)
- status.failed
- status.stopped
- status.interrupted

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
@MikeeBuilds MikeeBuilds added bug Something isn't working area/backend This is backend only priority/medium Normal priority labels Dec 27, 2025
Copy link
Owner

@AndyMik90 AndyMik90 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Auto Claude PR Review

Merge Verdict: 🟡 MERGE WITH CHANGES

4 high-priority issues to address

Risk Assessment

Factor Level Notes
Complexity Low Based on lines changed
Security Impact Medium Based on security findings
Scope Coherence Good Based on structural review

Findings Summary

  • High: 4 issue(s)
  • Medium: 3 issue(s)

Generated by Auto Claude PR Review

Findings (4 selected of 7 total)

🟠 [HIGH] Non-atomic file writes cause race condition

📁 apps/frontend/src/main/task-log-service.ts:proposed

Python backend uses atomic writes (temp file + rename), but TypeScript writeFileSync() is not atomic and could corrupt files during concurrent access.

Suggested fix:

Use temp file + renameSync() pattern for atomic writes

🟠 [HIGH] Path traversal vulnerability in specId

📁 apps/frontend/src/main/task-log-service.ts:123

specId is used directly in path construction without validation. Malicious specId like '../../etc' could escape project directory.

Suggested fix:

Add specId validation: /^[0-9]{3}-[a-z0-9-]+$/ and reject paths containing '..'

🟠 [HIGH] Missing taskId to specId mapping in TASK_STOP handler

📁 apps/frontend/src/main/ipc-handlers/task/execution-handlers.ts:183

TASK_STOP receives taskId but markActivePhasesStopped needs specId. Handler must call findTaskAndProject() to get the task's specId.

Suggested fix:

Add: const { task } = findTaskAndProject(taskId); then use task.specId

🟠 [HIGH] TaskLogPhaseStatus missing 'stopped' value

📁 apps/frontend/src/shared/types/task.ts:61

Type definition must include 'stopped' for the feature to work. Currently only has: pending, active, completed, failed.

Suggested fix:

Change to: 'pending' | 'active' | 'completed' | 'failed' | 'stopped'

This review was generated by Auto Claude.

@AndyMik90 AndyMik90 added the blocked Waiting on something label Dec 27, 2025
@AlexMadera AlexMadera self-assigned this Dec 29, 2025
JoshuaRileyDev and others added 2 commits December 29, 2025 10:25
Addresses PR review feedback with the following security improvements:

1. **Atomic file writes**: Use temp file + rename pattern to prevent file
   corruption during concurrent access. This ensures writes are atomic and
   matches the pattern used in the Python backend.

2. **Path traversal protection**: Add specId validation to prevent directory
   traversal attacks. Validates format (XXX-name) and rejects paths containing
   '..' or directory separators.

Fixes the two remaining high-priority security issues from PR review.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9c2fea0 and 52d4c36.

📒 Files selected for processing (1)
  • apps/frontend/src/main/task-log-service.ts
🧰 Additional context used
📓 Path-based instructions (2)
apps/frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

apps/frontend/src/**/*.{ts,tsx}: Always use translation keys with useTranslation() for all user-facing text in React/TypeScript frontend components - use format namespace:section.key (e.g., navigation:items.githubPRs)
Never use hardcoded strings in JSX/TSX files for user-facing text - always reference translation keys from apps/frontend/src/shared/i18n/locales/

Files:

  • apps/frontend/src/main/task-log-service.ts
apps/frontend/**/*.{ts,tsx}

⚙️ CodeRabbit configuration file

apps/frontend/**/*.{ts,tsx}: Review React patterns and TypeScript type safety.
Check for proper state management and component composition.

Files:

  • apps/frontend/src/main/task-log-service.ts
🧬 Code graph analysis (1)
apps/frontend/src/main/task-log-service.ts (1)
apps/frontend/src/shared/types/task.ts (2)
  • TaskLogs (87-96)
  • TaskLogPhase (60-60)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: CodeQL (python)
  • GitHub Check: CodeQL (javascript-typescript)
🔇 Additional comments (3)
apps/frontend/src/main/task-log-service.ts (3)

2-2: LGTM! Imports support atomic file operations.

The additional fs imports (writeFileSync, renameSync, unlinkSync) are necessary for the atomic write pattern implemented in the new updateLogFilePhaseStatus method, preventing file corruption during concurrent access.


418-462: Excellent atomic write implementation.

The atomic write pattern (temp file + rename) is well-implemented and addresses the file system race condition concern from previous reviews. Key strengths:

  • Writes to temp file first, then atomically renames to target (lines 447-448)
  • Proper cleanup of temp file on write failure (lines 452-453)
  • Only writes when changes are detected (line 441)
  • Graceful error handling allows task stopping to succeed even if log updates fail

469-478: No changes needed. The regex pattern /^[0-9]{3}-[a-z0-9-]+$/ is correct. All spec IDs in the codebase use lowercase-only format (e.g., 001-test-feature, 002-in-progress, 013-screenshots-on-tasks). No uppercase spec IDs exist anywhere, so the validation is not overly restrictive.

Likely an incorrect or invalid review comment.

Comment on lines +388 to +401
markActivePhasesStopped(specId: string, projectPath: string, specsRelPath: string): void {
// Validate specId to prevent path traversal attacks
if (!this.isValidSpecId(specId)) {
console.error(`[TaskLogService] Invalid specId format: ${specId}`);
return;
}

// Get watched paths for this spec
const watchedInfo = this.watchedPaths.get(specId);

// Build paths for main and worktree spec directories
const mainSpecDir = watchedInfo?.mainSpecDir || path.join(projectPath, specsRelPath, specId);
const worktreeSpecDir = watchedInfo?.worktreeSpecDir || path.join(projectPath, '.worktrees', specId, specsRelPath, specId);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check the full context of the markActivePhasesStopped method and find all callers

echo "=== Looking for markActivePhasesStopped method definition and calls ==="
rg -n 'markActivePhasesStopped' --type=ts

echo -e "\n=== Checking execution-handlers.ts for task stop handlers ==="
rg -n -A 15 -B 3 'TASK_STOP' apps/frontend/src/main/ipc-handlers/task/execution-handlers.ts

Repository: AndyMik90/Auto-Claude

Length of output: 1663


🏁 Script executed:

#!/bin/bash
# Verify the sources of the parameters passed to markActivePhasesStopped

echo "=== Finding findTaskAndProject function definition ==="
rg -n -A 15 'function findTaskAndProject|const findTaskAndProject' --type=ts

echo -e "\n=== Finding getSpecsDir function definition ==="
rg -n -A 10 'function getSpecsDir|const getSpecsDir' --type=ts

echo -e "\n=== Checking if project.path and task.specId are user-controllable ==="
rg -n -B 5 -A 3 'interface.*Project|type.*Project' apps/frontend/src/main/ --type=ts | head -50

Repository: AndyMik90/Auto-Claude

Length of output: 6557


🏁 Script executed:

#!/bin/bash
# Check where projects are created/added and how paths are validated

echo "=== Looking for project creation/import logic ==="
rg -n 'addProject|createProject|importProject|projects\.push' apps/frontend/src/main/ --type=ts | head -20

echo -e "\n=== Checking ProjectStore addProject method ==="
rg -n -A 20 'addProject.*{' apps/frontend/src/main/project-store.ts

echo -e "\n=== Checking if project paths are validated ==="
rg -n -B 5 -A 10 'path.isAbsolute|path.resolve|normalize' apps/frontend/src/main/project-store.ts | head -40

Repository: AndyMik90/Auto-Claude

Length of output: 2562


🏁 Script executed:

#!/bin/bash
# Check the addProject method properly

echo "=== Looking for addProject method implementation ==="
rg -n -A 30 'addProject\(projectPath' apps/frontend/src/main/project-store.ts

echo -e "\n=== Check where project paths come from in IPC handlers ==="
rg -n -B 10 'projectStore.addProject' apps/frontend/src/main/ipc-handlers/project-handlers.ts

echo -e "\n=== Check if paths are validated before being used ==="
rg -n 'existsSync|stat|isDirectory' apps/frontend/src/main/ipc-handlers/project-handlers.ts | head -20

Repository: AndyMik90/Auto-Claude

Length of output: 3060


🏁 Script executed:

#!/bin/bash
# Check how the project store is persisted and loaded

echo "=== Check projectStore save/load mechanism ==="
rg -n -A 15 'save\(' apps/frontend/src/main/project-store.ts | head -30

echo -e "\n=== Check how projects are loaded from storage ==="
rg -n -A 15 'load\(' apps/frontend/src/main/project-store.ts | head -40

echo -e "\n=== Check if there's any editing of project paths after creation ==="
rg -n 'path.*=' apps/frontend/src/main/project-store.ts | grep -v 'projectPath\|basePath\|projectName\|autoBuildPath'

Repository: AndyMik90/Auto-Claude

Length of output: 2102


🏁 Script executed:

#!/bin/bash
# Final verification: check if projectPath or specsRelPath are ever passed through IPC

echo "=== Check all IPC calls to markActivePhasesStopped ==="
rg -n -B 20 'markActivePhasesStopped' apps/frontend/src/main/ --type=ts | grep -A 20 -B 20 'ipcMain'

echo -e "\n=== Verify projectPath source in execution-handlers ==="
rg -n -B 30 'taskLogService.markActivePhasesStopped' apps/frontend/src/main/ipc-handlers/task/execution-handlers.ts | tail -50

echo -e "\n=== Check if any IPC handler takes path parameters ==="
rg -n 'ipcMain\.(on|handle).*projectPath|ipcMain\.(on|handle).*specsRelPath' apps/frontend/src/main/ --type=ts

Repository: AndyMik90/Auto-Claude

Length of output: 4231


🏁 Script executed:

#!/bin/bash
# Check if there are other entry points that could pass arbitrary projectPath/specsRelPath

echo "=== Check all methods that call updateLogFilePhaseStatus ==="
rg -n 'updateLogFilePhaseStatus' apps/frontend/src/main/ --type=ts

echo -e "\n=== Verify getSpecsDir implementation ==="
cat apps/frontend/src/shared/constants/config.ts | grep -A 5 'function getSpecsDir'

echo -e "\n=== Check if there are any other paths to modify project.path or autoBuildPath ==="
rg -n 'project\.path\s*=' apps/frontend/src/main/ --type=ts

Repository: AndyMik90/Auto-Claude

Length of output: 774


🏁 Script executed:

#!/bin/bash
# Final verification: trace complete parameter flow

echo "=== Verify complete parameter source chain ==="
echo "1. TASK_STOP handler receives taskId (UUID)"
echo "2. findTaskAndProject(taskId) is called"
echo "3. Let's check what projectStore actually returns"

rg -n -A 20 'getProjects\(\)|getTasks\(' apps/frontend/src/main/project-store.ts

echo -e "\n=== Check if projectStore data can be modified via IPC ==="
rg -n 'ipcMain.*projectStore' apps/frontend/src/main/ --type=ts

echo -e "\n=== Confirm: are project paths validated when retrieved from store ==="
rg -n -B 5 -A 5 'projects\s*=' apps/frontend/src/main/project-store.ts | head -30

Repository: AndyMik90/Auto-Claude

Length of output: 2403


🏁 Script executed:

#!/bin/bash
# One final check: see if specId itself is properly validated

echo "=== Check isValidSpecId implementation ==="
rg -n -A 10 'isValidSpecId' apps/frontend/src/main/task-log-service.ts

Repository: AndyMik90/Auto-Claude

Length of output: 1074


Consider adding path validation as defense-in-depth, though parameters come from trusted application storage.

While projectPath and specsRelPath are not validated for path traversal, these parameters originate from the application's own persistent storage rather than untrusted user input. They are retrieved from projectStore in the TASK_STOP IPC handler and come from project paths that were already validated with existsSync() during project creation.

However, adding validation for these parameters would still be reasonable as a defense-in-depth measure:

  • Check that normalized paths don't contain .. after being loaded from storage
  • Ensure paths remain within expected project boundaries

The approach in the proposed fix is sound, but the severity is lower than initially indicated since an attacker would need to compromise the application's persistent store file itself, not exploit untrusted IPC input.

🤖 Prompt for AI Agents
In apps/frontend/src/main/task-log-service.ts around lines 388 to 401, add
defense-in-depth validation for projectPath and specsRelPath before using them
to build file system paths: normalize and resolve each input (path.normalize +
path.resolve), reject or bail if the normalized value contains '..' path
segments or if the resolved path is not contained within the expected project
root (compare resolvedSpecPath.startsWith(resolvedProjectRoot + path.sep) or
equivalent), and log an error before returning; keep the existing isValidSpecId
check and use the validated/normalized paths when constructing mainSpecDir and
worktreeSpecDir.

@CLAassistant
Copy link

CLAassistant commented Dec 29, 2025

CLA assistant check
All committers have signed the CLA.


// Validate format: XXX-name (e.g., 001-feature, 123-bug-fix)
const specIdPattern = /^[0-9]{3}-[a-z0-9-]+$/;
return specIdPattern.test(specId);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SpecId validation rejects specs numbered 1000 or higher

The isValidSpecId regex pattern ^[0-9]{3}-[a-z0-9-]+$ requires exactly 3 digits at the start. However, spec numbers are generated using padStart(3, '0') which only pads smaller numbers but doesn't truncate larger ones. When a project has 1000+ specs, specIds like 1000-feature-name would fail validation, causing markActivePhasesStopped to silently return without updating the log files. The regex should use {3,} instead of {3} to allow 3 or more digits.

Fix in Cursor Fix in Web

const logFile = path.join(specDir, 'task_logs.json');
return existsSync(logFile);
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing phase_end event emission for stopped status

The emitNewEntries function emits phase_end stream-chunk events when phases transition to completed or failed, but the newly added stopped status is not included in this condition. When a phase transitions from active to stopped, listeners expecting phase_end events won't receive them, creating inconsistent event behavior. The condition at line 319 needs to include || currPhase.status === 'stopped' to maintain consistency across all terminal phase statuses.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/backend This is backend only blocked Waiting on something bug Something isn't working ❌ MERGE CONFLICTS priority/medium Normal priority

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants