コンテンツにスキップ

Task コマンド

タスク管理操作。サービス呼び出しは内部ヘルパー (スピナー + 計測) 経由。

一覧表示

poe cli task list --status inbox
poe cli task list --all            # 全ステータス

作成

poe cli task create --title "Write docs" --desc "Add CLI docs" --due 2025-09-30 --status inbox

対話モード (オプション省略時) も可。

取得

poe cli task get <TASK_ID>

更新

# すべて任意。未指定は対話 or 現在値を利用
poe cli task update <TASK_ID> --title "New title" --desc "New desc" --status next_action --due 2025-10-01

ステータス変更ショート

poe cli task status <TASK_ID> done

削除

poe cli task delete <TASK_ID>
poe cli task delete <TASK_ID> --force  # 確認なし

内部ヘルパー対応表

ヘルパー 説明 Service メソッド
_load_tasks ステータス別取得 get_tasks_by_status
_list_all_tasks 全ステータス dict 取得 get_all_tasks_by_status_dict
_create_task 作成 create_task
_get_task 単体取得 get_task_by_id
_update_task 更新 update_task
_change_status ステータス変更 update_task
_delete_task 削除 delete_task

統計表示 (stats)

タスク件数の簡易統計を表示。

poe cli task stats                # today/completed/overdue を表示
poe cli task stats --no-overdue   # overdue を省略

メトリクス:

  • Today: 期限日が今日のタスク件数
  • Completed: 完了済件数
  • Overdue: 期限超過 (未完了) 件数

内部では 3 つのサービスメソッドを個別に計測し、最大 elapsed を代表値として表示。

API リファレンス

Task related CLI commands.

Application Serviceを介したタスク操作。

app = typer.Typer(help='タスク CRUD / ステータス操作') module-attribute

console = Console() module-attribute

list_tasks(status=TaskStatus.INBOX, *, all_=typer.Option(None, '--all', '-a', help='flagを付けると全てのタスクを表示'))

タスクをステータス指定または全件で一覧表示するコマンド [AI GENERATED]

引数:

名前 タイプ デスクリプション デフォルト
status TaskStatus

単一表示するステータス ( --all 指定時は無視 )

INBOX
all_ bool

全ステータス横断表示フラグ

Option(None, '--all', '-a', help='flagを付けると全てのタスクを表示')
ソースコード位置: src/cli/commands/task.py
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
@app.command("list", help="ステータスで一覧表示")
@handle_cli_errors()
def list_tasks(
    status: TaskStatus = TaskStatus.INBOX,
    *,
    all_: bool = typer.Option(None, "--all", "-a", help="flagを付けると全てのタスクを表示"),
) -> None:
    """タスクをステータス指定または全件で一覧表示するコマンド [AI GENERATED]

    Args:
        status: 単一表示するステータス ( --all 指定時は無視 )
        all_: 全ステータス横断表示フラグ
    """
    if all_:
        all_tasks = _list_all_tasks()
        # all_tasksからtaskを取り出して表示
        tasks = []
        for task_list in all_tasks.result.values():
            tasks.extend(task_list)
        _print_tasks_table(tasks, "all", elapsed=all_tasks.elapsed)
        return

    tasks = _load_tasks(status)
    _print_tasks_table(tasks.result, status.value, elapsed=tasks.elapsed)

create_task(title=typer.Option(None, '--title', '-t'), description=typer.Option(None, '--desc', '-d'), status=TaskStatus.INBOX, due=typer.Option(None, '--due', help='YYYY-MM-DD'))

新しいタスクを作成するコマンド [AI GENERATED]

未指定項目は対話入力されます。

引数:

名前 タイプ デスクリプション デフォルト
title str | None

タイトル

Option(None, '--title', '-t')
description str | None

説明

Option(None, '--desc', '-d')
status TaskStatus

初期ステータス

INBOX
due str | None

期限 (YYYY-MM-DD)

