updates

ober

b02197c408ecc9a66edc9f46b0b4c1231f4259cc

diff --git a/src/jcode/core/config.ss b/src/jcode/core/config.ss
index 355b72b..fa54f9f 100644
--- a/src/jcode/core/config.ss
+++ b/src/jcode/core/config.ss
@@ -57,18 +57,32 @@
     (path-join (current-directory) "jcode.json")
     (path-join (jcode-home) "config.json")))
 
-(def (find-config-file)
-  (let loop ((paths (config-paths)))
-    (cond
-      ((null? paths) #f)
-      ((file-exists? (car paths)) (car paths))
-      (else (loop (cdr paths))))))
+(def (deep-merge! base overlay)
+  ;; Merge OVERLAY into BASE per-key. When both sides hold a hash the
+  ;; merge recurses; otherwise OVERLAY's value replaces BASE's.
+  (hash-for-each
+    (lambda (k v)
+      (let ((bv (hash-get base k)))
+        (if (and (hash-table? bv) (hash-table? v))
+          (deep-merge! bv v)
+          (hash-put! base k v))))
+    overlay)
+  base)
 
 (def (load-config)
-  (let* ((file (find-config-file))
-         (file-config (if file
-                        (call-with-input-file file read-json)
-                        (make-hash-table)))
+  ;; Global ~/.jcode/config.json is the base; project ./jcode.json
+  ;; deep-merges on top per-key, so a project file only overrides the
+  ;; keys it actually sets.
+  (let* ((file-config
+           (let loop ((paths (reverse (config-paths)))
+                      (acc (make-hash-table)))
+             (cond
+               ((null? paths) acc)
+               ((file-exists? (car paths))
+                (loop (cdr paths)
+                      (deep-merge! acc
+                        (call-with-input-file (car paths) read-json))))
+               (else (loop (cdr paths) acc)))))
          (config (merge-env-config file-config)))
     (*config* config)
     config))
diff --git a/src/jcode/core/models.ss b/src/jcode/core/models.ss
index 7ebb8d2..92cbe26 100644
--- a/src/jcode/core/models.ss
+++ b/src/jcode/core/models.ss
@@ -58,7 +58,7 @@
     ((openrouter)  "anthropic/claude-sonnet-4")
     ((deepseek)    "deepseek-chat")
     ((google)      "gemini-2.5-flash")
-    ((ollama)      "llama3.2")
+    ((ollama)      "qwen3-coder-next:q8_0")
     ((mlx)         "/Users/user/llm/mlx-models/Qwen3.6-35B-A3B-TurboQuant-6bit")
     ((xai)         "grok-3-mini")
     ((grok)        "grok-build")
@@ -217,7 +217,8 @@
     ("nousresearch/hermes-3-llama-3.1-405b" . "Hermes 3 405B")))
 
 (def ollama-models
-  '(("llama3.2"        . "Llama 3.2")
+  '(("qwen3-coder-next:q8_0" . "Qwen3 Coder Next (Q8_0)")
+    ("llama3.2"        . "Llama 3.2")
     ("llama3.1"        . "Llama 3.1")
     ("qwen2.5-coder"   . "Qwen 2.5 Coder")
     ("deepseek-r1"     . "DeepSeek R1")
diff --git a/src/jcode/core/repomap.ss b/src/jcode/core/repomap.ss
index d438538..07f1e68 100644
--- a/src/jcode/core/repomap.ss
+++ b/src/jcode/core/repomap.ss
@@ -74,6 +74,7 @@
       (let ((cache (repomap-cache-path)))
         (let ((dir (path-directory cache)))
           (unless (file-exists? dir) (mkdir-p dir)))
+        (when (file-exists? cache) (delete-file cache))
         (call-with-output-file cache
           (lambda (p) (display text p))))
       (catch (e)
diff --git a/src/jcode/provider/provider.ss b/src/jcode/provider/provider.ss
index 8d02112..a164a58 100644
--- a/src/jcode/provider/provider.ss
+++ b/src/jcode/provider/provider.ss
@@ -103,7 +103,11 @@
 (def make-provider
   (case-lambda
     ((name api-key model)
-     (make-provider-record name api-key model (provider-default-url name)))
+     ;; config providers.<name>.base_url overrides the built-in default,
+     ;; e.g. ollama behind an ssh tunnel on a non-standard port.
+     (make-provider-record name api-key model
+       (or (config-ref "providers" name "base_url")
+           (provider-default-url name))))
     ((name api-key model base-url)
      (make-provider-record name api-key model base-url))))