diff options
| -rw-r--r-- | .tasks/tasks.jsonl | 1 | ||||
| -rwxr-xr-x | Omni/Bild/audit.sh | 143 |
2 files changed, 144 insertions, 0 deletions
diff --git a/.tasks/tasks.jsonl b/.tasks/tasks.jsonl index ca1bb97..2762e82 100644 --- a/.tasks/tasks.jsonl +++ b/.tasks/tasks.jsonl @@ -170,6 +170,7 @@ {"taskCreatedAt":"2025-11-22T02:26:44.02456019Z","taskDependencies":[],"taskDescription":"Modify Omni/Agent/Git.hs to check for .git/rebase-merge or .git/rebase-apply before running git rebase --abort. This avoids blindly running abort commands.","taskId":"t-rWbPQPLps","taskNamespace":null,"taskParent":null,"taskPriority":"P2","taskStatus":"Done","taskTitle":"Detect in-progress rebase before aborting in Agent","taskType":"WorkTask","taskUpdatedAt":"2025-11-22T02:27:45.377866012Z"} {"taskCreatedAt":"2025-11-22T03:01:36.84628158Z","taskDependencies":[],"taskDescription":"Modify Omni/Agent/Worker.hs to check if the task branch already exists before trying to create it. If it exists, simply checkout the branch. This prevents 'fatal: a branch named ... already exists' errors when restarting the worker.","taskId":"t-rWbS8t1Wv","taskNamespace":"Omni/Agent.hs","taskParent":null,"taskPriority":"P2","taskStatus":"Done","taskTitle":"Handle existing task branch in Worker Agent","taskType":"WorkTask","taskUpdatedAt":"2025-11-22T03:02:31.746506652Z"} {"taskCreatedAt":"2025-11-22T03:09:54.022974779Z","taskDependencies":[],"taskDescription":"Implement the 2-line status UI described in Omni/Agent/DESIGN.md (Section 4.3). It should reserve 2 lines at the bottom for Meta (Task ID, Time) and Activity (current thought/action), allowing history to scroll above. Use ANSI codes for cursor management.","taskId":"t-rWbSG78jq","taskNamespace":"Omni/Agent/Log.hs","taskParent":null,"taskPriority":"P2","taskStatus":"Done","taskTitle":"Implement 2-line Agent Status UI","taskType":"WorkTask","taskUpdatedAt":"2025-11-22T03:21:54.480763142Z"} +{"taskCreatedAt":"2025-11-22T11:34:17.854509264Z","taskDependencies":[],"taskDescription":null,"taskId":"t-rWcpIf5ov","taskNamespace":null,"taskParent":null,"taskPriority":"P2","taskStatus":"Done","taskTitle":"--help","taskType":"WorkTask","taskUpdatedAt":"2025-11-22T11:39:43.304029721Z"} {"taskCreatedAt":"2025-11-22T04:02:16.914288868Z","taskDependencies":[{"depId":"t-rWbMpcV4v","depType":"Blocks"},{"depId":"t-rWbMpxaBk","depType":"Blocks"},{"depId":"t-rWbS8t1Wv","depType":"Blocks"}],"taskDescription":"Update Omni/Agent/Worker.hs to spawn a background thread that tails '_/llm/amp.log' while the Amp agent is running. For each new line in the log: 1. Parse it (it's JSON). 2. Extract a user-friendly summary (e.g. 'Thinking...', 'Tool: Bash'). 3. Update the status bar activity line (AgentLog.updateActivity) with this summary. This provides real-time visibility into what the agent is doing.","taskId":"t-rWbW6OnUO","taskNamespace":"Omni/Agent/Worker.hs","taskParent":null,"taskPriority":"P2","taskStatus":"Done","taskTitle":"Stream Amp logs to Agent status bar","taskType":"WorkTask","taskUpdatedAt":"2025-11-22T10:05:14.217613978Z"} {"taskCreatedAt":"2025-11-22T09:41:06.786529414Z","taskDependencies":[],"taskDescription":"Replace 'git rebase live' with 'git sync' (which maps to git-branchless sync) in Omni.Agent.Git.syncWithLive. This aligns with the branchless workflow and handles stack rebasing automatically.","taskId":"t-rWciiEsnZ","taskNamespace":"Omni/Agent/Git.hs","taskParent":null,"taskPriority":"P2","taskStatus":"Done","taskTitle":"Use 'git sync' instead of 'git rebase' in Agent","taskType":"WorkTask","taskUpdatedAt":"2025-11-22T09:42:37.875643446Z"} {"taskCreatedAt":"2025-11-22T09:50:59.154884329Z","taskDependencies":[],"taskDescription":"1. Add Thread ID to the status bar (requires log parsing later, but add field now). 2. Make the status layout responsive or vertical (4 lines) to fit on small screens (iPhone). 3. Reserve more lines in init.","taskId":"t-rWciWJYsi","taskNamespace":"Omni/Agent/Log.hs","taskParent":null,"taskPriority":"P2","taskStatus":"Done","taskTitle":"Improve Agent Status UI for mobile & debugging","taskType":"WorkTask","taskUpdatedAt":"2025-11-22T09:52:36.176467065Z"} diff --git a/Omni/Bild/audit.sh b/Omni/Bild/audit.sh new file mode 100755 index 0000000..1a0acd5 --- /dev/null +++ b/Omni/Bild/audit.sh @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +""" +Audit codebase builds. + +Iterates through every namespace in the project and runs 'bild'. +For every build failure encountered, it automatically creates a new task. +""" + +# : out bild-audit + +import os +import sys +import subprocess +import argparse +import shutil +import re + +# Extensions supported by bild (from Omni/Bild.hs and Omni/Namespace.hs) +EXTENSIONS = {'.c', '.hs', '.lisp', '.nix', '.py', '.scm', '.rs', '.toml'} + +def strip_ansi(text): + """Strip ANSI escape codes from text.""" + ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])') + return ansi_escape.sub('', text) + +def is_ignored(path): + """Check if a file is ignored by git.""" + res = subprocess.run( + ['git', 'check-ignore', path], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL + ) + return res.returncode == 0 + +def get_buildable_files(root_dir='.'): + """Find all files that bild can build.""" + targets = [] + for root, dirs, files in os.walk(root_dir): + # Skip hidden directories, build artifacts (_), and task db (.tasks) + dirs[:] = [d for d in dirs if not d.startswith('.') and d != '_'] + + for f in files: + ext = os.path.splitext(f)[1] + if ext in EXTENSIONS: + path = os.path.join(root, f) + # Clean up path + if path.startswith('./'): + path = path[2:] + + if not is_ignored(path): + targets.append(path) + return targets + +def run_bild(target): + """Run bild on the target.""" + # --time 0 disables timeout + # --loud enables output (which we capture) + cmd = ['bild', '--time', '0', '--loud', target] + result = subprocess.run(cmd, capture_output=True, text=True) + return result + +def create_task(target, result, parent_id=None): + """Create a task for a build failure.""" + # Construct a descriptive title + # Try to get the last meaningful line of error output + lines = (result.stdout + result.stderr).strip().split('\n') + last_line = lines[-1] if lines else "Unknown error" + last_line = strip_ansi(last_line).strip() + + if len(last_line) > 50: + last_line = last_line[:47] + "..." + + title = f"Build failed: {target} - {last_line}" + + cmd = [ + 'task', 'create', title, + '--priority', '2', + '--json' + ] + + if parent_id: + cmd.append(f'--discovered-from={parent_id}') + + # Try to infer namespace + parts = target.split('/') + if len(parts) > 1: + # e.g. Omni/Bild.hs -> Omni/Bild + # Omni/Bild/Audit.py -> Omni/Bild + ns = os.path.dirname(target) + if ns: + cmd.append(f'--namespace={ns}') + + print(f"Creating task for {target}...") + proc = subprocess.run(cmd, capture_output=True, text=True) + + if proc.returncode != 0: + print(f"Error creating task: {proc.stderr}", file=sys.stderr) + else: + # task create --json returns the created task json + print(f"Task created: {proc.stdout.strip()}") + +def main(): + parser = argparse.ArgumentParser(description='Audit codebase builds.') + parser.add_argument('--parent', help='Parent task ID to link discovered tasks to') + parser.add_argument('paths', nargs='*', default=['.'], help='Paths to search for targets') + args = parser.parse_args() + + # Check if bild is available + if not shutil.which('bild'): + print("Warning: 'bild' command not found. Ensure it is in PATH.", file=sys.stderr) + + print(f"Scanning for targets in {args.paths}...") + targets = [] + for path in args.paths: + if os.path.isfile(path): + targets.append(path) + else: + targets.extend(get_buildable_files(path)) + + # Remove duplicates + targets = sorted(list(set(targets))) + print(f"Found {len(targets)} targets.") + + failures = 0 + for i, target in enumerate(targets): + print(f"[{i+1}/{len(targets)}] Building {target} ... ", end='', flush=True) + res = run_bild(target) + + if res.returncode == 0: + print("OK") + else: + print("FAIL") + failures += 1 + create_task(target, res, args.parent) + + print(f"\nAudit complete. {failures} failures found.") + if failures > 0: + sys.exit(1) + else: + sys.exit(0) + +if __name__ == '__main__': + main() |
