tools: add repl-block, check-tangle; move existing tools into memex

New tools (projects/<tool>/ — standalone, git-committed):
- repl-block: extract and pipe lisp blocks from org files to the REPL
- check-tangle: tangle + compile in one step, reports errors

Existing tools moved from ~/.opencode/bin/ into memex (survives reinstalls):
- repl, tangle, org-eval, verify-repl

AGENTS.md updated:
- Tool reference table with all 7 tools
- Package reference table for passepartout and cl-tty
- Updated tangle command to use project-local tools

.opencode/commands/ added: check-parens, repl-block, check-tangle commands
This commit is contained in:
2026-05-13 12:54:38 -04:00
parent b0b9a25fb3
commit c9cc874e53
10 changed files with 526 additions and 4 deletions

74
projects/repl-tool/repl Executable file
View File

@@ -0,0 +1,74 @@
#!/usr/bin/env perl
# repl — evaluate Lisp forms against the running Passepartout daemon
# Usage: repl <lisp-form>
# or: echo '<lisp-form>' | repl
#
# Connects to the daemon on 127.0.0.1:9105, sends a repl-eval request
# via the framed TCP protocol, reads and prints the response.
use strict;
use warnings;
use IO::Socket::INET;
my $HOST = $ENV{PASSEPARTOUT_HOST} || "127.0.0.1";
my $PORT = $ENV{PASSEPARTOUT_PORT} || "9105";
my $TIMEOUT = $ENV{PASSEPARTOUT_REPL_TIMEOUT} || 10;
my $expr = join(" ", @ARGV);
if (!$expr) {
$expr = do { local $/; <STDIN> };
}
chomp($expr);
# Quote the expression for embedding in a Lisp string
$expr =~ s/\\/\\\\/g; # backslash → doubled
$expr =~ s/"/\\"/g; # " → \"
if (!$expr) {
die "Usage: repl <lisp-form>\n or: echo '(+ 1 2)' | repl\n";
}
my $sock = IO::Socket::INET->new(
PeerHost => $HOST,
PeerPort => $PORT,
Proto => "tcp",
Timeout => 2
) or die "Cannot connect to $HOST:$PORT: $!\n";
sub read_frame {
my ($sock) = @_;
my $hex;
$sock->read($hex, 6) or return undef;
my $len = hex($hex);
my $content;
$sock->read($content, $len);
return $content;
}
sub write_frame {
my ($sock, $content) = @_;
my $len = sprintf("%06X", length($content));
$sock->send($len . $content);
}
# Read handshake (discard)
my $handshake = read_frame($sock);
# Build framed message
my $msg = '(:TYPE :EVENT :PAYLOAD (:SENSOR :repl-eval :CODE "' . $expr . '"))';
write_frame($sock, $msg);
# Read response
my $response = read_frame($sock);
if ($response) {
if ($response =~ /:VALUE "([^"]*)"/s) {
print "$1\n";
} elsif ($response =~ /:message "([^"]*)"/s) {
print STDERR "$1\n";
exit 1;
} else {
print "Response: $response\n";
}
} else {
print STDERR "No response from daemon (is it running on $HOST:$PORT?)\n";
exit 1;
}
$sock->close();