add Go sidecar and CLI skeleton

cmd/clide/main.go is the single entry; the same binary will later
switch into sidecar-daemon mode via --daemon. internal/cli holds the
dispatch (stdlib flag for now, Cobra arrives with the first real
subcommand in Tier 2). internal/diag mirrors pql's exit-code contract
so the two tools share one mental model for callers. internal/version
exposes the build-info struct that the Makefile's -ldflags -X targets
stamp; Info() is wired to --version so the binary reports both the
declared project.yaml version and the commit it was built from.

The daemon, pty, proc, git, ipc, and pql sub-packages ship as doc.go
stubs naming the subsystem they will own. They keep the layout legible
before the code lands so tier work has a home on arrival.

Module path targets Gitea (git.schweitz.net/jpmschweitzer/clide/sidecar),
matching where the repo lives. Go module resolution works if the host
serves the meta tags; a vanity import path can be added later if
needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-20 22:11:54 +02:00
co-authored by Claude Opus 4.7
parent 4ae53ba16a
commit c39c2df6f5
12 changed files with 208 additions and 0 deletions
+58
View File
@@ -0,0 +1,58 @@
// Package diag defines the exit-code contract and emits structured
// diagnostics to stderr as line-delimited JSON.
//
// Mirrors pql's diag contract so Claude (and any other tool that
// consumes both CLIs) sees a single shape.
package diag
import (
"encoding/json"
"io"
"os"
)
// Exit codes. Same numeric space as pql's.
const (
OK = 0 // success
NoMatch = 2 // success with zero matches / nothing to do
Usage = 64 // EX_USAGE — bad CLI flag or missing subcommand
DataErr = 65 // EX_DATAERR — malformed request
NoInput = 66 // EX_NOINPUT — missing required resource (repo, socket, file)
Unavail = 69 // EX_UNAVAILABLE — sidecar unreachable / subsystem down
Software = 70 // EX_SOFTWARE — internal error
)
type Level string
const (
LevelWarn Level = "warn"
LevelError Level = "error"
)
// Diagnostic is one entry in the stderr JSON-per-line stream.
type Diagnostic struct {
Level Level `json:"level"`
Code string `json:"code"`
Msg string `json:"msg"`
Hint string `json:"hint,omitempty"`
}
// Emit writes a diagnostic as one JSON line to w.
func Emit(w io.Writer, d Diagnostic) {
b, err := json.Marshal(d)
if err != nil {
_, _ = io.WriteString(w, `{"level":"error","code":"diag.marshal","msg":"failed to marshal diagnostic"}`+"\n")
return
}
_, _ = w.Write(append(b, '\n'))
}
// Warn emits a warning diagnostic to stderr.
func Warn(code, msg string) {
Emit(os.Stderr, Diagnostic{Level: LevelWarn, Code: code, Msg: msg})
}
// Error emits an error diagnostic to stderr.
func Error(code, msg, hint string) {
Emit(os.Stderr, Diagnostic{Level: LevelError, Code: code, Msg: msg, Hint: hint})
}