-
Notifications
You must be signed in to change notification settings - Fork 8
chore: simplify running with different thv binary #1206
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: main
Are you sure you want to change the base?
Conversation
|
@claude can you please do a deep review of this pr |
|
Claude encountered an error —— View job I'll analyze this and get back to you. |
|
@claude can you please do a deep review of this pr |
|
Claude finished @kantord's task —— View job Deep PR ReviewI've completed a thorough review of this PR. Here's my detailed feedback: Tasks
SummaryThis PR adds development-time functionality to switch between different Critical Issues1. Race Condition in Config File Watching (main/src/main.ts:268-283)The file watcher uses a debounce without proper cleanup or state tracking: watch(cfgDir, (eventType, filename) => {
if (filename === cfgBase) {
scheduleToolhiveRestart(eventType, cfgBase)
}
})Issues:
Recommendation: let thvWatcher: fs.FSWatcher | undefined
try {
const cfgPath = getThvConfigPath()
const cfgDir = path.dirname(cfgPath)
const cfgBase = path.basename(cfgPath)
if (existsSync(cfgDir)) {
thvWatcher = watch(cfgDir, (eventType, filename) => {
if (filename === cfgBase && !isRestarting) {
scheduleToolhiveRestart(eventType, cfgBase)
}
})
log.info(`[thv-config] Watching for changes: ${cfgPath}`)
}
} catch (e) {
log.warn('[thv-config] Failed to set up watcher for .thv_bin:', e)
}
// Later, on app quit:
if (thvWatcher) {
thvWatcher.close()
}2. Type Safety Issues in Config Reading (main/src/toolhive-manager.ts:31-34)The code has unnecessary type casting that bypasses TypeScript's type system: const config = readConfig()
const rawMode = (config as { mode?: string }).mode
const mode: 'default' | 'custom' =
rawMode === 'custom' || rawMode === 'global' ? 'custom' : 'default'Issues:
Recommendation: type ThvBinaryMode = 'default' | 'custom'
// In scripts/use-thv.ts, add validation:
function readConfig(): ThvBinaryConfig {
// ... existing code ...
try {
const content = readFileSync(configPath, 'utf-8')
const parsed = JSON.parse(content)
// Normalize legacy 'global' mode to 'custom'
if (parsed.mode === 'global') {
parsed.mode = 'custom'
}
return parsed
} catch {
// ... existing code ...
}
}3. Process Spawning Without Timeout (main/src/toolhive-manager.ts:100-135)The const timer = setTimeout(() => {
child.kill('SIGKILL')
log.warn('thv version timed out')
resolve(null)
}, 3000)Issues:
Recommendation: let resolved = false
const timer = setTimeout(() => {
if (!resolved) {
resolved = true
child.kill('SIGKILL')
log.warn('thv version timed out')
resolve(null)
}
}, 3000)
child.on('close', () => {
if (!resolved) {
resolved = true
clearTimeout(timer)
const version = parseVersion(combined.trim())
if (version) cachedBinaryVersion = version
resolve(version)
}
})High Priority Issues4. Missing Error Handling in Script (scripts/use-thv.ts:42-48)JSON parsing has minimal error handling: try {
const content = readFileSync(configPath, 'utf-8')
return JSON.parse(content)
} catch {
console.warn('⚠️ Failed to parse .thv_bin, using defaults')
return { mode: 'default', customPath: '' }
}Issues:
Recommendation: try {
const content = readFileSync(configPath, 'utf-8')
const parsed = JSON.parse(content)
// Validate structure
if (typeof parsed.mode !== 'string' || typeof parsed.customPath !== 'string') {
console.warn('⚠️ Invalid .thv_bin structure, using defaults')
return { mode: 'default', customPath: '' }
}
return parsed
} catch (error) {
console.warn('⚠️ Failed to read/parse .thv_bin:', error.message)
return { mode: 'default', customPath: '' }
}5. Version Parsing Could Be More Robust (main/src/toolhive-manager.ts:100-106)The regex pattern may not catch all valid version formats: const parseVersion = (text: string): string | null => {
const current = text.match(/Currently running:\s*(v?[^\s]+)/i)?.[1]
if (current) return current
return (
text.match(/\bv\d+\.\d+(?:\.\d+)?(?:-[0-9A-Za-z\-.]+)?\b/)?.[0] ?? null
)
}Issue:
Recommendation: const parseVersion = (text: string): string | null => {
// Try structured format first
const current = text.match(/Currently running:\s*(v?[^\s]+)/i)?.[1]
if (current) return current
// Fallback to semver-like pattern (with optional 'v' prefix)
return (
text.match(/\bv?\d+\.\d+(?:\.\d+)?(?:[-+][0-9A-Za-z\-.]+)?\b/)?.[0] ?? null
)
}Medium Priority Issues6. React Component Could Handle Loading States Better (renderer/src/common/components/thv-binary-mode-banner.tsx:19-32)The component fetches data on mount but has no loading state: useEffect(() => {
Promise.all([
window.electronAPI.getThvBinaryMode(),
window.electronAPI.getToolhiveVersion().catch(() => null),
])
.then(([mode, ver]) => {
setBinaryMode(mode as ThvBinaryMode)
setVersion(typeof ver === 'string' ? ver : null)
})
.catch((error: unknown) => {
console.error('Failed to get thv binary info:', error)
})
}, [])Issues:
Recommendation: const [isLoading, setIsLoading] = useState(true)
useEffect(() => {
Promise.all([
window.electronAPI.getThvBinaryMode(),
window.electronAPI.getToolhiveVersion().catch(() => null),
])
.then(([mode, ver]) => {
setBinaryMode(mode)
setVersion(typeof ver === 'string' ? ver : null)
})
.catch((error: unknown) => {
console.error('Failed to get thv binary info:', error)
})
.finally(() => setIsLoading(false))
}, [])
if (isLoading || !binaryMode || binaryMode.isDefault) {
return null
}7. Inconsistent Naming in Package Scripts (package.json:23-25)The naming convention is inconsistent: "useThv:default": "ts-node ./scripts/use-thv.ts default",
"useThv:custom": "ts-node ./scripts/use-thv.ts custom",
"useThv:show": "ts-node ./scripts/use-thv.ts show"Issue:
Recommendation: "use-thv:default": "ts-node ./scripts/use-thv.ts default",
"use-thv:custom": "ts-node ./scripts/use-thv.ts custom",
"use-thv:show": "ts-node ./scripts/use-thv.ts show"8. Missing Test CoverageNo tests were added for the new functionality. Consider adding:
Low Priority / Style Issues9. Magic Numbers (main/src/main.ts:140)}, 300) // What does 300ms represent?Recommendation: const THV_RESTART_DEBOUNCE_MS = 300
setTimeout(async () => {
// ...
}, THV_RESTART_DEBOUNCE_MS)10. Commit MessagesThe commit history shows placeholder commit messages ( 11. Documentation in README (README.md:97-114)The developer notes section is well-written and clear. Good job! Consider adding:
Positive Observations
Recommendations SummaryBefore merging:
Nice to have: Questions for the Author
View job | Branch: |
|
Hi @claude Thanks! Kept this dev‑only and minimal: .thv_bin is now just a plain path (empty = default), watcher is debounced and cleaned up, and version Anything else you still think is critical? |
|
Claude finished @kantord's task —— View job Review of Updated ChangesTasks
AssessmentGreat work simplifying the implementation! I've reviewed the updated code and here's what I found: ✅ Critical Issues Addressed1. Type Safety & Config Structure - RESOLVED
2. Watcher Cleanup - RESOLVED
3. Process Timeout Logic - RESOLVED
4. Debouncing - IMPROVED
🟡 Minor Observations (Non-Critical)These are fine for dev-only code, but noting them for completeness: 1. Watcher Error Handling 2. Version Parsing 3. Banner Component ✅ Final VerdictNothing critical remains. The implementation is now:
The simplifications you made were smart decisions for a development-time feature. The code is solid for the intended purpose. Answer to Your Question
No, nothing critical. All the major issues from the previous review have been addressed:
The remaining observations are minor polish items that aren't necessary for dev-only functionality. You made good pragmatic choices by keeping this minimal and focused. Ready to merge from a code quality perspective! 🚀 View job | Branch: |
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.
Pull Request Overview
This PR adds a developer-only feature to switch between the embedded thv binary and a custom binary during local development. The app reads configuration from a .thv_bin file, watches for changes to automatically restart the ToolHive process, and displays a warning banner in development mode when using a non-default binary.
Key changes:
- Added CLI script (
scripts/use-thv.ts) for switching between default and customthvbinaries - Implemented file watcher in main process to detect
.thv_binchanges and restart ToolHive - Created warning banner component displayed in development mode when using custom binary
Reviewed Changes
Copilot reviewed 10 out of 11 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| scripts/use-thv.ts | New CLI script for managing thv binary configuration |
| renderer/src/routes/__root.tsx | Added ThvBinaryModeBanner to root component |
| renderer/src/common/components/ui/alert.tsx | Added warning variant to Alert component |
| renderer/src/common/components/thv-binary-mode-banner.tsx | New banner component showing custom binary info |
| preload/src/preload.ts | Exposed new IPC handlers for binary mode and version |
| package.json | Added npm scripts for binary switching commands |
| main/src/toolhive-manager.ts | Implemented binary path resolution and version detection |
| main/src/main.ts | Added file watcher and IPC handlers for binary configuration |
| docs/README.md | Added documentation for custom binary feature |
| README.md | Added developer notes about THV binary selection |
| .gitignore | Added .thv_bin config file to gitignore |
| setPort(toolhivePort) | ||
| }) | ||
| .catch((error: unknown) => { | ||
| console.error('Failed to get custom port info:', error) |
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.
use log instead of console.log
| default: 'bg-card text-card-foreground', | ||
| destructive: | ||
| 'text-destructive bg-card [&>svg]:text-current *:data-[slot=alert-description]:text-destructive/90', | ||
| warning: |
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.
remove warning style from here and instead override in the component itself (because the warning is not an official design)
lets you connect to a custom
thv serveusingTHV_PORT