Option(None, '--due', help='YYYY-MM-DD')
ソースコード位置: src/cli/commands/task.py
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
@app.command("create", help="タスク作成")
@handle_cli_errors()
def create_task(
    title: str | None = typer.Option(None, "--title", "-t"),
    description: str | None = typer.Option(None, "--desc", "-d"),
    status: TaskStatus = TaskStatus.INBOX,
    due: str | None = typer.Option(None, "--due", help="YYYY-MM-DD"),
) -> None:
    """新しいタスクを作成するコマンド [AI GENERATED]

    未指定項目は対話入力されます。

    Args:
        title: タイトル
        description: 説明
        status: 初期ステータス
        due: 期限 (YYYY-MM-DD)
    """
    from logic.commands.task_commands import CreateTaskCommand

    if title is None:
        title = questionary.text("Title?").ask()
    if description is None:
        description = questionary.text("Description? (optional)").ask()
    due_date: date | None = None
    if due:
        try:
            due_date = date.fromisoformat(due)
        except ValueError:
            console.print("[red]Invalid date format[/red]")
    if title is None:
        msg = "title 必須"
        raise typer.BadParameter(msg)
    cmd = CreateTaskCommand(title=title, description=description or "", status=status, due_date=due_date)
    task = _create_task(cmd)
    console.print(f"[green]Created:[/green] {task.result.title} ({task.result.id}) Elapsed: {task.elapsed:.2f}s")

get_task(task_id)

ID 指定でタスク詳細を取得するコマンド [AI GENERATED]

引数:

名前 タイプ デスクリプション デフォルト
task_id str

対象タスク UUID 文字列

必須
ソースコード位置: src/cli/commands/task.py
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
@app.command("get", help="IDで取得")
@handle_cli_errors()
def get_task(task_id: str) -> None:
    """ID 指定でタスク詳細を取得するコマンド [AI GENERATED]

    Args:
        task_id: 対象タスク UUID 文字列
    """
    from logic.queries.task_queries import GetTaskByIdQuery

    tid = uuid.UUID(task_id)
    task = _get_task(GetTaskByIdQuery(task_id=tid))
    if task.result is None:
        console.print("[yellow]Not found[/yellow]")
        raise typer.Exit(code=1)
    table = Table(title="Task Detail", box=box.MINIMAL_DOUBLE_HEAD)
    table.add_column("Field")
    table.add_column("Value")
    detail = task.result
    table.add_row("ID", str(detail.id))
    table.add_row("Title", detail.title)
    table.add_row("Status", detail.status.value)
    table.add_row("Description", detail.description or "")
    table.add_row("Due", detail.due_date.isoformat() if detail.due_date else "")
    table.caption = f"Elapsed: {task.elapsed:.2f}s"
    console.print(table)

update_task(task_id=typer.Argument(...), title=typer.Option(None, '--title', '-t'), description=typer.Option(None, '--desc', '-d'), status=None, due=typer.Option(None, '--due'))

既存タスクを更新するコマンド [AI GENERATED]

引数:

名前 タイプ デスクリプション デフォルト
task_id str

対象タスク UUID

Argument(...)
title str | None

新タイトル (None で変更しない)

Option(None, '--title', '-t')
description str | None

新説明 (None で変更しない)

Option(None, '--desc', '-d')
status TaskStatus | None

新ステータス (None で変更しない)

None
due str | None

新期限文字列 (None で変更しない)

Option(None, '--due')
ソースコード位置: src/cli/commands/task.py
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
@app.command("update", help="タスク更新")
@handle_cli_errors()
def update_task(
    task_id: str = typer.Argument(...),
    title: str | None = typer.Option(None, "--title", "-t"),
    description: str | None = typer.Option(None, "--desc", "-d"),
    status: TaskStatus | None = None,
    due: str | None = typer.Option(None, "--due"),
) -> None:
    """既存タスクを更新するコマンド [AI GENERATED]

    Args:
        task_id: 対象タスク UUID
        title: 新タイトル (None で変更しない)
        description: 新説明 (None で変更しない)
        status: 新ステータス (None で変更しない)
        due: 新期限文字列 (None で変更しない)
    """
    from logic.commands.task_commands import UpdateTaskCommand
    from logic.queries.task_queries import GetTaskByIdQuery

    tid = uuid.UUID(task_id)

    def prompt_interactive() -> tuple[str | None, str | None, TaskStatus | None, str | None]:
        new_title = questionary.text("New Title(blank=skip)").ask() or None
        new_desc = questionary.text("New Description(blank=skip)").ask() or None
        new_status: TaskStatus | None = None
        if questionary.confirm("Change status?").ask():
            status_choice = questionary.select("Status", choices=[s.value for s in TaskStatus]).ask()
            if status_choice:
                new_status = TaskStatus(status_choice)
        new_due: str | None = None
        if questionary.confirm("Change due date?").ask():
            new_due = questionary.text("YYYY-MM-DD(blank=skip)").ask() or None
        return new_title, new_desc, new_status, new_due

    if title is None and description is None and status is None and due is None:
        title, description, status, due = prompt_interactive()

    # 期限変換
    due_date: date | None = None
    if due:
        try:
            due_date = date.fromisoformat(due)
        except ValueError:
            console.print("[yellow]Invalid date -> ignore[/yellow]")
    current = _get_task(GetTaskByIdQuery(task_id=tid))
    if current.result is None:
        console.print("[red]Task not found[/red]")
        raise typer.Exit(code=1)
    current_task = current.result
    title = title or current_task.title
    if description is None:
        description = current_task.description
    status = status or current_task.status

    cmd = UpdateTaskCommand(task_id=tid, title=title, description=description or "", status=status, due_date=due_date)
    updated = _update_task(cmd)
    console.print(
        f"[green]Updated:[/green] {updated.result.title} ({updated.result.id}) Elapsed: {updated.elapsed:.2f}s"
    )

