Skip to content

Commit 1fd01b7

Browse files
cpcloudclaude
andauthored
feat(cli): add micasa status command for headless health checks (#930)
## Summary - Add `micasa status [--json] [--days N] [database-path]` command for non-TUI overdue/upcoming item checking - Exit codes: 0 (nothing needs attention), 1 (error), 2 (items need attention) — useful for cron jobs, shell prompts, status bar widgets - Extract duration helpers from `dashboard.go`/`table.go` to `internal/data/duration.go` (DRY) ## Reproduction steps 1. `micasa status` — text output showing overdue maintenance, open incidents, active projects 2. `micasa status --json` — JSON output for scripting 3. `micasa status --days 7` — narrow look-ahead window 4. Check exit code: `micasa status; echo $?` — 0 if clean, 2 if items need attention ## Changes - `cmd/micasa/status.go` — cobra command with text/JSON rendering, `--days`/`--json` flags - `cmd/micasa/status_test.go` — 24 tests covering output formats, exit codes, validation, sort order, error paths - `cmd/micasa/main.go` — `exitError` sentinel type, `extractExitCode`, custom fang error handler, command registration - `internal/data/duration.go` — extracted `DateDiffDays`, `ShortDur`, `DaysText`, `PastDur` - `internal/data/duration_test.go` — duration helper unit tests (100% coverage) - `internal/app/dashboard.go` — delegates to `data.*` helpers - `internal/app/table.go` — delegates `dateDiffDays` to `data.DateDiffDays` - `docs/content/docs/reference/cli.md` — regenerated CLI reference Closes #692 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent d6372a5 commit 1fd01b7

15 files changed

Lines changed: 3597 additions & 53 deletions

File tree

cmd/micasa/main.go

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,30 @@ func newRootCmd() *cobra.Command {
7878
newQueryCmd(),
7979
newGenCLIRefCmd(),
8080
newDBCmd(),
81+
newStatusCmd(),
8182
)
8283

8384
return root
8485
}
8586

87+
// exitError is a sentinel error that carries a process exit code.
88+
// It is not printed to stderr by the error handler.
89+
type exitError struct {
90+
code int
91+
}
92+
93+
func (e exitError) Error() string { return "" }
94+
95+
// extractExitCode returns the exit code from an exitError, or 1 for
96+
// any other error.
97+
func extractExitCode(err error) int {
98+
var ee exitError
99+
if errors.As(err, &ee) {
100+
return ee.code
101+
}
102+
return 1
103+
}
104+
86105
func main() {
87106
root := newRootCmd()
88107
if err := fang.Execute(
@@ -91,11 +110,18 @@ func main() {
91110
fang.WithVersion(versionString()),
92111
fang.WithColorSchemeFunc(wongColorScheme),
93112
fang.WithNotifySignal(os.Interrupt),
113+
fang.WithErrorHandler(func(w io.Writer, _ fang.Styles, err error) {
114+
var ee exitError
115+
if errors.As(err, &ee) {
116+
return
117+
}
118+
_, _ = fmt.Fprintln(w, err)
119+
}),
94120
); err != nil {
95121
if errors.Is(err, tea.ErrInterrupted) {
96122
os.Exit(130)
97123
}
98-
os.Exit(1)
124+
os.Exit(extractExitCode(err))
99125
}
100126
}
101127

0 commit comments

Comments
 (0)