mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-31 03:05:21 +00:00
- Prover-Integrated Orchestration Layers (L0-L3): Goedel-Prover-V2 watchdog, BFS-Prover-V2 swarm consensus, bf4prover topology adaptation - FAMM Verilator benchmark: uniform vs preshaped delay comparison (4.4x speedup) - Swarm topological device prober: 11 agents probing traces, caps, delays, errors, vias, PDN - Spec sheet puller: 10 components with key params and topological relevance - Virtual FPGA system tests: 6/6 passed, 134K ops/s throughput - Fixed merge conflicts in AI-Newton test_experiment.ipynb
244 lines
8.1 KiB
Python
Executable file
244 lines
8.1 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
"""Native wrapper for the repo-local Substack connector scripts."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import http.server
|
|
import json
|
|
import os
|
|
import shutil
|
|
import socketserver
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
from urllib.parse import quote
|
|
|
|
REPO_ROOT = Path(os.environ.get("RESEARCH_STACK_ROOT", "/home/allaun/Documents/Research Stack"))
|
|
CONNECTOR_DIR = Path(os.environ.get("SUBSTACK_CONNECTOR_DIR", REPO_ROOT / "plugins/substack-connector"))
|
|
PREPARE_SCRIPT = CONNECTOR_DIR / "scripts/prepare_substack_post.py"
|
|
UPDATE_SCRIPT = CONNECTOR_DIR / "scripts/update_existing_post.py"
|
|
SUBSTACK_PYTHON = Path(os.environ.get("SUBSTACK_PYTHON", "/home/allaun/.local/share/substack-env/bin/python"))
|
|
|
|
|
|
def read_metadata(path: Path) -> dict[str, object]:
|
|
metadata: dict[str, object] = {}
|
|
current_list: str | None = None
|
|
if not path.exists():
|
|
return metadata
|
|
|
|
for raw in path.read_text(encoding="utf-8").splitlines():
|
|
line = raw.rstrip()
|
|
if not line or line.lstrip().startswith("#"):
|
|
continue
|
|
if line.startswith(" - ") and current_list:
|
|
metadata.setdefault(current_list, []).append(line[4:].strip().strip('"'))
|
|
continue
|
|
if ":" not in line or line.startswith(" "):
|
|
continue
|
|
key, value = line.split(":", 1)
|
|
key = key.strip()
|
|
value = value.strip()
|
|
if value:
|
|
metadata[key] = value.strip('"')
|
|
current_list = None
|
|
else:
|
|
metadata[key] = []
|
|
current_list = key
|
|
return metadata
|
|
|
|
|
|
def article_dir(path: str) -> Path:
|
|
target = Path(path).expanduser().resolve()
|
|
if target.is_file():
|
|
return target.parent
|
|
return target
|
|
|
|
|
|
def source_markdown(root: Path) -> Path:
|
|
article = root / "article.md"
|
|
if article.exists():
|
|
return article
|
|
bundled = root / "substack_bundle" / "post.md"
|
|
if bundled.exists():
|
|
return bundled
|
|
meta = read_metadata(root / "metadata.yml")
|
|
source = meta.get("source")
|
|
if isinstance(source, str):
|
|
return root / source
|
|
return article
|
|
|
|
|
|
def build(root: Path) -> dict[str, object]:
|
|
src = source_markdown(root)
|
|
if not src.exists():
|
|
raise SystemExit(f"source markdown not found: {src}")
|
|
if not PREPARE_SCRIPT.exists():
|
|
raise SystemExit(f"prepare script not found: {PREPARE_SCRIPT}")
|
|
proc = subprocess.run(
|
|
[sys.executable, str(PREPARE_SCRIPT), str(src)],
|
|
check=False,
|
|
text=True,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.PIPE,
|
|
)
|
|
if proc.returncode != 0:
|
|
if proc.stdout:
|
|
print(proc.stdout, end="")
|
|
if proc.stderr:
|
|
print(proc.stderr, end="", file=sys.stderr)
|
|
raise SystemExit(proc.returncode)
|
|
try:
|
|
manifest = json.loads(proc.stdout)
|
|
except json.JSONDecodeError as exc:
|
|
raise SystemExit(f"prepare script did not emit JSON: {exc}") from exc
|
|
return manifest
|
|
|
|
|
|
def run_check(root: Path) -> int:
|
|
manifest = build(root)
|
|
post_md = Path(str(manifest["post_md"]))
|
|
status = 0
|
|
print(f"==> {post_md}")
|
|
if shutil.which("harper-cli"):
|
|
print("\n-- Harper --")
|
|
status |= subprocess.call(["harper-cli", "lint", "--no-color", "--format", "compact", str(post_md)])
|
|
if shutil.which("vale"):
|
|
print("\n-- Vale --")
|
|
config = find_vale_config(root)
|
|
cmd = ["vale", "--no-wrap", str(post_md)]
|
|
if config:
|
|
cmd.insert(1, f"--config={config}")
|
|
status |= subprocess.call(cmd)
|
|
return status
|
|
|
|
|
|
def find_vale_config(root: Path) -> str | None:
|
|
current = root
|
|
for candidate in [current, *current.parents]:
|
|
config = candidate / ".vale.ini"
|
|
if config.exists():
|
|
return str(config)
|
|
fallback = Path("/usr/share/substack-local-preview/vale.ini")
|
|
if fallback.exists():
|
|
return str(fallback)
|
|
return None
|
|
|
|
|
|
def preview(root: Path, port: int, open_browser: bool) -> int:
|
|
manifest = build(root)
|
|
bundle = Path(str(manifest["bundle_dir"]))
|
|
post_html = Path(str(manifest["post_html"]))
|
|
url = f"http://127.0.0.1:{port}/{quote(post_html.name)}"
|
|
if open_browser and shutil.which("xdg-open"):
|
|
subprocess.Popen(["xdg-open", url], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
|
|
print(f"Serving {bundle}")
|
|
print(f"Preview: {url}")
|
|
os.chdir(bundle)
|
|
with socketserver.TCPServer(("127.0.0.1", port), http.server.SimpleHTTPRequestHandler) as httpd:
|
|
try:
|
|
httpd.serve_forever()
|
|
except KeyboardInterrupt:
|
|
print("\nStopped preview server.")
|
|
return 0
|
|
|
|
|
|
def open_preview(root: Path) -> int:
|
|
manifest = build(root)
|
|
html_path = Path(str(manifest["post_html"]))
|
|
if not shutil.which("xdg-open"):
|
|
print(html_path)
|
|
return 0
|
|
return subprocess.call(["xdg-open", str(html_path)])
|
|
|
|
|
|
def publish_prep(root: Path) -> int:
|
|
status = run_check(root)
|
|
manifest = build(root)
|
|
post_md = Path(str(manifest["post_md"]))
|
|
print("\n==> Publish prep")
|
|
print(f"Title: {manifest['title']}")
|
|
print(f"Markdown: {post_md}")
|
|
print(f"Preview: {manifest['post_html']}")
|
|
copied = copy_to_clipboard(post_md.read_text(encoding="utf-8"))
|
|
if copied:
|
|
print("Copied post Markdown to clipboard.")
|
|
else:
|
|
print("Clipboard helper not found; open post_md manually.")
|
|
print("Open Substack editor, paste Markdown, upload assets if any, then publish manually.")
|
|
return status
|
|
|
|
|
|
def update_remote(root: Path, post_id: int, env_path: Path, publication_url: str, publish: bool) -> int:
|
|
manifest = build(root)
|
|
post_md = Path(str(manifest["post_md"]))
|
|
if not UPDATE_SCRIPT.exists():
|
|
print(f"update script not found: {UPDATE_SCRIPT}", file=sys.stderr)
|
|
return 2
|
|
if not SUBSTACK_PYTHON.exists():
|
|
print(f"Substack Python env not found: {SUBSTACK_PYTHON}", file=sys.stderr)
|
|
return 2
|
|
cmd = [
|
|
str(SUBSTACK_PYTHON),
|
|
str(UPDATE_SCRIPT),
|
|
str(post_md),
|
|
"--post-id",
|
|
str(post_id),
|
|
"--env-path",
|
|
str(env_path),
|
|
"--publication-url",
|
|
publication_url,
|
|
]
|
|
if publish:
|
|
cmd.append("--publish")
|
|
return subprocess.call(cmd)
|
|
|
|
|
|
def copy_to_clipboard(text: str) -> bool:
|
|
if shutil.which("wl-copy"):
|
|
subprocess.run(["wl-copy"], input=text.encode("utf-8"), check=False)
|
|
return True
|
|
if shutil.which("xclip"):
|
|
subprocess.run(["xclip", "-selection", "clipboard"], input=text.encode("utf-8"), check=False)
|
|
return True
|
|
return False
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
sub = parser.add_subparsers(dest="command", required=True)
|
|
for name in ["build", "check", "open", "publish-prep"]:
|
|
p = sub.add_parser(name)
|
|
p.add_argument("article")
|
|
for name in ["update", "publish"]:
|
|
p = sub.add_parser(name)
|
|
p.add_argument("article")
|
|
p.add_argument("--post-id", type=int, required=True)
|
|
p.add_argument("--env-path", type=Path, default=Path.home() / ".substack.env")
|
|
p.add_argument("--publication-url", default="https://froginnponds.substack.com")
|
|
p = sub.add_parser("preview")
|
|
p.add_argument("article")
|
|
p.add_argument("--port", type=int, default=8765)
|
|
p.add_argument("--open", action="store_true")
|
|
args = parser.parse_args()
|
|
root = article_dir(args.article)
|
|
if args.command == "build":
|
|
print(json.dumps(build(root), indent=2))
|
|
return 0
|
|
if args.command == "check":
|
|
return run_check(root)
|
|
if args.command == "open":
|
|
return open_preview(root)
|
|
if args.command == "publish-prep":
|
|
return publish_prep(root)
|
|
if args.command == "update":
|
|
return update_remote(root, args.post_id, args.env_path, args.publication_url, publish=False)
|
|
if args.command == "publish":
|
|
return update_remote(root, args.post_id, args.env_path, args.publication_url, publish=True)
|
|
if args.command == "preview":
|
|
return preview(root, args.port, args.open)
|
|
return 2
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|