Add --no-mcp flag, feature-gate jerboa-native-rs, fix binary build
ober
7030c5a4e95854d9494b1ae709f99c0a3578c018
--- a/Makefile +++ b/Makefile @@ -101,10 +101,13 @@ binary: build DYLD_LIBRARY_PATH=$(LDPATH) LD_LIBRARY_PATH=$(LDPATH) \ $(SCHEME) -q --libdirs $(JERBOA_HOME)/lib:./lib:vendor/chez-sqlite/src \ --script build-binary.ss + cp vendor/termbox2/jcode_tui_shim.dylib ./jcode_tui_shim.dylib 2>/dev/null || true + cp vendor/termbox2/jcode_tui_shim.so ./jcode_tui_shim.so 2>/dev/null || true install: binary mkdir -p $(HOME)/.local/bin cp jcode $(HOME)/.local/bin/jcode + cp vendor/termbox2/jcode_tui_shim.dylib $(HOME)/.local/bin/jcode_tui_shim.dylib 2>/dev/null || true cp vendor/chez-sqlite/chez_sqlite_shim.so $(PREFIX)/lib/chez_sqlite_shim.so 2>/dev/null || true @echo "Installed to ~/.local/bin/jcode" --- a/build-binary.ss +++ b/build-binary.ss @@ -185,22 +185,37 @@ (define tui-ffi-sls "lib/jcode/ui/tui-ffi.sls") (define tui-ffi-backup "lib/jcode/ui/tui-ffi.sls.bak") (system (format "cp ~a ~a" tui-ffi-sls tui-ffi-backup)) +;; In static binary, all termbox symbols are linked in via Sforeign_symbol, so +;; we just need _shim-loaded to be #t. Replace the multi-line definition. (let* ((src (call-with-input-file tui-ffi-sls get-string-all)) - (src (string-replace-first src - (string-append - "(def _shim-loaded\n" - " (or (guard (e [list #t #f])\n" - " (load-shared-object \"jcode_tui_shim.dylib\"))\n" - " (guard (e [list #t #f])\n" - " (load-shared-object \"jcode_tui_shim.so\"))\n" - " (guard (e [list #t #f])\n" - " (load-shared-object\n" - " (path-join\n" - " (path-directory (car (command-line)))\n" - " \"jcode_tui_shim.dylib\")))\n" - " #f))") - "(def _shim-loaded #t)"))) - (call-with-output-file tui-ffi-sls (lambda (p) (put-string p src)) 'replace)) + (start-marker "(def _shim-loaded") + (start-pos (let lp ((i 0)) + (cond + ((> (+ i (string-length start-marker)) (string-length src)) #f) + ((string=? start-marker + (substring src i (+ i (string-length start-marker)))) + i) + (else (lp (+ i 1))))))) + (when start-pos + ;; Find matching close paren for the (def ...) form + (let lp ((i start-pos) (depth 0) (started? #f)) + (cond + ((>= i (string-length src)) + (printf " Warning: could not find end of _shim-loaded definition~n")) + ((char=? (string-ref src i) #\() + (lp (+ i 1) (+ depth 1) #t)) + ((char=? (string-ref src i) #\)) + (if (and started? (= depth 1)) + ;; Found end — replace the whole form + (let ((replacement "(def _shim-loaded #t)")) + (call-with-output-file tui-ffi-sls + (lambda (p) + (put-string p (substring src 0 start-pos)) + (put-string p replacement) + (put-string p (substring src (+ i 1) (string-length src)))) + 'replace)) + (lp (+ i 1) (- depth 1) started?))) + (else (lp (+ i 1) depth started?)))))) (when (file-exists? "lib/jcode/ui/tui-ffi.so") (delete-file "lib/jcode/ui/tui-ffi.so")) --- a/lib/jcode/ui/cli.sls +++ b/lib/jcode/ui/cli.sls @@ -32,6 +32,7 @@ (printf "jcode ~a~n" *version*) (exit 0)) (when (assoc '\x2D;-debug opts) (current-log-level 'debug)) + (when (assoc '\x2D;-no-mcp opts) (set! *no-mcp* #t)) (load-config) (session-init-db) (init-tools) @@ -68,6 +69,8 @@ (loop (cdr args) (cons '(\x2D;-tui . #t) opts))] [(equal? (car args) "--no-tui") (loop (cdr args) (cons '(\x2D;-no-tui . #t) opts))] + [(equal? (car args) "--no-mcp") + (loop (cdr args) (cons '(\x2D;-no-mcp . #t) opts))] [(equal? (car args) "--verbose") (loop (cdr args) (cons '(\x2D;-verbose . #t) opts))] [(and (equal? (car args) "--model") (pair? (cdr args))) @@ -87,17 +90,18 @@ (cddr args) (cons (cons '\x2D;-provider (cadr args)) opts))] [else (cons (cons '\x2D;- args) (reverse opts))]))) + (def *no-mcp* #f) (def (init-tools) (init-file-tools) (init-bash-tool) (init-web-tools) (init-batch-tool) (init-git-tools) - (let ([t-mcp (spawn init-mcp-tools)] + (let ([t-mcp (and (not *no-mcp*) (spawn init-mcp-tools))] [t-lsp (spawn init-lsp-tools)] [t-plugins (spawn init-plugins)]) - (thread-join! t-mcp) + (when t-mcp (thread-join! t-mcp)) (thread-join! t-lsp) (thread-join! t-plugins))) (def (display-help) (display - "jcode - Portable AI coding agent\n\nUSAGE:\n jcode [OPTIONS] [PROMPT]\n jcode [COMMAND]\n\nOPTIONS:\n -h, --help Show this help message\n -v, --version Show version\n -d, --debug Enable debug logging\n -m, --model Model to use (default: claude-sonnet-4-20250514)\n -p, --provider Provider to use (default: anthropic)\n --tui Launch terminal UI mode\n --no-tui Force line-mode REPL (default)\n --verbose Log TUI events to ~/jcode.log\n\nCOMMANDS:\n session list List all sessions\n session resume Resume a previous session\n config Show or edit configuration\n serve Start JSONL server (stdio mode)\n serve --port N Start TCP server on 127.0.0.1:N\n serve --rotate-token Generate new auth token and exit\n serve --show-token Display current auth token and exit\n\nEXAMPLES:\n jcode Start interactive session\n jcode \"Read main.ss\" One-shot query\n jcode session list List sessions\n jcode serve --port 8321 Start TCP server for Android app\n")) + "jcode - Portable AI coding agent\n\nUSAGE:\n jcode [OPTIONS] [PROMPT]\n jcode [COMMAND]\n\nOPTIONS:\n -h, --help Show this help message\n -v, --version Show version\n -d, --debug Enable debug logging\n -m, --model Model to use (default: claude-sonnet-4-20250514)\n -p, --provider Provider to use (default: anthropic)\n --tui Launch terminal UI mode\n --no-tui Force line-mode REPL (default)\n --no-mcp Skip MCP server initialization\n --verbose Log TUI events to ~/jcode.log\n\nCOMMANDS:\n session list List all sessions\n session resume Resume a previous session\n config Show or edit configuration\n serve Start JSONL server (stdio mode)\n serve --port N Start TCP server on 127.0.0.1:N\n serve --rotate-token Generate new auth token and exit\n serve --show-token Display current auth token and exit\n\nEXAMPLES:\n jcode Start interactive session\n jcode \"Read main.ss\" One-shot query\n jcode session list List sessions\n jcode serve --port 8321 Start TCP server for Android app\n")) (def (interactive-mode opts) (printf "jcode ~a~n" *version*) (printf --- a/lib/jcode/ui/tui-ffi.sls +++ b/lib/jcode/ui/tui-ffi.sls @@ -43,15 +43,24 @@ (jerboa core) (jerboa runtime)) (def _shim-loaded - (or (guard (e [#t #f]) - (load-shared-object "jcode_tui_shim.dylib")) - (guard (e [#t #f]) (load-shared-object "jcode_tui_shim.so")) - (guard (e [#t #f]) - (load-shared-object - (path-join - (path-directory (car (command-line))) - "jcode_tui_shim.dylib"))) - #f)) + (let ([try-load + (lambda (p) + (guard (e [#t #f]) + (and (file-exists? p) (load-shared-object p))))]) + (or (try-load "jcode_tui_shim.dylib") + (try-load "jcode_tui_shim.so") + (try-load + (path-join (path-directory (car (command-line))) + "jcode_tui_shim.dylib")) + (try-load + (path-join (path-directory (car (command-line))) + "jcode_tui_shim.so")) + (try-load + (path-join (getenv "HOME") ".local" "bin" + "jcode_tui_shim.dylib")) + (try-load "vendor/termbox2/jcode_tui_shim.dylib") + (try-load "vendor/termbox2/jcode_tui_shim.so") + #f))) (defrule (define-tb name c-name arg-types ret-type) (def name --- a/src/jcode/ui/cli.ss +++ b/src/jcode/ui/cli.ss @@ -42,6 +42,8 @@ (printf "jcode ~a~n" *version*) (exit 0)) (when (assoc '--debug opts) (current-log-level 'debug)) + (when (assoc '--no-mcp opts) + (set! *no-mcp* #t)) (load-config) (session-init-db) (init-tools) @@ -74,6 +76,7 @@ ((equal? (car args) "-d") (loop (cdr args) (cons '(--debug . #t) opts))) ((equal? (car args) "--tui") (loop (cdr args) (cons '(--tui . #t) opts))) ((equal? (car args) "--no-tui") (loop (cdr args) (cons '(--no-tui . #t) opts))) + ((equal? (car args) "--no-mcp") (loop (cdr args) (cons '(--no-mcp . #t) opts))) ((equal? (car args) "--verbose") (loop (cdr args) (cons '(--verbose . #t) opts))) ((and (equal? (car args) "--model") (pair? (cdr args))) (loop (cddr args) (cons (cons '--model (cadr args)) opts))) @@ -85,6 +88,8 @@ (loop (cddr args) (cons (cons '--provider (cadr args)) opts))) (else (cons (cons '-- args) (reverse opts)))))) +(def *no-mcp* #f) + (def (init-tools) ;; Register local tools (fast, no I/O) (init-file-tools) @@ -93,10 +98,10 @@ (init-batch-tool) (init-git-tools) ;; External servers in parallel (spawn subprocesses, handshake) - (let ((t-mcp (spawn init-mcp-tools)) + (let ((t-mcp (and (not *no-mcp*) (spawn init-mcp-tools))) (t-lsp (spawn init-lsp-tools)) (t-plugins (spawn init-plugins))) - (thread-join! t-mcp) + (when t-mcp (thread-join! t-mcp)) (thread-join! t-lsp) (thread-join! t-plugins))) @@ -116,6 +121,7 @@ OPTIONS: -p, --provider Provider to use (default: anthropic) --tui Launch terminal UI mode --no-tui Force line-mode REPL (default) + --no-mcp Skip MCP server initialization --verbose Log TUI events to ~/jcode.log COMMANDS: --- a/src/jcode/ui/tui-ffi.ss +++ b/src/jcode/ui/tui-ffi.ss @@ -61,14 +61,21 @@ ;; ---- Load shared library ---- (def _shim-loaded - (or (guard (e [#t #f]) - (load-shared-object "jcode_tui_shim.dylib")) - (guard (e [#t #f]) - (load-shared-object "jcode_tui_shim.so")) - (guard (e [#t #f]) - (load-shared-object - (path-join (path-directory (car (command-line))) "jcode_tui_shim.dylib"))) - #f)) + (let ((try-load (lambda (p) + (guard (e [#t #f]) + (and (file-exists? p) + (load-shared-object p)))))) + (or (try-load "jcode_tui_shim.dylib") + (try-load "jcode_tui_shim.so") + ;; Next to the binary + (try-load (path-join (path-directory (car (command-line))) "jcode_tui_shim.dylib")) + (try-load (path-join (path-directory (car (command-line))) "jcode_tui_shim.so")) + ;; ~/.local/bin (common install location) + (try-load (path-join (getenv "HOME") ".local" "bin" "jcode_tui_shim.dylib")) + ;; vendor dir (development) + (try-load "vendor/termbox2/jcode_tui_shim.dylib") + (try-load "vendor/termbox2/jcode_tui_shim.so") + #f))) ;; Safe FFI binding — returns error-raising lambda if symbol not found (defrule (define-tb name c-name arg-types ret-type)