delete_task(task_id, force=typer.Option(default=False, help='確認なし'))

タスクを削除するコマンド [AI GENERATED]

引数:

名前 タイプ デスクリプション デフォルト
task_id str

削除対象 UUID

必須
force bool

確認ダイアログを省略するか

Option(default=False, help='確認なし')
ソースコード位置: src/cli/commands/task.py
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
@app.command("delete", help="タスク削除")
@handle_cli_errors()
def delete_task(task_id: str, force: bool = typer.Option(default=False, help="確認なし")) -> None:
    """タスクを削除するコマンド [AI GENERATED]

    Args:
        task_id: 削除対象 UUID
        force: 確認ダイアログを省略するか
    """
    from logic.commands.task_commands import DeleteTaskCommand

    tid = uuid.UUID(task_id)
    if (not force) and (not questionary.confirm("Delete this task?").ask()):
        console.print("[yellow]Cancelled[/yellow]")
        raise typer.Exit(code=1)
    deleted = _delete_task(DeleteTaskCommand(task_id=tid))
    console.print(f"[red]Deleted:[/red] {tid} Elapsed: {deleted.elapsed:.2f}s")

change_status(task_id, new_status)

タスクのステータスを変更するコマンド [AI GENERATED]

引数:

名前 タイプ デスクリプション デフォルト
task_id str

対象タスク UUID

必須
new_status TaskStatus

新しいステータス

必須
ソースコード位置: src/cli/commands/task.py
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
@app.command("status", help="ステータス変更")
@handle_cli_errors()
def change_status(task_id: str, new_status: TaskStatus) -> None:
    """タスクのステータスを変更するコマンド [AI GENERATED]

    Args:
        task_id: 対象タスク UUID
        new_status: 新しいステータス
    """
    from logic.commands.task_commands import UpdateTaskCommand
    from logic.queries.task_queries import GetTaskByIdQuery

    tid = uuid.UUID(task_id)
    current = _get_task(GetTaskByIdQuery(task_id=tid))
    if current.result is None:
        console.print("[red]Not found[/red]")
        raise typer.Exit(code=1)
    cmd = UpdateTaskCommand(
        task_id=tid,
        title=current.result.title,
        description=current.result.description or "",
        status=new_status,
        due_date=current.result.due_date,
    )
    updated = _change_status(cmd)
    console.print(f"[green]Status -> {updated.result.status.value}[/green] Elapsed: {updated.elapsed:.2f}s")

task_stats(show_overdue=typer.Option(default=True, help='期限超過件数を表示するか', rich_help_panel='Filters'))

タスク件数の統計 (today/completed/overdue) を表示するコマンド [AI GENERATED]

引数:

名前 タイプ デスクリプション デフォルト
show_overdue bool

期限超過を表示するかどうか

Option(default=True, help='期限超過件数を表示するか', rich_help_panel='Filters')
ソースコード位置: src/cli/commands/task.py
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
@app.command("stats", help="タスク件数統計表示 (today/completed/overdue)")
@handle_cli_errors()
def task_stats(
    show_overdue: bool = typer.Option(
        default=True,
        help="期限超過件数を表示するか",
        rich_help_panel="Filters",
    ),
) -> None:  # [AI GENERATED]
    """タスク件数の統計 (today/completed/overdue) を表示するコマンド [AI GENERATED]

    Args:
        show_overdue: 期限超過を表示するかどうか
    """
    today_res = _get_today_count()
    completed_res = _get_completed_count()
    overdue_res = _get_overdue_count() if show_overdue else None

    # 最大のelapsedを代表値とする(3回計測されるため)
    elapsed = max(
        today_res.elapsed,
        completed_res.elapsed,
        overdue_res.elapsed if overdue_res is not None else 0.0,
    )
    _print_stats(
        today=today_res.result,
        completed=completed_res.result,
        overdue=overdue_res.result if overdue_res is not None else 0,
        elapsed=elapsed,
    )