Skip to content

Commit aaf224f

Browse files
committed
chore: lint
1 parent 36d573a commit aaf224f

File tree

5 files changed

+214
-58
lines changed

5 files changed

+214
-58
lines changed

cmd/auth.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ This is useful when working with multiple organizations or environments.`,
265265
} else {
266266
// Interactive selection using survey
267267
var accountOptions []string
268-
var accountMap = make(map[string]string) // display name -> account key
268+
accountMap := make(map[string]string) // display name -> account key
269269

270270
for accountName, account := range accounts {
271271
displayName := accountName

cmd/phone.go

Lines changed: 68 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -78,14 +78,14 @@ var listPhoneCmd = &cobra.Command{
7878

7979
for _, phoneNumber := range phoneNumbers {
8080
// Extract common fields from the union type
81-
id, number, name, status, assistantId, createdAt := extractPhoneNumberFields(*phoneNumber)
81+
fields := extractPhoneNumberFields(*phoneNumber)
8282

8383
// Show assistant ID in a separate line if it exists
8484
fmt.Printf("%-36s %-16s %-25s %-8s %-20s\n",
85-
id, number, name, status, createdAt)
85+
fields.ID, fields.Number, fields.Name, fields.Status, fields.CreatedAt)
8686

87-
if assistantId != "None" {
88-
fmt.Printf(" └─ Assistant: %s\n", assistantId)
87+
if fields.AssistantID != "None" {
88+
fmt.Printf(" └─ Assistant: %s\n", fields.AssistantID)
8989
}
9090
}
9191

@@ -203,80 +203,107 @@ var deletePhoneCmd = &cobra.Command{
203203
},
204204
}
205205

206+
// PhoneNumberFields represents the common fields of a phone number
207+
type PhoneNumberFields struct {
208+
ID string
209+
Number string
210+
Name string
211+
Status string
212+
AssistantID string
213+
CreatedAt string
214+
}
215+
206216
// extractPhoneNumberFields extracts common fields from the union type phone number
207-
func extractPhoneNumberFields(phoneNumber vapi.PhoneNumbersListResponseItem) (id, number, name, status, assistantId, createdAt string) {
217+
func extractPhoneNumberFields(phoneNumber vapi.PhoneNumbersListResponseItem) PhoneNumberFields {
208218
// Handle VapiPhoneNumber
209219
if vapiPhone := phoneNumber.GetVapiPhoneNumber(); vapiPhone != nil {
210-
id = vapiPhone.GetId()
211-
number = getStringValue(vapiPhone.GetNumber())
212-
name = getStringValue(vapiPhone.GetName())
213-
status = "Unknown"
220+
status := "Unknown"
214221
if vapiPhone.GetStatus() != nil {
215222
status = string(*vapiPhone.GetStatus())
216223
}
217-
assistantId = getStringValue(vapiPhone.GetAssistantId())
218-
createdAt = vapiPhone.GetCreatedAt().Format("2006-01-02 15:04")
219-
return
224+
return PhoneNumberFields{
225+
ID: vapiPhone.GetId(),
226+
Number: getStringValue(vapiPhone.GetNumber()),
227+
Name: getStringValue(vapiPhone.GetName()),
228+
Status: status,
229+
AssistantID: getStringValue(vapiPhone.GetAssistantId()),
230+
CreatedAt: vapiPhone.GetCreatedAt().Format("2006-01-02 15:04"),
231+
}
220232
}
221233

222234
// Handle TwilioPhoneNumber
223235
if twilioPhone := phoneNumber.GetTwilioPhoneNumber(); twilioPhone != nil {
224-
id = twilioPhone.GetId()
225-
number = twilioPhone.GetNumber()
226-
name = getStringValue(twilioPhone.GetName())
227-
status = "Unknown"
236+
status := "Unknown"
228237
if twilioPhone.GetStatus() != nil {
229238
status = string(*twilioPhone.GetStatus())
230239
}
231-
assistantId = getStringValue(twilioPhone.GetAssistantId())
232-
createdAt = twilioPhone.GetCreatedAt().Format("2006-01-02 15:04")
233-
return
240+
return PhoneNumberFields{
241+
ID: twilioPhone.GetId(),
242+
Number: twilioPhone.GetNumber(),
243+
Name: getStringValue(twilioPhone.GetName()),
244+
Status: status,
245+
AssistantID: getStringValue(twilioPhone.GetAssistantId()),
246+
CreatedAt: twilioPhone.GetCreatedAt().Format("2006-01-02 15:04"),
247+
}
234248
}
235249

236250
// Handle VonagePhoneNumber
237251
if vonagePhone := phoneNumber.GetVonagePhoneNumber(); vonagePhone != nil {
238-
id = vonagePhone.GetId()
239-
number = vonagePhone.GetNumber()
240-
name = getStringValue(vonagePhone.GetName())
241-
status = "Unknown"
252+
status := "Unknown"
242253
if vonagePhone.GetStatus() != nil {
243254
status = string(*vonagePhone.GetStatus())
244255
}
245-
assistantId = getStringValue(vonagePhone.GetAssistantId())
246-
createdAt = vonagePhone.GetCreatedAt().Format("2006-01-02 15:04")
247-
return
256+
return PhoneNumberFields{
257+
ID: vonagePhone.GetId(),
258+
Number: vonagePhone.GetNumber(),
259+
Name: getStringValue(vonagePhone.GetName()),
260+
Status: status,
261+
AssistantID: getStringValue(vonagePhone.GetAssistantId()),
262+
CreatedAt: vonagePhone.GetCreatedAt().Format("2006-01-02 15:04"),
263+
}
248264
}
249265

250266
// Handle TelnyxPhoneNumber
251267
if telnyxPhone := phoneNumber.GetTelnyxPhoneNumber(); telnyxPhone != nil {
252-
id = telnyxPhone.GetId()
253-
number = telnyxPhone.GetNumber()
254-
name = getStringValue(telnyxPhone.GetName())
255-
status = "Unknown"
268+
status := "Unknown"
256269
if telnyxPhone.GetStatus() != nil {
257270
status = string(*telnyxPhone.GetStatus())
258271
}
259-
assistantId = getStringValue(telnyxPhone.GetAssistantId())
260-
createdAt = telnyxPhone.GetCreatedAt().Format("2006-01-02 15:04")
261-
return
272+
return PhoneNumberFields{
273+
ID: telnyxPhone.GetId(),
274+
Number: telnyxPhone.GetNumber(),
275+
Name: getStringValue(telnyxPhone.GetName()),
276+
Status: status,
277+
AssistantID: getStringValue(telnyxPhone.GetAssistantId()),
278+
CreatedAt: telnyxPhone.GetCreatedAt().Format("2006-01-02 15:04"),
279+
}
262280
}
263281

264282
// Handle ByoPhoneNumber
265283
if byoPhone := phoneNumber.GetByoPhoneNumber(); byoPhone != nil {
266-
id = byoPhone.GetId()
267-
number = getStringValue(byoPhone.GetNumber())
268-
name = getStringValue(byoPhone.GetName())
269-
status = "Unknown"
284+
status := "Unknown"
270285
if byoPhone.GetStatus() != nil {
271286
status = string(*byoPhone.GetStatus())
272287
}
273-
assistantId = getStringValue(byoPhone.GetAssistantId())
274-
createdAt = byoPhone.GetCreatedAt().Format("2006-01-02 15:04")
275-
return
288+
return PhoneNumberFields{
289+
ID: byoPhone.GetId(),
290+
Number: getStringValue(byoPhone.GetNumber()),
291+
Name: getStringValue(byoPhone.GetName()),
292+
Status: status,
293+
AssistantID: getStringValue(byoPhone.GetAssistantId()),
294+
CreatedAt: byoPhone.GetCreatedAt().Format("2006-01-02 15:04"),
295+
}
276296
}
277297

278298
// Fallback if no phone number type is set
279-
return "Unknown", "Unknown", "Unknown", "Unknown", "Unknown", "Unknown"
299+
return PhoneNumberFields{
300+
ID: "Unknown",
301+
Number: "Unknown",
302+
Name: "Unknown",
303+
Status: "Unknown",
304+
AssistantID: "Unknown",
305+
CreatedAt: "Unknown",
306+
}
280307
}
281308

282309
// getStringValue safely extracts string from pointer or returns fallback

cmd/tool.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ var listToolCmd = &cobra.Command{
8080

8181
for _, tool := range tools {
8282
// Extract common fields from the union type
83-
id, name, toolType, createdAt := extractToolFields(*tool)
83+
id, name, toolType, createdAt := extractToolFields(tool)
8484

8585
fmt.Printf("%-36s %-30s %-20s %-20s\n",
8686
id, name, toolType, createdAt)
@@ -292,7 +292,7 @@ var listToolTypesCmd = &cobra.Command{
292292
}
293293

294294
// extractToolFields extracts common fields from the union type tool
295-
func extractToolFields(tool vapi.ToolsListResponseItem) (id, name, toolType, createdAt string) {
295+
func extractToolFields(tool *vapi.ToolsListResponseItem) (id, name, toolType, createdAt string) {
296296
// Handle FunctionTool
297297
if funcTool := tool.GetFunctionTool(); funcTool != nil {
298298
id = funcTool.GetId()

cmd/update.go

Lines changed: 131 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -302,21 +302,147 @@ func installUpdate(release *GitHubRelease) error {
302302
return fmt.Errorf("binary not found in downloaded archive")
303303
}
304304

305-
// Get current executable path
305+
// Check if we need to migrate to new installation directory
306306
currentPath, err := os.Executable()
307307
if err != nil {
308308
return fmt.Errorf("failed to get current executable path: %w", err)
309309
}
310310

311-
// Replace the current binary
312-
fmt.Println("🔄 Installing update...")
313-
if err := replaceExecutable(binaryPath, currentPath); err != nil {
314-
return fmt.Errorf("failed to replace executable: %w", err)
311+
newInstallDir := getNewInstallDirectory()
312+
newBinaryPath := newInstallDir + "/vapi"
313+
if runtime.GOOS == "windows" {
314+
newBinaryPath += ".exe"
315+
}
316+
317+
// Check if we're migrating from old installation
318+
shouldMigrate := !strings.Contains(currentPath, "/.vapi/") && !strings.Contains(currentPath, "\\.vapi\\")
319+
320+
if shouldMigrate {
321+
fmt.Println("🔄 Migrating to new installation directory...")
322+
if err := migrateInstallation(binaryPath, newBinaryPath, currentPath); err != nil {
323+
return fmt.Errorf("failed to migrate installation: %w", err)
324+
}
325+
} else {
326+
// Normal update in current location
327+
fmt.Println("🔄 Installing update...")
328+
if err := replaceExecutable(binaryPath, currentPath); err != nil {
329+
return fmt.Errorf("failed to replace executable: %w", err)
330+
}
331+
}
332+
333+
return nil
334+
}
335+
336+
// getNewInstallDirectory returns the new standard installation directory
337+
func getNewInstallDirectory() string {
338+
homeDir, err := os.UserHomeDir()
339+
if err != nil {
340+
return os.Getenv("HOME") + "/.vapi/bin"
341+
}
342+
return homeDir + "/.vapi/bin"
343+
}
344+
345+
// migrateInstallation handles migration from old installation paths to new standard path
346+
func migrateInstallation(newBinary, targetPath, oldPath string) error {
347+
// Create new installation directory
348+
targetDir := strings.TrimSuffix(targetPath, "/vapi")
349+
if runtime.GOOS == "windows" {
350+
targetDir = strings.TrimSuffix(targetPath, "\\vapi.exe")
351+
}
352+
353+
if err := os.MkdirAll(targetDir, 0o750); err != nil {
354+
return fmt.Errorf("failed to create installation directory: %w", err)
355+
}
356+
357+
// Copy new binary to target location
358+
if err := replaceExecutable(newBinary, targetPath); err != nil {
359+
return fmt.Errorf("failed to install binary: %w", err)
360+
}
361+
362+
// Clean up old installation if it's in a system directory
363+
if strings.Contains(oldPath, "/usr/local/bin") || strings.Contains(oldPath, "/usr/bin") {
364+
fmt.Printf("⚠️ Note: Old installation remains at %s\n", oldPath)
365+
fmt.Printf(" You may want to remove it manually: sudo rm %s\n", oldPath)
366+
} else if strings.Contains(oldPath, "/.local/bin/") {
367+
// Try to remove old installation from ~/.local/bin
368+
if err := os.Remove(oldPath); err != nil {
369+
fmt.Printf("⚠️ Could not remove old installation at %s: %v\n", oldPath, err)
370+
} else {
371+
fmt.Printf("✅ Removed old installation from %s\n", oldPath)
372+
}
373+
}
374+
375+
// Update PATH in shell configs
376+
fmt.Println("🔄 Updating shell configuration...")
377+
if err := updateShellConfig(targetDir); err != nil {
378+
fmt.Printf("⚠️ Could not automatically update shell config: %v\n", err)
379+
fmt.Printf(" Please add %s to your PATH manually\n", targetDir)
315380
}
316381

382+
fmt.Printf("✅ Migrated installation to %s\n", targetPath)
383+
fmt.Println("🔄 Please restart your terminal to use the new installation path")
384+
317385
return nil
318386
}
319387

388+
// updateShellConfig adds the new installation directory to shell config files
389+
func updateShellConfig(binDir string) error {
390+
homeDir, err := os.UserHomeDir()
391+
if err != nil {
392+
return err
393+
}
394+
395+
// Determine shell and config file
396+
shell := os.Getenv("SHELL")
397+
var configFiles []string
398+
var pathExport string
399+
400+
switch {
401+
case strings.Contains(shell, "fish"):
402+
configFiles = []string{homeDir + "/.config/fish/config.fish"}
403+
pathExport = fmt.Sprintf("set -gx PATH %s $PATH", binDir)
404+
case strings.Contains(shell, "zsh"):
405+
configFiles = []string{homeDir + "/.zshrc"}
406+
pathExport = fmt.Sprintf("export PATH=\"%s:$PATH\"", binDir)
407+
case strings.Contains(shell, "bash"):
408+
configFiles = []string{homeDir + "/.bashrc", homeDir + "/.bash_profile"}
409+
pathExport = fmt.Sprintf("export PATH=\"%s:$PATH\"", binDir)
410+
default:
411+
configFiles = []string{homeDir + "/.profile"}
412+
pathExport = fmt.Sprintf("export PATH=\"%s:$PATH\"", binDir)
413+
}
414+
415+
// Try to add to the first writable config file
416+
for _, configFile := range configFiles {
417+
// Check if PATH entry already exists
418+
// #nosec G304 - configFile is constructed from known safe paths
419+
if content, err := os.ReadFile(configFile); err == nil {
420+
if strings.Contains(string(content), binDir) {
421+
return nil // Already in PATH
422+
}
423+
}
424+
425+
// #nosec G304 - configFile is constructed from known safe paths
426+
if file, err := os.OpenFile(configFile, os.O_APPEND|os.O_WRONLY, 0o600); err == nil {
427+
// Add to config file
428+
if _, err := fmt.Fprintf(file, "\n# vapi\n%s\n", pathExport); err == nil {
429+
// Close file before printing success message
430+
if closeErr := file.Close(); closeErr != nil {
431+
fmt.Printf("Warning: failed to close config file: %v\n", closeErr)
432+
}
433+
fmt.Printf("✅ Added %s to PATH in %s\n", binDir, configFile)
434+
return nil
435+
}
436+
// Close file if write failed
437+
if closeErr := file.Close(); closeErr != nil {
438+
fmt.Printf("Warning: failed to close config file: %v\n", closeErr)
439+
}
440+
}
441+
}
442+
443+
return fmt.Errorf("no writable shell config file found")
444+
}
445+
320446
func getOSName() string {
321447
switch runtime.GOOS {
322448
case "darwin":

pkg/auth/auth.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -434,19 +434,22 @@ func GetStatus() (*AuthStatus, error) {
434434
// 2. If from account, authenticated if active account exists and has valid API key
435435
// 3. If from legacy config, authenticated if API key is not empty
436436
if apiKey != "" {
437-
if apiKeySource == "environment variable" {
437+
switch apiKeySource {
438+
case "environment variable":
438439
status.IsAuthenticated = true
439-
} else if status.TotalAccounts > 0 && status.ActiveAccount != "" {
440-
// Check if active account actually exists and has API key
441-
if activeAccount := cfg.GetActiveAccount(); activeAccount != nil && activeAccount.APIKey != "" {
442-
status.IsAuthenticated = true
440+
case "config file (legacy)": // #nosec G101 - This is not a hardcoded credential but a source description
441+
status.IsAuthenticated = true
442+
default:
443+
// From account - check if active account exists and has API key
444+
if status.TotalAccounts > 0 && status.ActiveAccount != "" {
445+
if activeAccount := cfg.GetActiveAccount(); activeAccount != nil && activeAccount.APIKey != "" {
446+
status.IsAuthenticated = true
447+
} else {
448+
status.IsAuthenticated = false
449+
}
443450
} else {
444451
status.IsAuthenticated = false
445452
}
446-
} else if apiKeySource == "config file (legacy)" {
447-
status.IsAuthenticated = true
448-
} else {
449-
status.IsAuthenticated = false
450453
}
451454
} else {
452455
status.IsAuthenticated = false

0 commit comments

Comments
 (0)