Commit graph

1010 commits

Author SHA1 Message Date
Snider
f1bd36db2e fix(critical): Codex review — 7 high-severity issues resolved
Critical:
- Result.Result() zero args returns receiver instead of panicking

High:
- i18n.SetLanguage: added mutex, forwards to translator
- embed.GetAsset: hold RLock through assets map read (race fix)
- cli.PrintHelp: safe type assertion on Translate result
- task.PerformAsync: guard nil task in reflect.TypeOf
- Service/Command registries initialised in New() (race fix)

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 17:20:08 +00:00
Snider
bc06480b58 fix: AX audit round 7 — Err.Err renamed to Err.Cause
Remaining 32 Rule 1 violations are valid but not P0:
- Subsystem accessors returning typed pointers (fluent API)
- Error creators returning error (should return Result)
- Void fire-and-forget operations (Must, Progress, Log)
- Iterator returning iter.Seq (should use modern Go patterns)

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 16:54:27 +00:00
Snider
2f39e8e1f4 fix: AX audit round 6 — Result returns, naming, literal style
- Data.Get, Drive.Get → Result (was typed pointers)
- I18n.Translator, I18n.Locales → Result
- Translator interface: Translate returns Result
- Array.Filter → Result, Core.Embed → Result
- Embed.BaseDir → BaseDirectory
- TaskState.ID → Identifier, SetTaskIdentifier method fix
- fs.go: Result{nil, true} → Result{OK: true} (5 lines)

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 16:46:39 +00:00
Snider
298322ed89 fix: AX audit round 5 — full naming, Result returns throughout
Renames (via GoLand refactor):
- Option.K → Key, Option.V → Value
- Err.Op → Operation, Err.Msg → Message, Err.Err → Error
- CrashSystem.OS → OperatingSystem, Arch → Architecture
- TaskID → TaskIdentifier, TaskWithID → TaskWithIdentifier
- Ipc → IPC, BaseDir → BaseDirectory
- ServiceRuntime.Opts → Options

Return type changes:
- Options.Get, Config.Get → Result (was (any, bool))
- Embed.ReadDir → Result (was ([]fs.DirEntry, error))
- Translator.Translate, I18n.Translate → Result (was string)

Rule 6:
- data.go: propagate opts.Get failure, typed error for bad fs.FS

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 16:32:43 +00:00
Snider
cf25af1a13 fix: AX audit round 4 — semantic naming, Result returns
- Op → Operation, AllOps → AllOperations (no abbreviations)
- Translator.T → Translator.Translate (avoids testing.T confusion)
- Lock.Mu → Lock.Mutex, ServiceRuntime.Opts → .Options
- ErrorLog.Error/Warn return Result instead of error
- ErrorPanic.Reports returns Result instead of ([]CrashReport, error)
- Core.LogError/LogWarn simplified to passthrough

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 16:00:41 +00:00
Snider
b2d0deb99b fix: AX audit round 3 — 8 violations resolved
- core.go: Result{Value: wrapped} → Result{wrapped, false} (explicit failure)
- error.go: fmt.Sprint → Sprint wrapper, removed fmt import
- fs.go: Stat/Open propagate validatePath failures (return vp)
- lock.go: Startables/Stoppables return Result
- task.go: PerformAsync returns Result
- runtime.go: updated to unwrap Result from Startables/Stoppables

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 15:49:33 +00:00
Snider
8801e2ea10 fix: final AX audit — 9 remaining violations resolved
- fs.go: propagate validatePath failures (return vp) instead of bare Result{}
- app.go: Find() returns Result instead of *App
- log.go: fmt import removed — uses Sprint/Sprintf/Print from string.go/utils.go
- string.go: added Sprint() and Sprintf() wrappers for any-to-string formatting

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 15:43:19 +00:00
Snider
f8e1459bd1 fix: AX audit — eloquent Result literals, renamed abbreviations, error propagation
- Result{x, true} positional literals replace verbose Result{Value: x, OK: true}
- Result{err, false} replaces bare Result{} where errors were swallowed
- ErrCode → ErrorCode, LogPan → LogPanic (no abbreviations)
- NewBuilder()/NewReader() wrappers in string.go, removed strings import from embed.go
- fmt.Errorf in log.go replaced with NewError(fmt.Sprint(...))
- 14 files, 66 audit violations resolved

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 15:36:33 +00:00
Snider
a845866c25 fix: embed.go Result{}.Result() pattern + utils test coverage
- embed.go: replace 27 manual Result{} constructions with Result{}.Result()
  — errors now propagate instead of being silently swallowed
