diff --git a/CHANGELOG.md b/CHANGELOG.md index 53186838..acf2f7b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,11 +8,12 @@ Format: [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) · Versioning: ## [Unreleased] ### Changed -- **Renamed host product references from hawk to rho.** Host config paths - (`~/.rho/`), the `rho_build`/`rho_build_concise` tool namespaces, the - `rho_response` schema name, and the `EXPORT_RHO_FIXTURE` env var now use the - rho identity. Retired ecosystem repos (`shrike`, `harrier`, `kestrel`, - `merlin`) are no longer referenced. +- **Renamed host product references to rho.** Host config paths (`~/.rho/`), + the `rho_build`/`rho_build_concise` tool namespaces, the `rho_response` + schema name, and the `EXPORT_RHO_FIXTURE` env var now use the rho identity. + References to retired ecosystem repos were removed. +- **Credential env-file migration falls back to the pre-rename host config + directory** so installs created before the rename still migrate. ## [0.0.1] — 2026-09-15 diff --git a/README.md b/README.md index 033dbb8e..c6ad2a70 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,6 @@ and two Go AST tests in `rho/internal/testaudit/`. - do not import `rho/internal/*` - do not import the removed legacy path `rho/shared/types` -- do not import other engines (`swift`) — engines are peers, not dependencies ## Quick Start @@ -320,7 +319,6 @@ flux is part of the graycode-eco: |---|---|---| | **rho** | [GrayCodeAI/rho](https://github.com/GrayCodeAI/rho) | AI coding agent | | **flux** | This repo | LLM provider runtime | -| **swift** | [GrayCodeAI/swift](https://github.com/GrayCodeAI/swift) | Session capture | ## Development diff --git a/credentials/migrate.go b/credentials/migrate.go index 233f40d5..954450e9 100644 --- a/credentials/migrate.go +++ b/credentials/migrate.go @@ -25,7 +25,9 @@ func markEnvFileMigrationDone() { } // MigrateEnvFileCredentials imports API keys from plaintext credential files -// (~/.rho/env, ~/.rho/.env) into the OS secret store and removes them. +// (~/.rho/env, ~/.rho/.env) into the OS secret store and removes them. It also +// checks the pre-rename host config directory (~/.hawk/env, ~/.hawk/.env) so +// installs created before the rename still migrate. func MigrateEnvFileCredentials(ctx context.Context) (int, error) { if ctx == nil { ctx = context.Background() @@ -34,7 +36,7 @@ func MigrateEnvFileCredentials(ctx context.Context) (int, error) { return 0, nil } total := 0 - for _, path := range []string{rhoEnvPath(), rhoDotEnvPath()} { + for _, path := range []string{rhoEnvPath(), rhoDotEnvPath(), legacyEnvPath(), legacyDotEnvPath()} { n, err := migrateEnvFileAt(ctx, path) if err != nil && !os.IsNotExist(err) { return total, err @@ -93,6 +95,19 @@ func rhoDotEnvPath() string { return filepath.Join(home, ".rho", ".env") } +// legacyEnvPath is the pre-rename host config file path, kept so installs +// created before the rename still migrate. +func legacyEnvPath() string { + home, _ := os.UserHomeDir() + return filepath.Join(home, ".hawk", "env") +} + +// legacyDotEnvPath is the pre-rename host dotenv file path. +func legacyDotEnvPath() string { + home, _ := os.UserHomeDir() + return filepath.Join(home, ".hawk", ".env") +} + func readEnvFile(path string) (map[string]string, error) { data, err := os.ReadFile(path) // #nosec G304 -- path is built from os.UserHomeDir() in rhoDotEnvPath, not untrusted input if err != nil { diff --git a/credentials/migrate_test.go b/credentials/migrate_test.go index d02887e0..70c33681 100644 --- a/credentials/migrate_test.go +++ b/credentials/migrate_test.go @@ -311,6 +311,37 @@ func TestMigrateEnvFileCredentials_BothPaths(t *testing.T) { } } +func TestMigrateEnvFileCredentials_LegacyPaths(t *testing.T) { + ms := &MapStore{} + cs := &CombinedStore{Keychain: ms} + SetDefaultStore(cs) + t.Cleanup(func() { SetDefaultStore(nil) }) + + dir := t.TempDir() + t.Setenv("HOME", dir) + + legacyDir := filepath.Join(dir, ".hawk") + if err := os.MkdirAll(legacyDir, 0o700); err != nil { + t.Fatal(err) + } + envPath := filepath.Join(legacyDir, "env") + if err := os.WriteFile(envPath, []byte("ANTHROPIC_API_KEY=sk-legacy\n"), 0o600); err != nil { + t.Fatal(err) + } + + ctx := context.Background() + n, err := MigrateEnvFileCredentials(ctx) + if err != nil { + t.Fatalf("error: %v", err) + } + if n != 1 { + t.Fatalf("expected 1 migrated from legacy path, got %d", n) + } + if _, err := os.Stat(envPath); !os.IsNotExist(err) { + t.Error("legacy ~/.hawk/env should be removed after migration") + } +} + func TestMigrateEnvFileCredentialsAt_NilKeychain(t *testing.T) { // When DefaultStore is a CombinedStore with nil Keychain, migration should fail. cs := &CombinedStore{Keychain: nil} diff --git a/docs/guides/CREDENTIAL-SETUP-FLOW.md b/docs/guides/CREDENTIAL-SETUP-FLOW.md index c999d485..b38c809c 100644 --- a/docs/guides/CREDENTIAL-SETUP-FLOW.md +++ b/docs/guides/CREDENTIAL-SETUP-FLOW.md @@ -69,7 +69,7 @@ Setup is **gateway-first**: pick the gateway on the Gateways tab, paste any non- → Pick model → ListModels (auto) when credentials exist ``` -## Host API (rho uses `internal/fluxclient` only) +## Host API (rho integrates through `flux/engine`) - `ResolveCredentialForHost` / `SaveCredentialForHost` - `ApplyFluxCredentials` diff --git a/internal/observability/genai_semconv.go b/internal/observability/genai_semconv.go index a7048ead..bb53f7a9 100644 --- a/internal/observability/genai_semconv.go +++ b/internal/observability/genai_semconv.go @@ -3,7 +3,7 @@ // These exported constants are the canonical, ecosystem-wide attribute keys for // describing LLM / AI agent operations. They follow the OpenTelemetry GenAI // semantic conventions (gen_ai.*) and are shared as the reference set that the -// other graycode-eco repos (rho, swift) should mirror when emitting +// other graycode-eco repos should mirror when emitting // spans, so dashboards and exporters can correlate cost/usage/identity across // the whole ecosystem. // diff --git a/scripts/check-ecosystem-boundaries.sh b/scripts/check-ecosystem-boundaries.sh index a40d9eba..dc51e3fc 100755 --- a/scripts/check-ecosystem-boundaries.sh +++ b/scripts/check-ecosystem-boundaries.sh @@ -8,16 +8,11 @@ cd "$ROOT_DIR" # Shared ecosystem vocabulary lives in rho/internal/contracts, which # hosts vendor rather than import from here. FORBIDDEN_RHO='github\.com/GrayCodeAI/rho(/|")' -FORBIDDEN_ENGINES='github\.com/GrayCodeAI/swift(/|")' - -exit_code=0 if command -v rg >/dev/null 2>&1; then violations="$(rg -n "$FORBIDDEN_RHO" --glob '*.go' . || true)" - engine_violations="$(rg -n "$FORBIDDEN_ENGINES" --glob '*.go' . || true)" else violations="$(grep -rn --include='*.go' -E "$FORBIDDEN_RHO" . || true)" - engine_violations="$(grep -rn --include='*.go' -E "$FORBIDDEN_ENGINES" . || true)" fi if [[ -n "${violations}" ]]; then @@ -25,19 +20,7 @@ if [[ -n "${violations}" ]]; then echo "${violations}" echo echo "flux must use local contracts, never the Rho product module" - exit_code=1 -fi - -if [[ -n "${engine_violations}" ]]; then - echo "forbidden cross-engine imports found:" - echo "${engine_violations}" - echo - echo "support engines must not import other engines directly — they are peers, not dependencies" - exit_code=1 -fi - -if [[ $exit_code -ne 0 ]]; then - exit $exit_code + exit 1 fi -echo "ecosystem boundary guard passed" +echo "ecosystem boundary guard passed" \ No newline at end of file diff --git a/tools/versioning.go b/tools/versioning.go index 18882f08..67b2be73 100644 --- a/tools/versioning.go +++ b/tools/versioning.go @@ -33,7 +33,7 @@ func BehaviorPresetFrom(s string) (BehaviorPreset, error) { } // FinalizeErrorCode classifies a finalize warning or violation, mirroring the -// FINALIZE_ERROR_CODE enum in proto/rho/contracts/v1/tool.proto. +// FINALIZE_ERROR_CODE enum in the host tool contract. type FinalizeErrorCode int const ( @@ -90,7 +90,7 @@ func (r FinalizeResult) Ok() bool { } // ToolMeta is the canonical identity envelope attached to tool-call events, -// mirroring the ToolMeta message in proto/rho/contracts/v1/tool.proto. +// mirroring the ToolMeta message in the host tool contract. // version is an additive-only bump: new additive fields do NOT change it. type ToolMeta struct { Version string `json:"version"` @@ -102,11 +102,11 @@ type ToolMeta struct { } // ToolNamespace is a CLOSED enum identifying the harness that owns a tool, -// mirroring the ToolNamespace enum in proto/rho/contracts/v1/tool.proto. A new +// mirroring the ToolNamespace enum in the host tool contract. A new // unknown namespace is a wire-breaking change that intentionally fails // ToolNamespaceFrom (forward-safety): a deploy that rolls the contract forward // before the consumer code cannot silently mis-route a tool it doesn't -// understand. ToolNamespaceAcp is reserved for the forthcoming rho-acp repo. +// understand. ToolNamespaceAcp is reserved for a forthcoming ACP harness. type ToolNamespace string const ( @@ -116,7 +116,7 @@ const ( ToolNamespaceCodex ToolNamespace = "codex" // codex harness ToolNamespaceOpencode ToolNamespace = "opencode" // opencode harness ToolNamespaceMcp ToolNamespace = "mcp" // MCP servers (falcon) - ToolNamespaceAcp ToolNamespace = "acp" // reserved: rho-acp + ToolNamespaceAcp ToolNamespace = "acp" // reserved: ACP harness ) // ToolNamespaceFrom parses a namespace string into a ToolNamespace. The set is