Skip to content

Conversation

@galligan
Copy link
Contributor

@galligan galligan commented Jan 23, 2026

Summary

Adds foundation module stubs for the daemon package:

  • errors.ts - DaemonError taxonomy (ALREADY_RUNNING, NOT_RUNNING, PID_ERROR, etc.)
  • platform.ts - Platform detection and path utilities
  • locking.ts - PID-based daemon locking with stale lock detection

Test plan

  • Stubs compile without errors
  • Types are exported correctly
  • Foundation for TDD RED phase (tests branch)

🤖 Generated with Claude Code

Contributes to #56

This was referenced Jan 23, 2026
Copy link
Contributor Author

galligan commented Jan 23, 2026

Warning

This pull request is not mergeable via GitHub because a downstack PR is open. Once all requirements are satisfied, merge this PR as a stack on Graphite.
Learn more

This stack of pull requests is managed by Graphite. Learn more about stacking.

@greptile-apps
Copy link

greptile-apps bot commented Jan 23, 2026

Greptile Summary

  • Scaffolds foundation modules for the daemon package including error taxonomy, platform detection utilities, and PID-based locking mechanisms
  • Establishes public API surface through comprehensive exports in packages/daemon/src/index.ts with organized section headers and clear documentation
  • Creates cross-platform abstractions for daemon file paths with XDG compliance and support for both Unix domain sockets and Windows named pipes

Important Files Changed

Filename Overview
packages/daemon/src/locking.ts New PID-based locking implementation with critical bugs in process liveness detection and lock file cleanup
packages/daemon/src/errors.ts New comprehensive error taxonomy using TaggedError pattern for daemon operations
packages/daemon/src/platform.ts New cross-platform path utilities with XDG compliance for daemon file locations

Confidence score: 2/5

  • This PR has significant implementation issues that could cause daemon malfunction in production
  • Score lowered due to incorrect process liveness detection logic treating permission errors as "process doesn't exist" and improper lock cleanup that clears files instead of unlinking them
  • Pay close attention to packages/daemon/src/locking.ts which needs fixes for isProcessAlive exception handling and releaseDaemonLock file cleanup logic

Sequence Diagram

sequenceDiagram
    participant User
    participant Platform as "Platform Module"
    participant Locking as "Locking Module" 
    participant FileSystem as "File System"
    participant Process as "Process"

    User->>Platform: "getDaemonDir(toolName)"
    Platform->>Platform: "getRuntimeDir()"
    Platform-->>User: "daemonDir"

    User->>Platform: "getLockPath(toolName)"
    Platform-->>User: "lockPath"

    User->>Locking: "acquireDaemonLock(lockPath)"
    Locking->>FileSystem: "check if lock file exists"
    FileSystem-->>Locking: "file status"

    alt Lock file exists
        Locking->>FileSystem: "read PID from lock file"
        FileSystem-->>Locking: "existingPid"
        Locking->>Process: "isProcessAlive(existingPid)"
        Process-->>Locking: "process status"
        
        alt Process is alive
            Locking-->>User: "LockError (daemon already running)"
        else Process is dead
            Locking->>FileSystem: "write current PID to lock file"
            FileSystem-->>Locking: "write success"
            Locking-->>User: "LockHandle"
        end
    else Lock file doesn't exist
        Locking->>FileSystem: "write current PID to lock file"
        FileSystem-->>Locking: "write success"
        Locking-->>User: "LockHandle"
    end

    User->>User: "run daemon operations"

    User->>Locking: "releaseDaemonLock(handle)"
    Locking->>FileSystem: "verify PID matches in lock file"
    FileSystem-->>Locking: "PID verification"
    Locking->>FileSystem: "clear lock file"
    FileSystem-->>Locking: "clear success"
    Locking-->>User: "lock released"
Loading

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

4 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

Comment on lines 57 to 61
} catch {
// ESRCH = no such process, EPERM = exists but no permission
// Both mean process exists or doesn't - EPERM means it exists
return false;
}
Copy link

Choose a reason for hiding this comment

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

logic: Logic error: EPERM means process exists but no permission to signal it, so should return true, not false

