feat(coord): add due_at field to coord_todos
Migration 20260526_150000 adds nullable due_at datetime column. Model, schemas (create/update/response), and sync.sh display updated. Sync output now shows due:YYYY-MM-DDTHH:MM alongside any todo with a due date. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -482,9 +482,11 @@ for group_name in sorted(groups.keys(), key=lambda x: (x == "Personal", x)):
|
|||||||
if t.get("assigned_to_machine") and t["assigned_to_machine"].upper() != "$TODO_MACHINE".upper():
|
if t.get("assigned_to_machine") and t["assigned_to_machine"].upper() != "$TODO_MACHINE".upper():
|
||||||
assigned += f"/{t['assigned_to_machine']}"
|
assigned += f"/{t['assigned_to_machine']}"
|
||||||
auto = " [auto]" if t.get("auto_created") else ""
|
auto = " [auto]" if t.get("auto_created") else ""
|
||||||
print(f" [ ] {t['text']}{auto}{assigned} (id:{t['id'][:8]})")
|
due = f" due:{t['due_at'][:16]}" if t.get("due_at") else ""
|
||||||
|
print(f" [ ] {t['text']}{auto}{due}{assigned} (id:{t['id'][:8]})")
|
||||||
for st in subtask_map.get(t["id"], []):
|
for st in subtask_map.get(t["id"], []):
|
||||||
print(f" [ ] {st['text']} (id:{st['id'][:8]})")
|
st_due = f" due:{st['due_at'][:16]}" if st.get("due_at") else ""
|
||||||
|
print(f" [ ] {st['text']}{st_due} (id:{st['id'][:8]})")
|
||||||
PYEOF
|
PYEOF
|
||||||
echo ""
|
echo ""
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -60,6 +60,11 @@ class CoordTodo(Base, UUIDMixin, TimestampMixin):
|
|||||||
doc="Status: pending / done / cancelled"
|
doc="Status: pending / done / cancelled"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
due_at: Mapped[Optional[datetime]] = mapped_column(
|
||||||
|
DateTime,
|
||||||
|
doc="When the item is due"
|
||||||
|
)
|
||||||
|
|
||||||
completed_at: Mapped[Optional[datetime]] = mapped_column(
|
completed_at: Mapped[Optional[datetime]] = mapped_column(
|
||||||
DateTime,
|
DateTime,
|
||||||
doc="When the item was marked done"
|
doc="When the item was marked done"
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ class CoordTodoCreate(BaseModel):
|
|||||||
assigned_to_machine: Optional[str] = Field(None, description="Target hostname", max_length=100)
|
assigned_to_machine: Optional[str] = Field(None, description="Target hostname", max_length=100)
|
||||||
auto_created: bool = Field(False, description="True when Claude auto-generated this item")
|
auto_created: bool = Field(False, description="True when Claude auto-generated this item")
|
||||||
source_context: Optional[str] = Field(None, description="Why Claude auto-created this item")
|
source_context: Optional[str] = Field(None, description="Why Claude auto-created this item")
|
||||||
|
due_at: Optional[datetime] = Field(None, description="When the item is due")
|
||||||
created_by_user: str = Field(..., description="User creating the item", max_length=50)
|
created_by_user: str = Field(..., description="User creating the item", max_length=50)
|
||||||
created_by_machine: str = Field(..., description="Hostname where the item is created", max_length=100)
|
created_by_machine: str = Field(..., description="Hostname where the item is created", max_length=100)
|
||||||
|
|
||||||
@@ -31,6 +32,7 @@ class CoordTodoUpdate(BaseModel):
|
|||||||
assigned_to_user: Optional[str] = Field(None, max_length=50)
|
assigned_to_user: Optional[str] = Field(None, max_length=50)
|
||||||
assigned_to_machine: Optional[str] = Field(None, max_length=100)
|
assigned_to_machine: Optional[str] = Field(None, max_length=100)
|
||||||
project_key: Optional[str] = Field(None, max_length=100)
|
project_key: Optional[str] = Field(None, max_length=100)
|
||||||
|
due_at: Optional[datetime] = Field(None, description="When the item is due")
|
||||||
completed_by: Optional[str] = Field(None, description="Session or user completing the item", max_length=100)
|
completed_by: Optional[str] = Field(None, description="Session or user completing the item", max_length=100)
|
||||||
|
|
||||||
|
|
||||||
@@ -45,6 +47,7 @@ class CoordTodoResponse(BaseModel):
|
|||||||
assigned_to_machine: Optional[str]
|
assigned_to_machine: Optional[str]
|
||||||
auto_created: bool
|
auto_created: bool
|
||||||
source_context: Optional[str]
|
source_context: Optional[str]
|
||||||
|
due_at: Optional[datetime]
|
||||||
status: str
|
status: str
|
||||||
completed_at: Optional[datetime]
|
completed_at: Optional[datetime]
|
||||||
completed_by: Optional[str]
|
completed_by: Optional[str]
|
||||||
|
|||||||
24
migrations/versions/20260526_150000_coord_todos_due_at.py
Normal file
24
migrations/versions/20260526_150000_coord_todos_due_at.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
"""coord_todos add due_at column
|
||||||
|
|
||||||
|
Revision ID: 20260526_150000
|
||||||
|
Revises: 20260526_120000
|
||||||
|
Create Date: 2026-05-26 15:00:00
|
||||||
|
"""
|
||||||
|
|
||||||
|
from typing import Sequence, Union
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from alembic import op
|
||||||
|
|
||||||
|
revision: str = "20260526_150000"
|
||||||
|
down_revision: Union[str, None] = "20260526_120000"
|
||||||
|
branch_labels: Union[str, Sequence[str], None] = None
|
||||||
|
depends_on: Union[str, Sequence[str], None] = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
op.add_column("coord_todos", sa.Column("due_at", sa.DateTime(), nullable=True))
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
op.drop_column("coord_todos", "due_at")
|
||||||
Reference in New Issue
Block a user