docs(go): audit README and AGENTS

Align the README API reference with the exported surface, add the
upgrade note, document the shared modules and Linux test setup in
AGENTS.md, and scope the Grok expandable-path assertion to Windows.

Claude-Session: https://claude.ai/code/session_01Agoc9bRVE9KL7mmWtey9Vq
This commit is contained in:
雷电芽衣 committed 2026-09-03 02:43:55 -04:00
1 parent 96489cd051
commit 301210ff25
3 files changed
+63 -27

No files matched your search

+12 -1
View File
@@ -47,6 +47,15 @@ This repository owns the public Go SDK, the `cmd/elydora` CLI, local signing beh
- Preserve JSONC comments, line endings, and unknown future hook fields. Reject trailing commas and duplicate keys, validate all 21 current events plus command, HTTP, and prompt handlers, reject settings-defined function handlers, and apply Node.js `RegExp` semantics only to the 15 matcher-enabled events.
- Own one exact named matchless `PreToolUse`, `PostToolUse`, and `PostToolUseFailure` triple with 10,000 millisecond timeouts. Generate guard, strict runtime config, canonical private key, and native-payload audit runtime with user settings in one rollback-capable transaction. Propagate frozen and revoked agents through exit code `2`; require effective hooks to be enabled, one exact triple, physical runtime files, strict identity, and exact generated sources for healthy status; direct users to `/hooks` for review.
## Shared Modules
- `cmd/elydora/plugins/managed_runtime.go` owns install-config validation, managed runtime paths, runtime config validation, runtime identity checks, and the strict and presence-only status contracts. `managed_changes.go` owns runtime config encoding, the four runtime file changes, and the shared directory-plus-commit writer.
- `cmd/elydora/plugins/shell_command.go` owns Node.js resolution, POSIX and PowerShell quoting, encoded Windows commands, the shell and encoded command builders and parsers, and the pre-2.1 quoted Windows parser.
- `cmd/elydora/plugins/jsonc.go` owns strict JSON object decoding, JSONC editing, and `cloneJSONObject`; `managed_files.go` owns physical file and directory inspection; `transaction*.go` owns the rollback-capable commit.
- Provider files keep only their hook document schema, ownership rules, rendering, and provider-specific preconditions. Add a provider-local helper only when the shared module cannot express the provider contract.
- `jsonutil.go` and `legacy_hook_entries.go` serve the Kiro CLI, Letta, and OpenCode adapters, which write settings without the managed transaction; moving them onto the managed model is a product decision.
- Recognizing pre-2.1 Elydora commands stays in place so `elydora install` replaces older entries during upgrades.
## Code Quality
- Preserve the minimum Go version declared in `go.mod`.
@@ -65,7 +74,7 @@ This repository owns the public Go SDK, the `cmd/elydora` CLI, local signing beh
Run the focused adapter test during development, then execute all release gates before commit:
```powershell
```sh
go test ./cmd/elydora/plugins -run <Provider> -count=1
go test ./...
go test -race ./...
@@ -75,6 +84,8 @@ govulncheck ./...
git diff --check
```
The Linux test environment leaks provider config into `$HOME`; run the suite with `HOME` and `XDG_CONFIG_HOME` pointed at a scratch directory while `GOPATH`, `GOMODCACHE`, and `GOCACHE` keep their real values.
Provider adapter tests must cover installation, idempotency, official event forwarding, blocking behavior, status, missing runtime files, uninstall ownership, and malformed configuration preservation.
Commit and push one root issue before starting the next one.
+50 -25
View File
@@ -10,6 +10,8 @@ go get github.com/Elydora-Infrastructure/Elydora-Go-SDK/v2
Requires Go 1.21+. The CLI uses focused TOML and JSONC parsers to preserve user-owned agent configuration.
Upgrading from 2.0.x: run `elydora install` again for every agent. The generated runtimes changed, and `elydora status` does not detect stale runtimes for every adapter.
## Quick Start
```go
@@ -23,18 +25,12 @@ import (
)
func main() {
// Authenticate
auth, err := elydora.Login("https://api.elydora.com", "user@example.com", "password")
if err != nil {
log.Fatal(err)
}
// Create client
// Create client with an API token issued in the Console
client, err := elydora.NewClient(&elydora.Config{
OrgID: auth.User.OrgID,
OrgID: "org-123",
AgentID: "my-agent-id",
PrivateKey: "<base64url-encoded-ed25519-seed>",
Token: auth.Token,
Token: "<api-token>",
})
if err != nil {
log.Fatal(err)
@@ -113,8 +109,9 @@ Qwen Code `0.20.0` installation writes native user hooks to `$QWEN_HOME/settings
|---------|-------------|
| `elydora install` | Install Elydora audit hook for a coding agent |
| `elydora uninstall` | Remove Elydora audit hook for a coding agent |
| `elydora status` | Show installation status for all agents |
| `elydora status` | Show installation status for one agent or all agents |
| `elydora agents` | List supported coding agents |
| `elydora version` | Print the CLI version |
### Supported Agents
@@ -162,24 +159,23 @@ client.SetToken("new-api-token")
### Authentication
```go
// Register a new user and organization
reg, err := elydora.Register(baseURL, email, password,
elydora.WithDisplayName("Alice"),
elydora.WithOrgName("Acme Corp"),
)
// Login and receive a session token
auth, err := elydora.Login(baseURL, email, password)
// Get current authenticated user profile
// Get the authenticated user and current organization
me, err := client.GetMe()
// me.User.Email, me.User.Role, me.CurrentOrganization.OrgID
// Issue a new API token (with optional TTL)
// Issue an API token; this call needs a client whose Token is a Console session token
tokenResp, err := client.IssueApiToken(&elydora.IssueApiTokenRequest{
TTLSeconds: &ttlSeconds,
})
client.SetToken(tokenResp.Token)
// Rotate the installed API token; the response carries the replacement
rotated, err := client.RotateApiToken()
client.SetToken(rotated.Token)
```
`elydora.Register` and `elydora.Login` remain for password accounts and are deprecated; use the Console sign-in flow.
### Operations
```go
@@ -219,8 +215,11 @@ agent, err := client.RegisterAgent(&elydora.RegisterAgentRequest{
// Get agent details
details, err := client.GetAgent(agentID)
// Change the integration type
updated, err := client.UpdateAgent(agentID, elydora.IntegrationTypeClaudecode)
// Freeze an agent
err := client.FreezeAgent(agentID, "security review")
frozen, err := client.FreezeAgent(agentID, "security review")
// Revoke a key
err := client.RevokeKey(agentID, kid, "key rotation")
@@ -229,7 +228,7 @@ err := client.RevokeKey(agentID, kid, "key rotation")
agents, err := client.ListAgents()
// Unfreeze a previously frozen agent
err := client.UnfreezeAgent(agentID, "review complete")
unfrozen, err := client.UnfreezeAgent(agentID, "review complete")
// Delete an agent permanently
deleted, err := client.DeleteAgent(agentID)
@@ -270,6 +269,25 @@ detail, err := client.GetExport(exportID)
data, err := client.DownloadExport(exportID)
```
### Webhooks
```go
webhook, err := client.RegisterWebhook(&elydora.RegisterWebhookRequest{
EndpointURL: "https://example.com/elydora",
Events: []string{"operation.accepted"},
Secret: "<signing-secret>",
})
webhooks, err := client.ListWebhooks()
err = client.DeleteWebhook(webhook.Webhook.WebhookID)
```
### Organization
```go
members, err := client.ListMembers()
events, err := client.ListAdminEvents(50)
```
### JWKS
```go
@@ -281,7 +299,11 @@ jwks, err := client.GetJWKS()
```go
// Check API health (no authentication required, does not need a client)
health, err := elydora.Health("https://api.elydora.com")
// health.Status, health.Version, health.ProtocolVersion, health.Timestamp
// health.Status, health.Version, health.ProtocolVersion, health.Capabilities, health.Timestamp
// Check dependency health (D1, auth storage, R2, KV)
deep, err := elydora.DeepHealth("https://api.elydora.com")
// deep.Dependencies.D1.Status, deep.Dependencies.KV.LatencyMs
```
### Constants
@@ -299,8 +321,11 @@ elydora.GenesisChainHash // "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
| `KeyStatus` | `KeyStatusActive`, `KeyStatusRetired`, `KeyStatusRevoked` |
| `ExportStatus` | `ExportStatusQueued`, `ExportStatusRunning`, `ExportStatusDone`, `ExportStatusFailed` |
| `ExportFormat` | `ExportFormatJSON`, `ExportFormatPDF` |
| `WebhookStatus` | `WebhookStatusActive`, `WebhookStatusDisabled` |
| `IntegrationType` | One constant per supported agent key plus `IntegrationTypeEnterprise`, `IntegrationTypeGUI`, `IntegrationTypeSDK`, `IntegrationTypeOther` |
| `AdminAction` | One constant per admin event action, for example `AdminActionAgentFreeze` |
| `RbacRole` | `RbacRoleOrgOwner`, `RbacRoleSecurityAdmin`, `RbacRoleComplianceAuditor`, `RbacRoleReadonlyInvestigator`, `RbacRoleIntegrationEngineer` |
| `ErrorCode` | `ErrorCodeInvalidSignature`, `ErrorCodeUnknownAgent`, `ErrorCodeKeyRevoked`, `ErrorCodeAgentFrozen`, `ErrorCodeTTLExpired`, `ErrorCodeReplayDetected`, `ErrorCodePrevHashMismatch`, `ErrorCodePayloadTooLarge`, `ErrorCodeRateLimited`, `ErrorCodeInternalError`, `ErrorCodeUnauthorized`, `ErrorCodeForbidden`, `ErrorCodeNotFound`, `ErrorCodeValidationError` |
| `ErrorCode` | `ErrorCodeInvalidSignature`, `ErrorCodeUnknownAgent`, `ErrorCodeKeyRevoked`, `ErrorCodeKeyRetired`, `ErrorCodeAgentFrozen`, `ErrorCodeAgentRevoked`, `ErrorCodeTTLExpired`, `ErrorCodeReplayDetected`, `ErrorCodePrevHashMismatch`, `ErrorCodePayloadTooLarge`, `ErrorCodeRateLimited`, `ErrorCodeInternalError`, `ErrorCodeUnauthorized`, `ErrorCodeForbidden`, `ErrorCodeNotFound`, `ErrorCodeValidationError` |
## Error Handling
+1 -1
View File
@@ -36,7 +36,7 @@ func TestGrokCommandRoundTripAndRejectsInjection(t *testing.T) {
!sameManagedPath(script, fixture.guardPath) {
t.Fatalf("parsed Grok command = %q, %q, %v", executable, script, ok)
}
if strings.Contains(command, "%ELYDORA_HOOK_PATH%") {
if runtime.GOOS == "windows" && strings.Contains(command, "%ELYDORA_HOOK_PATH%") {
t.Fatalf("Grok command exposes an expandable path: %q", command)
}
if _, err := buildEncodedCommand("Grok", "node", fixture.guardPath); err == nil {