(in-package :opencortex) (defstruct skill "Represents a hot-reloadable module of intelligence or actuation." name priority dependencies trigger-fn probabilistic-prompt deterministic-fn) (defmacro defskill (name &key (priority 0) dependencies trigger probabilistic deterministic) "Registers a new skill into the global harness registry." `(setf (gethash (string-downcase (string ',name)) *skills-registry*) (make-skill :name (string-downcase (string ',name)) :priority ,priority :dependencies ,dependencies :trigger-fn ,trigger :probabilistic-prompt ,probabilistic :deterministic-fn ,deterministic))) (defun validate-lisp-syntax (file-path) "Parses a Lisp file without evaluation to verify syntactic integrity." (handler-case (with-open-file (stream file-path) (loop for form = (read stream nil :eof) until (eq form :eof)) t) (error (c) (harness-log "SYNTAX ERROR in ~a: ~a" file-path c) nil))) (defun load-skill-from-org (org-file-path) "Tangles and loads a single Org-mode skill file." (let* ((filename (file-name-nondirectory (namestring org-file-path))) (skill-id (pathname-name org-file-path)) (lisp-file (merge-pathnames (concatenate 'string "library/gen/" skill-id ".lisp") (asdf:system-source-directory :opencortex)))) (ensure-directories-exist lisp-file) (harness-log "LOADER: Loading ~a..." skill-id) ;; 1. Tangle the Org file into Lisp (uiop:run-program (list "emacs" "--batch" "--eval" "(require 'org)" "--eval" (format nil "(org-babel-tangle-file \"~a\")" org-file-path)) :output t) ;; 2. Verify and Load (if (validate-lisp-syntax lisp-file) (progn (handler-case (load lisp-file) (error (c) (harness-log "LOADER ERROR in skill '~a': ~a" skill-id c))) t) nil))) (defun topological-sort-skills (skills) "Calculates the correct loading order based on #+DEPENDS_ON metadata." ;; Placeholder: Currently sorts by priority as a proxy for dependencies. (sort skills #'> :key #'skill-priority)) (defun initialize-all-skills () "Discovers and loads all Org files in the SKILLS_DIR." (let* ((skills-dir (uiop:getenv "SKILLS_DIR")) (files (when (and skills-dir (uiop:directory-exists-p skills-dir)) (uiop:directory-files skills-dir "*.org")))) (dolist (f files) (load-skill-from-org f)) (harness-log "LOADER: Boot Complete. [Ready: ~a] [Failed: 0]" (hash-table-count *skills-registry*)))) (defun find-triggered-skill (context) "Iterates through the registry and returns the first skill whose trigger returns true." (let ((skills nil)) (maphash (lambda (name skill) (declare (ignore name)) (push skill skills)) *skills-registry*) (setf skills (sort skills #'> :key #'skill-priority)) (dolist (s skills) (let ((trigger (skill-trigger-fn s))) (when (and trigger (funcall trigger context)) (return-from find-triggered-skill s)))) nil))