| (defpackage #:nekod.cli
|
| (:use #:cl #:nekod #:nekod.docker #:nekod.moe #:nekod.llm2asm)
|
| (:export #:neko-main))
|
|
|
| (in-package #:nekod.cli)
|
|
|
|
|
|
|
|
|
|
|
| (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)))))
|
|
|
|
|
|
|
| (defun print-usage ()
|
| (format t "~&neko -- Nekomata container engine~%")
|
| (format t "~%Usage: neko <command> [args]~%")
|
| (format t "~%Container commands:~%")
|
| (format t " run <spec-file> Run containers from s-expression spec file~%")
|
| (format t " ps List running containers~%")
|
| (format t " inspect <name> Inspect a running container~%")
|
| (format t "~%Intent commands:~%")
|
| (format t " intent <string> Compile NL intent string to ASM and execute~%")
|
| (format t " compile <string> Compile NL intent to ASM, show bytes only~%")
|
| (format t "~%Policy commands:~%")
|
| (format t " policy list List active policies~%")
|
| (format t " policy check <p1> <p2> 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 <id> Restore a state snapshot~%")
|
| (format t " repl Enter the infrastructure REPL~%")
|
| (format t " version Show Nekomata version~%"))
|
|
|
|
|
|
|
| (defun cmd-run (args)
|
| "Run containers from a spec file."
|
| (when (null args)
|
| (format t "Usage: neko run <spec-file>~%")
|
| (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 <name-or-id>~%")
|
| (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)))))
|
|
|
|
|
|
|
| (defun cmd-intent (args)
|
| "Compile and execute a natural language intent."
|
| (when (null args)
|
| (format t "Usage: neko intent <string>~%")
|
| (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 <string>~%")
|
| (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)))))
|
|
|
|
|
|
|
| (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 <policy1> <policy2>~%")
|
| (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)))))
|
|
|
|
|
|
|
| (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.~%"))))))
|
|
|
|
|
|
|
| (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 <id>~%")
|
| (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)))))
|
|
|
|
|
|
|
| (defun cmd-version ()
|
| (format t "Nekomata ~a~%" nekod:*nekomata-version*)
|
| (format t "Common Lisp: ~a ~a~%"
|
| (lisp-implementation-type)
|
| (lisp-implementation-version)))
|
|
|