-
Notifications
You must be signed in to change notification settings - Fork 0
feat(daemon): add errors, platform, and locking module stubs #87
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: p3-24/outfitter/doctor-cmd
Are you sure you want to change the base?
Conversation
a0a54d6 to
e067804
Compare
6150ed0 to
6a060dd
Compare
Greptile Summary
|
| 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.tswhich needs fixes forisProcessAliveexception handling andreleaseDaemonLockfile 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"
There was a problem hiding this 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
packages/daemon/src/locking.ts
Outdated
| } catch { | ||
| // ESRCH = no such process, EPERM = exists but no permission | ||
| // Both mean process exists or doesn't - EPERM means it exists | ||
| return false; | ||
| } |
There was a problem hiding this comment.
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
| } 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.
packages/daemon/src/locking.ts
Outdated
| await Bun.write(lockPath, ""); // Clear file | ||
| // Note: Proper implementation would use unlink | ||
| // For now, clearing is a stub behavior |
There was a problem hiding this comment.
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.
packages/daemon/src/platform.ts
Outdated
| /** | ||
| * Get the directory containing daemon files for a tool. | ||
| * | ||
| * Creates the directory if it doesn't exist (on Unix platforms). |
There was a problem hiding this comment.
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.
| * 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.6a060dd to
43ba5e1
Compare
e067804 to
16edd51
Compare
|
Restacked this branch with the updated downstack; re-submitted after tests. No additional code changes beyond the rebase. |
43ba5e1 to
ec39151
Compare
|
Addressed review items: isProcessAlive now treats EPERM as alive, releaseDaemonLock unlinks the lock file, and clarified getDaemonDir docs (keeps no side effects). |
ec39151 to
8c0c488
Compare
8d26b54 to
aed02b9
Compare
|
Restacked after downstack update (formatRelative test stabilization); no additional changes in this PR. |
8c0c488 to
e3558b0
Compare
aed02b9 to
d0959a5
Compare
|
Greptile notes checked: EPERM now treated as alive, lock release unlinks instead of clearing, and daemon dir docstring reflects behavior. Restacked and resubmitted. |

Summary
Adds foundation module stubs for the daemon package:
Test plan
🤖 Generated with Claude Code
Contributes to #56