chore: avance acumulado de sesiones previas (reorg dev/issues + ajustes)
Reorganizacion de dev/issues en subcarpetas (completed/, cpp/, gamedev/, kanban/, trading/, imagegen/, matrix/) y cambios acumulados en cmd/fn/pyrunner, .claude/commands y settings. Trabajo de otro LLM/sesion, commiteado a peticion del usuario para desbloquear el working tree. Excluido logs/ardour_mcp_server.log (ruido).
This commit is contained in:
+50
-34
@@ -18,6 +18,7 @@ type pyParam struct {
|
||||
Default string // empty if required
|
||||
IsKwargs bool // **kwargs
|
||||
IsRegistry bool // type is a registry type (needs factory)
|
||||
KwOnly bool // declared after a bare "*" or "*args" — must be passed by keyword
|
||||
}
|
||||
|
||||
// pyFactory links a registry type to the function that creates it.
|
||||
@@ -45,12 +46,21 @@ func parsePySignature(sig string) []pyParam {
|
||||
// Split by comma, respecting nested brackets
|
||||
parts := splitParams(raw)
|
||||
var params []pyParam
|
||||
kwOnly := false
|
||||
for _, part := range parts {
|
||||
part = strings.TrimSpace(part)
|
||||
if part == "" || part == "self" || part == "cls" {
|
||||
continue
|
||||
}
|
||||
// A bare "*" (PEP 3102) or "*args" var-positional marks the start of
|
||||
// keyword-only params. Neither maps cleanly to positional CLI args, so
|
||||
// skip the marker itself and flag every following param as keyword-only.
|
||||
if part == "*" || (strings.HasPrefix(part, "*") && !strings.HasPrefix(part, "**")) {
|
||||
kwOnly = true
|
||||
continue
|
||||
}
|
||||
p := parseSingleParam(part)
|
||||
p.KwOnly = kwOnly
|
||||
params = append(params, p)
|
||||
}
|
||||
return params
|
||||
@@ -189,11 +199,19 @@ func generatePyRunner(fn *registry.Function, db *registry.DB, registryRoot strin
|
||||
// Classify params
|
||||
var factoryImports []string // import lines for factories
|
||||
var factorySetup []string // code to create factory objects
|
||||
var argLines []string // code to parse CLI args
|
||||
var callArgs []string // arguments to pass to the function
|
||||
var bodyLines []string // code that fills _call_args / _call_kwargs
|
||||
|
||||
cliArgIdx := 0
|
||||
|
||||
// emitCall appends one param to _call_args (positional) or _call_kwargs
|
||||
// (keyword-only). indent prefixes the line (for params read inside an `if`).
|
||||
emitCall := func(p pyParam, indent string) string {
|
||||
if p.KwOnly {
|
||||
return fmt.Sprintf("%s_call_kwargs[%q] = %s", indent, p.Name, p.Name)
|
||||
}
|
||||
return fmt.Sprintf("%s_call_args.append(%s)", indent, p.Name)
|
||||
}
|
||||
|
||||
for _, p := range params {
|
||||
if p.IsKwargs {
|
||||
// Skip **kwargs for now — can't auto-resolve from CLI
|
||||
@@ -235,27 +253,35 @@ func generatePyRunner(fn *registry.Function, db *registry.DB, registryRoot strin
|
||||
fmt.Sprintf("%s = %s(%s)", p.Name, factory.FuncName,
|
||||
strings.Join(factoryArgs, ", ")))
|
||||
|
||||
callArgs = append(callArgs, p.Name)
|
||||
// Factory objects are always present (required).
|
||||
bodyLines = append(bodyLines, emitCall(p, ""))
|
||||
} else {
|
||||
// Primitive type — from CLI args
|
||||
// Primitive type — from CLI args.
|
||||
if p.Default != "" {
|
||||
// Optional param with default
|
||||
argLines = append(argLines,
|
||||
fmt.Sprintf("%s = _args[%d] if len(_args) > %d else %s",
|
||||
p.Name, cliArgIdx, cliArgIdx, convertDefault(p.Type, p.Default)))
|
||||
argLines = append(argLines,
|
||||
convertArg(p.Name, p.Type, true))
|
||||
// Optional: only pass when the CLI arg is present. When absent we
|
||||
// DON'T replicate the signature default (it may reference a module
|
||||
// constant that doesn't exist in this runner) — we simply omit the
|
||||
// argument so the function applies its own native default.
|
||||
bodyLines = append(bodyLines,
|
||||
fmt.Sprintf("if len(_args) > %d:", cliArgIdx))
|
||||
bodyLines = append(bodyLines,
|
||||
fmt.Sprintf(" %s = _args[%d]", p.Name, cliArgIdx))
|
||||
if conv := convertArg(p.Name, p.Type, true); conv != "" {
|
||||
bodyLines = append(bodyLines, " "+conv)
|
||||
}
|
||||
bodyLines = append(bodyLines, emitCall(p, " "))
|
||||
} else {
|
||||
// Required param
|
||||
argLines = append(argLines,
|
||||
// Required param.
|
||||
bodyLines = append(bodyLines,
|
||||
fmt.Sprintf("if len(_args) <= %d: sys.exit('error: missing required arg: %s (%s)')",
|
||||
cliArgIdx, p.Name, p.Type))
|
||||
argLines = append(argLines,
|
||||
bodyLines = append(bodyLines,
|
||||
fmt.Sprintf("%s = _args[%d]", p.Name, cliArgIdx))
|
||||
argLines = append(argLines,
|
||||
convertArg(p.Name, p.Type, false))
|
||||
if conv := convertArg(p.Name, p.Type, false); conv != "" {
|
||||
bodyLines = append(bodyLines, conv)
|
||||
}
|
||||
bodyLines = append(bodyLines, emitCall(p, ""))
|
||||
}
|
||||
callArgs = append(callArgs, p.Name)
|
||||
cliArgIdx++
|
||||
}
|
||||
}
|
||||
@@ -289,18 +315,18 @@ func generatePyRunner(fn *registry.Function, db *registry.DB, registryRoot strin
|
||||
sb.WriteString("\n")
|
||||
}
|
||||
|
||||
// Arg parsing
|
||||
if len(argLines) > 0 {
|
||||
sb.WriteString("# --- parse CLI args ---\n")
|
||||
for _, line := range argLines {
|
||||
sb.WriteString(line + "\n")
|
||||
}
|
||||
sb.WriteString("\n")
|
||||
// Arg parsing — build the positional/keyword argument collections.
|
||||
sb.WriteString("# --- parse CLI args ---\n")
|
||||
sb.WriteString("_call_args = []\n")
|
||||
sb.WriteString("_call_kwargs = {}\n")
|
||||
for _, line := range bodyLines {
|
||||
sb.WriteString(line + "\n")
|
||||
}
|
||||
sb.WriteString("\n")
|
||||
|
||||
// Call
|
||||
sb.WriteString("# --- execute ---\n")
|
||||
sb.WriteString(fmt.Sprintf("_result = %s(%s)\n", fn.Name, strings.Join(callArgs, ", ")))
|
||||
sb.WriteString(fmt.Sprintf("_result = %s(*_call_args, **_call_kwargs)\n", fn.Name))
|
||||
sb.WriteString("\n")
|
||||
|
||||
// Output
|
||||
@@ -365,16 +391,6 @@ func convertArg(name, typ string, _ bool) string {
|
||||
}
|
||||
}
|
||||
|
||||
// convertDefault ensures the default value is valid Python for the given type.
|
||||
func convertDefault(_, def string) string {
|
||||
// Most defaults from the signature are already valid Python
|
||||
// Just handle the None case for Optional types
|
||||
if def == "None" || def == "" {
|
||||
return "None"
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
// pythonList creates a Python list literal from strings: ["a", "b", "c"]
|
||||
func pythonList(items []string) string {
|
||||
quoted := make([]string, len(items))
|
||||
|
||||
Reference in New Issue
Block a user