pyworklog 0.7.0__tar.gz → 0.8.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyworklog-0.7.0 → pyworklog-0.8.0}/.github/workflows/release.yml +2 -2
- {pyworklog-0.7.0 → pyworklog-0.8.0}/.github/workflows/test.yml +13 -6
- {pyworklog-0.7.0 → pyworklog-0.8.0}/.gitignore +1 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/AGENTS.md +11 -7
- pyworklog-0.8.0/CHANGELOG.md +215 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/CONTRIBUTING.md +21 -10
- {pyworklog-0.7.0 → pyworklog-0.8.0}/DESIGN.md +41 -22
- {pyworklog-0.7.0 → pyworklog-0.8.0}/DESIGN.zh.md +6 -6
- {pyworklog-0.7.0 → pyworklog-0.8.0}/Makefile +8 -2
- {pyworklog-0.7.0 → pyworklog-0.8.0}/PKG-INFO +33 -1
- {pyworklog-0.7.0 → pyworklog-0.8.0}/README.md +29 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/README.zh.md +21 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/pyproject.toml +16 -1
- {pyworklog-0.7.0 → pyworklog-0.8.0}/skills/worklog-cli/SKILL.md +23 -7
- pyworklog-0.8.0/skills/worklog-cli/integrations/statusline-wl.sh +17 -0
- pyworklog-0.8.0/skills/worklog-cli/integrations/wl-session-context.sh +27 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/skills/worklog-cli/references/features.md +35 -8
- pyworklog-0.8.0/skills/worklog-cli/references/setup.md +118 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/cli.py +342 -122
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/commands/__init__.py +26 -24
- pyworklog-0.8.0/src/worklog/commands/admin.py +145 -0
- pyworklog-0.8.0/src/worklog/commands/alias.py +84 -0
- pyworklog-0.8.0/src/worklog/commands/checkin.py +210 -0
- pyworklog-0.8.0/src/worklog/commands/dateinfo.py +102 -0
- pyworklog-0.8.0/src/worklog/commands/goal.py +220 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/commands/help.py +54 -18
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/commands/query.py +266 -42
- pyworklog-0.8.0/src/worklog/commands/sched.py +178 -0
- pyworklog-0.8.0/src/worklog/commands/semantic.py +291 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/commands/state.py +327 -45
- pyworklog-0.8.0/src/worklog/commands/timenodes.py +66 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/commands/views.py +271 -33
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/completion.py +13 -9
- pyworklog-0.8.0/src/worklog/config.py +127 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/db.py +31 -0
- pyworklog-0.8.0/src/worklog/embedding.py +80 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/add.md +1 -0
- pyworklog-0.8.0/src/worklog/help/en/agent.md +85 -0
- pyworklog-0.8.0/src/worklog/help/en/alias.md +20 -0
- pyworklog-0.8.0/src/worklog/help/en/area.md +18 -0
- pyworklog-0.8.0/src/worklog/help/en/config.md +31 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/day.md +6 -2
- pyworklog-0.8.0/src/worklog/help/en/goal.md +37 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/index.md +4 -3
- pyworklog-0.8.0/src/worklog/help/en/kinds.md +15 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/logs.md +3 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/ls.md +7 -1
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/metric.md +6 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/node.md +1 -1
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/planning.md +7 -6
- pyworklog-0.8.0/src/worklog/help/en/project.md +18 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/projects.md +1 -0
- pyworklog-0.8.0/src/worklog/help/en/prop.md +37 -0
- pyworklog-0.8.0/src/worklog/help/en/query.md +35 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/recap.md +4 -4
- pyworklog-0.8.0/src/worklog/help/en/reindex.md +22 -0
- pyworklog-0.8.0/src/worklog/help/en/relation.md +57 -0
- pyworklog-0.8.0/src/worklog/help/en/set.md +11 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/shortcuts.md +3 -3
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/show.md +7 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/summary.md +7 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/tag.md +1 -1
- pyworklog-0.8.0/src/worklog/help/en/task.md +18 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/tree.md +5 -0
- pyworklog-0.8.0/src/worklog/help/en/unset.md +11 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/helpers.py +79 -3
- pyworklog-0.8.0/src/worklog/migrations/0010_overview_top5_into_goal.sql +9 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/queries.py +231 -13
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/render.py +134 -18
- pyworklog-0.8.0/src/worklog/templates/config.ini +32 -0
- pyworklog-0.8.0/src/worklog/vectorstore.py +279 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/xdg.py +22 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/conftest.py +5 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_add.py +7 -0
- pyworklog-0.8.0/tests/test_agent.py +320 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_alias.py +12 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_aliases.py +82 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_checkin.py +5 -5
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_config.py +22 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_day.py +157 -8
- pyworklog-0.8.0/tests/test_embedding.py +143 -0
- pyworklog-0.8.0/tests/test_embedding_config.py +143 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_filters.py +110 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_find.py +2 -1
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_help.py +12 -2
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_logs.py +17 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_ls.py +39 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_meta.py +33 -37
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_metric.py +4 -4
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_migrations.py +31 -0
- pyworklog-0.8.0/tests/test_plan.py +207 -0
- pyworklog-0.8.0/tests/test_projects.py +122 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_prop_clock.py +22 -7
- pyworklog-0.8.0/tests/test_query.py +361 -0
- pyworklog-0.8.0/tests/test_relation.py +276 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_render.py +156 -2
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_show.py +61 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_summary.py +28 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_tree.py +37 -2
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_ux.py +1 -1
- pyworklog-0.8.0/tests/test_vectorstore.py +125 -0
- pyworklog-0.8.0/uv.lock +1216 -0
- pyworklog-0.7.0/CHANGELOG.md +0 -383
- pyworklog-0.7.0/skills/worklog-cli/references/setup.md +0 -81
- pyworklog-0.7.0/src/worklog/commands/meta.py +0 -848
- pyworklog-0.7.0/src/worklog/help/en/agent.md +0 -72
- pyworklog-0.7.0/src/worklog/help/en/alias.md +0 -15
- pyworklog-0.7.0/src/worklog/help/en/config.md +0 -8
- pyworklog-0.7.0/src/worklog/help/en/goal.md +0 -14
- pyworklog-0.7.0/src/worklog/help/en/meta.md +0 -19
- pyworklog-0.7.0/src/worklog/help/en/prop.md +0 -17
- pyworklog-0.7.0/src/worklog/help/en/set.md +0 -11
- pyworklog-0.7.0/src/worklog/help/en/unset.md +0 -10
- pyworklog-0.7.0/tests/test_agent.py +0 -129
- pyworklog-0.7.0/tests/test_projects.py +0 -49
- pyworklog-0.7.0/uv.lock +0 -545
- {pyworklog-0.7.0 → pyworklog-0.8.0}/LICENSE +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/pytest.ini +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/skills/worklog-cli/references/bulk.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/__init__.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/commands/bulk.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/commands/metric.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/db_table.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/active.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/admin.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/agenda.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/ancestors.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/apply.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/bulk.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/cancel.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/changes.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/checkin.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/clock.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/date.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/dateinfo.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/defer.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/delete.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/descendants.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/done.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/find.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/focus.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/ids.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/import.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/init.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/kind.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/link.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/log.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/migrate.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/para.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/planned.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/print-completion.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/priority.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/relog.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/reopen.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/reporting.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/sched.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/spent.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/start.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/status.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/stop.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/themes.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/tick.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/time.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/tracking.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/unlink.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/unlog.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/wait.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/help/en/window.md +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/migrations/0001_initial_schema.sql +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/migrations/0002_metric_and_log_tag.sql +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/migrations/0003_backfill_checkin_metrics.sql +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/migrations/0004_meta_props_to_typed_logs.sql +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/migrations/0005_clock_table.sql +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/migrations/0006_rename_log_type_to_tag.sql +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/migrations/0007_utc_timestamps.sql +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/migrations/0008_soft_delete_tombstones.sql +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/migrations/0009_tombstone_node_path_view.sql +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/src/worklog/timeutil.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/__init__.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_brief.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_cascade.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_changes.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_clock.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_completion.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_cycle_safety.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_dateinfo.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_db_table.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_default_verb.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_focus.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_import_apply.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_init.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_link_set.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_log.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_log_format.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_node.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_sample.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_sched.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_state.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_timeutil.py +0 -0
- {pyworklog-0.7.0 → pyworklog-0.8.0}/tests/test_xdg.py +0 -0
|
@@ -20,7 +20,7 @@ jobs:
|
|
|
20
20
|
id-token: write # for PyPI Trusted Publisher (OIDC)
|
|
21
21
|
actions: read # to read the Test workflow's run status for this commit (release gate)
|
|
22
22
|
steps:
|
|
23
|
-
- uses: actions/checkout@
|
|
23
|
+
- uses: actions/checkout@v6
|
|
24
24
|
with:
|
|
25
25
|
fetch-depth: 0 # need full history for auto-generated release notes
|
|
26
26
|
|
|
@@ -62,7 +62,7 @@ jobs:
|
|
|
62
62
|
exit 1
|
|
63
63
|
|
|
64
64
|
- name: Install uv
|
|
65
|
-
uses: astral-sh/setup-uv@
|
|
65
|
+
uses: astral-sh/setup-uv@v8.2.0
|
|
66
66
|
with:
|
|
67
67
|
python-version: '3.12'
|
|
68
68
|
enable-cache: true
|
|
@@ -16,10 +16,10 @@ jobs:
|
|
|
16
16
|
python-version: ['3.9', '3.10', '3.11', '3.12', '3.13', '3.14']
|
|
17
17
|
|
|
18
18
|
steps:
|
|
19
|
-
- uses: actions/checkout@
|
|
19
|
+
- uses: actions/checkout@v6
|
|
20
20
|
|
|
21
21
|
- name: Install uv
|
|
22
|
-
uses: astral-sh/setup-uv@
|
|
22
|
+
uses: astral-sh/setup-uv@v8.2.0
|
|
23
23
|
with:
|
|
24
24
|
python-version: ${{ matrix.python-version }}
|
|
25
25
|
enable-cache: true
|
|
@@ -32,7 +32,7 @@ jobs:
|
|
|
32
32
|
|
|
33
33
|
- name: Upload coverage to Codecov
|
|
34
34
|
if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12'
|
|
35
|
-
uses: codecov/codecov-action@
|
|
35
|
+
uses: codecov/codecov-action@v7
|
|
36
36
|
with:
|
|
37
37
|
token: ${{ secrets.CODECOV_TOKEN }}
|
|
38
38
|
files: ./coverage.xml
|
|
@@ -40,12 +40,19 @@ jobs:
|
|
|
40
40
|
|
|
41
41
|
- name: Smoke test CLI
|
|
42
42
|
run: |
|
|
43
|
+
set -euo pipefail
|
|
43
44
|
export WORKLOG_DB=$(mktemp -d)/worklog.db
|
|
44
45
|
uv run wl init
|
|
45
46
|
uv run wl --version
|
|
46
|
-
uv run wl add "ci smoke task" -k task -p A
|
|
47
|
+
uv run wl add "ci smoke task" -k task -p A --sched today
|
|
47
48
|
uv run wl log 1 "hello from CI"
|
|
48
|
-
uv run wl
|
|
49
|
+
uv run wl recap "ci smoke recap" # creates today's day skeleton so the overview renders
|
|
49
50
|
uv run wl show 1
|
|
50
|
-
uv run wl
|
|
51
|
+
uv run wl day
|
|
52
|
+
# wl tree must render real structure (the timeline + the scheduled task),
|
|
53
|
+
# not just exit 0 on an empty overview — assert the task title shows up.
|
|
54
|
+
tree=$(uv run wl tree)
|
|
55
|
+
printf '%s\n' "$tree"
|
|
56
|
+
printf '%s\n' "$tree" | grep -q "ci smoke task" || { echo "::error::wl tree rendered no structure"; exit 1; }
|
|
57
|
+
uv run wl done 1
|
|
51
58
|
uv run wl migrate
|
|
@@ -7,7 +7,7 @@ Primary operating guide for AI coding agents (Claude Code, Cursor, Aider, etc.)
|
|
|
7
7
|
- **`DESIGN.md`** is canonical for every shared convention (command style, state machine, marker symbols, time-window flags, rendering, schema, import/apply formats, color theming, scheduled time, planned/unplanned derivation, etc.). Read the relevant section before adding a command or changing a format — keeping `src/worklog/cli.py`, the tests, the completion strings, and DESIGN in sync is the project's hardest rule.
|
|
8
8
|
- **`CONTRIBUTING.md`** holds the full dev setup, TDD + DRY conventions, local Makefile overrides, and release process. Do not duplicate that content here.
|
|
9
9
|
- **`skills/worklog-cli/SKILL.md`** is the Claude Code skill (AI-facing usage guide: when to use `wl`, scenario→command table, bulk `import` / `apply` patterns, `-q` brief mode for token savings). Update this when usage patterns change.
|
|
10
|
-
- `README.md` is the project overview + install pointer only; `tests/
|
|
10
|
+
- `README.md` is the project overview + install pointer only; the `tests/test_*.py` suite (split by area) is the de-facto contract for every command.
|
|
11
11
|
|
|
12
12
|
## Common commands
|
|
13
13
|
|
|
@@ -17,7 +17,7 @@ make test # pytest in parallel (-n auto) with the 95% cov gate from py
|
|
|
17
17
|
make test-v # sequential, no cov — debug noisy output
|
|
18
18
|
make test-fast # parallel, no cov gate — quick dev loop
|
|
19
19
|
make cov # detailed term-missing coverage report
|
|
20
|
-
make demo #
|
|
20
|
+
make demo # populate a FRESH demo DB (refuses if the DB exists; use WORKLOG_DB=/tmp/wl-demo.db)
|
|
21
21
|
make reset # interactive: drop current DB + re-init
|
|
22
22
|
make ship # test then push (only pushes if green)
|
|
23
23
|
```
|
|
@@ -25,7 +25,7 @@ make ship # test then push (only pushes if green)
|
|
|
25
25
|
Single-test invocation:
|
|
26
26
|
|
|
27
27
|
```fish
|
|
28
|
-
uv run pytest tests/
|
|
28
|
+
uv run pytest tests/test_add.py::TestAdd::test_add_task -v --no-cov
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
Ad-hoc DB for scratch work without touching `~/.local/share/worklog/worklog.db`:
|
|
@@ -41,30 +41,34 @@ wl --db /tmp/scratch.db add "..."
|
|
|
41
41
|
|
|
42
42
|
**Single-package CLI.** `src/worklog/` holds everything: `cli.py` (~5000 lines) is the implementation, `migrations/NNNN_*.sql` is the schema (one initial file at v0.3.0, more added per schema change), `__init__.py` re-exports `__version__`. No further submodule split inside `cli.py` — kept this way intentionally; reconsider only when a feature truly cannot be co-located.
|
|
43
43
|
|
|
44
|
-
**One polymorphic `node` table.** The `kind` column distinguishes `lifetime / decade / year / quarter / month / week / day / area / project / task / meetlog / habit / signal`; `parent_id` self-reference builds the tree. Two parallel sub-trees hang under `lifetime`: a **responsibility line** (`area → project → task`, PARA-style) and a **time line** (`year → quarter → month → week → day`, time skeleton +
|
|
44
|
+
**One polymorphic `node` table.** The `kind` column distinguishes `lifetime / decade / year / quarter / month / week / day / area / project / task / meetlog / habit / signal`; `parent_id` self-reference builds the tree. Two parallel sub-trees hang under `lifetime`: a **responsibility line** (`area → project → task`, PARA-style) and a **time line** (`year → quarter → month → week → day`, time skeleton + each level's `goal` / the day's `summary` reserved-tag logs). Day/week/month views are **log-driven** (`logged_at` + ancestor chain + tags), not via fixed parent-of-task — moving projects between areas does not break per-day views. Tables: `node / tag / log / prop / link / sched / date_meta` + recursive CTE view `v_node_path`.
|
|
45
45
|
|
|
46
46
|
**Path resolution.** Priority: `wl --db PATH` flag → `$WORKLOG_DB` env → `$XDG_DATA_HOME/worklog/worklog.db` (default `~/.local/share/worklog/worklog.db`). Config is `$XDG_CONFIG_HOME/worklog/aliases.ini`. `_resolve_db_path(args)` is the only resolver; `cmd_config` displays which branch fired.
|
|
47
47
|
|
|
48
|
-
**Subcommand dispatch.** `build_parser()` constructs the argparse tree (one `sub.add_parser(...)` block per command, with `help` + `description` + `epilog`). `HANDLERS = {"cmd": cmd_handler}` maps the parsed name to `cmd_<name>(args, con) -> None`. `main()` resolves user aliases (`~/.config/worklog/aliases.ini`), routes
|
|
48
|
+
**Subcommand dispatch.** `build_parser()` constructs the argparse tree (one `sub.add_parser(...)` block per command, with `help` + `description` + `epilog`). `HANDLERS = {"cmd": cmd_handler}` maps the parsed name to `cmd_<name>(args, con) -> None`. `main()` resolves user aliases (`~/.config/worklog/aliases.ini`), routes bootstrap commands (`print-completion`, `config`) that bypass `ensure_db()`, applies `--db` override, then calls the handler. Tests invoke `HANDLERS[cmd](args, con)` directly through the `cli` fixture to bypass `main()`.
|
|
49
49
|
|
|
50
50
|
**Rendering pipeline.** All output goes through `out()` (rich-aware) — never bare `print()` for user-visible rows. `_c(text, style)` is the single coloring entry: when `_CONSOLE` is set, it escapes content via `rich.markup.escape` (so `[x]`, `[[doc]]`, `[#A]` aren't eaten as rich markup) and wraps with `[style]…[/style]`; when console is plain, it returns the string. **Any fragment that may contain `[ ]` must go through `_c`** — direct insertion triggers `rich.MarkupError` or silent eating. `_node_line(con, n, ...)` is the **only node renderer**; reuse it everywhere listing nodes, including new commands, to inherit highlighting + search-hit emphasis for free. `_init_console` runs once in `main()`; tests run in plain mode (no TTY).
|
|
51
51
|
|
|
52
|
+
**"meta" is internal-only — never a user-facing concept.** The string `meta` survives in the code ONLY in implementation roles, none of which denote a wl feature: the `"meta"` theme/style key (the grey auxiliary-text rendering role, used as `_c(text, "meta")`), the `date_meta` table name, argparse parser-metadata helpers (`_collect_sub_meta`), and incidental module names. There is **no "meta field" / "meta" concept in wl's design** — that was removed; a node's forward `goal` and backward `summary` are *reserved-tag logs* (`log.tag`), managed by `wl goal` (see `wl help goal`). Do **not** reintroduce "meta" in any user-facing surface — command names, `--help` text, `-o json` keys, or DESIGN's user-model sections. These internal usages are kept only because renaming them is churn with zero behavior change; they must stay invisible to the user.
|
|
53
|
+
|
|
52
54
|
**Shell completion is generated, not hand-written.** `wl print-completion {fish,bash,zsh}` walks the argparse tree at runtime and emits a script tailored to that shell. Each shell template contains a `__wl_db_path[_bash|_zsh]` helper that queries SQLite directly for dynamic node-id / tag completions — **no Python startup**, so Tab is <50ms. When you add a subcommand or flag, completion is automatic; **but** if it takes a node id or tag, register it in `_FISH_POSITIONAL_NODE` / `_FISH_HELPERS` / `_BASH_DYN_HELPERS` so dynamic completion fires.
|
|
53
55
|
|
|
54
56
|
**Coverage gate is hard (95%).** `pytest.ini` enforces `--cov-fail-under=95`; the CI runs the same. The two pragma-no-cover regions are TTY/escape-sequence probes in `_detect_bg_is_dark` and the bare `main()` entrypoint (tests bypass it).
|
|
55
57
|
|
|
56
58
|
## Core principles
|
|
57
59
|
|
|
58
|
-
- **TDD (Red → Green → Refactor).** Behavioral changes start with a failing test in `tests/
|
|
60
|
+
- **TDD (Red → Green → Refactor).** Behavioral changes start with a failing test in the matching `tests/test_<area>.py` that reproduces the bug or pins the new behavior. Confirm it fails for the right reason, then write the minimum code to make it pass, then refactor. Tests stay green at every step. A PR that adds behavior without adding the test that drives it is rejected. See CONTRIBUTING.md "TDD" for the full loop.
|
|
59
61
|
- **DRY (Don't Repeat Yourself).** The codebase has a small set of single-source helpers — `_status_marker`, `_node_line`, `out`/`_c`, `_resolve_window`, `_resolve_db_path`, `_project_members`, `_node_clock_min`, `_collect_descendants` (see DESIGN §12 for the full list). New code reuses them; re-implementing one of them in a fresh form is a review block. Same rule for docs: install / dev / release info is in CONTRIBUTING.md and only there — link to it, don't restate it.
|
|
60
62
|
|
|
61
63
|
## Hard rules
|
|
62
64
|
|
|
63
|
-
- **
|
|
65
|
+
- **Keep every surface in sync, same commit.** A command/flag/behavior change isn't done until all its descriptions agree — update `src/worklog/cli.py` (incl. its `help=`/`epilog`/`description`) + shell completion + the `wl help <topic>` doc + `tests/` + a `CHANGELOG.md` `[Unreleased]` line, plus `DESIGN.md` (+`.zh`) if a convention changed and `SKILL.md` if everyday usage changed. Drift between them is the failure mode this project guards against. (Full checklist: CONTRIBUTING.md "Keep every surface in sync".)
|
|
64
66
|
- **Status / priority / theme key names** are enumerated in DESIGN §3/§5/§19; add to `_THEME_KEYS` when introducing a new palette entry — `test_themes_have_same_keys` catches misses.
|
|
65
67
|
- **No bare `print()` for renderable content**; all rows go through `out()` + `_c()`.
|
|
66
68
|
- **Bulk writes default to `--dry-run`.** `wl apply` and `wl import` validate first, then execute as a single transaction (`_collect_descendants` recurses for the `-` delete prefix because the FK is `ON DELETE SET NULL`, not cascade). Update flags strictly: only fields that appear in the diff are touched — see DESIGN §18.2 "anti-wipe" rule.
|
|
67
69
|
- **No internal task-tracker ids in the repo.** This is a public repo; the maintainer tracks work in a private system whose ids are meaningless to outside readers. Never write a `WL#NNN` or a bareword `#NNN` design backref in source comments, docstrings, tests, the changelog, or commit / PR text — a bare `#NNN` also renders as a GitHub issue/PR link and misleads. Describe the change in prose instead ("the dedup-warning feature", "the focus-on-day-node fix"); if you must label it, write `task NNN` without the `#`. **Preserved** (these are not backrefs): illustrative example ids in usage snippets (`wl show 42`), the `#L<id>` / `node #123` format documentation, and the deliberately-nonexistent ids in apply/import test fixtures (`#999` / `#888`).
|
|
70
|
+
- **Write docs terse.** SKILL.md, CHANGELOG, help topics, DESIGN: short, plain sentences — say it clearly and stop. No multi-clause run-ons, no over-explaining. A CHANGELOG entry is one tight highlight line (command + what changed), not a paragraph; SKILL rows stay scannable.
|
|
71
|
+
- **No links to the maintainer's private files.** Never reference a private memory (`feedback_…`) or a maintainer-specific path (their `~/projects/…`, personal notes) from anything in this repo — those mean nothing to other readers; keep guidance self-contained. (Standard user-config targets in install instructions, e.g. `~/.claude/hooks/` / `~/.claude/settings.json`, are fine — every user has those.)
|
|
68
72
|
- **i18n layout.** README + DESIGN are bilingual (`*.zh.md`), `src/worklog/cli.py` strings + tests + SKILL.md are English. CJK fixtures in tests are intentional (they exercise unicode width / sort / title handling).
|
|
69
73
|
- **`tmp_path_home` test fixture pattern.** When a test changes `$HOME` to assert path resolution, it must also `monkeypatch.delenv("XDG_CONFIG_HOME")` + `delenv("XDG_DATA_HOME")` — CI runners preset XDG vars and otherwise leak through. See `TestUserAliasesIni._setup_aliases` for the working pattern.
|
|
70
74
|
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to **worklog** are documented here. The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
4
|
+
|
|
5
|
+
The autogenerated `Commits since vX.Y.Z` block on each GitHub Release captures every commit; this file is the human-curated highlight reel — keep entries to one tight line. **Breaking changes go in a `### Breaking` section, listed first in the release** (env/path/schema migrations, renamed or removed commands/flags, changed contracts).
|
|
6
|
+
|
|
7
|
+
## [Unreleased]
|
|
8
|
+
|
|
9
|
+
## [0.8.0] - 2026-06-14
|
|
10
|
+
|
|
11
|
+
### Breaking
|
|
12
|
+
- **`wl meta` removed — merged into `wl goal`.** `meta set/ls/rm` → `goal set/ls/rm <node>`; `overview`/`top5` collapse into one `goal` tag (level = node kind); migration 0010 retags old logs.
|
|
13
|
+
|
|
14
|
+
### Changed
|
|
15
|
+
- **`wl agent ls` reworked** — recency-sorted, capped at 12 (`--all`), width-adaptive session id, per-day grouping by default (`--flat` off), `--by active|bound`.
|
|
16
|
+
- **Unset priority renders `[# ]`** (4 cols, one `_pri_marker`) — fixes column misalignment + the `[ ]`/TODO collision.
|
|
17
|
+
- **`wl agent` records which runtime** (claude/cursor/codex, from `--agent`/`$WL_AGENT`), writing `agent_session` + `agent` metrics.
|
|
18
|
+
- **`wl agent <id>` records history by default** (was `--record`; `--no-record` skips).
|
|
19
|
+
- **`wl tree`'s empty overview is honest** — tells a truly-empty DB from out-of-scope nodes (points at `--depth 9` / `ls --all`).
|
|
20
|
+
- **Migrations snapshot the DB first** to `<db>.pre-v<N>.bak`, so a bad migration is recoverable.
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
- **`wl query` / `wl reindex` — hybrid (semantic + keyword) search.** `wl reindex` embeds each node's chunks (head + per-log) via an OpenAI-compatible server (default local Ollama) into a sidecar LanceDB; `wl query` RRF-fuses best-chunk cosine with a jieba-segmented, `[synonyms]`-expanded keyword match — paraphrases *and* exact names both surface — showing the matched passage, term-highlighted (`--limit`/`--threshold`/`-o json`). Configurable backend + `query_prompt` template (`wl config`). Pluggable, graceful degradation: the `semantic` extra (LanceDB + jieba) is the fast path, but absent it `wl query`/`reindex` auto-fall-back to a pure-Python SQLite vector store + `\w+` segmentation — so semantic search works on every Python 3.9–3.14 / platform with no required extras (slower where there's no LanceDB wheel: Intel macOS, musl, …).
|
|
24
|
+
- **`wl help` is a short overview; `wl help --all` lists every topic.**
|
|
25
|
+
- **Structured goal targets — `wl goal "..." <ids>`** records the task nodes a goal targets (order = priority) as queryable `goal` metrics; shown as `[done/total]` in `wl day`/`wl goal`.
|
|
26
|
+
- **`wl show` timeline marks a log's tag** — `✎ goal`/`✎ summary`/`✎ <custom>` vs plain `✎ log`.
|
|
27
|
+
- **`wl day` header shows the day node id** (`#<id>`).
|
|
28
|
+
- **Relations show under `props:` + derived `=backrels`** in `wl show` / `-o json`.
|
|
29
|
+
- **Node ids are highlighted** (green) across all output.
|
|
30
|
+
- **`wl relation`** — task↔task relations (`split-from`/`split-into`/`related`), bidirectional, stored as `relation.*` props; `wl add --relation` links at creation.
|
|
31
|
+
- **`wl kinds` / `wl tags` / `wl props` / `wl metrics`** — cross-node "vocabulary in use" lists (+ `-o json`).
|
|
32
|
+
- **`wl agent context`** — prints the session binding (`--hook` for `UserPromptSubmit` JSON); ships jq-free integrations.
|
|
33
|
+
- **`--width {full,help,N}` / `$WORKLOG_WIDTH`** — cap output width.
|
|
34
|
+
- **`--title {wrap,clip}` / `$WORKLOG_TITLE`** — wrap long titles hang-indented (default) or clip to one line.
|
|
35
|
+
- **`wl day` / `wl tree` titles wrap hang-indented too** (shared with `_node_line`).
|
|
36
|
+
- **Aliases can carry arguments** — `wl alias add w "day -t work"` → `wl w` == `wl day -t work`.
|
|
37
|
+
- **`--prop` filter** on list/view — `--prop release=v0.7.0` / `linear.id` / `github.*`; repeatable = AND.
|
|
38
|
+
- **`--priority` / `-p` filter** on `ls`/`tree`/`day`/`agenda`/`logs`; `--status` takes comma any-of.
|
|
39
|
+
- **`-o json` output** on `show`/`ls`/`logs`/`projects`/`day`/`tree`/`summary` — stable field names, empty → `[]`.
|
|
40
|
+
- **`wl day` header is clearer** — distinct markers for goal/recap/week/month (🎯/📝/📅/⭐); goals naming `#ids` show `[done/total]`.
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
- **`wl find` highlights hits in tag/prop/link matches too.**
|
|
44
|
+
- **Fish completion of an alias offers the target's positional args** (`wl w <TAB>` suggests dates).
|
|
45
|
+
- **Fish completion no longer breaks on a `"` in help text** (descriptions single-quoted).
|
|
46
|
+
- **`wl agent ls` columns align** (`#id` + `<agent>:<sid>` padded uniform).
|
|
47
|
+
- **`wl summary --by day` shows a `worked` group per day** — tasks logged that day.
|
|
48
|
+
- **`make demo` refuses to overwrite an existing DB.**
|
|
49
|
+
- **`wl add` / `wl log` stamp the current time** in the success line.
|
|
50
|
+
|
|
51
|
+
## [0.7.0] - 2026-06-09
|
|
52
|
+
|
|
53
|
+
### Added
|
|
54
|
+
- **Signed relative-delta dates** — `+1` / `-2d` / `+3w` / `+1m` / `-1y` on every date-accepting command (`wl day -2`, `wl sched 42 +3w`, `wl log … --date -1d`); month/year deltas clamp the day.
|
|
55
|
+
- **Relative date words resolve everywhere, connector- and case-insensitive** — `next-week`/`-month`/`-quarter` → that period's first day; `NEXT_WEEK` / `next week` / plurals parse. `someday` stays `defer`-only.
|
|
56
|
+
- **`wl agent`** — bind the current AI session to a task (`wl agent <id>` / show / `ls` / `rm`); stored as the `agent_session.claude` prop, rebinding moves it.
|
|
57
|
+
- **`wl agent <id> --record`** — also writes a log + an `agent_session` metric with the full session id, so `wl metric ls <id> --tag agent_session --all` recovers every session a node was worked under. (Became the default in [Unreleased].)
|
|
58
|
+
|
|
59
|
+
### Changed
|
|
60
|
+
- **`wl set` / `wl prop set` / import `props` refuse reserved node-field names** (`status`/`priority`/`title`/…) so a prop can't shadow a real column (it had produced two `status` values in `wl show`).
|
|
61
|
+
- **Wider Python support: 3.9–3.14** (was 3.11+) — no 3.10/3.11-only feature used; CI tests the full matrix on Ubuntu + macOS.
|
|
62
|
+
|
|
63
|
+
### Docs
|
|
64
|
+
- **README reframed around AI-first / local-first** — scannable Why/Features, a Quickstart, Python req in prose (EN + 中文).
|
|
65
|
+
- **Internal task-tracker ids dropped from the public repo** + a hard rule in `AGENTS.md`.
|
|
66
|
+
|
|
67
|
+
## [0.6.0] - 2026-06-07
|
|
68
|
+
|
|
69
|
+
### Added
|
|
70
|
+
- **`wl show` annotates a recurring schedule with its next occurrence** (`recur weekly:Mon,Fri (next 2026-06-08 Mon)`).
|
|
71
|
+
- **`wl help` — a topic browser** (`wl help` index / `wl help <topic>`): repo-managed Markdown under `src/worklog/help/<lang>/`, i18n-ready, tab-completable; `--help` points into it. 18 topics.
|
|
72
|
+
- **`wl node` group** — `node add / ls / show / edit / rm / reparent`; starts the `<entity> <verb>` reshape (`wl add` == `wl node add`). `reparent` has cycle guards; `rm` is soft-delete.
|
|
73
|
+
- **`wl prop` + `wl clock` groups** — `prop set/ls/rm` (with a `wl unset` shortcut to finally remove a prop); `clock ls/edit/rm` (intervals still created by `start`/`stop`/`spent`).
|
|
74
|
+
- **`wl link` group + default-verb mechanism** — `link add/ls/rm`; for a collision-name entity, a non-verb token after it is taken as an id, so `wl link 42 doc` still works.
|
|
75
|
+
- **`wl tag` / `wl log` / `wl sched` reshaped into default-verb groups** — everyday `wl tag 42 +x` / `wl log 42 "…"` / `wl sched 42 <when>` unchanged; each gains `ls`/`rm` (+ `log edit`/`rm` = relog/unlog).
|
|
76
|
+
- **`wl date` group** (`date set/ls/rm/import`) completes the reshape; `wl dateinfo` stays the shortcut.
|
|
77
|
+
- **`wl meta` group** — `meta set/ls/rm <node> <field>` for goal/summary/overview/top5 (append typed log); `wl set`/`unset` key-route to meta vs prop.
|
|
78
|
+
- **`wl alias add/ls/rm`** — manage `~/.config/worklog/aliases.ini` (`wl d` == `wl day`).
|
|
79
|
+
- **Newcomer-friendlier `--help`** — quickstart line, commands-by-purpose map, Concepts glossary, per-arg help, and explainers on `wl add`/`day`/`goal`/`recap`.
|
|
80
|
+
- **Single-letter flags** `-d` (`--date`) / `-n` (`--note`) on the daily-workflow commands.
|
|
81
|
+
- **Help cross-references shortcut ↔ canonical both ways** (DESIGN §1.2).
|
|
82
|
+
|
|
83
|
+
### Changed
|
|
84
|
+
- **`wl -h` colorizes to match `wl help`** (3-tier scheme; no-op when color is off; epilogs may use the restricted Markdown).
|
|
85
|
+
- **`--help` epilogs slimmed** — full detail moved to `wl help` topics, leaving summary + examples + a pointer (~23 commands).
|
|
86
|
+
- **`--help` wraps with a hanging indent + caps width** (`_WlHelpFormatter`, 100 cols), measured on visible width.
|
|
87
|
+
- **Removals are reversible (soft-delete tombstones), FKs off** — `deleted_at` on every table; reads filter tombstones; app-level cascade (prep for CRDT sync). Migrations 0008/0009.
|
|
88
|
+
|
|
89
|
+
### Fixed
|
|
90
|
+
- **Width handling hardened** (GPT-5.5 / Kimi / Codex cross-model review) — display-column measurement everywhere (`east_asian_width`, CJK=2, separators=1), char-break for over-long tokens, mono no longer leaks italics, narrow-terminal floors.
|
|
91
|
+
- **`wl show` timeline lines no longer overflow** — truncation budgets the real prefix width.
|
|
92
|
+
- **`wl help <topic>` renders a Markdown subset + escapes literal brackets** (no crash on `[ ]`/`[x]`).
|
|
93
|
+
- **`wl tree --root <month>` / `focus <month>` show `@month`-pinned tasks** (the parent_id walk missed them → false "nothing scheduled").
|
|
94
|
+
- **Shell completion for default-verb group leaf args** (`wl sched <id> --recur`, `wl log <id> --date`).
|
|
95
|
+
- **`parent_id` cycle safety** — bulk apply/import refuse a self/descendant parent; ancestor/descendant walks are visited-set guarded.
|
|
96
|
+
- **`wl link` strips an outer `[[ ]]`** — `[[X]]` and `X` store identically.
|
|
97
|
+
- **`wl day` drops the redundant `«planned·not-done»` hint under `--by plan`.**
|
|
98
|
+
|
|
99
|
+
### Internal
|
|
100
|
+
- **Command taxonomy documented (DESIGN §1.1)** — primitive CRUD / composite helper / view.
|
|
101
|
+
- **More raw SQL moved onto `db_table`** — `_insert_log` returns the id; only genuinely complex JOIN/window/aggregate SQL stays raw.
|
|
102
|
+
|
|
103
|
+
## [0.5.0] — 2026-06-05
|
|
104
|
+
|
|
105
|
+
### Breaking
|
|
106
|
+
- **`at`/`date` timestamp convention — `*_at` instants stored UTC, `*date` calendar days kept local.** `node.scheduled_at`→`scheduled_date`, `deadline_at`→`deadline_date` (column rename); existing rows migrated local→UTC (migration 0007). Transparent to CLI users; **direct-DB consumers must use the new column names and expect UTC instants.** `$WORKLOG_TZ` pins a fixed offset.
|
|
107
|
+
|
|
108
|
+
### Added
|
|
109
|
+
- **Shared `--tag`/`--kind`/`--status` filter across `ls`/`tree`/`day`/`logs`/`agenda`** — one meaning everywhere; `-t` is comma-separated AND.
|
|
110
|
+
- **`wl day` header states the day's nature** — `workday`/`weekend`, refined to `holiday`/`leave` via `wl dateinfo`.
|
|
111
|
+
|
|
112
|
+
### Changed
|
|
113
|
+
- **Day-grouping converts UTC→local before bucketing** (so a log near local midnight lands on the right day).
|
|
114
|
+
- **Habit month-to-date label → English** (`(this month N/M)`).
|
|
115
|
+
|
|
116
|
+
### Internal
|
|
117
|
+
- **Zero-dependency single-table CRUD layer (`db_table`)** — all single-table SQL routes through it; codified as design goal G3 (complex queries stay raw).
|
|
118
|
+
|
|
119
|
+
## [0.4.0] — 2026-06-05
|
|
120
|
+
|
|
121
|
+
### Fixed
|
|
122
|
+
- **`wl sched` is idempotent** — re-scheduling the same date/recurrence reports `= already scheduled`, no duplicate row.
|
|
123
|
+
- **`wl day` no longer tags DONE/CANCELED tasks `«planned·not-done»`.**
|
|
124
|
+
- **`wl focus <day>` expands that day's activity** (was missing tasks hung under projects/habit groups).
|
|
125
|
+
- **Auto-created day builds its full time-ancestor chain** (fixes broken per-month aggregation).
|
|
126
|
+
- **`wl apply` gives an actionable error for an un-indented field op** (instead of "cannot parse").
|
|
127
|
+
- **Shell completion stops offering `someday` for concrete-date commands.**
|
|
128
|
+
- **Flat `wl logs` row stays one line with CJK titles** (display-width budget, not a 30-char slice).
|
|
129
|
+
- **`wl day` plan grouping collapsed to planned/unplanned** (dropped the confusing third bucket).
|
|
130
|
+
|
|
131
|
+
### Added
|
|
132
|
+
- **`wl agenda <start> <end>`** — cross-range scheduling overview reading both schedule sources (concrete days + fuzzy `@month`/`someday` pins).
|
|
133
|
+
- **`wl add` warns when a similar open task/project exists** (non-blocking title-similarity check).
|
|
134
|
+
- **`wl tag <id> +work -planned`** — edit real tags; rejects the old shadow-`tags`-prop footgun.
|
|
135
|
+
- **`wl unlink <id> "doc"`** — remove a single vault link.
|
|
136
|
+
- **`wl recap --date`** — read/back-fill a past day's recap; stamps the staleness marker; builds the day on demand.
|
|
137
|
+
- **Habit lines show month-to-date completion** (`(this month N/M)`).
|
|
138
|
+
- **Metrics fold under their node/log** in `show`/`day`/`tree` (`↳ [glucose] 5.4 mmol/L`).
|
|
139
|
+
- **`node → log → metric` data model** — `metric` table for structured datapoints; `log` gains a `tag`. Migrations 0002/0006.
|
|
140
|
+
- **`wl metric add/ls/edit/rm`** — datapoint CRUD; ids are `#M<id>`.
|
|
141
|
+
- **`--metric` shortcut on `wl log` / `wl add`.**
|
|
142
|
+
- **Habit check-in is a structured signal** — `checkin` metric (idempotent per day); migration 0003 backfills.
|
|
143
|
+
- **`wl import` supports metrics.**
|
|
144
|
+
- **Structured time tracking (`clock` table)** — `start`/`stop`/`spent`/`wait` use a typed interval table; migration 0005.
|
|
145
|
+
- **Day/week/month meta fields keep history** (typed logs, not props); migration 0004.
|
|
146
|
+
- **`wl show` displays the schedule.**
|
|
147
|
+
- **`-q`/`--brief` accepted after the subcommand too** (`wl day -q`).
|
|
148
|
+
- **`wl done` warns on recurring tasks** (use `wl tick` for one occurrence).
|
|
149
|
+
|
|
150
|
+
## [0.3.0] — 2026-06-01
|
|
151
|
+
|
|
152
|
+
### Added
|
|
153
|
+
- **`pip install pyworklog`** — ships as a proper package with a `wl` entry point; dist name is `pyworklog` (short names were taken).
|
|
154
|
+
- **SQL migrations runner** — `migrations/NNNN_*.sql` tracked by `PRAGMA user_version`; `wl migrate` is the explicit form.
|
|
155
|
+
- **Downgrade guard** — aborts if the DB is newer than the running build.
|
|
156
|
+
|
|
157
|
+
### Changed
|
|
158
|
+
- `wl.py` → `src/worklog/cli.py`, `schema.sql` → `migrations/0001_initial_schema.sql`.
|
|
159
|
+
- `__version__` reads from package metadata — `pyproject.toml` is the single version source.
|
|
160
|
+
- `--cov` target `wl` → `worklog`.
|
|
161
|
+
|
|
162
|
+
### Removed
|
|
163
|
+
- Hand-edited `__version__` in `wl.py`.
|
|
164
|
+
|
|
165
|
+
### Migration notes
|
|
166
|
+
- DB path unchanged; existing DBs upgrade transparently (verified on a 311 KB backup, integrity ok). Re-run `make install` so `~/bin/wl` points at the new venv.
|
|
167
|
+
|
|
168
|
+
## [0.2.0] — 2026-05-31
|
|
169
|
+
|
|
170
|
+
### Breaking
|
|
171
|
+
- **Namespace `wl` → `worklog`** — DB + config paths and env vars renamed: `~/.local/share/wl/wl.db` → `…/worklog/worklog.db`, `~/.config/wl/aliases.ini` → `…/worklog/`, `$WL_DB`/`$WL_COLOR`/`$WL_THEME` → `$WORKLOG_*`. The `wl` command itself is unchanged — but **move your DB/config and update env vars** (or re-run `make setup`). The pre-XDG fallback `~/.worklog/wl.db` is gone.
|
|
172
|
+
|
|
173
|
+
### Added
|
|
174
|
+
- **`wl config`** — prints resolved paths / env / runtime info (read-only).
|
|
175
|
+
- **`wl --db PATH`** — per-invocation DB override (beats `$WORKLOG_DB` + XDG default).
|
|
176
|
+
- **XDG Base Directory spec** — DB at `$XDG_DATA_HOME/worklog/`, aliases at `$XDG_CONFIG_HOME/worklog/`.
|
|
177
|
+
- **CI matrix** (Ubuntu + macOS × Python 3.11–3.13) + Codecov + README badges.
|
|
178
|
+
- **Release workflow** — a `v*` tag verifies version anchors, runs tests, publishes a GitHub Release.
|
|
179
|
+
- **`AGENTS.md`** (TDD/DRY rules) + **`CONTRIBUTING.md`** (dev setup, release).
|
|
180
|
+
|
|
181
|
+
### Changed
|
|
182
|
+
- **uv replaces venv/pip/requirements** (`pyproject.toml` + `uv.lock`).
|
|
183
|
+
- Test fixture clears `XDG_CONFIG_HOME` / `XDG_DATA_HOME`.
|
|
184
|
+
|
|
185
|
+
### Removed
|
|
186
|
+
- `requirements*.txt`.
|
|
187
|
+
|
|
188
|
+
## [0.1.0] — 2026-05-31
|
|
189
|
+
|
|
190
|
+
Initial open-source release of `worklog-cli` (`wl`).
|
|
191
|
+
|
|
192
|
+
### Added
|
|
193
|
+
- **Single-table execution-system model** — one `node` table (13 kinds, one id space, `parent_id` tree) + 6 sibling tables (`log`/`tag`/`sched`/`prop`/`link`/`date_meta`).
|
|
194
|
+
- **Seven-state lifecycle** — TODO/DOING/LATER/WAIT/DONE/DEFERRED/CANCELED (superset of markdown's four) + A/B/C priority + auto `closed_at`.
|
|
195
|
+
- **37 subcommands** — create/edit, logging, state transitions, views, meta fields, scheduling, bulk I/O, search, display (most with short aliases).
|
|
196
|
+
- **Scheduling with recurrence** — `sched` table holds one-off dates + rrules; "planned" is derived from it, not a manual tag.
|
|
197
|
+
- **Time tracking** — `start`/`stop`/`spent`/`active`/`wait`.
|
|
198
|
+
- **Project association via shared tags** — `wl projects` rolls members up by children + shared tags (generic tags excluded).
|
|
199
|
+
- **Bulk loaders** — `wl import` (JSON) / `wl apply` (wl-diff).
|
|
200
|
+
- **Compound flags** on `add`/`done`/`cancel` (create + log + close + timestamp + link + schedule in one).
|
|
201
|
+
- **Date aliases** — `today`/`yesterday`/… + Chinese equivalents.
|
|
202
|
+
- **Brief mode `-q`** on every command (~50–90% fewer chars for AI consumers).
|
|
203
|
+
- **`rich` highlighting** with dark/light/mono themes (background auto-detect).
|
|
204
|
+
- **Shell completion** (fish/bash/zsh) via `wl print-completion`.
|
|
205
|
+
- **Vault integration** — `wl link` ↔ Obsidian docs (`[[doc]]`).
|
|
206
|
+
- Bilingual docs (EN + 中文); MIT License.
|
|
207
|
+
|
|
208
|
+
[Unreleased]: https://github.com/xyb/worklog/compare/v0.7.0...HEAD
|
|
209
|
+
[0.7.0]: https://github.com/xyb/worklog/compare/v0.6.0...v0.7.0
|
|
210
|
+
[0.6.0]: https://github.com/xyb/worklog/compare/v0.5.0...v0.6.0
|
|
211
|
+
[0.5.0]: https://github.com/xyb/worklog/compare/v0.4.0...v0.5.0
|
|
212
|
+
[0.4.0]: https://github.com/xyb/worklog/compare/v0.3.0...v0.4.0
|
|
213
|
+
[0.3.0]: https://github.com/xyb/worklog/compare/v0.2.0...v0.3.0
|
|
214
|
+
[0.2.0]: https://github.com/xyb/worklog/compare/v0.1.0...v0.2.0
|
|
215
|
+
[0.1.0]: https://github.com/xyb/worklog/releases/tag/v0.1.0
|
|
@@ -5,7 +5,7 @@ Thanks for considering a contribution! This guide covers the local setup, the de
|
|
|
5
5
|
## Prerequisites
|
|
6
6
|
|
|
7
7
|
- [uv](https://docs.astral.sh/uv/) — install via `brew install uv` or `pipx install uv`.
|
|
8
|
-
- Python ≥ 3.
|
|
8
|
+
- Python ≥ 3.9 (tested on 3.9–3.14). `uv` handles the interpreter — no system Python juggling.
|
|
9
9
|
|
|
10
10
|
## Quick start
|
|
11
11
|
|
|
@@ -25,8 +25,8 @@ make test # parallel, cov, 95% gate — pre-commit baseline
|
|
|
25
25
|
make test-fast # parallel, no cov, no gate — quick iteration
|
|
26
26
|
make test-v # sequential, verbose, no cov — debug a single failure
|
|
27
27
|
|
|
28
|
-
# single test by node id
|
|
29
|
-
uv run pytest tests/
|
|
28
|
+
# single test by node id (tests are split by area: test_add.py / test_agent.py / …)
|
|
29
|
+
uv run pytest tests/test_add.py::TestAdd::test_add_task -v --no-cov
|
|
30
30
|
|
|
31
31
|
# coverage gate already lives in pytest.ini (--cov-fail-under=95); `make cov`
|
|
32
32
|
# just re-runs `make test` with term-missing output for inspection.
|
|
@@ -44,10 +44,21 @@ wl --db /tmp/scratch.db add "experiment"
|
|
|
44
44
|
|
|
45
45
|
## Architecture
|
|
46
46
|
|
|
47
|
-
`DESIGN.md` is canonical for every shared convention — command style, state machine, marker symbols, time-window flags, render pipeline, schema, `import` / `apply` formats, theme keys, scheduled-time resolution, planned/unplanned derivation. Read the relevant section before adding a command or changing a format.
|
|
47
|
+
`DESIGN.md` is canonical for every shared convention — command style, state machine, marker symbols, time-window flags, render pipeline, schema, `import` / `apply` formats, theme keys, scheduled-time resolution, planned/unplanned derivation. Read the relevant section before adding a command or changing a format.
|
|
48
48
|
|
|
49
49
|
`AGENTS.md` is the operating guide for AI coding agents (Claude Code, Cursor, Aider). Skim it once even if you code by hand; it concentrates the hard-rules into one page.
|
|
50
50
|
|
|
51
|
+
### Keep every surface in sync (same commit)
|
|
52
|
+
|
|
53
|
+
A command/flag/behavior is described in many places; a change isn't done until they all agree. Drift between them is the failure mode this project guards against. When you touch one, update in the **same commit**:
|
|
54
|
+
|
|
55
|
+
- **`src/worklog/cli.py`** — the implementation + its argparse `help=` / `epilog` / `description`.
|
|
56
|
+
- **Shell completion** — a new command/flag must appear; if it takes a node id or tag, also wire `_FISH_POSITIONAL_NODE` / the dynamic helpers (it regenerates from the parser, but id/tag completion is hand-registered).
|
|
57
|
+
- **`wl help <topic>`** — the matching topic doc under `src/worklog/help/<lang>/`.
|
|
58
|
+
- **`CHANGELOG.md`** — a one-line `[Unreleased]` entry; a **breaking** change (env/path/schema migration, renamed or removed command/flag, changed contract) goes in a `### Breaking` section, listed first in the release.
|
|
59
|
+
- **`tests/test_<area>.py`** — the test that pins it.
|
|
60
|
+
- **`DESIGN.md`** (+ `DESIGN.zh.md`) if a convention changed; **`skills/worklog-cli/SKILL.md`** if everyday usage changed.
|
|
61
|
+
|
|
51
62
|
## Writing `wl help` topics
|
|
52
63
|
|
|
53
64
|
`wl help <topic>` is an info-style browser over Markdown docs in `src/worklog/help/<lang>/<topic>.md` (architecture: DESIGN §25). `en` is the source language and the per-topic fallback; other languages mirror the same topic ids. To add or edit a topic, just add/edit a `.md` file — the loader, the index, shell completion, and each command's `--help` pointer pick it up automatically.
|
|
@@ -93,13 +104,13 @@ Everything else is printed verbatim, so **lay the body out as readable plain tex
|
|
|
93
104
|
|
|
94
105
|
Every change touching behavior follows the [Red-Green-Refactor cycle](https://brennanbrown.github.io/notes/programming/python-tdd/):
|
|
95
106
|
|
|
96
|
-
1. **Red** — add a failing test in `tests/
|
|
107
|
+
1. **Red** — add a failing test in the matching `tests/test_<area>.py` first. Run it; confirm it fails for the reason you expect (not an import error). A test that never fails is not a test.
|
|
97
108
|
2. **Green** — write the minimum production code to make that test pass. Resist the urge to also fix neighboring code; one cycle, one concern.
|
|
98
109
|
3. **Refactor** — clean up. Extract helpers, remove duplication, rename. Tests still green at every step.
|
|
99
110
|
|
|
100
111
|
Bug fixes follow the same path: write a regression test that reproduces the bug first, then fix.
|
|
101
112
|
|
|
102
|
-
Tests
|
|
113
|
+
Tests need a docstring saying what behavior they pin down. One `Test<Command>` class per command. Cover happy path + boundaries (missing id, empty DB, illegal flag values) — boundaries are where DESIGN drift surfaces first.
|
|
103
114
|
|
|
104
115
|
## DRY: there is exactly one of each
|
|
105
116
|
|
|
@@ -130,7 +141,7 @@ After saving, `make help` lists `push-gitea` alongside the built-in targets.
|
|
|
130
141
|
|
|
131
142
|
## Release process
|
|
132
143
|
|
|
133
|
-
Version has a **single** in-repo source: `version = "X.Y.Z"` in `pyproject.toml`. `__version__` in `src/worklog/cli.py` reads it via `importlib.metadata.version("
|
|
144
|
+
Version has a **single** in-repo source: `version = "X.Y.Z"` in `pyproject.toml`. `__version__` in `src/worklog/cli.py` reads it via `importlib.metadata.version("pyworklog")` — never edit it by hand. The git tag `vX.Y.Z` must match the pyproject version; the release workflow enforces that.
|
|
134
145
|
|
|
135
146
|
The `Release` workflow (`.github/workflows/release.yml`) is triggered by pushing a `v*` tag. It verifies tag == pyproject version, re-runs the test suite, then calls `softprops/action-gh-release@v2` to publish a GitHub Release with auto-generated notes (commits since the previous tag).
|
|
136
147
|
|
|
@@ -139,7 +150,7 @@ To cut a release:
|
|
|
139
150
|
```fish
|
|
140
151
|
# 1. bump version in pyproject.toml only
|
|
141
152
|
# 2. refresh the lock entry so uv.lock pins the new version
|
|
142
|
-
uv lock --upgrade-package
|
|
153
|
+
uv lock --upgrade-package pyworklog
|
|
143
154
|
# 3. commit + tag + push
|
|
144
155
|
git commit -am "chore: bump version to X.Y.Z"
|
|
145
156
|
git tag vX.Y.Z
|
|
@@ -153,5 +164,5 @@ The workflow fails the release if any of the three version anchors disagree, so
|
|
|
153
164
|
|
|
154
165
|
- Branch from `main`. PRs target `main`.
|
|
155
166
|
- Each PR moves the test count up: a refactor adds no tests but keeps coverage ≥95%; a feature/fix adds the test that exercises it.
|
|
156
|
-
- Run `make test` locally before pushing. CI runs the same parallel pytest + 95% gate across ubuntu + macos × Python 3.
|
|
157
|
-
-
|
|
167
|
+
- Run `make test` locally before pushing. CI runs the same parallel pytest + 95% gate across ubuntu + macos × Python 3.9–3.14.
|
|
168
|
+
- Doc/completion/help/changelog drift is the most common review block — run the "Keep every surface in sync" checklist above before pushing.
|