From e4aaa25991ad9764001b1aa6c71ceec2245d7aa1 Mon Sep 17 00:00:00 2001 From: Levi Neely Date: Tue, 14 Apr 2026 09:00:57 +0200 Subject: [PATCH] tools: add task_plan and task_complete as shell/python scripts Replaces the removed built-in task server. Plans are written to $OLLIE_9MOUNT/pl/ (persistent, shared across sessions). Scripts live in the tools directory and are invoked via execute_tool. Co-Authored-By: Claude Sonnet 4.6 --- tools/task_complete.py | 52 ++++++++++++++++++++++++++++++++++++++++++ tools/task_plan.sh | 37 ++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100755 tools/task_complete.py create mode 100755 tools/task_plan.sh diff --git a/tools/task_complete.py b/tools/task_complete.py new file mode 100755 index 0000000..bc9e92e --- /dev/null +++ b/tools/task_complete.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python3 +# description: Mark a plan step complete; returns remaining steps +# Args: +import sys, os, re + +if len(sys.argv) < 3: + print("usage: task_complete ", file=sys.stderr) + sys.exit(1) + +ollie = os.environ.get('OLLIE_9MOUNT', os.path.expanduser('~/mnt/ollie')) +plan_dir = os.path.join(ollie, 'pl') + +# Accept either a bare filename or a path; always resolve against plan_dir +filepath = os.path.join(plan_dir, os.path.basename(sys.argv[1])) +substring = sys.argv[2].lower() + +with open(filepath) as f: + lines = f.readlines() + +matched = False +for i, line in enumerate(lines): + if re.match(r'^- \[ \] ', line) and substring in line.lower(): + lines[i] = line.replace('- [ ] ', '- [x] ', 1) + matched = True + break + +if not matched: + print(f"no unchecked step matching {sys.argv[2]!r}", file=sys.stderr) + sys.exit(1) + +remaining = [line[6:].strip() for line in lines if re.match(r'^- \[ \] ', line)] + +def restat(path, status): + return re.sub(r'__(todo|wip|complete)\.md$', f'__{status}.md', path) + +if '__todo' in filepath: + newpath = restat(filepath, 'wip') +elif not remaining and '__wip' in filepath: + newpath = restat(filepath, 'complete') +else: + newpath = filepath + +with open(filepath, 'w') as f: + f.writelines(lines) + +if newpath != filepath: + os.rename(filepath, newpath) + +if remaining: + print('\n'.join(f'- {s}' for s in remaining)) +else: + print('all steps complete') diff --git a/tools/task_plan.sh b/tools/task_plan.sh new file mode 100755 index 0000000..36d4190 --- /dev/null +++ b/tools/task_plan.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# description: Create a task plan with ordered steps as a markdown checklist +# Args: [step2] ... +# Output: relative path to the created plan file +set -euo pipefail + +OLLIE="${OLLIE_9MOUNT:-$HOME/mnt/ollie}" +PLAN_DIR="$OLLIE/pl" + +GOAL="${1:?usage: task_plan [step2] ...}" +shift + +if [ $# -eq 0 ]; then + echo "error: at least one step required" >&2 + exit 1 +fi + +TIMESTAMP=$(date '+%Y%m%dT%H%M%S') +UID8=$(cat /proc/sys/kernel/random/uuid 2>/dev/null | tr -d '-' | cut -c1-8 \ + || od -A n -t x1 /dev/urandom | tr -d ' \n' | cut -c1-8) +SLUG=$(printf '%s' "$GOAL" \ + | tr '[:upper:]' '[:lower:]' \ + | tr -cs 'a-z0-9' '-' \ + | sed 's/^-//;s/-$//' \ + | cut -c1-48) + +FILENAME="${TIMESTAMP}_${UID8}--${SLUG}__todo.md" +FILEPATH="$PLAN_DIR/$FILENAME" + +{ + printf '# %s\n\n' "$GOAL" + for step in "$@"; do + printf '- [ ] %s\n' "$step" + done +} > "$FILEPATH" + +echo "$FILENAME"