Files changed: - CHANGES.md - INSTALL.md - VERSION - instructions/dev/version-parts.md - instructions/gtd-weekly-review/SKILL.md - tools/CONTRACT.md - tools/chemenu/commands/doctor.py - tools/chemenu/commands/version_cmd.py - tools/chemenu/review.py - tools/chemenu/tasks/__init__.py - tools/chemenu/tasks/caldav.py - tools/chemenu/tasks/config.py - tools/chemenu/tests/test_caldav.py - tools/chemenu/tests/test_doctor.py - tools/chemenu/tests/test_review.py - tools/requirements.txt
75 lines
3.6 KiB
Python
75 lines
3.6 KiB
Python
"""The task-tracker provider layer (Gitea #124, #119 D2/D3/D25).
|
|
|
|
`kb/` owns a project's durable memory; a task tracker owns its momentary open
|
|
loops (#119 D1). This package is the one place `wikitool` crosses that line -
|
|
never an instruction, never a second MCP server (#119 D25): a provider is a
|
|
Python object behind `chemenu.tasks.protocol.TaskReader`/`TaskWriter`, and
|
|
everything above this package (`wikitool review`/`new project`, #125/#126)
|
|
talks to that protocol and nothing provider-specific.
|
|
|
|
No command lives here yet - this package is a library, per #124's own scope
|
|
note ("Kein Kommando. Diese Schicht ist Bibliothek").
|
|
|
|
`build_reader`/`build_writer` below are the one dispatch table from
|
|
`TasksConfig.provider` to a concrete adapter, shared by `chemenu.review`
|
|
(#125) and `chemenu.commands.new_page`'s `project` handling (#126) - kept in
|
|
one place per `AGENTS.md` invariant 8, rather than two copies of the same
|
|
`if cfg.provider == "superproductivity": ...` drifting apart.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from chemenu.errors import ValidationError
|
|
from chemenu.tasks.config import TasksConfig
|
|
from chemenu.tasks.protocol import TaskReader, TaskWriter
|
|
|
|
|
|
def build_reader(cfg: TasksConfig) -> TaskReader:
|
|
"""Dispatch on `cfg.provider` to a concrete `TaskReader`. For
|
|
`superproductivity` the concrete class also depends on
|
|
`access` (Gitea #133): `"api"` reads the live local REST API,
|
|
`"snapshot"` reads the backup file - never both, never a fallback."""
|
|
if cfg.provider == "superproductivity":
|
|
from chemenu.tasks import superproductivity as sp
|
|
|
|
sp_cfg = sp.SuperProductivityConfig.from_dict(cfg.provider_config)
|
|
if sp_cfg.access == sp.ACCESS_API:
|
|
return sp.SuperProductivityApiReader(sp_cfg)
|
|
return sp.SuperProductivityReader(sp_cfg)
|
|
if cfg.provider == "caldav":
|
|
from chemenu.tasks import caldav as cd
|
|
|
|
cd_cfg = cd.CalDAVConfig.from_dict(cfg.provider_config)
|
|
return cd.CalDAVReader(cd_cfg)
|
|
raise ValidationError(f"No reader is wired up for task provider {cfg.provider!r}.")
|
|
|
|
|
|
def build_writer(cfg: TasksConfig, reader: TaskReader) -> TaskWriter:
|
|
"""Dispatch on `cfg.provider` to a concrete `TaskWriter`, over an
|
|
already-built `reader` - a writer that needs to re-check the read path
|
|
(e.g. `SuperProductivityWriter`'s own collision preflight) reads through
|
|
the same object its caller does, rather than opening a second one.
|
|
|
|
For `superproductivity`, a writer exists only when `access: "api"`
|
|
(Gitea #133): on `access: "snapshot"` the tracker is read-only from here
|
|
by construction, so this raises `ValidationError` rather than returning a
|
|
writer that could never do anything - the same posture as "no writer is
|
|
wired up for this provider at all", just scoped to one access mode of
|
|
one provider instead of the whole provider."""
|
|
if cfg.provider == "superproductivity":
|
|
from chemenu.tasks import superproductivity as sp
|
|
|
|
sp_cfg = sp.SuperProductivityConfig.from_dict(cfg.provider_config)
|
|
if sp_cfg.access != sp.ACCESS_API:
|
|
raise ValidationError(
|
|
"superproductivity: the tracker is read-only from here (access: "
|
|
f"'{sp_cfg.access}') - the write path only exists on an access: 'api' "
|
|
"instance (Gitea #133)."
|
|
)
|
|
return sp.SuperProductivityWriter(sp_cfg, reader)
|
|
if cfg.provider == "caldav":
|
|
from chemenu.tasks import caldav as cd
|
|
|
|
cd_cfg = cd.CalDAVConfig.from_dict(cfg.provider_config)
|
|
return cd.CalDAVWriter(cd_cfg, reader)
|
|
raise ValidationError(f"No writer is wired up for task provider {cfg.provider!r}.")
|