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
|
|
|
// SPDX-License-Identifier: EUPL-1.2
|
|
|
|
|
|
|
|
|
|
// Contracts, options, and type definitions for the Core framework.
|
|
|
|
|
|
|
|
|
|
package core
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
feat: WithService with v0.3.3 name discovery + IPC handler auto-registration
- WithService now calls factory, discovers service name from package path via
reflect/runtime (last path segment, _test suffix stripped, lowercased), and
calls RegisterService — which handles Startable/Stoppable/HandleIPCEvents
- If factory returns nil Value (self-registered), WithService returns OK without
a second registration
- Add contract_test.go with _Good/_Bad tests covering all three code paths
- Fix core.go Cli() accessor: use ServiceFor[*Cli](c, "cli") (was cli.New())
- Fix pre-existing })) → }}) syntax errors in command_test, service_test, lock_test
- Fix pre-existing Options{...} → NewOptions(...) in core_test, data_test,
drive_test, i18n_test (Options is a struct, not a slice)
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-24 20:02:53 +00:00
|
|
|
"reflect"
|
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
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Message is the type for IPC broadcasts (fire-and-forget).
|
|
|
|
|
type Message any
|
|
|
|
|
|
|
|
|
|
// Query is the type for read-only IPC requests.
|
|
|
|
|
type Query any
|
|
|
|
|
|
|
|
|
|
// Task is the type for IPC requests that perform side effects.
|
|
|
|
|
type Task any
|
|
|
|
|
|
2026-03-20 16:46:39 +00:00
|
|
|
// TaskWithIdentifier is an optional interface for tasks that need to know their assigned identifier.
|
|
|
|
|
type TaskWithIdentifier interface {
|
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
|
|
|
Task
|
2026-03-20 16:46:39 +00:00
|
|
|
SetTaskIdentifier(id string)
|
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
|
|
|
GetTaskIdentifier() string
|
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
|
|
|
}
|
|
|
|
|
|
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
|
|
|
// QueryHandler handles Query requests. Returns Result{Value, OK}.
|
|
|
|
|
type QueryHandler func(*Core, Query) Result
|
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
|
|
|
|
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
|
|
|
// TaskHandler handles Task requests. Returns Result{Value, OK}.
|
|
|
|
|
type TaskHandler func(*Core, Task) Result
|
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
|
|
|
|
|
|
|
|
// Startable is implemented by services that need startup initialisation.
|
|
|
|
|
type Startable interface {
|
|
|
|
|
OnStartup(ctx context.Context) error
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Stoppable is implemented by services that need shutdown cleanup.
|
|
|
|
|
type Stoppable interface {
|
|
|
|
|
OnShutdown(ctx context.Context) error
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- Action Messages ---
|
|
|
|
|
|
|
|
|
|
type ActionServiceStartup struct{}
|
|
|
|
|
type ActionServiceShutdown struct{}
|
|
|
|
|
|
|
|
|
|
type ActionTaskStarted struct {
|
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
|
|
|
TaskIdentifier string
|
|
|
|
|
Task Task
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type ActionTaskProgress struct {
|
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
|
|
|
TaskIdentifier string
|
|
|
|
|
Task Task
|
|
|
|
|
Progress float64
|
|
|
|
|
Message string
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type ActionTaskCompleted struct {
|
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
|
|
|
TaskIdentifier string
|
|
|
|
|
Task Task
|
|
|
|
|
Result any
|
|
|
|
|
Error error
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// --- Constructor ---
|
|
|
|
|
|
2026-03-24 16:23:33 +00:00
|
|
|
// CoreOption is a functional option applied during Core construction.
|
|
|
|
|
// Returns Result — if !OK, New() stops and returns the error.
|
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
|
|
|
//
|
2026-03-24 16:23:33 +00:00
|
|
|
// core.New(
|
|
|
|
|
// core.WithService(agentic.Register),
|
|
|
|
|
// core.WithService(monitor.Register),
|
|
|
|
|
// core.WithServiceLock(),
|
|
|
|
|
// )
|
|
|
|
|
type CoreOption func(*Core) Result
|
|
|
|
|
|
|
|
|
|
// New initialises a Core instance by applying options in order.
|
|
|
|
|
// Services registered here form the application conclave — they share
|
|
|
|
|
// IPC access and participate in the lifecycle (ServiceStartup/ServiceShutdown).
|
|
|
|
|
//
|
|
|
|
|
// r := core.New(
|
2026-03-24 20:29:55 +00:00
|
|
|
// core.WithOptions(core.NewOptions(core.Option{Key: "name", Value: "myapp"})),
|
2026-03-24 16:23:33 +00:00
|
|
|
// core.WithService(auth.Register),
|
|
|
|
|
// core.WithServiceLock(),
|
|
|
|
|
// )
|
|
|
|
|
// if !r.OK { log.Fatal(r.Value) }
|
|
|
|
|
// c := r.Value.(*Core)
|
|
|
|
|
func New(opts ...CoreOption) Result {
|
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
|
|
|
c := &Core{
|
2026-03-20 17:20:08 +00:00
|
|
|
app: &App{},
|
|
|
|
|
data: &Data{},
|
|
|
|
|
drive: &Drive{},
|
2026-03-24 20:40:33 +00:00
|
|
|
fs: (&Fs{}).New("/"),
|
|
|
|
|
config: (&Config{}).New(),
|
2026-03-20 17:20:08 +00:00
|
|
|
error: &ErrorPanic{},
|
2026-03-24 20:40:33 +00:00
|
|
|
log: &ErrorLog{},
|
2026-03-20 17:20:08 +00:00
|
|
|
lock: &Lock{},
|
|
|
|
|
ipc: &Ipc{},
|
feat: add core.Env() — read-only system information registry
Env is environment, Config is ours. Provides centralised access to
system facts (OS, ARCH, hostname, user, directories, timestamps)
via string key lookup, populated once at package init.
Keys: OS, ARCH, GO, DS, PS, HOSTNAME, USER, PID, NUM_CPU,
DIR_HOME, DIR_CONFIG, DIR_CACHE, DIR_DATA, DIR_TMP, DIR_CWD,
DIR_DOWNLOADS, DIR_CODE, CORE_START.
17 tests covering all keys + unknown key + Core instance accessor.
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-22 09:08:26 +00:00
|
|
|
info: systemInfo,
|
2026-03-20 17:20:08 +00:00
|
|
|
i18n: &I18n{},
|
|
|
|
|
services: &serviceRegistry{services: make(map[string]*Service)},
|
|
|
|
|
commands: &commandRegistry{commands: make(map[string]*Command)},
|
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
|
|
|
}
|
2026-03-20 18:02:07 +00:00
|
|
|
c.context, c.cancel = context.WithCancel(context.Background())
|
2026-03-24 19:48:12 +00:00
|
|
|
|
|
|
|
|
// Core services
|
|
|
|
|
CliRegister(c)
|
2026-03-24 16:23:33 +00:00
|
|
|
|
|
|
|
|
for _, opt := range opts {
|
|
|
|
|
if r := opt(c); !r.OK {
|
|
|
|
|
return r
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-24 20:09:06 +00:00
|
|
|
// Apply service lock after all opts — v0.3.3 parity
|
|
|
|
|
c.LockApply()
|
|
|
|
|
|
2026-03-24 16:23:33 +00:00
|
|
|
return Result{c, true}
|
|
|
|
|
}
|
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
|
|
|
|
2026-03-24 16:23:33 +00:00
|
|
|
// WithOptions applies key-value configuration to Core.
|
|
|
|
|
//
|
2026-03-24 20:29:55 +00:00
|
|
|
// core.WithOptions(core.NewOptions(core.Option{Key: "name", Value: "myapp"}))
|
2026-03-24 16:23:33 +00:00
|
|
|
func WithOptions(opts Options) CoreOption {
|
|
|
|
|
return func(c *Core) Result {
|
2026-03-24 19:17:12 +00:00
|
|
|
c.options = &opts
|
|
|
|
|
if name := opts.String("name"); name != "" {
|
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
|
|
|
c.app.Name = name
|
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
|
|
|
}
|
2026-03-24 16:23:33 +00:00
|
|
|
return Result{OK: true}
|
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
|
|
|
}
|
2026-03-24 16:23:33 +00:00
|
|
|
}
|
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
|
|
|
|
2026-03-24 16:23:33 +00:00
|
|
|
// WithService registers a service via its factory function.
|
feat: WithService with v0.3.3 name discovery + IPC handler auto-registration
- WithService now calls factory, discovers service name from package path via
reflect/runtime (last path segment, _test suffix stripped, lowercased), and
calls RegisterService — which handles Startable/Stoppable/HandleIPCEvents
- If factory returns nil Value (self-registered), WithService returns OK without
a second registration
- Add contract_test.go with _Good/_Bad tests covering all three code paths
- Fix core.go Cli() accessor: use ServiceFor[*Cli](c, "cli") (was cli.New())
- Fix pre-existing })) → }}) syntax errors in command_test, service_test, lock_test
- Fix pre-existing Options{...} → NewOptions(...) in core_test, data_test,
drive_test, i18n_test (Options is a struct, not a slice)
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-24 20:02:53 +00:00
|
|
|
// If the factory returns a non-nil Value, WithService auto-discovers the
|
|
|
|
|
// service name from the factory's package path (last path segment, lowercase,
|
|
|
|
|
// with any "_test" suffix stripped) and calls RegisterService on the instance.
|
|
|
|
|
// IPC handler auto-registration is handled by RegisterService.
|
|
|
|
|
//
|
|
|
|
|
// If the factory returns nil Value (it registered itself), WithService
|
|
|
|
|
// returns success without a second registration.
|
2026-03-24 16:23:33 +00:00
|
|
|
//
|
|
|
|
|
// core.WithService(agentic.Register)
|
|
|
|
|
// core.WithService(display.Register(nil))
|
|
|
|
|
func WithService(factory func(*Core) Result) CoreOption {
|
|
|
|
|
return func(c *Core) Result {
|
feat: WithService with v0.3.3 name discovery + IPC handler auto-registration
- WithService now calls factory, discovers service name from package path via
reflect/runtime (last path segment, _test suffix stripped, lowercased), and
calls RegisterService — which handles Startable/Stoppable/HandleIPCEvents
- If factory returns nil Value (self-registered), WithService returns OK without
a second registration
- Add contract_test.go with _Good/_Bad tests covering all three code paths
- Fix core.go Cli() accessor: use ServiceFor[*Cli](c, "cli") (was cli.New())
- Fix pre-existing })) → }}) syntax errors in command_test, service_test, lock_test
- Fix pre-existing Options{...} → NewOptions(...) in core_test, data_test,
drive_test, i18n_test (Options is a struct, not a slice)
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-24 20:02:53 +00:00
|
|
|
r := factory(c)
|
|
|
|
|
if !r.OK {
|
|
|
|
|
return r
|
|
|
|
|
}
|
|
|
|
|
if r.Value == nil {
|
|
|
|
|
// Factory self-registered — nothing more to do.
|
|
|
|
|
return Result{OK: true}
|
|
|
|
|
}
|
2026-03-24 20:05:36 +00:00
|
|
|
// Auto-discover the service name from the instance's package path.
|
|
|
|
|
instance := r.Value
|
|
|
|
|
typeOf := reflect.TypeOf(instance)
|
|
|
|
|
if typeOf.Kind() == reflect.Ptr {
|
|
|
|
|
typeOf = typeOf.Elem()
|
|
|
|
|
}
|
|
|
|
|
pkgPath := typeOf.PkgPath()
|
|
|
|
|
parts := Split(pkgPath, "/")
|
|
|
|
|
name := Lower(parts[len(parts)-1])
|
|
|
|
|
if name == "" {
|
|
|
|
|
return Result{E("core.WithService", Sprintf("service name could not be discovered for type %T", instance), nil), false}
|
|
|
|
|
}
|
feat: WithService with v0.3.3 name discovery + IPC handler auto-registration
- WithService now calls factory, discovers service name from package path via
reflect/runtime (last path segment, _test suffix stripped, lowercased), and
calls RegisterService — which handles Startable/Stoppable/HandleIPCEvents
- If factory returns nil Value (self-registered), WithService returns OK without
a second registration
- Add contract_test.go with _Good/_Bad tests covering all three code paths
- Fix core.go Cli() accessor: use ServiceFor[*Cli](c, "cli") (was cli.New())
- Fix pre-existing })) → }}) syntax errors in command_test, service_test, lock_test
- Fix pre-existing Options{...} → NewOptions(...) in core_test, data_test,
drive_test, i18n_test (Options is a struct, not a slice)
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-24 20:02:53 +00:00
|
|
|
|
2026-03-24 20:05:36 +00:00
|
|
|
// IPC handler discovery
|
|
|
|
|
instanceValue := reflect.ValueOf(instance)
|
|
|
|
|
handlerMethod := instanceValue.MethodByName("HandleIPCEvents")
|
|
|
|
|
if handlerMethod.IsValid() {
|
|
|
|
|
if handler, ok := handlerMethod.Interface().(func(*Core, Message) Result); ok {
|
|
|
|
|
c.RegisterAction(handler)
|
|
|
|
|
}
|
|
|
|
|
}
|
feat: WithService with v0.3.3 name discovery + IPC handler auto-registration
- WithService now calls factory, discovers service name from package path via
reflect/runtime (last path segment, _test suffix stripped, lowercased), and
calls RegisterService — which handles Startable/Stoppable/HandleIPCEvents
- If factory returns nil Value (self-registered), WithService returns OK without
a second registration
- Add contract_test.go with _Good/_Bad tests covering all three code paths
- Fix core.go Cli() accessor: use ServiceFor[*Cli](c, "cli") (was cli.New())
- Fix pre-existing })) → }}) syntax errors in command_test, service_test, lock_test
- Fix pre-existing Options{...} → NewOptions(...) in core_test, data_test,
drive_test, i18n_test (Options is a struct, not a slice)
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-24 20:02:53 +00:00
|
|
|
|
2026-03-24 20:05:36 +00:00
|
|
|
return c.RegisterService(name, instance)
|
feat: WithService with v0.3.3 name discovery + IPC handler auto-registration
- WithService now calls factory, discovers service name from package path via
reflect/runtime (last path segment, _test suffix stripped, lowercased), and
calls RegisterService — which handles Startable/Stoppable/HandleIPCEvents
- If factory returns nil Value (self-registered), WithService returns OK without
a second registration
- Add contract_test.go with _Good/_Bad tests covering all three code paths
- Fix core.go Cli() accessor: use ServiceFor[*Cli](c, "cli") (was cli.New())
- Fix pre-existing })) → }}) syntax errors in command_test, service_test, lock_test
- Fix pre-existing Options{...} → NewOptions(...) in core_test, data_test,
drive_test, i18n_test (Options is a struct, not a slice)
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-24 20:02:53 +00:00
|
|
|
}
|
2026-03-24 16:23:33 +00:00
|
|
|
}
|
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
|
|
|
|
2026-03-24 20:06:56 +00:00
|
|
|
// WithName registers a service with an explicit name (no reflect discovery).
|
|
|
|
|
//
|
|
|
|
|
// core.WithName("ws", func(c *Core) Result {
|
|
|
|
|
// return Result{Value: hub, OK: true}
|
|
|
|
|
// })
|
|
|
|
|
func WithName(name string, factory func(*Core) Result) CoreOption {
|
|
|
|
|
return func(c *Core) Result {
|
|
|
|
|
r := factory(c)
|
|
|
|
|
if !r.OK {
|
|
|
|
|
return r
|
|
|
|
|
}
|
|
|
|
|
if r.Value == nil {
|
|
|
|
|
return Result{E("core.WithName", Sprintf("failed to create service %q", name), nil), false}
|
|
|
|
|
}
|
|
|
|
|
return c.RegisterService(name, r.Value)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-24 19:17:12 +00:00
|
|
|
// WithOption is a convenience for setting a single key-value option.
|
|
|
|
|
//
|
|
|
|
|
// core.New(
|
|
|
|
|
// core.WithOption("name", "myapp"),
|
|
|
|
|
// core.WithOption("port", 8080),
|
|
|
|
|
// )
|
|
|
|
|
func WithOption(key string, value any) CoreOption {
|
|
|
|
|
return func(c *Core) Result {
|
|
|
|
|
if c.options == nil {
|
|
|
|
|
opts := NewOptions()
|
|
|
|
|
c.options = &opts
|
|
|
|
|
}
|
|
|
|
|
c.options.Set(key, value)
|
|
|
|
|
if key == "name" {
|
|
|
|
|
if s, ok := value.(string); ok {
|
|
|
|
|
c.app.Name = s
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return Result{OK: true}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-24 16:23:33 +00:00
|
|
|
// WithServiceLock prevents further service registration after construction.
|
|
|
|
|
//
|
|
|
|
|
// core.New(
|
|
|
|
|
// core.WithService(auth.Register),
|
|
|
|
|
// core.WithServiceLock(),
|
|
|
|
|
// )
|
|
|
|
|
func WithServiceLock() CoreOption {
|
|
|
|
|
return func(c *Core) Result {
|
|
|
|
|
c.LockEnable()
|
|
|
|
|
return Result{OK: true}
|
|
|
|
|
}
|
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
|
|
|
}
|