detached 956b0a2

Merge remote-tracking branch 'origin/main' into pr-11

commit
956b0a24e2600dbd767aec81254e73edf32b2e8b
author
patriceckhart · · 2026-06-08 13:23 UTC
merge of
ab6d543 + eef2714 · diff against the first parent
signature
unsigned
2 files · +40 -2
M packages/agent/build.go +9 -2
@@ -317,8 +317,15 @@ func Resolve(args Args, requireCred bool) (Resolved, error) {
317317 // never shows a "not logged in" banner.
318318 userPickedProvider := args.Provider != ""
319319 if credErr != nil && !userPickedProvider && provName != "ollama" {
320- for _, other := range []string{"anthropic", "openai", "openai-codex", "kimi", "deepseek", "google"} {
321- if other == provName {
320+ // Scan every known provider (not a hardcoded subset) so any
321+ // env-based credential is discovered, e.g. an env-only
322+ // amazon-bedrock setup (AWS_BEARER_TOKEN_BEDROCK / AWS_PROFILE /
323+ // IAM keys) when no config.json pins the provider, such as after
324+ // pointing ZOT_HOME at a fresh home dir. Iteration order of
325+ // knownProviders defines fallback priority. ollama is skipped:
326+ // it has no credential and would always "match".
327+ for _, other := range knownProviders {
328+ if other == provName || other == "ollama" {
322329 continue
323330 }
324331 if c, m, a, err := ResolveCredentialFull(other, args.APIKey); err == nil {
@@ -317,8 +317,15 @@ func Resolve(args Args, requireCred bool) (Resolved, error) {
317 // never shows a "not logged in" banner.317 // never shows a "not logged in" banner.
318 userPickedProvider := args.Provider != ""318 userPickedProvider := args.Provider != ""
319 if credErr != nil && !userPickedProvider && provName != "ollama" {319 if credErr != nil && !userPickedProvider && provName != "ollama" {
320- for _, other := range []string{"anthropic", "openai", "openai-codex", "kimi", "deepseek", "google"} {320+ // Scan every known provider (not a hardcoded subset) so any
321- if other == provName {321+ // env-based credential is discovered, e.g. an env-only
322+ // amazon-bedrock setup (AWS_BEARER_TOKEN_BEDROCK / AWS_PROFILE /
323+ // IAM keys) when no config.json pins the provider, such as after
324+ // pointing ZOT_HOME at a fresh home dir. Iteration order of
325+ // knownProviders defines fallback priority. ollama is skipped:
326+ // it has no credential and would always "match".
327+ for _, other := range knownProviders {
328+ if other == provName || other == "ollama" {
322 continue329 continue
323 }330 }
324 if c, m, a, err := ResolveCredentialFull(other, args.APIKey); err == nil {331 if c, m, a, err := ResolveCredentialFull(other, args.APIKey); err == nil {
M packages/agent/build_test.go +31 -0
@@ -111,6 +111,37 @@ func TestResolveExplicitFlagStaleDoesNotRepairConfig(t *testing.T) {
111111 }
112112 }
113113
114+// TestResolveEnvOnlyBedrockDiscoveredWithoutConfig reproduces issue
115+// #15: pointing ZOT_HOME at a fresh dir drops the persisted
116+// config.json (which pinned provider=amazon-bedrock). Resolve must
117+// still discover bedrock from the AWS env vars instead of falling back
118+// to anthropic and reporting "not logged in".
119+func TestResolveEnvOnlyBedrockDiscoveredWithoutConfig(t *testing.T) {
120+ t.Setenv("ZOT_HOME", t.TempDir()) // fresh home: no config.json
121+ // Disable the Kimi CLI token fallback so a developer machine with a
122+ // real Kimi CLI login doesn't pre-empt bedrock in the scan.
123+ if err := SetKimiCLIFallbackDisabled(true); err != nil {
124+ t.Fatal(err)
125+ }
126+ t.Setenv("AWS_BEARER_TOKEN_BEDROCK", "test-bedrock-token")
127+ t.Setenv("AWS_REGION", "us-east-1")
128+ // Make sure no other provider's env credential pre-empts bedrock.
129+ for _, k := range []string{"ANTHROPIC_API_KEY", "ANTHROPIC_OAUTH_TOKEN", "OPENAI_API_KEY", "GEMINI_API_KEY", "GOOGLE_API_KEY", "DEEPSEEK_API_KEY", "KIMI_API_KEY", "MOONSHOT_API_KEY"} {
130+ t.Setenv(k, "")
131+ }
132+
133+ r, err := Resolve(Args{}, true)
134+ if err != nil {
135+ t.Fatalf("Resolve errored with env-only bedrock: %v", err)
136+ }
137+ if r.Provider != "amazon-bedrock" {
138+ t.Fatalf("provider = %q, want amazon-bedrock", r.Provider)
139+ }
140+ if !r.HasCredential() {
141+ t.Fatalf("bedrock credential not resolved from env")
142+ }
143+}
144+
114145 func TestResolveOllamaUsesModelBaseURLBeforeDefault(t *testing.T) {
115146 t.Setenv("ZOT_HOME", t.TempDir())
116147 provider.SetLiveModels(nil)
@@ -111,6 +111,37 @@ func TestResolveExplicitFlagStaleDoesNotRepairConfig(t *testing.T) {
111 }111 }
112 }112 }
113 113
114+// TestResolveEnvOnlyBedrockDiscoveredWithoutConfig reproduces issue
115+// #15: pointing ZOT_HOME at a fresh dir drops the persisted
116+// config.json (which pinned provider=amazon-bedrock). Resolve must
117+// still discover bedrock from the AWS env vars instead of falling back
118+// to anthropic and reporting "not logged in".
119+func TestResolveEnvOnlyBedrockDiscoveredWithoutConfig(t *testing.T) {
120+ t.Setenv("ZOT_HOME", t.TempDir()) // fresh home: no config.json
121+ // Disable the Kimi CLI token fallback so a developer machine with a
122+ // real Kimi CLI login doesn't pre-empt bedrock in the scan.
123+ if err := SetKimiCLIFallbackDisabled(true); err != nil {
124+ t.Fatal(err)
125+ }
126+ t.Setenv("AWS_BEARER_TOKEN_BEDROCK", "test-bedrock-token")
127+ t.Setenv("AWS_REGION", "us-east-1")
128+ // Make sure no other provider's env credential pre-empts bedrock.
129+ for _, k := range []string{"ANTHROPIC_API_KEY", "ANTHROPIC_OAUTH_TOKEN", "OPENAI_API_KEY", "GEMINI_API_KEY", "GOOGLE_API_KEY", "DEEPSEEK_API_KEY", "KIMI_API_KEY", "MOONSHOT_API_KEY"} {
130+ t.Setenv(k, "")
131+ }
132+
133+ r, err := Resolve(Args{}, true)
134+ if err != nil {
135+ t.Fatalf("Resolve errored with env-only bedrock: %v", err)
136+ }
137+ if r.Provider != "amazon-bedrock" {
138+ t.Fatalf("provider = %q, want amazon-bedrock", r.Provider)
139+ }
140+ if !r.HasCredential() {
141+ t.Fatalf("bedrock credential not resolved from env")
142+ }
143+}
144+
114 func TestResolveOllamaUsesModelBaseURLBeforeDefault(t *testing.T) {145 func TestResolveOllamaUsesModelBaseURLBeforeDefault(t *testing.T) {
115 t.Setenv("ZOT_HOME", t.TempDir())146 t.Setenv("ZOT_HOME", t.TempDir())
116 provider.SetLiveModels(nil)147 provider.SetLiveModels(nil)

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 1

Tags 476

↑↓ moveenter openesc close