- utils_test.go: add 22 tests for IsFlag, Arg, ArgString, ArgInt, ArgBool,
  and Result.Result() (252 tests, 78.8% coverage)

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 15:25:37 +00:00
Snider
b0ec660e78 fix: fs.go use Result{}.Result() return value, i18n uses i.locale
fs.go: Value receiver Result() returns new Result — must use return
value not discard it. Changed from r.Result(...); return *r to
return Result{}.Result(os.ReadDir(...)).

i18n: SetLanguage sets i.locale directly. Language() reads i.locale.
Translator reload is core/go-i18n's responsibility.

231 tests passing.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 15:13:36 +00:00
Snider
9bcb367dd0 feat: Command() and i18n.SetLanguage() return Result
Command(path, Command{Action: handler}) — typed struct input, Result output.
Command fields exported: Name, Description, Path, Action, Lifecycle, Flags, Hidden.

i18n.SetLanguage returns Result instead of error.

All public methods across core/go now return Result where applicable.

231 tests, 76.5% coverage.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 14:44:29 +00:00
Snider
3bab201229 feat: fs.go returns Result throughout
All 14 public Fs methods return Result instead of (value, error).
validatePath returns Result internally.

Tests updated to use r.OK / r.Value pattern.

231 tests, 77.1% coverage.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 14:37:06 +00:00
Snider
7d34436fc6 feat: Result.Result() — unified get/set, AX pattern
Zero args returns Value. With args, sets Value from Go (value, error).

r.Result()            // get
r.Result(file, err)   // set — OK = err == nil
r.Result(value)       // set — OK = true

One method. Get and set. Same pattern as Service(), Command().

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 14:33:26 +00:00
Snider
9161ed2a79 refactor: Result.New() and Result.Result() — pointer receiver, AX pattern
New() sets Value/OK on the receiver and returns *Result.
Result() returns the Value. Both pointer receivers.

r := &Result{}
r.New(file, err)  // OK = err == nil
val := r.Result()

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 14:32:16 +00:00
Snider
01dec6dbe7 feat: Result.New() — maps Go (value, error) to Result
Result{}.New(file, err)  // OK = err == nil, Value = file
Result{}.New(value)      // OK = true, Value = value
Result{}.New()           // OK = false

Enables: return Result{}.New(s.fsys.Open(path))
Replaces manual if err != nil { return Result{} } blocks.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 14:27:12 +00:00
Snider
2d6415b3aa feat: embed.go and data.go return Result throughout
Mount, MountEmbed, Open, ReadFile, ReadString, Sub, GetAsset,
GetAssetBytes, ScanAssets, GeneratePack, Extract → all return Result.

Data.ReadFile, ReadString, List, ListNames, Extract → Result.
Data.New uses Mount's Result internally.

Internal helpers (WalkDir callback, copyFile) stay error — they're
not public API.

231 tests, 77.4% coverage.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 14:13:47 +00:00
Snider
94f2e54abe feat: IPC, task, lifecycle all return Result
Action, Query, QueryAll, Perform → Result
QueryHandler, TaskHandler → func returning Result
RegisterAction/RegisterActions → handler returns Result
ServiceStartup, ServiceShutdown → Result
LogError, LogWarn → Result
ACTION, QUERY, QUERYALL, PERFORM aliases → Result

Tests updated to match new signatures.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 13:59:45 +00:00
Snider
f5611b1002 refactor: AX audit fixes — no direct strings/fmt, full type names
Direct strings import removed from: data.go, error.go, fs.go
  → uses Split, SplitN, TrimPrefix, TrimSuffix, HasPrefix, Replace, Contains, Join

Direct fmt import removed from: fs.go
  → uses Print() from utils.go

fmt.Errorf in panic recovery → NewError(fmt.Sprint("panic: ", r))

Abbreviated type names renamed:
  ConfigOpts → ConfigOptions
  LogOpts → LogOptions
  RotationLogOpts → RotationLogOptions

embed.go keeps strings import (strings.NewReader, strings.Builder).
error.go keeps fmt import (fmt.Sprint for panic values).

232 tests, 77.8% coverage.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 13:47:23 +00:00
Snider
cb16b63b19 refactor: replace fmt.Sprintf in errors with Join/Concat
All error message string building now uses core string primitives.
Remaining fmt usage: code generation (%q quoting) and log formatting (%v).

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 13:38:53 +00:00
Snider
5d67088080 feat: Service as typed struct, Result without generics
Service is now a proper struct with OnStart/OnStop/OnReload lifecycle
functions — not a registry wrapping any. Packages create Service{} with
typed fields, same pattern as Command and Option.

Result drops generics — Value is any. The struct is the container,
Value is the generic. No more Result[T] ceremony.

