(defpackage #:nekod.cli (:use #:cl #:nekod #:nekod.docker #:nekod.moe #:nekod.llm2asm) (:export #:neko-main)) (in-package #:nekod.cli) ;; neko -- Nekomata CLI ;; Thin wrapper over the Nekomata core. All commands end up as ;; function calls into the live Lisp image. (defun neko-main () "neko CLI entry point." (let ((args (uiop:command-line-arguments))) (cond ((null args) (print-usage)) ((string= (first args) "run") (cmd-run (rest args))) ((string= (first args) "ps") (cmd-ps)) ((string= (first args) "inspect") (cmd-inspect (rest args))) ((string= (first args) "intent") (cmd-intent (rest args))) ((string= (first args) "compile") (cmd-compile (rest args))) ((string= (first args) "policy") (cmd-policy (rest args))) ((string= (first args) "evolve") (cmd-evolve (rest args))) ((string= (first args) "snap") (cmd-snap (rest args))) ((string= (first args) "repl") (nekod:nekod-repl)) ((string= (first args) "version") (cmd-version)) (t (format t "Unknown command: ~a~%" (first args)) (print-usage) (uiop:quit 1))))) ;; ---- Help ------------------------------------------------------------------- (defun print-usage () (format t "~&neko -- Nekomata container engine~%") (format t "~%Usage: neko [args]~%") (format t "~%Container commands:~%") (format t " run Run containers from s-expression spec file~%") (format t " ps List running containers~%") (format t " inspect Inspect a running container~%") (format t "~%Intent commands:~%") (format t " intent Compile NL intent string to ASM and execute~%") (format t " compile Compile NL intent to ASM, show bytes only~%") (format t "~%Policy commands:~%") (format t " policy list List active policies~%") (format t " policy check Check if two policies conflict~%") (format t "~%System commands:~%") (format t " evolve [N] Run N evolutionary generations (default: 1)~%") (format t " snap save [label] Save a state snapshot~%") (format t " snap list List saved snapshots~%") (format t " snap restore Restore a state snapshot~%") (format t " repl Enter the infrastructure REPL~%") (format t " version Show Nekomata version~%")) ;; ---- Container commands ----------------------------------------------------- (defun cmd-run (args) "Run containers from a spec file." (when (null args) (format t "Usage: neko run ~%") (uiop:quit 1)) (let ((spec-file (first args))) (unless (probe-file spec-file) (format t "Error: file not found: ~a~%" spec-file) (uiop:quit 1)) (format t "Loading spec: ~a~%" spec-file) (load spec-file) (let ((registered (nekod:list-registered))) (format t "Registered containers: ~{~a~^, ~}~%" registered) (dolist (name registered) (let ((spec (nekod:lookup-container name))) (when spec (handler-case (let ((id (nekod.docker:create-container spec))) (nekod.docker:start-container id) (format t " Started ~a (~a)~%" name id)) (error (e) (format t " Failed ~a: ~a~%" name e))))))))) (defun cmd-ps () "List running containers." (handler-case (let ((containers (nekod.docker:list-containers))) (if (null containers) (format t "No containers running.~%") (progn (format t "~%~16a ~30a ~10a~%" "CONTAINER ID" "IMAGE" "STATUS") (format t "~a~%" (make-string 60 :initial-element #\-)) (dolist (c containers) (format t "~16a ~30a ~10a~%" (or (cdr (assoc "Id" c :test #'string=)) "?") (or (cdr (assoc "Image" c :test #'string=)) "?") (or (cdr (assoc "State" c :test #'string=)) "?")))))) (error (e) (format t "Error listing containers: ~a~%" e)))) (defun cmd-inspect (args) "Inspect a running container." (when (null args) (format t "Usage: neko inspect ~%") (uiop:quit 1)) (let ((name (first args))) (handler-case (let ((info (nekod.docker:inspect-container name))) (format t "~a~%" info)) (error (e) (format t "Error inspecting ~a: ~a~%" name e))))) ;; ---- Intent commands -------------------------------------------------------- (defun cmd-intent (args) "Compile and execute a natural language intent." (when (null args) (format t "Usage: neko intent ~%") (format t "Example: neko intent deploy the api server~%") (uiop:quit 1)) (let ((intent-string (format nil "~{~a~^ ~}" args))) (format t "~%Intent: ~s~%" intent-string) (multiple-value-bind (bytes ast reason) (nekod.llm2asm:safe-compile-intent intent-string) (if bytes (progn (format t "AST type: ~a~%" (nekod.llm2asm:infra-ast-type ast)) (format t "AST target: ~a~%" (nekod.llm2asm:infra-ast-target ast)) (format t "Byte count: ~a~%" (length bytes)) (format t "Bytes: ~{#x~2,'0x~^ ~}~%" (coerce bytes 'list)) (format t "~%JIT-linking...~%") (nekod.llm2asm:jit-link bytes (nekod.llm2asm:infra-ast-target ast)) (format t "Executed.~%")) (format t "Compile failed: ~a~%" reason))))) (defun cmd-compile (args) "Compile a natural language intent to ASM bytes (no execution)." (when (null args) (format t "Usage: neko compile ~%") (uiop:quit 1)) (let ((intent-string (format nil "~{~a~^ ~}" args))) (format t "~%Intent: ~s~%" intent-string) (multiple-value-bind (bytes ast reason) (nekod.llm2asm:safe-compile-intent intent-string) (if bytes (progn (format t "AST type: ~a~%" (nekod.llm2asm:infra-ast-type ast)) (format t "Byte count: ~a~%" (length bytes)) (format t "~%Hex dump:~%") (loop for i from 0 below (length bytes) do (format t "~2,'0x " (aref bytes i)) (when (= (mod (1+ i) 16) 0) (format t "~%"))) (format t "~%")) (format t "Compile failed: ~a~%" reason))))) ;; ---- Policy commands -------------------------------------------------------- (defun cmd-policy (args) "Policy management commands." (let ((sub (first args)) (rest-args (rest args))) (cond ((or (null sub) (string= sub "list")) (format t "Active policies: (policy engine not yet wired to CLI)~%")) ((string= sub "check") (when (< (length rest-args) 2) (format t "Usage: neko policy check ~%") (uiop:quit 1)) (format t "Policy conflict check: ~a vs ~a~%" (first rest-args) (second rest-args)) (format t "(Policy conflict detection: load the regex-math module)~%")) (t (format t "Unknown policy sub-command: ~a~%" sub) (uiop:quit 1))))) ;; ---- Evolutionary commands -------------------------------------------------- (defun cmd-evolve (args) "Run evolutionary optimization." (let ((n (if args (parse-integer (first args) :junk-allowed t) 1))) (format t "Running ~a evolutionary generation~p...~%" n n) (when (fboundp 'nekod.selfmod:evolve) (let ((pop (symbol-value 'nekod.selfmod:*population*)) (telemetry (list :uptime 0.9 :cpu 0.4 :memory 0.3))) (if pop (let ((new-pop (nekod.selfmod:evolve pop telemetry))) (setf (symbol-value 'nekod.selfmod:*population*) new-pop) (format t "Generation ~a complete. Population: ~a~%" (symbol-value 'nekod.selfmod:*generation*) (length new-pop))) (format t "Population is empty. Load container specs first.~%")))))) ;; ---- Snapshot commands ------------------------------------------------------ (defun cmd-snap (args) "State snapshot management." (let ((sub (first args)) (rest-args (rest args))) (cond ((or (null sub) (string= sub "list")) (if (fboundp 'nekod.selfmod:list-snapshots) (let ((snaps (nekod.selfmod:list-snapshots))) (if snaps (dolist (s snaps) (format t " ~a: gen ~a, ~a containers~%" (getf s :id) (getf s :generation) (getf s :containers))) (format t "No snapshots.~%"))) (format t "(selfmod not loaded)~%"))) ((string= sub "save") (let ((label (or (first rest-args) "manual"))) (if (fboundp 'nekod.selfmod:capture-state) (let ((id (nekod.selfmod:capture-state (list :label label)))) (format t "Saved snapshot ~a (~s)~%" id label)) (format t "(selfmod not loaded)~%")))) ((string= sub "restore") (when (null rest-args) (format t "Usage: neko snap restore ~%") (uiop:quit 1)) (let ((id (parse-integer (first rest-args) :junk-allowed t))) (if (fboundp 'nekod.selfmod:restore-state) (nekod.selfmod:restore-state id) (format t "(selfmod not loaded)~%")))) (t (format t "Unknown snap sub-command: ~a~%" sub) (uiop:quit 1))))) ;; ---- Version ---------------------------------------------------------------- (defun cmd-version () (format t "Nekomata ~a~%" nekod:*nekomata-version*) (format t "Common Lisp: ~a ~a~%" (lisp-implementation-type) (lisp-implementation-version)))