office: worktrees when the folder is a repository, ask before making one, refuse a folder agents cannot see

This commit is contained in:
Sam
2026-11-12 18:09:05 +11:00
parent 55085ba40a
commit f7b77f370f
11 changed files with 1821 additions and 4 deletions

69
bin/lib/repo.py Normal file
View File

@@ -0,0 +1,69 @@
"""What a folder needs to be before Paperclip can give a task its own worktree.
A worktree is a git feature: Paperclip makes a directory and a branch per task
from the project's repository. A folder that is not a repository cannot have
one, and a repository with no commit has no branch to cut from. Both cases are
checked here, and neither is repaired without being asked.
"""
import os
import subprocess
def git(folder, *args, timeout=60):
return subprocess.run(["git", "-C", folder] + list(args),
capture_output=True, text=True, timeout=timeout)
def is_repo(folder):
if not os.path.isdir(folder):
return False
return git(folder, "rev-parse", "--is-inside-work-tree").stdout.strip() == "true"
def has_commit(folder):
return git(folder, "rev-parse", "--verify", "HEAD").returncode == 0
def branch(folder):
"""The branch to cut task branches from: what is checked out, else main, else master."""
out = git(folder, "symbolic-ref", "--short", "HEAD").stdout.strip()
if out:
return out
for name in ("main", "master"):
if git(folder, "rev-parse", "--verify", name).returncode == 0:
return name
return "main"
def untracked_and_modified(folder):
out = git(folder, "status", "--porcelain").stdout.splitlines()
return len([ln for ln in out if ln.strip()])
def has_ignored(folder):
return os.path.isfile(os.path.join(folder, ".gitignore"))
def make_repo(folder, quiet=False):
"""git init, add everything, and one commit. Returns (ok, message)."""
say = (lambda *_: None) if quiet else print
steps = [
("init", ["init", "-b", "main"]),
]
for label, args in steps:
r = git(folder, *args)
if r.returncode != 0:
return False, "git %s failed: %s" % (label, (r.stderr or r.stdout).strip()[:200])
if git(folder, "add", "-A").returncode != 0:
return False, "git add failed"
r = git(folder, "-c", "user.name=Paperclip Harness",
"-c", "user.email=harness@localhost",
"commit", "-q", "-m", "Initial commit, before any Paperclip task")
if r.returncode != 0:
detail = (r.stderr or r.stdout).strip()
if "nothing to commit" in detail:
return False, "the folder has no files to commit"
return False, "git commit failed: %s" % detail[:200]
say(" made a repository on branch %s, one commit" % branch(folder))
return True, ""