Service(name, Service{}) to register, Service(name) to get — both
return Result. ServiceFactory returns Result not (any, error).

NewWithFactories/NewRuntime return Result.

232 tests, 77.8% coverage.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 13:30:22 +00:00
Snider
996853bd53 refactor: Command and Service use Arg() for type-checked extraction
Both registries now use Arg(0, args...) instead of ArgString directly.
Type checking flows through Arg's switch before assertion.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 12:52:19 +00:00
Snider
4cc2e5bf15 refactor: Arg(index, args...) — type-checks then delegates
Arg() detects the type at index and delegates to ArgString/ArgInt/ArgBool.
Index-first, args variadic. Typed extractors validate with ok check.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 12:50:59 +00:00
Snider
0c97415d77 feat: Arg() type-checked extractor — delegates to ArgString/ArgInt/ArgBool
core.Arg(args, 0) returns any with bounds check.
ArgString/ArgInt/ArgBool delegate through Arg() for type detection.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 12:46:52 +00:00
Snider
02d966d184 feat: ArgString helper — safe variadic any→string extraction
core.ArgString(args, 0) replaces args[0].(string) pattern.
Bounds-checked, returns empty string on miss or wrong type.
Used by Command() and Service() registries.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 12:44:57 +00:00
Snider
f1d6c2a174 feat: Join() reclaimed for strings — ErrorJoin for errors
core.Join("/", "deploy", "to", "homelab") → "deploy/to/homelab"
core.Join(".", "cmd", "deploy", "description") → "cmd.deploy.description"

Join builds via Concat — same hook point for security/validation.
errors.Join wrapper renamed to ErrorJoin.
JoinPath now delegates to Join("/", ...).

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 12:42:10 +00:00
Snider
2fab391cc9 feat: Concat() string helper — hook point for validation/security
core.Concat("cmd.", key, ".description") — variadic string builder.
Gives a single point to add sanitisation, injection checks, or
encoding later. command.go I18nKey uses it.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 12:34:38 +00:00
Snider
e12526dca6 feat: string.go — core string primitives, same pattern as array.go
HasPrefix, HasSuffix, TrimPrefix, TrimSuffix, Contains, Split, SplitN,
StringJoin, Replace, Lower, Upper, Trim, RuneCount.

utils.go and command.go now use string.go helpers — zero direct
strings import in either file.

234 tests, 79.8% coverage.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 12:29:15 +00:00
Snider
c8ebf40e78 feat: IsFlag helper — cli.go now has zero string imports
core.IsFlag(arg) checks if an argument starts with a dash.
Cli.go no longer imports strings — all string ops via utils.go helpers.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 12:24:39 +00:00
Snider
c3f457c151 feat: JoinPath helper — joins segments with /
core.JoinPath("deploy", "to", "homelab") → "deploy/to/homelab"
Cli.Run uses it for command path resolution.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 12:23:05 +00:00
Snider
e220b9faab rename: Printl → Print
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 12:20:36 +00:00
Snider
d8ad60ce8a refactor: Printl helper in utils.go — Cli.Print delegates to it
core.Printl(w, format, args...) writes a formatted line to any writer,
defaulting to os.Stdout. Cli.Print() delegates to Printl.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 12:19:11 +00:00
Snider
6687db76f3 refactor: Cli output via Print() — single output path, redirectable
All CLI output goes through Cli.Print() instead of direct fmt calls.
SetOutput() allows redirecting (testing, logging, etc).

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 12:17:30 +00:00
Snider
8854d5c79f feat: utils.go — FilterArgs, ParseFlag with short/long flag rules
- FilterArgs: removes empty strings and Go test runner flags
- ParseFlag: single dash (-v, -🔥) must be 1 char, double dash (--verbose) must be 2+ chars
- Cli.Run() now uses FilterArgs and ParseFlag — no test flag awareness in surface layer
- Invalid flags silently ignored (e.g. -verbose, --v)

221 tests, 79.7% coverage.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 12:15:57 +00:00
Snider
c61a2d3dfe test: 214 tests, 79% coverage — GeneratePack with real files, SetOutput, crash reports
Hit compress/compressFile via GeneratePack with actual asset files on disk.
Added SetOutput log test. Crash report test covers Reports() graceful nil.

Remaining 0%: getAllFiles (group dir scan), appendReport (unexported filePath).
Both are internal plumbing — public API is fully covered.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 12:10:41 +00:00
Snider
afc235796f feat: Command DTO + Cli surface — AX-native CLI primitives
Command is now a DTO with no root/child awareness:
- Path-based registration: c.Command("deploy/to/homelab", handler)
- Description is an i18n key derived from path: cmd.deploy.to.homelab.description
- Lifecycle: Run(), Start(), Stop(), Restart(), Reload(), Signal()
- All return core.Result — errors flow through Core internally
- Parent commands auto-created from path segments

