• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

stacklok / toolhive-studio / 21517492961

30 Jan 2026 01:30PM UTC coverage: 55.297% (+2.0%) from 53.322%
21517492961

Pull #1513

github

web-flow
Merge dde9744f8 into 41647b5d0
Pull Request #1513: feat(cli): add CLI alignment flow

2410 of 4590 branches covered (52.51%)

461 of 612 new or added lines in 18 files covered. (75.33%)

2 existing lines in 2 files now uncovered.

3843 of 6718 relevant lines covered (57.2%)

119.57 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

67.14
/main/src/cli/constants.ts
1
/**
2
 * CLI Alignment Constants (THV-0020)
3
 */
4

5
import { homedir } from 'node:os'
2✔
6
import path from 'node:path'
7
import type { Platform } from './types'
8

9
/** Paths checked for package manager installations (Homebrew, Winget, etc.) */
10
export const EXTERNAL_CLI_PATHS: Record<Platform, string[]> = {
2✔
11
  darwin: ['/opt/homebrew/bin/thv', '/usr/local/bin/thv'],
12
  linux: [
13
    '/home/linuxbrew/.linuxbrew/bin/thv',
14
    '/usr/local/bin/thv',
15
    '/usr/bin/thv',
16
  ],
17
  win32: [
18
    path.join(
19
      process.env.ProgramFiles || 'C:\\Program Files',
4✔
20
      'toolhive',
21
      'thv.exe'
22
    ),
23
    path.join(
24
      process.env.LOCALAPPDATA || path.join(homedir(), 'AppData', 'Local'),
4✔
25
      'Programs',
26
      'toolhive',
27
      'thv.exe'
28
    ),
29
  ],
30
}
31

32
export function getDesktopCliPath(
33
  platform: Platform = process.platform as Platform
4✔
34
): string {
35
  const home = homedir()
4✔
36

37
  switch (platform) {
4✔
38
    case 'darwin':
39
    case 'linux':
40
      return path.join(home, '.toolhive', 'bin', 'thv')
2✔
41
    case 'win32':
42
      return path.join(
1✔
43
        process.env.LOCALAPPDATA || path.join(home, 'AppData', 'Local'),
2✔
44
        'ToolHive',
45
        'bin',
46
        'thv.exe'
47
      )
48
    default:
49
      throw new Error(`Unsupported platform: ${platform}`)
1✔
50
  }
51
}
52

53
export function getMarkerFilePath(): string {
54
  return path.join(homedir(), '.toolhive', '.cli-source')
1✔
55
}
56

57
export function getShellRcFiles(): Record<string, string[]> {
58
  const home = homedir()
3✔
59

60
  return {
3✔
61
    bash: [path.join(home, '.bashrc'), path.join(home, '.bash_profile')],
62
    zsh: [path.join(home, '.zshrc')],
63
    fish: [path.join(home, '.config', 'fish', 'config.fish')],
64
  }
65
}
66

67
export const SHELL_PATH_ENTRY = 'export PATH="$HOME/.toolhive/bin:$PATH"'
2✔
68

69
export const SHELL_PATH_MARKERS = {
2✔
70
  start: '# Added by ToolHive Studio - do not modify this block',
71
  end: '# End ToolHive Studio',
72
}
73

74
export const FISH_PATH_ENTRY = 'fish_add_path -g $HOME/.toolhive/bin'
2✔
75

76
export function getCliSourceFromPath(
77
  cliPath: string,
78
  platform: Platform = process.platform as Platform
10✔
79
): 'homebrew' | 'winget' | 'manual' {
80
  const normalizedPath = cliPath.toLowerCase()
10✔
81

82
  if (platform === 'darwin' || platform === 'linux') {
10!
83
    if (
10✔
84
      normalizedPath.includes('/homebrew/') ||
20✔
85
      normalizedPath.includes('/opt/homebrew/') ||
86
      normalizedPath.includes('/linuxbrew/')
87
    ) {
88
      return 'homebrew'
6✔
89
    }
90
  }
91

92
  if (platform === 'win32') {
4!
93
    // Check for WinGet packages directory (e.g., stacklok.thv_Microsoft.Winget.Source_*)
NEW
94
    if (
×
95
      normalizedPath.includes('microsoft\\winget\\packages') ||
×
96
      normalizedPath.includes('microsoft/winget/packages')
97
    ) {
NEW
98
      return 'winget'
×
99
    }
100

101
    // Check for typical winget installation paths
NEW
102
    const programFiles = (process.env.ProgramFiles || '').toLowerCase()
×
NEW
103
    const localAppData = (process.env.LOCALAPPDATA || '').toLowerCase()
×
104

NEW
105
    if (
×
106
      normalizedPath.includes(programFiles) ||
×
107
      normalizedPath.includes(localAppData)
108
    ) {
109
      // Could be winget or manual - default to winget for program files
NEW
110
      if (normalizedPath.includes('programs')) {
×
NEW
111
        return 'winget'
×
112
      }
113
    }
114
  }
115

116
  return 'manual'
4✔
117
}
118

119
export function getUninstallInstructions(
120
  source: 'homebrew' | 'winget' | 'manual'
121
): string {
122
  switch (source) {
3✔
123
    case 'homebrew':
124
      return 'To uninstall, run:\n  brew uninstall toolhive'
1✔
125
    case 'winget':
126
      return 'To uninstall, run:\n  winget uninstall toolhive'
1✔
127
    case 'manual':
128
      return 'Please manually remove the external ToolHive CLI installation.'
1✔
129
  }
130
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc