0db31d21b9
The vendored copy of github.com/kami/hexis predated Client.WithToken: no token field, no setter, no header hook, and an unexported httpClient, so there was no way to attach auth from outside the package. wireEcosystem handled that by refusing to wire Hexis at all when a token was configured, which was the honest reading of the code but left the deployment silently without its executing service. go.mod already replaces the module with /home/kami/apps/hexis, and that source has had WithToken and the Bearer header for a while. Only the checked-in vendor/ copy was stale. Refreshed it (client.go plus the new capability.go) and wired Hexis like Nexus and Praxis. Two tests cover the outcome the refusal was standing in for: a configured token reaches the wire as Authorization, and no token still wires unauthed, because Hexis without auth is a valid deployment on a trusted box. Also corrected the discoverCapabilities comment. It claimed the client stamped the correlation header on Execute only; do() stamps it on every request, and did before the re-vendor too. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TrVSBKe3RFDF4fGYKWYQnX
63 lines
2.9 KiB
Go
63 lines
2.9 KiB
Go
package client
|
|
|
|
import "time"
|
|
|
|
// Capability is THE wire shape for a Hexis capability.
|
|
//
|
|
// There is exactly one definition of it, here, and every producer in this
|
|
// repository serializes through it: the HTTP handler (GET/POST
|
|
// /api/v1/capabilities, GET /api/v1/capabilities/{id}), the MCP adapter
|
|
// (hexis.list_capabilities), and this client's decode path. It lives in
|
|
// pkg/client rather than internal/ so that external consumers get the shape
|
|
// without vendoring internal packages; internal/wire holds the
|
|
// domain.Capability -> Capability conversion.
|
|
//
|
|
// Compatibility note — `id` and `capability_id` are BOTH emitted, deliberately.
|
|
// They always carry the same value. Maven's vendored consumer decodes `id`
|
|
// (cmd/mavend/voice.go matches on Capability.ID); the ECOSYSTEM-SPEC.md §4.1
|
|
// schema and the rest of the Hexis API name the column `capability_id`. Hexis
|
|
// is mid-rollout of bearer auth on /api/v1/, which is already one breaking
|
|
// change for that consumer; dropping either alias here would stack a second,
|
|
// silent one on top. Both stay until every consumer is confirmed to read
|
|
// `capability_id`, at which point `id` can be removed in a deliberate,
|
|
// announced change. Do not "clean this up" incidentally.
|
|
type Capability struct {
|
|
// CapabilityID is the canonical field (ECOSYSTEM-SPEC.md §4.1).
|
|
CapabilityID string `json:"capability_id"`
|
|
// ID is a deprecated alias for CapabilityID, kept for wire compatibility.
|
|
// Always identical to CapabilityID. Prefer CapabilityID in new code.
|
|
ID string `json:"id"`
|
|
|
|
Name string `json:"name"`
|
|
Description string `json:"description,omitempty"`
|
|
TargetTypes []string `json:"target_types"`
|
|
TargetEntityID string `json:"target_entity_id,omitempty"`
|
|
Provider string `json:"provider"`
|
|
Operation string `json:"operation"`
|
|
Risk string `json:"risk,omitempty"`
|
|
ReadOnly bool `json:"read_only"`
|
|
ExpectedSideEffects string `json:"expected_side_effects,omitempty"`
|
|
|
|
// RequiresConfirmation and Enabled are server-derived from the risk tier
|
|
// and are never settable by a caller. listCapabilities used to omit both,
|
|
// which left clients unable to tell a callable capability from one that
|
|
// would be rejected with 403; the unified shape always carries them.
|
|
RequiresConfirmation bool `json:"requires_confirmation"`
|
|
Enabled bool `json:"enabled"`
|
|
TimeoutSeconds int `json:"timeout_seconds,omitempty"`
|
|
|
|
Attributes map[string]any `json:"attributes,omitempty"`
|
|
CreatedAt time.Time `json:"created_at,omitempty"`
|
|
UpdatedAt time.Time `json:"updated_at,omitempty"`
|
|
Version int64 `json:"version,omitempty"`
|
|
}
|
|
|
|
// EffectiveID returns the capability ID, tolerating a peer that sends only one
|
|
// of the two aliases.
|
|
func (c Capability) EffectiveID() string {
|
|
if c.CapabilityID != "" {
|
|
return c.CapabilityID
|
|
}
|
|
return c.ID
|
|
}
|