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:
@@ -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 ==="
|
||||
|
||||
|
||||
Reference in New Issue
Block a user