fix(ax): align core-agent CLI bootstrap

Co-Authored-By: Virgil <virgil@lethean.io>
This commit is contained in:
Virgil 2026-03-29 21:02:14 +00:00
parent c77a9b93bc
commit 547f23a6f0
5 changed files with 60 additions and 111 deletions

View file

@ -434,6 +434,7 @@ func (s *PrepSubsystem) gitCmd(ctx context.Context, dir string, args ...string)
## Changelog
- 2026-03-29: cmd/core-agent no longer rewrites `os.Args` before startup. The binary-owned commands now use named handlers, keeping the entrypoint on Core CLI primitives instead of repo-local argument mutation.
- 2026-03-26: WIP — net/http consolidated to transport.go (ONE file). net/url + io/fs eliminated. RFC-025 updated with 3 new quality gates (net/http, net/url, io/fs). 1:1 test + example test coverage. Array[T].Deduplicate replaces custom helpers. Remaining: remove dead `client` field from test literals, brain/provider.go Gin handler.
- 2026-03-25: Quality gates pass. Zero disallowed imports (all 10). encoding/json→Core JSON. path/filepath→Core Path. os→Core Env/Fs. io→Core ReadAll/WriteAll. go-process fully Result-native. ServiceRuntime on all subsystems. 22 named Actions + Task pipeline. ChannelNotifier→IPC. Reference docs synced.
- 2026-03-25: Initial spec — written with full core/go v0.8.0 domain context.

View file

