chore: sync from fn-registry agent

This commit is contained in:
fn-registry agent
2026-05-17 02:44:02 +02:00
commit 46b0826a9f
17 changed files with 2090 additions and 0 deletions
+210
View File
@@ -0,0 +1,210 @@
package main
import (
"fmt"
"os"
"path/filepath"
"strings"
)
// Flags holds all parsed CLI flags.
type Flags struct {
JSON bool
Domain string
IssueType string // --type
Status string
Prio string
App string
Pattern string
Risk string
}
func main() {
args := os.Args[1:]
if len(args) == 0 {
printUsage()
os.Exit(0)
}
// Parse global flags and collect remaining args
var noun, verb string
var rest []string
flags := Flags{}
// First arg is noun, second is verb, rest are flags/args
pos := 0
for pos < len(args) {
arg := args[pos]
if strings.HasPrefix(arg, "--") {
flag, val, ok := parseFlag(args, pos)
pos += flag.consumed
if !ok {
fmt.Fprintf(os.Stderr, "unknown flag: %s\n", arg)
os.Exit(1)
}
applyFlag(&flags, flag.name, val)
} else {
// Positional
if noun == "" {
noun = arg
} else if verb == "" {
verb = arg
} else {
rest = append(rest, arg)
}
pos++
}
}
// Dispatch
switch noun {
case "issue":
if verb == "" {
fmt.Fprintln(os.Stderr, "usage: dev_console issue <list|show|status|board>")
os.Exit(1)
}
cmdIssue(append([]string{verb}, rest...), flags)
case "flow":
if verb == "" {
fmt.Fprintln(os.Stderr, "usage: dev_console flow <list|show|status>")
os.Exit(1)
}
cmdFlow(append([]string{verb}, rest...), flags)
case "work":
if verb == "" {
fmt.Fprintln(os.Stderr, "usage: dev_console work <today|dashboard>")
os.Exit(1)
}
cmdWork(append([]string{verb}, rest...), flags)
case "help", "--help", "-h":
printUsage()
os.Exit(0)
default:
fmt.Fprintf(os.Stderr, "unknown command: %s\n", noun)
printUsage()
os.Exit(1)
}
}
type parsedFlag struct {
name string
consumed int
}
func parseFlag(args []string, pos int) (parsedFlag, string, bool) {
arg := args[pos]
// Strip leading --
name := strings.TrimPrefix(arg, "--")
// Check for --key=value form
if idx := strings.Index(name, "="); idx != -1 {
key := name[:idx]
val := name[idx+1:]
return parsedFlag{name: key, consumed: 1}, val, true
}
// Boolean flags (no value)
switch name {
case "json":
return parsedFlag{name: name, consumed: 1}, "true", true
}
// Flags that take a value
switch name {
case "domain", "type", "status", "prio", "app", "pattern", "risk", "epic", "days":
if pos+1 < len(args) && !strings.HasPrefix(args[pos+1], "--") {
return parsedFlag{name: name, consumed: 2}, args[pos+1], true
}
return parsedFlag{name: name, consumed: 1}, "", true
}
return parsedFlag{consumed: 1}, "", false
}
func applyFlag(flags *Flags, name, val string) {
switch name {
case "json":
flags.JSON = true
case "domain":
flags.Domain = val
case "type":
flags.IssueType = val
case "status":
flags.Status = val
case "prio":
flags.Prio = val
case "app":
flags.App = val
case "pattern":
flags.Pattern = val
case "risk":
flags.Risk = val
}
}
func printUsage() {
fmt.Print(`dev_console — CLI unificado para issues + flows del registry
Usage:
dev_console issue list [--domain X] [--type Y] [--status Z] [--prio P] [--json]
dev_console issue show NNNN [--json]
dev_console issue status NNNN [--json]
dev_console issue board [--json]
dev_console flow list [--app X] [--pattern P] [--risk R] [--json]
dev_console flow show NNNN [--json]
dev_console flow status NNNN [--json]
dev_console work today [--json]
dev_console work dashboard
Stubs (v2):
issue dep|roadmap|tag|done|stale|create
flow create|dod|trace|user-test|run|chain|done
work weekly|search
Env:
FN_REGISTRY_ROOT Root of the fn_registry repo (auto-detected if not set)
`)
}
// mustRegistryRoot returns the registry root or exits.
func mustRegistryRoot() string {
root, err := findRegistryRoot()
if err != nil {
fatalf("cannot find registry root: %v\nSet FN_REGISTRY_ROOT env var or run from within fn_registry.", err)
}
return root
}
// findRegistryRoot tries FN_REGISTRY_ROOT, then walks up from cwd looking for registry.db.
func findRegistryRoot() (string, error) {
if r := os.Getenv("FN_REGISTRY_ROOT"); r != "" {
return r, nil
}
cwd, err := os.Getwd()
if err != nil {
return "", err
}
dir := cwd
for {
if _, err := os.Stat(filepath.Join(dir, "registry.db")); err == nil {
return dir, nil
}
parent := filepath.Dir(dir)
if parent == dir {
break
}
dir = parent
}
return "", fmt.Errorf("registry.db not found walking up from %s", cwd)
}
// fatalf prints an error to stderr and exits with code 1.
func fatalf(format string, args ...any) {
fmt.Fprintf(os.Stderr, "error: "+format+"\n", args...)
os.Exit(1)
}