Cli is now a surface layer that reads from Core's command registry:
- Resolves os.Args to command path
- Parses flags into Options (--port=8080 → Option{K:"port", V:"8080"})
- Calls command action with parsed Options
- Banner and help use i18n

Old Clir code preserved in tests/testdata/cli_clir.go.bak for reference.

211 tests, 77.5% coverage.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 12:08:19 +00:00
Snider
b2d07e7883 test: 200 tests, 50.2% coverage — Data, I18n, Fs, Log, Embed, Runtime
New tests: Data List/ListNames/Extract, I18n with mock Translator,
Fs full surface (EnsureDir, IsDir, IsFile, Exists, List, Stat, Open,
Create, Append, ReadStream, WriteStream, Delete, DeleteAll, Rename),
Log all levels + Security + Username + Default + LogErr + LogPan,
Embed ScanAssets + GeneratePack + MountEmbed, Runtime ServiceName,
Core LogError/LogWarn/Must helpers.

Fixes: NewCommand inits flagset, New() wires Cli root command + app.

Remaining 0% (excluding CLI/App): compress, getAllFiles (internal),
Reports/appendReport (needs ErrorPanic filePath), SetOutput (trivial).

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 10:49:33 +00:00
Snider
1ca010e1fb test: rewrite test suite for AX primitives API
164 tests, 41.3% coverage. Tests written against the public API only
(external test package, no _test.go in pkg/core/).

Covers: New(Options), Data, Drive, Config, Service, Error, IPC,
Fs, Cli, Lock, Array, Log, App, Runtime, Task.

Fixes: NewCommand now inits flagset, New() wires Cli root command.

Old tests removed — they referenced With*, RegisterService, and
other patterns that no longer exist.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 08:42:38 +00:00
Snider
f51c748f49 feat: AX primitives — Option/Options/Result, Data, Drive, full names
Core primitives:
- Option{K, V} atom, Options []Option universal input, Result[T] universal return
- Replaces With* functional options, Must*, For[T] patterns
- New(Options) returns *Core (no error — Core handles internally)

New subsystems:
- Data: embedded content mount registry (packages mount assets)
- Drive: transport handle registry stub (API, MCP, SSH, VPN)

Renames (AX principle — predictable names):
- ErrPan → ErrorPanic, ErrLog → ErrorLog, ErrSink → ErrorSink
- srv → service, cfg → config, err → error, emb → legacy accessor
- ErrorOptions/ErrorPanicOptions/NewErrorLog/NewErrorPanic removed
- Contract/ConfigService removed (unused)