@ -1,31 +1,13 @@
// SPDX-License-Identifier: EUPL-1.2
package main
import (
"os"
"dappco.re/go/core"
)
// applyLogLevel scans os.Args for --quiet/-q/--debug before Core starts.
// Must run before c.Run() so ServiceStartup logs respect the level.
//
// core-agent --quiet version → errors only
// core-agent --debug mcp → full debug output
// core-agent status → default (info)
func applyLogLevel() {
var cleaned []string
cleaned = append(cleaned, os.Args[0])
for _, arg := range os.Args[1:] {
switch arg {
case "--quiet", "-q":
core.SetLevel(core.LevelError)
case "--debug", "-d":
core.SetLevel(core.LevelDebug)
default:
cleaned = append(cleaned, arg)
}
}
os.Args = cleaned
type appCommandSet struct {
core *core.Core
}
// registerAppCommands adds app-level CLI commands (version, check, env).
@ -35,61 +17,69 @@ func applyLogLevel() {
// core-agent check — health check
// core-agent env — environment variables
func registerAppCommands(c *core.Core) {
commands := appCommandSet{core: c}
c.Command("version", core.Command{
Description: "Print version and build info",
Action: func(opts core.Options) core.Result {
core.Print(nil, "core-agent %s", c.App().Version)
core.Print(nil, " go: %s", core.Env("GO"))
core.Print(nil, " os: %s/%s", core.Env("OS"), core.Env("ARCH"))
core.Print(nil, " home: %s", core.Env("DIR_HOME"))
core.Print(nil, " hostname: %s", core.Env("HOSTNAME"))
core.Print(nil, " pid: %s", core.Env("PID"))
core.Print(nil, " channel: %s", updateChannel())
return core.Result{OK: true}
},
Action: commands.version,
})
c.Command("check", core.Command{
Description: "Verify workspace, deps, and config",
Action: func(opts core.Options) core.Result {
fs := c.Fs()
core.Print(nil, "core-agent %s health check", c.App().Version)
core.Print(nil, "")
core.Print(nil, " binary: core-agent")
agentsPath := core.Path("Code", ".core", "agents.yaml")
if fs.IsFile(agentsPath) {
core.Print(nil, " agents: %s (ok)", agentsPath)
} else {
core.Print(nil, " agents: %s (MISSING)", agentsPath)
}
wsRoot := core.Path("Code", ".core", "workspace")
if fs.IsDir(wsRoot) {
entries := core.PathGlob(core.JoinPath(wsRoot, "*"))
core.Print(nil, " workspace: %s (%d entries)", wsRoot, len(entries))
} else {
core.Print(nil, " workspace: %s (MISSING)", wsRoot)
}
core.Print(nil, " services: %d registered", len(c.Services()))
core.Print(nil, " actions: %d registered", len(c.Actions()))
core.Print(nil, " commands: %d registered", len(c.Commands()))
core.Print(nil, " env keys: %d loaded", len(core.EnvKeys()))
core.Print(nil, "")
core.Print(nil, "ok")
return core.Result{OK: true}
},
Action: commands.check,
})
c.Command("env", core.Command{
Description: "Show all core.Env() keys and values",
Action: func(opts core.Options) core.Result {
keys := core.EnvKeys()
for _, k := range keys {
core.Print(nil, " %-15s %s", k, core.Env(k))
}
return core.Result{OK: true}
},
Action: commands.env,
})
}
func (commands appCommandSet) version(_ core.Options) core.Result {
core.Print(nil, "core-agent %s", commands.core.App().Version)
core.Print(nil, " go: %s", core.Env("GO"))
core.Print(nil, " os: %s/%s", core.Env("OS"), core.Env("ARCH"))
core.Print(nil, " home: %s", core.Env("DIR_HOME"))
core.Print(nil, " hostname: %s", core.Env("HOSTNAME"))
core.Print(nil, " pid: %s", core.Env("PID"))
core.Print(nil, " channel: %s", updateChannel())
return core.Result{OK: true}
}
func (commands appCommandSet) check(_ core.Options) core.Result {
fs := commands.core.Fs()
core.Print(nil, "core-agent %s health check", commands.core.App().Version)
core.Print(nil, "")
core.Print(nil, " binary: core-agent")
agentsPath := core.Path("Code", ".core", "agents.yaml")
if fs.IsFile(agentsPath) {
core.Print(nil, " agents: %s (ok)", agentsPath)
} else {
core.Print(nil, " agents: %s (MISSING)", agentsPath)
}
wsRoot := core.Path("Code", ".core", "workspace")
if fs.IsDir(wsRoot) {
entries := core.PathGlob(core.JoinPath(wsRoot, "*"))
core.Print(nil, " workspace: %s (%d entries)", wsRoot, len(entries))
} else {
core.Print(nil, " workspace: %s (MISSING)", wsRoot)
}
core.Print(nil, " services: %d registered", len(commands.core.Services()))
core.Print(nil, " actions: %d registered", len(commands.core.Actions()))
core.Print(nil, " commands: %d registered", len(commands.core.Commands()))
core.Print(nil, " env keys: %d loaded", len(core.EnvKeys()))
core.Print(nil, "")
core.Print(nil, "ok")
return core.Result{OK: true}
}
func (commands appCommandSet) env(_ core.Options) core.Result {
keys := core.EnvKeys()
for _, key := range keys {
core.Print(nil, " %-15s %s", key, core.Env(key))
}
return core.Result{OK: true}
}

View file

@ -3,7 +3,6 @@
package main
import (
"os"
"testing"
"dappco.re/go/core"
@ -19,44 +18,6 @@ func newTestCore(t *testing.T) *core.Core {
return c
}
// --- applyLogLevel ---
func TestCommands_ApplyLogLevel_Good(t *testing.T) {
original := os.Args
defer func() { os.Args = original }()
os.Args = []string{"core-agent", "--quiet", "version"}
applyLogLevel()
assert.Equal(t, []string{"core-agent", "version"}, os.Args)
}
func TestCommands_ApplyLogLevel_Good_Debug(t *testing.T) {
original := os.Args
defer func() { os.Args = original }()
os.Args = []string{"core-agent", "-d", "check"}
applyLogLevel()
assert.Equal(t, []string{"core-agent", "check"}, os.Args)
}
func TestCommands_ApplyLogLevel_Bad_NoFlag(t *testing.T) {
original := os.Args
defer func() { os.Args = original }()
os.Args = []string{"core-agent", "status"}
applyLogLevel()
assert.Equal(t, []string{"core-agent", "status"}, os.Args)
}
func TestCommands_ApplyLogLevel_Ugly_FlagAfterCommand(t *testing.T) {
original := os.Args
defer func() { os.Args = original }()
os.Args = []string{"core-agent", "version", "-q"}
applyLogLevel()
assert.Equal(t, []string{"core-agent", "version"}, os.Args)
}
// --- registerAppCommands ---
func TestCommands_RegisterAppCommands_Good(t *testing.T) {

View file

@ -12,10 +12,6 @@ import (
)
func main() {
// Set log level early — before ServiceStartup to suppress startup noise.
// --quiet/-q reduces to errors only, --debug shows everything.
applyLogLevel()
c := core.New(
core.WithOption("name", "core-agent"),
core.WithService(agentic.ProcessRegister),

View file

@ -434,6 +434,7 @@ func (s *PrepSubsystem) gitCmd(ctx context.Context, dir string, args ...string)
## Changelog
- 2026-03-29: cmd/core-agent no longer rewrites `os.Args` before startup. The binary-owned commands now use named handlers, keeping the entrypoint on Core CLI primitives instead of repo-local argument mutation.
- 2026-03-29: brain/provider.go no longer imports net/http for Gin handlers. Handler responses now use named status constants and shared response helpers. HTTP remains intentionally centralised in pkg/agentic/transport.go.
- 2026-03-26: WIP — net/http consolidated to transport.go (ONE file). net/url + io/fs eliminated. RFC-025 updated with 3 new quality gates (net/http, net/url, io/fs). 1:1 test + example test coverage. Array[T].Deduplicate replaces custom helpers.
- 2026-03-25: Quality gates pass. Zero disallowed imports (all 10). encoding/json→Core JSON. path/filepath→Core Path. os→Core Env/Fs. io→Core ReadAll/WriteAll. go-process fully Result-native. ServiceRuntime on all subsystems. 22 named Actions + Task pipeline. ChannelNotifier→IPC. Reference docs synced.