feat(coord): add todos system with per-user/machine/project scoping

New coord_todos table and API endpoints (GET/POST/PUT/DELETE /api/coord/todos)
supporting manual and auto-created items, sub-tasks via parent_id, and inclusive
for_user/for_machine filters (OR-null) for sync/save display. sync.sh Phase 7
now shows pending todos grouped by project after every sync. CLAUDE.md documents
auto-creation behavior for unresolved follow-up. Web/email pricing doc updated:
block time rate clarified, INKY reference removed, dates updated.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-26 07:53:22 -07:00
parent 7a5c12d2af
commit 4be89035cc
10 changed files with 552 additions and 5 deletions

View File

@@ -417,7 +417,84 @@ else
cd "$CLAUDETOOLS_DIR"
fi
# Phase 7: Summary
# Phase 7: Pending To-Do Review
echo ""
echo "=== Phase 7: Pending To-Dos ==="
COORD_API="http://172.16.3.30:8001"
TODO_USER=""
TODO_MACHINE="$MACHINE"
if [ -f ".claude/identity.json" ]; then
TODO_USER=$($PYTHON -c "import json; d=json.load(open('.claude/identity.json')); print(d.get('user',''))" 2>/dev/null || echo "")
fi
if [ -n "$TODO_USER" ]; then
TODO_JSON=$(curl -s --max-time 5 \
"${COORD_API}/api/coord/todos?for_user=${TODO_USER}&for_machine=${TODO_MACHINE}&status_filter=pending&limit=200" \
2>/dev/null || echo "[]")
TODO_COUNT=$($PYTHON -c "
import json, sys
try:
data = json.loads('''$TODO_JSON''')
print(len(data))
except:
print(0)
" 2>/dev/null || echo 0)
if [ "$TODO_COUNT" -gt 0 ]; then
echo -e "${YELLOW} $TODO_COUNT pending item(s) for ${TODO_USER}/${TODO_MACHINE}:${NC}"
$PYTHON - <<PYEOF
import json, sys
raw = """$TODO_JSON"""
try:
todos = json.loads(raw)
except Exception as e:
print(f" [WARNING] Could not parse todos: {e}")
sys.exit(0)
# Group by project_key; None -> "Personal"
groups = {}
for t in todos:
if t.get("parent_id"):
continue # sub-tasks shown under parent
key = t.get("project_key") or "Personal"
groups.setdefault(key, []).append(t)
# Build sub-task lookup
subtask_map = {}
for t in todos:
pid = t.get("parent_id")
if pid:
subtask_map.setdefault(pid, []).append(t)
CYAN = "\033[0;36m"
RESET = "\033[0m"
YELLOW= "\033[1;33m"
for group_name in sorted(groups.keys(), key=lambda x: (x == "Personal", x)):
print(f"\n {CYAN}[{group_name}]{RESET}")
for t in groups[group_name]:
assigned = ""
if t.get("assigned_to_user") and t["assigned_to_user"] != "$TODO_USER":
assigned = f" -> {t['assigned_to_user']}"
if t.get("assigned_to_machine") and t["assigned_to_machine"].upper() != "$TODO_MACHINE".upper():
assigned += f"/{t['assigned_to_machine']}"
auto = " [auto]" if t.get("auto_created") else ""
print(f" [ ] {t['text']}{auto}{assigned} (id:{t['id'][:8]})")
for st in subtask_map.get(t["id"], []):
print(f" [ ] {st['text']} (id:{st['id'][:8]})")
PYEOF
echo ""
else
echo -e "${GREEN}[OK]${NC} No pending to-dos."
fi
else
echo -e "${YELLOW}[INFO]${NC} No identity — skipping todo check."
fi
# Phase 8: Summary
echo ""
echo "=== Sync Summary ==="