a39805aa89
Empty cli/ Go module with Factory + Options skeleton that all v0.x commands plug into. Foundation packages (10 internal/): - cmdutil: Factory(3 closure: Config/Client/Prompter) + Options + Errors with namespaced ErrorCode + typed predicates (IsAuthError / IsNotFound / IsTransient / IsAuthExpired) + Exporter + AddJSONFlags + ExitCode/PrintError - iostreams: package singleton with TTY detection; ColorEnabled honors NO_COLOR / TERM=dumb on demand - agent: mode + detect + annotations (Stripe pkg/useragent pattern; CLAUDECODE / CURSOR_AGENT / CODEX_* / AIDER_* / CONTINUE_* / OPENCODE_* / GEMINICODER env detection) - build: ldflags-injected version/commit/date - safepaths: separator-aware path-traversal protection - config: yaml.v3 schema + atomic save 0600 (XDG-style) - format: success/failure envelope (code/hint/request_id/risk/retryable/ console_url) with typed RiskLevel - prompt: Prompter interface + AgentPrompter (rejects in agent mode) - secrets: file 0600 store with weknora:<context>:<key> namespace - testutil: XDGTempDir(t) test helper Smoke command: weknora version (-/--json). Build/test/vet matrix in .github/workflows/cli.yml across linux x macos x windows x Go 1.24. Factory.Client returns CodeLocalUnimplemented until PR-3 wires the SDK adapter; PR-1 commands (version) don't need it.
51 lines
1.5 KiB
Go
51 lines
1.5 KiB
Go
package format
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestSuccessEnvelope(t *testing.T) {
|
|
env := Success(map[string]string{"id": "kb_abc"}, &Meta{Context: "prod", RequestID: "cli-01"})
|
|
var buf bytes.Buffer
|
|
require.NoError(t, WriteEnvelope(&buf, env))
|
|
var got map[string]any
|
|
require.NoError(t, json.Unmarshal(buf.Bytes(), &got))
|
|
assert.Equal(t, true, got["ok"])
|
|
assert.NotNil(t, got["data"])
|
|
assert.NotNil(t, got["_meta"])
|
|
assert.Nil(t, got["error"])
|
|
}
|
|
|
|
func TestFailureEnvelope(t *testing.T) {
|
|
env := Failure(&ErrorBody{
|
|
Code: "auth.unauthenticated",
|
|
Message: "no creds",
|
|
Hint: "run weknora auth login",
|
|
Risk: RiskRead,
|
|
Retryable: false,
|
|
})
|
|
var buf bytes.Buffer
|
|
require.NoError(t, WriteEnvelope(&buf, env))
|
|
var got map[string]any
|
|
require.NoError(t, json.Unmarshal(buf.Bytes(), &got))
|
|
assert.Equal(t, false, got["ok"])
|
|
errBody := got["error"].(map[string]any)
|
|
assert.Equal(t, "auth.unauthenticated", errBody["code"])
|
|
assert.Equal(t, "run weknora auth login", errBody["hint"])
|
|
assert.Equal(t, "read", errBody["risk"])
|
|
}
|
|
|
|
func TestEnvelope_NoEscapeHTML(t *testing.T) {
|
|
// Hints / messages may include & or <; ensure we don't HTML-escape them
|
|
// (would break agent jq pipelines).
|
|
env := Failure(&ErrorBody{Code: "x", Message: "a & b < c"})
|
|
var buf bytes.Buffer
|
|
require.NoError(t, WriteEnvelope(&buf, env))
|
|
assert.Contains(t, buf.String(), "a & b < c")
|
|
}
|