feat: implement core CLI packages and Phase 3 commands
- config: resolve binary dir, load/save .hf-config.json - mode: detect padded-cell vs manual mode via pass_mgr - client: HTTP client wrapper with auth header support - passmgr: pass_mgr integration (get-secret, set, generate) - output: human-readable + JSON output formatting with tables - help: help and help-brief renderer for groups/commands - commands: version, health, config (--url, --acc-mgr-token, show) - auth: token resolution helper (padded-cell auto / manual explicit) - main: command dispatcher with --json global flag support - README: updated with current package layout and status
This commit is contained in:
36
internal/commands/auth.go
Normal file
36
internal/commands/auth.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"git.hangman-lab.top/zhi/HarborForge.Cli/internal/mode"
|
||||
"git.hangman-lab.top/zhi/HarborForge.Cli/internal/output"
|
||||
"git.hangman-lab.top/zhi/HarborForge.Cli/internal/passmgr"
|
||||
)
|
||||
|
||||
// ResolveToken resolves the auth token based on runtime mode.
|
||||
// In padded-cell mode, tokenFlag must be empty (enforced).
|
||||
// In manual mode, tokenFlag is required.
|
||||
func ResolveToken(tokenFlag string) string {
|
||||
if mode.IsPaddedCell() {
|
||||
if tokenFlag != "" {
|
||||
output.Error("padded-cell installed, --token flag disabled, use command directly")
|
||||
}
|
||||
tok, err := passmgr.GetToken()
|
||||
if err != nil {
|
||||
output.Errorf("cannot resolve token: %v", err)
|
||||
}
|
||||
return tok
|
||||
}
|
||||
// manual mode
|
||||
if tokenFlag == "" {
|
||||
output.Error("--token <token> required or execute this with pcexec")
|
||||
}
|
||||
return tokenFlag
|
||||
}
|
||||
|
||||
// RejectTokenInPaddedCell checks if --token was passed in padded-cell mode
|
||||
// and terminates with the standard error message.
|
||||
func RejectTokenInPaddedCell(tokenFlag string) {
|
||||
if mode.IsPaddedCell() && tokenFlag != "" {
|
||||
output.Error("padded-cell installed, --token flag disabled, use command directly")
|
||||
}
|
||||
}
|
||||
53
internal/commands/config.go
Normal file
53
internal/commands/config.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.hangman-lab.top/zhi/HarborForge.Cli/internal/config"
|
||||
"git.hangman-lab.top/zhi/HarborForge.Cli/internal/mode"
|
||||
"git.hangman-lab.top/zhi/HarborForge.Cli/internal/output"
|
||||
"git.hangman-lab.top/zhi/HarborForge.Cli/internal/passmgr"
|
||||
)
|
||||
|
||||
// RunConfigURL sets the base URL in the config file.
|
||||
func RunConfigURL(url string) {
|
||||
if url == "" {
|
||||
output.Error("usage: hf config --url <hf-url>")
|
||||
}
|
||||
if err := config.UpdateURL(url); err != nil {
|
||||
output.Errorf("failed to update config: %v", err)
|
||||
}
|
||||
fmt.Printf("base-url set to %s\n", url)
|
||||
}
|
||||
|
||||
// RunConfigAccMgrToken stores the account-manager token via pass_mgr.
|
||||
func RunConfigAccMgrToken(token string) {
|
||||
if token == "" {
|
||||
output.Error("usage: hf config --acc-mgr-token <token>")
|
||||
}
|
||||
if !mode.IsPaddedCell() {
|
||||
output.Error("--acc-mgr-token can only be set with padded-cell plugin")
|
||||
}
|
||||
if err := passmgr.SetAccountManagerToken(token); err != nil {
|
||||
output.Errorf("failed to store acc-mgr-token: %v", err)
|
||||
}
|
||||
fmt.Println("account-manager token stored successfully")
|
||||
}
|
||||
|
||||
// RunConfigShow displays the current config.
|
||||
func RunConfigShow() {
|
||||
cfg, err := config.Load()
|
||||
if err != nil {
|
||||
output.Errorf("config error: %v", err)
|
||||
}
|
||||
if output.JSONMode {
|
||||
output.PrintJSON(cfg)
|
||||
} else {
|
||||
p, _ := config.ConfigPath()
|
||||
output.PrintKeyValue(
|
||||
"base-url", cfg.BaseURL,
|
||||
"config-file", p,
|
||||
"mode", mode.Detect().String(),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
package commands
|
||||
|
||||
// Package commands will define the hf command tree.
|
||||
32
internal/commands/health.go
Normal file
32
internal/commands/health.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.hangman-lab.top/zhi/HarborForge.Cli/internal/client"
|
||||
"git.hangman-lab.top/zhi/HarborForge.Cli/internal/config"
|
||||
"git.hangman-lab.top/zhi/HarborForge.Cli/internal/output"
|
||||
)
|
||||
|
||||
// RunHealth checks the HarborForge API health endpoint.
|
||||
func RunHealth() {
|
||||
cfg, err := config.Load()
|
||||
if err != nil {
|
||||
output.Errorf("config error: %v", err)
|
||||
}
|
||||
c := client.New(cfg.BaseURL, "")
|
||||
result, err := c.Health()
|
||||
if err != nil {
|
||||
output.Errorf("health check failed: %v", err)
|
||||
}
|
||||
if output.JSONMode {
|
||||
output.PrintJSON(result)
|
||||
} else {
|
||||
status, _ := result["status"].(string)
|
||||
if status == "" {
|
||||
status = "unknown"
|
||||
}
|
||||
fmt.Printf("HarborForge API: %s\n", status)
|
||||
fmt.Printf("URL: %s\n", cfg.BaseURL)
|
||||
}
|
||||
}
|
||||
19
internal/commands/version.go
Normal file
19
internal/commands/version.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"git.hangman-lab.top/zhi/HarborForge.Cli/internal/output"
|
||||
)
|
||||
|
||||
// Version is the CLI version string, set at build time via ldflags.
|
||||
var Version = "dev"
|
||||
|
||||
// RunVersion prints the CLI version.
|
||||
func RunVersion() {
|
||||
if output.JSONMode {
|
||||
output.PrintJSON(map[string]string{"version": Version})
|
||||
} else {
|
||||
fmt.Printf("hf %s\n", Version)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user