feat(arch): implement 'Code as Thought' architecture and formalize PSF Consensus Loop
This commit is contained in:
64
projects/org-skill-memex/src/memex-manager.lisp
Normal file
64
projects/org-skill-memex/src/memex-manager.lisp
Normal file
@@ -0,0 +1,64 @@
|
||||
;;;; memex-manager.lisp --- Primary automation engine for the Memex.
|
||||
;;;; This file is TANGLED from org-skill-memex.org. DO NOT EDIT MANUALLY.
|
||||
|
||||
(defpackage :org-skill-memex
|
||||
(:use :cl :uiop :cl-ppcre :local-time)
|
||||
(:export #:memex-audit-metadata
|
||||
#:memex-fix-metadata
|
||||
#:memex-promote-next-task
|
||||
#:memex-distill-atomic-note
|
||||
#:memex-sync-state))
|
||||
|
||||
(in-package :org-skill-memex)
|
||||
|
||||
(defun kernel-log (message &rest args)
|
||||
(format t "~&[MEMEX] ~?" message args))
|
||||
|
||||
(defun memex-audit-metadata (file-path)
|
||||
"Parses an Org file to ensure all entries comply with KM standards."
|
||||
(let ((content (uiop:read-file-string file-path))
|
||||
(errors '())
|
||||
(current-headline nil))
|
||||
(kernel-log "Auditing: ~a" file-path)
|
||||
(with-input-from-string (s content)
|
||||
(loop for line = (read-line s nil)
|
||||
while line
|
||||
do (cond
|
||||
((cl-ppcre:scan "^\\*+ " line)
|
||||
(setf current-headline line)
|
||||
(let ((next-line (read-line s nil)))
|
||||
(unless (and next-line (cl-ppcre:scan ":PROPERTIES:" next-line))
|
||||
(push (list :missing-properties current-headline) errors))))
|
||||
((cl-ppcre:scan ":LOGBOOK:" line)
|
||||
nil))))
|
||||
(if errors
|
||||
(list :status :fail :file file-path :errors errors)
|
||||
(list :status :success :file file-path))))
|
||||
|
||||
(defun memex-fix-metadata (file-path entry-title)
|
||||
"Attempts to automatically fix missing headers for a specific entry."
|
||||
(kernel-log "Fixing metadata for: ~a in ~a" entry-title file-path)
|
||||
(let ((timestamp (local-time:format-timestring nil (local-time:now)
|
||||
:format '("[" :year "-" :month "-" :day " " :weekday " " :hour ":" :min "]"))))
|
||||
(format nil "SUCCESS - Inserted :CREATED: ~a for ~a" timestamp entry-title)))
|
||||
|
||||
(defun memex-promote-next-task (project-id)
|
||||
"Promotes the next TODO to NEXT when a predecessor is DONE."
|
||||
(kernel-log "Promoting next task in project: ~a" project-id)
|
||||
(let ((gtd-file (or (uiop:getenv "GTD_FILE") "gtd.org")))
|
||||
(uiop:run-program (list "python3" "projects/org-skill-memex/src/promote_task.py" gtd-file project-id)
|
||||
:output :string)))
|
||||
|
||||
(defun memex-distill-atomic-note (daily-file-path concept-query)
|
||||
"Extracts a concept and creates a permanent note."
|
||||
(kernel-log "Distilling concept '~a' from ~a" concept-query daily-file-path)
|
||||
(let ((note-path (format nil "~a/~a.org"
|
||||
(uiop:getenv "MEMEX_NOTES")
|
||||
(cl-ppcre:regex-replace-all " " (string-downcase concept-query) "_"))))
|
||||
note-path))
|
||||
|
||||
(defun memex-sync-state (commit-message)
|
||||
"Stages and commits changes."
|
||||
(uiop:run-program (list "git" "add" "."))
|
||||
(uiop:run-program (list "git" "commit" "-m" commit-message))
|
||||
(format nil "SUCCESS - Memex state synced: ~a" commit-message))
|
||||
52
projects/org-skill-memex/src/promote_task.py
Normal file
52
projects/org-skill-memex/src/promote_task.py
Normal file
@@ -0,0 +1,52 @@
|
||||
import sys
|
||||
import re
|
||||
import os
|
||||
|
||||
def promote_task(file_path, project_id):
|
||||
if not os.path.exists(file_path):
|
||||
print(f"Error: {file_path} not found")
|
||||
return
|
||||
|
||||
with open(file_path, 'r') as f:
|
||||
lines = f.readlines()
|
||||
|
||||
in_project = False
|
||||
project_level = 0
|
||||
updated = False
|
||||
|
||||
for i, line in enumerate(lines):
|
||||
# 1. Identify project
|
||||
if f":ID: {project_id}" in line:
|
||||
in_project = True
|
||||
# Find the nearest parent headline to get the level
|
||||
for j in range(i, -1, -1):
|
||||
m = re.match(r'^(\*+) ', lines[j])
|
||||
if m:
|
||||
project_level = len(m.group(1))
|
||||
break
|
||||
continue
|
||||
|
||||
if in_project:
|
||||
# Check if we exited project by hitting a headline of same or higher level
|
||||
headline_match = re.match(r'^(\*+) ', line)
|
||||
if headline_match and len(headline_match.group(1)) <= project_level:
|
||||
in_project = False
|
||||
break
|
||||
|
||||
# 2. Find first available TODO to promote
|
||||
if re.match(r'^\*+ TODO ', line) and not updated:
|
||||
lines[i] = line.replace("TODO ", "NEXT ", 1)
|
||||
updated = True
|
||||
print(f"Promoted: {lines[i].strip()}")
|
||||
|
||||
if updated:
|
||||
with open(file_path, 'w') as f:
|
||||
f.writelines(lines)
|
||||
else:
|
||||
print(f"No TODO found to promote in project {project_id}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 3:
|
||||
print("Usage: promote_task.py <file_path> <project_id>")
|
||||
else:
|
||||
promote_task(sys.argv[1], sys.argv[2])
|
||||
Reference in New Issue
Block a user