RFC-025: Agent Experience updated to match implementation.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-20 08:22:30 +00:00
Snider
7c7a257c19 fix: clone Meta per crash report + sync Reports reads with crashMu
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-18 13:33:55 +00:00
Snider
4fa90a8294 fix: guard ErrLog against nil Log — falls back to defaultLog
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-18 13:28:01 +00:00
Snider
ead9ea00e5 fix: resolve CodeRabbit findings — init ordering, crash safety, lock order
- log.go: remove atomic.Pointer — defaultLog init was nil (var runs before init())
- error.go: Reports(n) validates n<=0, appendReport creates parent dir
- contract.go: WithServiceLock is order-independent (LockApply after all opts)

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-18 13:20:30 +00:00
Snider
2406e81c20 fix(critical): RegisterAction infinite recursion + restore missing methods
- core.go: removed self-calling RegisterAction/RegisterActions aliases (stack overflow)
- task.go: restored RegisterAction/RegisterActions implementations
- contract.go: removed WithIO/WithMount (intentional simplification)

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-18 11:05:29 +00:00
Snider
c2227fbb33 feat: complete DTO pattern — struct literals, no constructors
- All New* constructors removed (NewApp, NewIO, NewCoreCli, NewBus, NewService, NewCoreI18n, NewConfig)
- New() uses pure struct literals: &App{}, &Fs{}, &Config{ConfigOpts:}, &Cli{opts:}, &Service{}, &Ipc{}, &I18n{}
- Ipc methods moved to func (c *Core) — Ipc is now a DTO
- LockApply only called from WithServiceLock, not on every New()
- Service map lazy-inits on first write
- CliOpts DTO with Version/Name/Description

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-18 10:53:13 +00:00
Snider
173067719e fix: resolve Codex review findings — stale comments, constructor patterns
- config.go: comments updated from Cfg/NewEtc to Config/NewConfig
- service.go: comment updated from NewSrv to NewService
- embed.go: comments updated from Emb to Embed
- command.go: panic strings updated from NewSubFunction to NewChildCommandFunction
- fs.go: error ops updated from local.Delete to core.Delete
- core.go: header updated to reflect actual file contents
- contract.go: thin constructors inlined as struct literals (NewConfig, NewService, NewCoreI18n, NewBus)

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-18 09:37:34 +00:00
Snider
2525d10515 fix: resolve Gemini review findings — race conditions and error handling
- error.go: appendReport now mutex-protected, handles JSON errors, uses 0600 perms
- log.go: keyvals slice copied before mutation to prevent caller data races
- log.go: defaultLog uses atomic.Pointer for thread-safe replacement

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-18 09:20:10 +00:00
Snider
8199727537 feat: restructure Core as unified struct with DTO pattern
Complete architectural overhaul of pkg/core:
- All subsystem types renamed to idiomatic Go (no stutter)
- Core struct: App, Embed, Fs, Config, ErrPan, ErrLog, Cli, Service, Lock, Ipc, I18n
- Exports consolidated in core.go, contracts/options in contract.go
- Service() unified get/register: c.Service(), c.Service("name"), c.Service("name", svc)
- Lock() named mutex map: c.Lock("srv"), c.Lock("ipc")
- Error system: Err/ErrLog/ErrPan + Log/LogErr/LogPan (shared ErrSink interface)
- CoreCommand with optional description (i18n resolves from command path)
- Tests moved to tests/ directory (black-box package core_test)
- Removed: ServiceFor/MustServiceFor, global instance, Display/Workspace/Crypt interfaces
- New files: app.go, fs.go, ipc.go, lock.go, i18n.go, task.go, runtime.go, contract.go

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-18 09:12:29 +00:00
Snider
bcaf1554f8 fix: resolve 3 critical review findings
C1: mnt_extract.go rename bug — source path was mutated before
    reading from fs.FS. Now uses separate sourcePath/targetPath.

C2: cli_command.go os.Stderr = nil — replaced with
    flags.SetOutput(io.Discard). No more global nil stderr.

C3: Cli() returned nil — now initialised in New() with
    NewCliApp("", "", "").

Found by opus code-reviewer agent (final review pass).

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-18 02:40:00 +00:00
Snider
3b3b042509 feat: add c.Cli() — zero-dep CLI framework on Core struct
Absorbs leaanthony/clir (1526 lines, 0 deps) into pkg/core:
  cli.go         — NewCliApp constructor
  cli_app.go     — CliApp struct (commands, flags, run)
  cli_action.go  — CliAction type
  cli_command.go — Command (subcommands, flags, help, run)

Any CoreGO package can declare CLI commands without importing
a CLI package:

  c.Cli().NewSubCommand("health", "Check status").Action(func() error {
      return c.Io().Read("status.json")
  })

Uses stdlib flag package only. Zero external dependencies.
core/cli becomes the rich TUI/polish layer on top.

Based on leaanthony/clir — zero-dep CLI, 0 byte go.sum.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-18 01:43:03 +00:00
Snider
8f2e3d9457 chore: clean up — remove core.go re-export, pkg/mnt, go-io/go-log deps
Removed:
- core.go (top-level re-export layer, no longer needed)
- pkg/mnt/ (absorbed into pkg/core/mnt.go)
- pkg/log/ (absorbed into pkg/core/log.go)
- go-io dependency (absorbed into pkg/core/io.go)
- go-log dependency (absorbed into pkg/core/error.go + log.go)

Remaining: single package pkg/core/ with 14 source files.
Only dependency: testify (test-only).
Production code: zero external dependencies.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-18 01:28:14 +00:00
Snider
16a985ad5c feat: absorb go-log into core — error.go + log.go in pkg/core
Brings go-log's errors and logger directly into the Core package:
  core.E("pkg.Method", "msg", err)     — structured errors
  core.Err{Op, Msg, Err, Code}         — error type
  core.Wrap(err, op, msg)              — error wrapping
  core.NewLogger(opts)                 — structured logger
  core.Info/Warn/Error/Debug(msg, kv)  — logging functions

Removed:
  pkg/core/e.go — was re-exporting from go-log, now source is inline
  pkg/log/ — was re-exporting, no longer needed

Renames to avoid conflicts:
  log.New() → core.NewLogger() (core.New is the DI constructor)
  log.Message() → core.ErrorMessage() (core.Message is the IPC type)

go-log still exists as a separate module for external consumers.
Core framework now has errors + logging built-in. Zero deps.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-18 01:23:02 +00:00