2026-01-31 10:27:04 +00:00
|
|
|
package cli
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
2026-01-31 23:04:42 +00:00
|
|
|
"strings"
|
2026-01-31 10:27:04 +00:00
|
|
|
|
|
|
|
|
"github.com/host-uk/core/pkg/i18n"
|
|
|
|
|
)
|
|
|
|
|
|
2026-01-31 22:56:52 +00:00
|
|
|
// Blank prints an empty line.
|
|
|
|
|
func Blank() {
|
|
|
|
|
fmt.Println()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Echo translates a key via i18n.T and prints with newline.
|
|
|
|
|
// No automatic styling - use Success/Error/Warn/Info for styled output.
|
|
|
|
|
func Echo(key string, args ...any) {
|
2026-01-31 10:27:04 +00:00
|
|
|
fmt.Println(i18n.T(key, args...))
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-31 22:56:52 +00:00
|
|
|
// Print outputs formatted text (no newline).
|
|
|
|
|
// Glyph shortcodes like :check: are converted.
|
|
|
|
|
func Print(format string, args ...any) {
|
|
|
|
|
fmt.Print(compileGlyphs(fmt.Sprintf(format, args...)))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Println outputs formatted text with newline.
|
|
|
|
|
// Glyph shortcodes like :check: are converted.
|
|
|
|
|
func Println(format string, args ...any) {
|
|
|
|
|
fmt.Println(compileGlyphs(fmt.Sprintf(format, args...)))
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-31 23:36:43 +00:00
|
|
|
// Text prints arguments like fmt.Println, but handling glyphs.
|
|
|
|
|
func Text(args ...any) {
|
|
|
|
|
fmt.Println(compileGlyphs(fmt.Sprint(args...)))
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-31 22:56:52 +00:00
|
|
|
// Success prints a success message with checkmark (green).
|
|
|
|
|
func Success(msg string) {
|
|
|
|
|
fmt.Println(SuccessStyle.Render(Glyph(":check:") + " " + msg))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Successf prints a formatted success message.
|
|
|
|
|
func Successf(format string, args ...any) {
|
|
|
|
|
Success(fmt.Sprintf(format, args...))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Error prints an error message with cross (red).
|
|
|
|
|
func Error(msg string) {
|
|
|
|
|
fmt.Println(ErrorStyle.Render(Glyph(":cross:") + " " + msg))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Errorf prints a formatted error message.
|
|
|
|
|
func Errorf(format string, args ...any) {
|
|
|
|
|
Error(fmt.Sprintf(format, args...))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Warn prints a warning message with warning symbol (amber).
|
|
|
|
|
func Warn(msg string) {
|
|
|
|
|
fmt.Println(WarningStyle.Render(Glyph(":warn:") + " " + msg))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Warnf prints a formatted warning message.
|
|
|
|
|
func Warnf(format string, args ...any) {
|
|
|
|
|
Warn(fmt.Sprintf(format, args...))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Info prints an info message with info symbol (blue).
|
|
|
|
|
func Info(msg string) {
|
|
|
|
|
fmt.Println(InfoStyle.Render(Glyph(":info:") + " " + msg))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Infof prints a formatted info message.
|
|
|
|
|
func Infof(format string, args ...any) {
|
|
|
|
|
Info(fmt.Sprintf(format, args...))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Dim prints dimmed text.
|
|
|
|
|
func Dim(msg string) {
|
|
|
|
|
fmt.Println(DimStyle.Render(msg))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Progress prints a progress indicator that overwrites the current line.
|
|
|
|
|
// Uses i18n.Progress for gerund form ("Checking...").
|
|
|
|
|
func Progress(verb string, current, total int, item ...string) {
|
|
|
|
|
msg := i18n.Progress(verb)
|
|
|
|
|
if len(item) > 0 && item[0] != "" {
|
|
|
|
|
fmt.Printf("\033[2K\r%s %d/%d %s", DimStyle.Render(msg), current, total, item[0])
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Printf("\033[2K\r%s %d/%d", DimStyle.Render(msg), current, total)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ProgressDone clears the progress line.
|
|
|
|
|
func ProgressDone() {
|
|
|
|
|
fmt.Print("\033[2K\r")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Label prints a "Label: value" line.
|
|
|
|
|
func Label(word, value string) {
|
|
|
|
|
fmt.Printf("%s %s\n", KeyStyle.Render(i18n.Label(word)), value)
|
|
|
|
|
}
|
2026-01-31 10:27:04 +00:00
|
|
|
|
2026-01-31 22:56:52 +00:00
|
|
|
// Scanln reads from stdin.
|
2026-01-31 10:27:04 +00:00
|
|
|
func Scanln(a ...any) (int, error) {
|
|
|
|
|
return fmt.Scanln(a...)
|
2026-01-31 23:04:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Task prints a task header: "[label] message"
|
|
|
|
|
//
|
|
|
|
|
// cli.Task("php", "Running tests...") // [php] Running tests...
|
|
|
|
|
// cli.Task("go", i18n.Progress("build")) // [go] Building...
|
|
|
|
|
func Task(label, message string) {
|
|
|
|
|
fmt.Printf("%s %s\n\n", DimStyle.Render("["+label+"]"), message)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Section prints a section header: "── SECTION ──"
|
|
|
|
|
//
|
|
|
|
|
// cli.Section("audit") // ── AUDIT ──
|
|
|
|
|
func Section(name string) {
|
|
|
|
|
header := "── " + strings.ToUpper(name) + " ──"
|
|
|
|
|
fmt.Println(AccentStyle.Render(header))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Hint prints a labelled hint: "label: message"
|
|
|
|
|
//
|
|
|
|
|
// cli.Hint("install", "composer require vimeo/psalm")
|
|
|
|
|
// cli.Hint("fix", "core php fmt --fix")
|
|
|
|
|
func Hint(label, message string) {
|
|
|
|
|
fmt.Printf(" %s %s\n", DimStyle.Render(label+":"), message)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Severity prints a severity-styled message.
|
|
|
|
|
//
|
|
|
|
|
// cli.Severity("critical", "SQL injection") // red, bold
|
|
|
|
|
// cli.Severity("high", "XSS vulnerability") // orange
|
|
|
|
|
// cli.Severity("medium", "Missing CSRF") // amber
|
|
|
|
|
// cli.Severity("low", "Debug enabled") // gray
|
|
|
|
|
func Severity(level, message string) {
|
|
|
|
|
var style *AnsiStyle
|
|
|
|
|
switch strings.ToLower(level) {
|
|
|
|
|
case "critical":
|
|
|
|
|
style = NewStyle().Bold().Foreground(ColourRed500)
|
|
|
|
|
case "high":
|
|
|
|
|
style = NewStyle().Bold().Foreground(ColourOrange500)
|
|
|
|
|
case "medium":
|
|
|
|
|
style = NewStyle().Foreground(ColourAmber500)
|
|
|
|
|
case "low":
|
|
|
|
|
style = NewStyle().Foreground(ColourGray500)
|
|
|
|
|
default:
|
|
|
|
|
style = DimStyle
|
|
|
|
|
}
|
|
|
|
|
fmt.Printf(" %s %s\n", style.Render("["+level+"]"), message)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Result prints a result line: "✓ message" or "✗ message"
|
|
|
|
|
//
|
|
|
|
|
// cli.Result(passed, "All tests passed")
|
|
|
|
|
// cli.Result(false, "3 tests failed")
|
|
|
|
|
func Result(passed bool, message string) {
|
|
|
|
|
if passed {
|
|
|
|
|
Success(message)
|
|
|
|
|
} else {
|
|
|
|
|
Error(message)
|
|
|
|
|
}
|
feat: git command, build improvements, and go fmt git-aware (#74)
* feat(go): make go fmt git-aware by default
- By default, only check changed Go files (modified, staged, untracked)
- Add --all flag to check all files (previous behaviour)
- Reduces noise when running fmt on large codebases
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(build): minimal output by default, add missing i18n
- Default output now shows single line: "Success Built N artifacts (dir)"
- Add --verbose/-v flag to show full detailed output
- Add all missing i18n translations for build commands
- Errors still show failure reason in minimal mode
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: add root-level `core git` command
- Create pkg/gitcmd with git workflow commands as root menu
- Export command builders from pkg/dev (AddCommitCommand, etc.)
- Commands available under both `core git` and `core dev` for compatibility
- Git commands: health, commit, push, pull, work, sync, apply
- GitHub orchestration stays in dev: issues, reviews, ci, impact
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat(qa): add docblock coverage checking
Implement docblock/docstring coverage analysis for Go code:
- New `core qa docblock` command to check coverage
- Shows compact file:line list when under threshold
- Integrate with `core go qa` as a default check
- Add --docblock-threshold flag (default 80%)
The checker uses Go AST parsing to find exported symbols
(functions, types, consts, vars) without documentation.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address CodeRabbit review feedback
- Fix doc comment: "status" → "health" in gitcmd package
- Implement --check flag for `core go fmt` (exits non-zero if files need formatting)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* docs: add docstrings for 100% coverage
Add documentation comments to all exported symbols:
- pkg/build: ProjectType constants
- pkg/cli: LogLevel, RenderStyle, TableStyle
- pkg/framework: ServiceFor, MustServiceFor, Core.Core
- pkg/git: GitError.Error, GitError.Unwrap
- pkg/i18n: Handler Match/Handle methods
- pkg/log: Level constants
- pkg/mcp: Tool input/output types
- pkg/php: Service constants, QA types, service methods
- pkg/process: ServiceError.Error
- pkg/repos: RepoType constants
- pkg/setup: ChangeType, ChangeCategory constants
- pkg/workspace: AddWorkspaceCommands
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore: standardize line endings to LF
Add .gitattributes to enforce LF line endings for all text files.
Normalize all existing files to use Unix-style line endings.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address CodeRabbit review feedback
- cmd_format.go: validate --check/--fix mutual exclusivity, capture stderr
- cmd_docblock.go: return error instead of os.Exit(1) for proper error handling
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: address CodeRabbit review feedback (round 2)
- linuxkit.go: propagate state update errors, handle cmd.Wait() errors in waitForExit
- mcp.go: guard against empty old_string in editDiff to prevent runaway edits
- cmd_docblock.go: log parse errors instead of silently skipping
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 10:48:44 +00:00
|
|
|
}
|