6c92f85d10
Bring the Nexus/Praxis/Hexis integration in line with MAVEN_ECOSYSTEM_ARCHITECTURE.md: - Praxis over HTTP: drop the in-process praxis.db open (praxisstore/ praxistools) and call praxisd's /api/v1/tools/* API via a new praxisClient. Honors the "no component reads another's DB" invariant (AC#12). PraxisConfig.DBPath -> URL. - Hexis confirmation gate: mutating capabilities (ReadOnly=false) now park a bound pendingHexis confirmation and require a spoken "да" before executing; read-only run immediately (AC#7, no auto attention->action). - Capability safety: >1 verb match is ambiguous -> ask instead of firing the first; ambiguous Nexus resolution asks for clarification (AC#2). - Correlation IDs on Hexis execute, recorded in the cross-service trace. - Bug: importance arrives as JSON float64 over HTTP, not int. - Tests: confirm-gate, decline, read-only, and ambiguity paths. Build: vendor/ bakes in the hexis client (replace-directed at a sibling repo outside the Docker context); Dockerfile builds from vendor and no longer `go mod download`s the unreachable replace paths. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
108 lines
1.8 KiB
Go
108 lines
1.8 KiB
Go
package strftime
|
|
|
|
import "unicode/utf8"
|
|
|
|
type parser struct {
|
|
format func(spec, flag byte) error
|
|
literal func(byte) error
|
|
}
|
|
|
|
func (p *parser) parse(fmt string) error {
|
|
const (
|
|
initial = iota
|
|
percent
|
|
flagged
|
|
modified
|
|
)
|
|
|
|
var flag, modifier byte
|
|
var err error
|
|
state := initial
|
|
start := 0
|
|
for i, b := range []byte(fmt) {
|
|
switch state {
|
|
default:
|
|
if b == '%' {
|
|
state = percent
|
|
start = i
|
|
continue
|
|
}
|
|
err = p.literal(b)
|
|
|
|
case percent:
|
|
if b == '-' || b == ':' {
|
|
state = flagged
|
|
flag = b
|
|
continue
|
|
}
|
|
if b == 'E' || b == 'O' {
|
|
state = modified
|
|
modifier = b
|
|
flag = 0
|
|
continue
|
|
}
|
|
err = p.format(b, 0)
|
|
state = initial
|
|
|
|
case flagged:
|
|
if b == 'E' || b == 'O' {
|
|
state = modified
|
|
modifier = b
|
|
continue
|
|
}
|
|
err = p.format(b, flag)
|
|
state = initial
|
|
|
|
case modified:
|
|
if okModifier(modifier, b) {
|
|
err = p.format(b, flag)
|
|
} else {
|
|
err = p.literals(fmt[start : i+1])
|
|
}
|
|
state = initial
|
|
}
|
|
|
|
if err != nil {
|
|
if err, ok := err.(formatError); ok {
|
|
err.setDirective(fmt, start, i)
|
|
return err
|
|
}
|
|
return err
|
|
}
|
|
}
|
|
|
|
if state != initial {
|
|
return p.literals(fmt[start:])
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (p *parser) literals(literal string) error {
|
|
for _, b := range []byte(literal) {
|
|
if err := p.literal(b); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
type literalErr string
|
|
|
|
func (e literalErr) Error() string {
|
|
return "strftime: unsupported literal: " + string(e)
|
|
}
|
|
|
|
type formatError struct {
|
|
message string
|
|
directive string
|
|
}
|
|
|
|
func (e formatError) Error() string {
|
|
return "strftime: unsupported directive: " + e.directive + " " + e.message
|
|
}
|
|
|
|
func (e *formatError) setDirective(str string, i, j int) {
|
|
_, n := utf8.DecodeRuneInString(str[j:])
|
|
e.directive = str[i : j+n]
|
|
}
|