Suggested change
} catch {
// ESRCH = no such process, EPERM = exists but no permission
// Both mean process exists or doesn't - EPERM means it exists
return false;
}
} catch (error) {
// ESRCH = no such process, EPERM = exists but no permission
// EPERM means process exists but we lack permission - still alive
if (error instanceof Error && 'code' in error && error.code === 'EPERM') {
return true;
}
return false;
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/daemon/src/locking.ts
Line: 57:61

Comment:
**logic:** Logic error: EPERM means process exists but no permission to signal it, so should return true, not false

```suggestion
	} catch (error) {
		// ESRCH = no such process, EPERM = exists but no permission
		// EPERM means process exists but we lack permission - still alive
		if (error instanceof Error && 'code' in error && error.code === 'EPERM') {
			return true;
		}
		return false;
	}
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 214 to 216
await Bun.write(lockPath, ""); // Clear file
// Note: Proper implementation would use unlink
// For now, clearing is a stub behavior
Copy link

Choose a reason for hiding this comment

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

logic: Critical issue: clearing file content doesn't release lock properly - other processes will see empty file as invalid PID and may acquire false locks

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/daemon/src/locking.ts
Line: 214:216

Comment:
**logic:** Critical issue: clearing file content doesn't release lock properly - other processes will see empty file as invalid PID and may acquire false locks

How can I resolve this? If you propose a fix, please make it concise.

/**
* Get the directory containing daemon files for a tool.
*
* Creates the directory if it doesn't exist (on Unix platforms).
Copy link

Choose a reason for hiding this comment

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

logic: Comment states 'Creates the directory if it doesn't exist' but the function doesn't actually create directories. Either remove this claim from the comment or implement directory creation.

Suggested change
* Creates the directory if it doesn't exist (on Unix platforms).
* Get the directory containing daemon files for a tool.
*
* @param toolName - Name of the tool (e.g., "waymark", "firewatch")
* @returns Absolute path to the daemon directory

Should this function actually create the directory, or should the comment be corrected to reflect that it only returns the path?

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/daemon/src/platform.ts
Line: 143:143

Comment:
**logic:** Comment states 'Creates the directory if it doesn't exist' but the function doesn't actually create directories. Either remove this claim from the comment or implement directory creation.

```suggestion
 * Get the directory containing daemon files for a tool.
 *
 * @param toolName - Name of the tool (e.g., "waymark", "firewatch")
 * @returns Absolute path to the daemon directory
```

 Should this function actually create the directory, or should the comment be corrected to reflect that it only returns the path?

How can I resolve this? If you propose a fix, please make it concise.

@galligan galligan changed the base branch from p3-24/outfitter/doctor-cmd to graphite-base/87 January 23, 2026 22:09
@galligan galligan changed the base branch from graphite-base/87 to p3-24/outfitter/doctor-cmd January 23, 2026 22:10
@galligan
Copy link
Contributor Author

Restacked this branch with the updated downstack; re-submitted after tests. No additional code changes beyond the rebase.

@galligan galligan changed the base branch from p3-24/outfitter/doctor-cmd to graphite-base/87 January 23, 2026 22:57
@galligan galligan changed the base branch from graphite-base/87 to p3-24/outfitter/doctor-cmd January 23, 2026 23:00
@galligan
Copy link
Contributor Author

Addressed review items: isProcessAlive now treats EPERM as alive, releaseDaemonLock unlinks the lock file, and clarified getDaemonDir docs (keeps no side effects).

@galligan galligan force-pushed the p3-24/outfitter/doctor-cmd branch from 8d26b54 to aed02b9 Compare January 23, 2026 23:09
@galligan
Copy link
Contributor Author

Restacked after downstack update (formatRelative test stabilization); no additional changes in this PR.

@galligan galligan changed the base branch from p3-24/outfitter/doctor-cmd to graphite-base/87 January 24, 2026 03:15
@galligan galligan changed the base branch from graphite-base/87 to p3-24/outfitter/doctor-cmd January 24, 2026 03:17
@galligan
Copy link
Contributor Author

Greptile notes checked: EPERM now treated as alive, lock release unlinks instead of clearing, and daemon dir docstring reflects behavior. Restacked and resubmitted.

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants