RELEASE: Final semantic reorganization and artifact cleanup v0.1.0
Some checks failed
Deploy-Agent-V15-Stdin / JOB-V15-STDIN (push) Failing after 3s

- Moved Docker assets to infrastructure/docker.
- Purged dated/redundant docs and non-literated scripts.
- Renamed legacy test artifacts.
- Consolidated empty infrastructure targets.
This commit is contained in:
2026-04-21 13:12:13 -04:00
parent 8e48d057fa
commit f0d27ac9f3
14 changed files with 25 additions and 570 deletions

View File

@@ -1,32 +0,0 @@
FROM debian:bullseye-slim
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y \
sbcl \
emacs-nox \
curl \
git \
socat \
netcat-openbsd \
libssl-dev \
libncurses5-dev \
libffi-dev \
zlib1g-dev \
libsqlite3-dev \
&& rm -rf /var/lib/apt/lists/*
# Install Quicklisp
RUN curl -O https://beta.quicklisp.org/quicklisp.lisp \
&& sbcl --non-interactive --load quicklisp.lisp --eval "(quicklisp-quickstart:install)" --eval "(ql-util:without-prompting (ql:add-to-init-file))" \
&& rm quicklisp.lisp
WORKDIR /app
COPY . .
# Initialize system in non-interactive mode
RUN mkdir -p /root/memex /app/environment/logs && ./opencortex.sh setup --non-interactive
EXPOSE 9105
CMD ["./opencortex.sh", "boot"]

View File

@@ -1,93 +0,0 @@
#+TITLE: OpenCortex MVP (v0.1.0) Specification & Release Plan
#+STARTUP: content
* Objective
Define detailed specifications for the OpenCortex MVP (v0.1.0). This MVP establishes the autonomous foundation and introduces a native Common Lisp Terminal User Interface (TUI) for improved UX, alongside a comprehensive release plan.
* 1. Core Architecture & Environment (Completed)
- *System Harness:* A minimal, un-brittle Common Lisp (SBCL) microkernel that orchestrates the Perceive -> Probabilistic -> Deterministic -> Dispatch pipeline.
- *Dual-Engine Cognition:*
- /Probabilistic Engine:/ The LLM gateway handling semantic translation, multi-modal ingestion, and intent parsing (supporting Anthropic, Gemini, Groq, OpenAI, and Ollama).
- /Deterministic Engine:/ The Lisp logical core that mathematically verifies LLM-proposed actions against system rules prior to execution.
- *Data Stores:*
- /Linguistic Substrate:/ Org-mode plaintext files acting as the universal Abstract Syntax Tree (AST) for both humans and the agent.
- /Lisp Memory:/ A live, threaded graph of Lisp objects representing the Memex in RAM for instant, token-efficient traversal (Sparse Trees).
- *Skill Architecture:* All agent capabilities are encapsulated in single-file Literate Programs (~org-skill-*.org~). They are topologically loaded, dynamically compiled, and hot-reloadable.
* 2. Mandatory Security & Containment (Completed)
- *Formal Verification Gate:* Evaluates actions before they hit the OS.
- /Path Confinement:/ Guarantees file writes are physically locked to the `~/memex/` root directory.
- /Network Exfiltration:/ Intercepts and blocks unauthorized external generic HTTP or socket requests.
- *System Policy Gate:* Enforces the "Zero-Bloat" and "Autonomy Above All" invariants.
- *Credentials Vault:* API keys and ~.env~ files are stored in a secure, masked Lisp enclave, rendering them invisible to the LLM's context window.
* 3. Autonomous Background Workers (Completed)
- *The Scribe (~org-skill-scribe.org~):* A distillation engine that periodically reads the chronological logs (e.g., daily journal files) and autonomously extracts concepts into permanent Zettelkasten notes.
- *The Gardener (~org-skill-gardener.org~):* A heartbeat-driven, idle process that continuously walks the memory graph. It automatically repairs broken internal links, infers missing metadata, and flags orphaned ideas for the user.
* 4. Native Terminal User Interface (UX Target)
- *Objective:* Eliminate raw ~stdout~ shell piping in favor of a rich, structured, and interactive Common Lisp TUI.
- *Library:* ~croatoan~ (A high-level CLOS wrapper for ncurses) will be used for rapid, robust UI development.
- *Layout:*
- /Main Viewport:/ A read-only, scrollable panel that renders Org-mode headlines, syntax-highlighted Lisp/Python code blocks, and system logs.
- /Input Box:/ A fixed, multi-line input area pinned to the bottom of the screen, supporting standard Readline keybindings.
- /Status Bar:/ A persistent bar at the top or bottom displaying the health and current activity of background workers (Scribe/Gardener) and memory usage.
- *Interactive Control (Slash Commands):*
- ~/help~: View system overview and command syntax.
- ~/clear~: Clear the viewport buffer.
- ~/skill-load <skill-name>~: Dynamically reload a modified Lisp skill into the active image.
- ~/exit~: Gracefully shut down the harness and exit the environment.
- ~/status~: Print diagnostic report (memory, git status, worker uptimes).
- ~/config~: Display active config/env vars (masking secrets).
- ~/search <query>~: Raw deterministic regex/vector search across the Memex.
- ~/commit~: Trigger Engineering Standard check, stage, and commit Memex state.
- *Refactoring:* Reroute the existing ~:cli~ actuator and inbound gateway to exclusively utilize the new TUI rendering engine.
* 5. Release & Publication Plan (v0.1.0)
- *Documentation:*
- ~USER_MANUAL.md~: A comprehensive guide on the one-liner installation (~opencortex.sh~), daily workflow, and navigating the Memex directory structure.
- ~CONTRIBUTING.md~: A guide to "Literate Granularity" engineering standards and creating new ~org-skill-*.org~ files.
- *Legal Finalization:*
- Assign the *AGPLv3* open-source license.
- Implement a broad *Contributor License Agreement (CLA)* process for external contributors to license rights back to the core project.
- Update ~LICENSE~ and finalize ~CHANGELOG.org~.
- *End-to-End Walkthrough:* Execute a clean-slate test of the installation script, boot sequence, environment variable parsing, and autonomous background worker triggers.
- *Marketing & Launch:* Migrate the canonical repository to GitHub (configure topics, badges, and issue templates). Record a high-fidelity GIF/video of the new TUI interaction and execute announcements on Hacker News, Reddit, and X/Twitter.
* 6. User-Centric End-to-End Test Plan
This section defines the precise workflow and expected user experience for the v0.1.0 MVP. It serves as the definitive manual testing script before release.
** Phase 1: The One-Liner Installation & Boot
- *Action:* The user executes the canonical curl-bash script: ~curl -fsSL https://raw.githubusercontent.com/gharbeia/opencortex/main/opencortex.sh | bash~
- *Expected Experience:*
1. The script detects the OS and installs any missing system dependencies (e.g., Docker, SBCL, Quicklisp).
2. It interactively prompts the user to enter as many LLM API keys as they choose to (e.g., Gemini, Anthropic, OpenAI). The user can skip this step and configure them later.
3. It asks the user for their existing folder structure and fills in the corresponding values (INBOX_DIR, DAILY_DIR, etc.) in ~.env.example~ to generate a valid ~.env~ file.
4. It compiles and launches the ~opencortex-server~ daemon in the background.
5. The user is greeted with a success message instructing them to run ~opencortex tui~.
** Phase 2: First Contact (The TUI Experience)
- *Action:* The user types ~opencortex tui~ in their terminal.
- *Expected Experience:*
1. The terminal clears and launches the Croatoan UI.
2. The *Status Bar* appears at the bottom, indicating: ~[Scribe: Idle] [Gardener: Sleeping]~.
3. The user types a natural language message in the input box: "Hello, what is my current Memex structure?" and presses Enter.
4. The input box clears, and the user's message appears in the main viewport.
5. A few seconds later, the agent responds with a formatted Org-mode list of the directories, demonstrating successful Lisp s-expression communication over the TCP socket and valid probabilistic reasoning.
** Phase 3: The Autonomous Subroutines
- *Action:* The user creates a messy text file in ~/memex/daily/YYYY-MM-DD.org~ with a scattered thought about a new project, then waits.
- *Expected Experience:*
1. Without any user prompting, the *Status Bar* updates to ~[Scribe: Distilling...]~.
2. A quiet log message appears in the TUI viewport: ~*System*: Scribe extracted 1 new Zettelkasten note.~
3. The user inspects ~/memex/notes/~ and finds a cleanly formatted, semantically tagged Org node containing the distilled thought.
4. The user intentionally breaks an Org-roam link in one of their notes. Minutes later, the Gardener awakens (~[Gardener: Auditing]~), and a log message appears indicating the link was repaired or flagged.
** Phase 4: Deterministic Actuation (Slash Commands)
- *Action:* The user types ~/status~ in the TUI.
- *Expected Experience:* The TUI instantly prints a diagnostic report showing memory usage, uptime, and git status, bypassing the LLM entirely.
- *Action:* The user types ~/commit~.
- *Expected Experience:* The system runs the Engineering Standard gate, stages all changes in ~/memex~, and creates a git commit. The TUI confirms success.
- *Action:* The user types ~/exit~.
- *Expected Experience:* The TUI client gracefully disconnects and closes, returning the user to their standard bash prompt. The ~opencortex-server~ continues running safely in the background.

View File

@@ -1,46 +0,0 @@
#+TITLE: v0.1.0 Launch & Marketing Plan
#+AUTHOR: Amr
#+FILETAGS: :marketing:release:autonomy:
#+STARTUP: content
* Overview
With the v0.1.0 "Autonomous MVP" released, the goal is to leverage GitHub's social graph to build a community of early adopters, contributors, and power users who resonate with the "Thin Harness, Fat Skills" and "Local-First" philosophy.
* 1. Licensing Strategy
Before wide promotion, the project's license must align with its goals.
- **MIT License (Current):** Maximum adoption, frictionless for developers to embed in their own tools. Good for rapid growth.
- **GPLv3 / AGPLv3:** Enforces copyleft. Ensures any modifications or integrations by corporations must remain open-source. Protects the "Autonomous" ethos from proprietary enclosure.
- **Dual Licensing:** Open-source for individuals, commercial license for enterprise usage (if monetization is a future goal).
*Decision Needed:* Do we stick with MIT, or switch to a copyleft license (AGPL) to protect the autonomous nature of the project?
* 2. The GitHub Migration & Setup
To maximize visibility, the repository must be optimized for GitHub's ecosystem.
- [ ] **Mirror/Migrate to GitHub:** Move the primary remote from the self-hosted Gitea to GitHub.
- [ ] **README Optimization:** Add badges (License, Build Status, Version). Ensure the "Zero-to-One" curl command is prominent. Add an architecture diagram (mermaid).
- [ ] **Repository Topics:** Add tags like `common-lisp`, `autonomous-agents`, `org-mode`, `pkm`, `zettelkasten`, `llm`, `local-first`.
- [ ] **Contributing Guide:** Add `CONTRIBUTING.md` to explain the Literate Programming standard and how to add new "Skills".
- [ ] **Issue Templates:** Create templates for "Bug Report" and "Skill Proposal".
* 3. The PR & Social Media Campaign
The narrative: "An autonomous AI agent that doesn't just chat, but lives natively in your Org-mode Memex. No Python glue code, no cloud lock-in—just pure, homoiconic Common Lisp."
** Target Audiences & Channels
1. **The Emacs / Org-mode Community:**
- *Channels:* `r/emacs`, `r/orgmode`, Hacker News (`/r/lisp`), Emacs News.
- *Hook:* "A background daemon that autonomously distills your daily logs into a Zettelkasten using LLMs."
2. **The Local-First / PKM Community:**
- *Channels:* `r/Zettelkasten`, `r/PKM`, Obsidian/Logseq diaspora looking for more power.
- *Hook:* "Own your brain. An AI agent that runs locally on your Markdown/Org files with mathematical security gates."
3. **The AI / Autonomous Agent Hackers:**
- *Channels:* Hacker News (Show HN), Twitter/X (AI tech Twitter).
- *Hook:* "Tired of fragile Python/Playwright agent wrappers? opencortex uses a deterministic Lisp microkernel to formally verify LLM actions before execution."
** Launch Materials
- **Demo Video (2 minutes):** Show the one-liner install, the agent running the `Scribe` skill in the background, and the user querying it via `opencortex chat`.
- **Blog Post / Essay:** "Why we built an Autonomous Agent in Common Lisp." Discuss the fragility of current SOTA (Devin/SWE-agent) and the necessity of the Bouncer/Policy gates.
* 4. Post-Launch Community Engagement
- Encourage "Show and Tell" in GitHub Discussions.
- Create a "Skill Directory" where users can share their custom `.org` skills.
- Actively solicit feedback for the v0.2.0 (Lisp TUI) roadmap.

View File

@@ -1,66 +0,0 @@
#+TITLE: User Experience (UX) Journey
#+AUTHOR: Amr
#+FILETAGS: :ux:design:autonomy:
#+STARTUP: content
* Overview
This document traces the intended User Experience (UX) journey for the ~opencortex~. It serves as a living design document to ensure that architectural decisions align with a frictionless, autonomous, and intuitive user interaction model.
* 1. The Zero-to-One Experience (Onboarding)
** Goal
A user should be able to go from discovering the project to having a running, calibrated agent in under 3 minutes, with zero prerequisite knowledge of Lisp.
** The Appliance Paradigm (Primary Path)
The user runs a single command in their terminal:
#+begin_src bash
curl -fsSL https://raw.githubusercontent.com/gharbeia/opencortex/main/scripts/install.sh | bash
#+end_src
** The Interactive Wizard
The script verifies Docker presence and then launches an interactive prompt before booting the container:
1. *Identity:* "What is your name?" -> Configures ~$MEMEX_USER~
2. *Assistant:* "What shall we name your Assistant?" -> Configures ~$MEMEX_ASSISTANT~
3. *Neural Provider:* "Select your primary neural provider [Gemini/OpenRouter/Anthropic/OpenAI]" -> Configures API Keys.
4. *Data Gravity:* "Where is your Memex located?" -> Maps the host directory to the Docker container.
*Outcome:* The `.env` is generated, core skills are seeded into the user's Memex, and `docker-compose up -d` launches the daemon in the background. The user sees: /"Booting your autonomous brain in the background..."/
* 2. The First Contact (The CLI Gateway)
** Goal
Immediately after boot, the user needs a way to verify the agent is alive and capable of answering questions about their Memex without configuring complex third-party integrations (like Telegram bots).
** The Interaction
The user types a local client command to connect to the background daemon:
#+begin_src bash
opencortex chat
#+end_src
This opens a slick, colorful interactive terminal session:
#+begin_example
> User: Hello, what are my active projects?
> Agent: [Thinking...]
> Agent: You currently have 3 active projects:
> 1. OpenCortex v1.0
> 2. Home Renovation
> 3. Read 'The Autonomous Individual'
#+end_example
** Behind the Scenes
1. The ~opencortex chat~ client connects to the daemon's local port (e.g., 9105).
2. It sends a ~:chat-message~ signal.
3. The core harness routes this to the Probabilistic Engine.
4. The Context Manager retrieves active projects from the Memex AST.
5. The Deterministic Engine (Bouncer) verifies it is a safe read-only action.
6. The ~:cli~ Actuator formats the Lisp response into Markdown and sends it back over the socket.
* 3. The Interactive Refinement (v0.2.0)
** Goal
Transition from a "Verified Wrapper" around netcat to a high-fidelity, native Common Lisp TUI that rivals the experience of ~gemini-cli~.
** Features
- *Homoiconic UI:* The TUI is rendered directly by the Lisp kernel, allowing for live introspection of the agent's thoughts.
- *Rich Formatting:* ANSI colors, bold headers, and syntax-highlighted code blocks.
- *Command Palette:* Slash commands for system control without leaving the chat.
* 4. The Continuous Loop (Daily Usage)
(To be defined as the agent's capabilities expand into Scribe, Gardener, and Emacs-native interactions).

View File

@@ -1,44 +1,32 @@
FROM debian:bookworm-slim
FROM debian:bullseye-slim
# Install SBCL, ripgrep, and build dependencies
RUN apt-get update && \
apt-get install -y sbcl build-essential curl git ripgrep libsqlite3-dev lynx python3 python3-pip && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
ENV DEBIAN_FRONTEND=noninteractive
# Install Quicklisp globally
RUN curl -O https://beta.quicklisp.org/quicklisp.lisp && \
sbcl --non-interactive \
--load quicklisp.lisp \
--eval '(quicklisp-quickstart:install :path "/opt/quicklisp")' \
--eval '(ql-util:without-prompting (ql:add-to-init-file))' && \
rm quicklisp.lisp
RUN apt-get update && apt-get install -y \
sbcl \
emacs-nox \
curl \
git \
socat \
netcat-openbsd \
libssl-dev \
libncurses5-dev \
libffi-dev \
zlib1g-dev \
libsqlite3-dev \
&& rm -rf /var/lib/apt/lists/*
# Install Quicklisp
RUN curl -O https://beta.quicklisp.org/quicklisp.lisp \
&& sbcl --non-interactive --load quicklisp.lisp --eval "(quicklisp-quickstart:install)" --eval "(ql-util:without-prompting (ql:add-to-init-file))" \
&& rm quicklisp.lisp
# Set up the working directory
WORKDIR /app
COPY . .
# Copy source code and system definition
COPY opencortex.asd /app/
COPY src/ /app/src/
# Initialize system in non-interactive mode
RUN mkdir -p /root/memex /app/environment/logs && ./opencortex.sh setup --non-interactive
# Ensure we aren't using a stale binary from the host
RUN rm -f /app/opencortex-server
EXPOSE 9105
# Build the standalone binary natively inside the container
# This ensures GLIBC compatibility with the runtime environment.
RUN sbcl --non-interactive \
--eval '(push "/app/" asdf:*central-registry*)' \
--eval '(ql:quickload :opencortex)' \
--eval '(asdf:make :opencortex)'
# Ensure the binary is executable
RUN chmod +x /app/opencortex-server
# Expose the communication protocol and Web Dashboard ports
EXPOSE 9105 8080
# The app expects the memex to be mounted here
VOLUME /memex
# Run the natively compiled standalone daemon
CMD ["./opencortex-server"]
CMD ["./opencortex.sh", "boot"]

View File

@@ -1,14 +0,0 @@
;; opencortex: Guix Environment Manifest
;; Usage: guix shell -m manifest.scm -- sbcl --eval ...
(specifications->manifest
'("sbcl"
"sbcl-cl-json"
"sbcl-bordeaux-threads"
"sbcl-usocket"
"sbcl-dexador"
"sbcl-cl-ppcre"
"ripgrep"
"git"
"curl"
"sqlite"))

View File

@@ -1,33 +0,0 @@
#+TITLE: LXC / Systemd-nspawn Deployment Guide
#+AUTHOR: opencortex
* Overview
For users who prefer containerization without the overhead or dependency on the Docker daemon, `opencortex` can be run within a standard Linux Container (LXC) or a systemd-nspawn container.
* Systemd-nspawn Setup (Fastest for Linux users)
1. **Create the container root:**
#+begin_src bash
sudo debootstrap --arch=amd64 bookworm /var/lib/machines/opencortex
#+end_src
2. **Start and enter the container:**
#+begin_src bash
sudo systemd-nspawn -D /var/lib/machines/opencortex
#+end_src
3. **Install dependencies (inside container):**
#+begin_src bash
apt-get update && apt-get install -y sbcl curl git ripgrep libsqlite3-dev build-essential
#+end_src
4. **Bind mount the Memex directory:**
Add this to your container startup or use the `--bind` flag:
#+begin_src bash
sudo systemd-nspawn -D /var/lib/machines/opencortex --bind /home/amr/.openclaw/workspace/memex
#+end_src
* Proxmox LXC Setup
1. Create a new LXC container using the Debian 12 template.
2. Ensure the network is bridged so Emacs can reach it.
3. Run the `deploy/bare-metal/install.sh` script inside the container.

View File

@@ -1,22 +0,0 @@
Vagrant.configure("2") do |config|
config.vm.box = "debian/bookworm64"
config.vm.network "forwarded_port", guest: 9105, host: 9105
config.vm.provider "virtualbox" do |vb|
vb.memory = "1024"
vb.cpus = 2
end
config.vm.provision "shell", inline: <<-SHELL
apt-get update
apt-get install -y sbcl curl git ripgrep libsqlite3-dev build-essential
# Setup for opencortex
mkdir -p /home/vagrant/opencortex
cp -r /vagrant/* /home/vagrant/opencortex/
chown -R vagrant:vagrant /home/vagrant/opencortex
# Build binary natively
sudo -u vagrant bash -c "cd /home/vagrant/opencortex && ./deploy/bare-metal/install.sh"
SHELL
end

View File

@@ -1,21 +0,0 @@
Vagrant.configure("2") do |config|
config.vm.box = "fedora/39-cloud-base"
config.vm.network "forwarded_port", guest: 9105, host: 9105
config.vm.provider "virtualbox" do |vb|
vb.memory = "1024"
vb.cpus = 2
end
config.vm.provision "shell", inline: <<-SHELL
dnf install -y sbcl curl git ripgrep sqlite-devel make gcc
# Setup for opencortex
mkdir -p /home/vagrant/opencortex
cp -r /vagrant/* /home/vagrant/opencortex/
chown -R vagrant:vagrant /home/vagrant/opencortex
# Build binary natively
sudo -u vagrant bash -c "cd /home/vagrant/opencortex && ./deploy/bare-metal/install.sh"
SHELL
end

View File

@@ -1,54 +0,0 @@
#!/usr/bin/env python3
import sys
import json
import base64
from playwright.sync_api import sync_playwright
def run_bridge():
# Read command from stdin
try:
raw_input = sys.stdin.read()
if not raw_input:
print(json.dumps({"status": "error", "message": "No input provided"}))
return
args = json.loads(raw_input)
except Exception as e:
print(json.dumps({"status": "error", "message": f"Invalid JSON input: {str(e)}"}))
return
url = args.get("url")
action = args.get("action", "extract_text")
selector = args.get("selector", "body")
if not url:
print(json.dumps({"status": "error", "message": "No URL provided"}))
return
try:
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
# Navigate and wait for network to be idle
page.goto(url, wait_until="networkidle")
result = {"status": "success", "url": url}
if action == "extract_text":
result["content"] = page.inner_text(selector)
elif action == "screenshot":
screenshot_bytes = page.screenshot()
result["screenshot_base64"] = base64.b64encode(screenshot_bytes).decode("utf-8")
else:
result["status"] = "error"
result["message"] = f"Unknown action: {action}"
browser.close()
print(json.dumps(result))
except Exception as e:
print(json.dumps({"status": "error", "message": f"Playwright Error: {str(e)}"}))
if __name__ == "__main__":
run_bridge()

View File

@@ -1,85 +0,0 @@
import pty
import os
import sys
import time
import select
import re
class VirtualTerminal:
def __init__(self, rows=24, cols=80):
self.rows = rows
self.cols = cols
self.buffer = [[' ' for _ in range(cols)] for _ in range(rows)]
self.cursor_y = 0
self.cursor_x = 0
def _strip_ansi(self, text):
# Very basic ANSI parser for cursor moves and clears
# CSI n ; m H (cursor move)
# CSI J (clear screen)
# CSI K (clear line)
# This is a simplified state machine
parts = re.split(r'(\x1b\[[0-9;?]*[a-zA-Z])', text)
for part in parts:
if part.startswith('\x1b['):
cmd = part[-1]
params = part[2:-1].split(';')
if cmd == 'H' or cmd == 'f': # Move cursor
self.cursor_y = int(params[0]) - 1 if params[0] else 0
self.cursor_x = int(params[1]) - 1 if (len(params) > 1 and params[1]) else 0
elif cmd == 'J': # Clear
mode = int(params[0]) if params[0] else 0
if mode == 2: # Full clear
self.buffer = [[' ' for _ in range(self.cols)] for _ in range(self.rows)]
elif cmd == 'm': # Attributes - ignore for now
pass
else:
for char in part:
if char == '\n':
self.cursor_y += 1
self.cursor_x = 0
elif char == '\r':
self.cursor_x = 0
elif 0 <= self.cursor_y < self.rows and 0 <= self.cursor_x < self.cols:
self.buffer[self.cursor_y][self.cursor_x] = char
self.cursor_x += 1
def get_screen(self):
return "\n".join(["".join(row) for row in self.buffer])
def run_test(command, input_sequence, wait_time=5):
pid, fd = pty.fork()
if pid == 0:
os.environ["TERM"] = "xterm"
os.environ["COLUMNS"] = "80"
os.environ["LINES"] = "24"
os.execvp(command[0], command)
else:
vt = VirtualTerminal()
start_time = time.time()
input_sent = False
while time.time() - start_time < wait_time:
r, w, e = select.select([fd], [], [], 0.1)
if fd in r:
try:
data = os.read(fd, 8192).decode(errors='ignore')
vt._strip_ansi(data)
except OSError:
break
if not input_sent and time.time() - start_time > 2:
os.write(fd, input_sequence.encode())
input_sent = True
os.kill(pid, 9)
os.waitpid(pid, 0)
return vt
if __name__ == "__main__":
# Example usage: python3 ui_driver.py sbcl --eval ...
vt = run_test(sys.argv[1:], "Hi\r", wait_time=10)
print("--- VIRTUAL SCREEN SNAPSHOT ---")
print(vt.get_screen())
print(f"--- CURSOR POSITION: ({vt.cursor_y}, {vt.cursor_x}) ---")

View File

@@ -1,67 +0,0 @@
import sys
import os
import time
# Add scripts directory to path to import ui_driver
sys.path.append(os.path.join(os.getcwd(), 'scripts'))
from ui_driver import run_test
def wait_for_brain():
print("[UI TEST] Waiting for Brain to wake up...")
for i in range(60):
if os.path.exists('brain.log'):
with open('brain.log', 'r') as f:
if 'Boot Complete' in f.read():
print("[UI TEST] Brain is Green. Waiting for TCP listener...")
time.sleep(5)
return True
time.sleep(2)
return False
def test_tui_boot_and_input():
if not wait_for_brain():
print("FAIL: Brain failed to boot within timeout.")
return
print("[UI TEST] Launching TUI and sending 'Hi'...")
# We run the TUI script via bash
# Direct SBCL launch to bypass shell script noise
command = ["sbcl", "--disable-debugger",
"--eval", "(load (merge-pathnames \"quicklisp/setup.lisp\" (user-homedir-pathname)))",
"--eval", "(push (truename \"\") asdf:*central-registry*)",
"--eval", "(ql:quickload :opencortex/tui)",
"--eval", "(opencortex.tui:main)"]
vt = run_test(command, "Hi\r", wait_time=15)
screen = vt.get_screen()
# 1. Verify Prompt
if "> Hi" in screen:
print("PASS: Local Echo found in chat history.")
elif ">" in screen:
print("PASS: Input prompt found.")
else:
print("FAIL: No input prompt found.")
# 2. Verify Status Bar
if "[Scribe:" in screen and "Gardener:" in screen:
print("PASS: Status bar rendered correctly.")
else:
print("FAIL: Status bar missing.")
# 3. Verify Cursor Position (should be at the end of the empty prompt after Enter)
# The prompt is line 23 (h-1), col 2 (after "> ")
if vt.cursor_y == 23 and vt.cursor_x == 2:
print(f"PASS: Cursor is correctly pinned to prompt at ({vt.cursor_y}, {vt.cursor_x}).")
else:
print(f"WARN: Cursor at unexpected position ({vt.cursor_y}, {vt.cursor_x}).")
print("\n--- FINAL SCREEN SNAPSHOT ---")
print(screen)
if __name__ == "__main__":
test_tui_boot_and_input()