weektag 0.0.1__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.
Files changed (38) hide show
  1. weektag-0.0.1/.github/workflows/ci.yml +28 -0
  2. weektag-0.0.1/.github/workflows/release.yml +31 -0
  3. weektag-0.0.1/.gitignore +218 -0
  4. weektag-0.0.1/CLAUDE.md +63 -0
  5. weektag-0.0.1/LICENSE +21 -0
  6. weektag-0.0.1/PKG-INFO +130 -0
  7. weektag-0.0.1/README.ja.md +111 -0
  8. weektag-0.0.1/README.md +112 -0
  9. weektag-0.0.1/docs/adr/README.md +26 -0
  10. weektag-0.0.1/docs/adr/latest/0001-cli-first-positioning.md +18 -0
  11. weektag-0.0.1/docs/adr/latest/0002-recording-model.md +18 -0
  12. weektag-0.0.1/docs/adr/latest/0003-weekly-jsonl-storage.md +22 -0
  13. weektag-0.0.1/docs/adr/latest/0004-record-schema.md +24 -0
  14. weektag-0.0.1/docs/adr/latest/0005-v1-command-set.md +31 -0
  15. weektag-0.0.1/docs/adr/latest/0006-report-export-split.md +21 -0
  16. weektag-0.0.1/docs/adr/latest/0007-daily-export-preset.md +20 -0
  17. weektag-0.0.1/docs/adr/latest/0008-naming-weektag-tt.md +24 -0
  18. weektag-0.0.1/docs/adr/latest/0009-stack-typer-py311.md +22 -0
  19. weektag-0.0.1/docs/adr/latest/0010-repo-ci-publishing.md +20 -0
  20. weektag-0.0.1/pyproject.toml +45 -0
  21. weektag-0.0.1/src/weektag/__init__.py +0 -0
  22. weektag-0.0.1/src/weektag/cli.py +262 -0
  23. weektag-0.0.1/src/weektag/export.py +95 -0
  24. weektag-0.0.1/src/weektag/ops.py +203 -0
  25. weektag-0.0.1/src/weektag/report.py +46 -0
  26. weektag-0.0.1/src/weektag/storage.py +116 -0
  27. weektag-0.0.1/src/weektag/timeutil.py +117 -0
  28. weektag-0.0.1/src/weektag/ulid.py +33 -0
  29. weektag-0.0.1/tests/conftest.py +23 -0
  30. weektag-0.0.1/tests/test_cli.py +247 -0
  31. weektag-0.0.1/tests/test_export.py +133 -0
  32. weektag-0.0.1/tests/test_frozen_time.py +29 -0
  33. weektag-0.0.1/tests/test_ops.py +226 -0
  34. weektag-0.0.1/tests/test_report.py +49 -0
  35. weektag-0.0.1/tests/test_storage.py +121 -0
  36. weektag-0.0.1/tests/test_timeutil.py +115 -0
  37. weektag-0.0.1/tests/test_ulid.py +40 -0
  38. weektag-0.0.1/uv.lock +214 -0
@@ -0,0 +1,28 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ strategy:
11
+ fail-fast: false
12
+ matrix:
13
+ os: [ubuntu-latest, macos-latest, windows-latest]
14
+ python-version: ["3.11", "3.12", "3.13"]
15
+ runs-on: ${{ matrix.os }}
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+ - uses: astral-sh/setup-uv@v5
19
+ with:
20
+ python-version: ${{ matrix.python-version }}
21
+ - name: Install
22
+ run: uv sync
23
+ - name: Lint
24
+ run: |
25
+ uv run ruff check .
26
+ uv run ruff format --check .
27
+ - name: Test
28
+ run: uv run pytest -q
@@ -0,0 +1,31 @@
1
+ name: Release
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+
7
+ jobs:
8
+ build:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v4
12
+ - uses: astral-sh/setup-uv@v5
13
+ - name: Build
14
+ run: uv build
15
+ - uses: actions/upload-artifact@v4
16
+ with:
17
+ name: dist
18
+ path: dist/
19
+
20
+ publish:
21
+ needs: build
22
+ runs-on: ubuntu-latest
23
+ environment: pypi
24
+ permissions:
25
+ id-token: write # PyPI Trusted Publishing (OIDC), no API tokens (ADR 0010)
26
+ steps:
27
+ - uses: actions/download-artifact@v4
28
+ with:
29
+ name: dist
30
+ path: dist/
31
+ - uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,218 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ lib64/
19
+ parts/
20
+ sdist/
21
+ var/
22
+ wheels/
23
+ share/python-wheels/
24
+ *.egg-info/
25
+ .installed.cfg
26
+ *.egg
27
+ MANIFEST
28
+
29
+ # PyInstaller
30
+ # Usually these files are written by a python script from a template
31
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
32
+ *.manifest
33
+ *.spec
34
+
35
+ # Installer logs
36
+ pip-log.txt
37
+ pip-delete-this-directory.txt
38
+
39
+ # Unit test / coverage reports
40
+ htmlcov/
41
+ .tox/
42
+ .nox/
43
+ .coverage
44
+ .coverage.*
45
+ .cache
46
+ nosetests.xml
47
+ coverage.xml
48
+ *.cover
49
+ *.py.cover
50
+ .hypothesis/
51
+ .pytest_cache/
52
+ cover/
53
+
54
+ # Translations
55
+ *.mo
56
+ *.pot
57
+
58
+ # Django stuff:
59
+ *.log
60
+ local_settings.py
61
+ db.sqlite3
62
+ db.sqlite3-journal
63
+
64
+ # Flask stuff:
65
+ instance/
66
+ .webassets-cache
67
+
68
+ # Scrapy stuff:
69
+ .scrapy
70
+
71
+ # Sphinx documentation
72
+ docs/_build/
73
+
74
+ # PyBuilder
75
+ .pybuilder/
76
+ target/
77
+
78
+ # Jupyter Notebook
79
+ .ipynb_checkpoints
80
+
81
+ # IPython
82
+ profile_default/
83
+ ipython_config.py
84
+
85
+ # pyenv
86
+ # For a library or package, you might want to ignore these files since the code is
87
+ # intended to run in multiple environments; otherwise, check them in:
88
+ # .python-version
89
+
90
+ # pipenv
91
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
93
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
94
+ # install all needed dependencies.
95
+ # Pipfile.lock
96
+
97
+ # UV
98
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
99
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
100
+ # commonly ignored for libraries.
101
+ # uv.lock
102
+
103
+ # poetry
104
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
105
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
106
+ # commonly ignored for libraries.
107
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
108
+ # poetry.lock
109
+ # poetry.toml
110
+
111
+ # pdm
112
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
113
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
114
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
115
+ # pdm.lock
116
+ # pdm.toml
117
+ .pdm-python
118
+ .pdm-build/
119
+
120
+ # pixi
121
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
122
+ # pixi.lock
123
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
124
+ # in the .venv directory. It is recommended not to include this directory in version control.
125
+ .pixi
126
+
127
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
128
+ __pypackages__/
129
+
130
+ # Celery stuff
131
+ celerybeat-schedule
132
+ celerybeat.pid
133
+
134
+ # Redis
135
+ *.rdb
136
+ *.aof
137
+ *.pid
138
+
139
+ # RabbitMQ
140
+ mnesia/
141
+ rabbitmq/
142
+ rabbitmq-data/
143
+
144
+ # ActiveMQ
145
+ activemq-data/
146
+
147
+ # SageMath parsed files
148
+ *.sage.py
149
+
150
+ # Environments
151
+ .env
152
+ .envrc
153
+ .venv
154
+ env/
155
+ venv/
156
+ ENV/
157
+ env.bak/
158
+ venv.bak/
159
+
160
+ # Spyder project settings
161
+ .spyderproject
162
+ .spyproject
163
+
164
+ # Rope project settings
165
+ .ropeproject
166
+
167
+ # mkdocs documentation
168
+ /site
169
+
170
+ # mypy
171
+ .mypy_cache/
172
+ .dmypy.json
173
+ dmypy.json
174
+
175
+ # Pyre type checker
176
+ .pyre/
177
+
178
+ # pytype static type analyzer
179
+ .pytype/
180
+
181
+ # Cython debug symbols
182
+ cython_debug/
183
+
184
+ # PyCharm
185
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
186
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
187
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
188
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
189
+ # .idea/
190
+
191
+ # Abstra
192
+ # Abstra is an AI-powered process automation framework.
193
+ # Ignore directories containing user credentials, local state, and settings.
194
+ # Learn more at https://abstra.io/docs
195
+ .abstra/
196
+
197
+ # Visual Studio Code
198
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
199
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
200
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
201
+ # you could uncomment the following to ignore the entire vscode folder
202
+ # .vscode/
203
+ # Temporary file for partial code execution
204
+ tempCodeRunnerFile.py
205
+
206
+ # Ruff stuff:
207
+ .ruff_cache/
208
+
209
+ # PyPI configuration file
210
+ .pypirc
211
+
212
+ # Marimo
213
+ marimo/_static/
214
+ marimo/_lsp/
215
+ __marimo__/
216
+
217
+ # Streamlit
218
+ .streamlit/secrets.toml
@@ -0,0 +1,63 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## What this is
6
+
7
+ **weektag** — a CLI-first, tag-based time tracker (command name: `tt`) distributed on PyPI as `weektag`. Its differentiator is agent-readability: the data files must be directly readable by humans, `jq`, and coding agents with no preprocessing.
8
+
9
+ Implementation lives in `src/weektag/` (`cli.py` typer commands → `ops.py` operations → `storage.py` JSONL I/O, plus `timeutil.py`, `ulid.py`, `report.py`, `export.py`). Tests in `tests/` pin the current time by monkeypatching `timeutil.now_local` (see `conftest.py` fixtures `data_dir` / `freeze_now`) so results don't depend on the machine timezone.
10
+
11
+ ## Design source of truth: docs/adr/
12
+
13
+ `docs/adr/latest/` (Japanese) is the **single canonical source** for all design decisions. Read the relevant ADRs before implementing or reviewing anything, and resolve design questions against them.
14
+
15
+ ADR rules: new decisions get a new sequential number in `latest/`; numbers are never reused or renumbered. To change a decision, move the old ADR to `archive/{NNNN}/` and write a new one under a new number. Each ADR has four sections: ステータス / コンテキスト / 決定 / 結果.
16
+
17
+ ## Architecture (decided in ADRs 0001–0010)
18
+
19
+ **Recording model (0002):** start/stop interval records only. At most **one running task** — `start` while another runs auto-stops it. A running task is simply a record with no `stop` key; there is no separate state file. `add`/`edit`/`rm`/`cancel` provide after-the-fact correction.
20
+
21
+ **Storage (0003):** weekly JSONL files are the **only source of truth** — no index, no DB, no hidden state. Location: `~/.local/share/weektag/events/` (XDG), overridable via `WEEKTAG_DATA_DIR`. Files are named by ISO 8601 week (`2026-W27.jsonl`), weeks start **Monday (unchangeable)**. A record belongs to the week of its **start time**; week-spanning records are not split. Writes go through temp file + atomic `os.replace`. Hand-editing by users/agents is officially supported. The running task is found by scanning recent week files for a record lacking `stop`.
22
+
23
+ **Record schema (0004):** one JSON object per line:
24
+ ```json
25
+ {"id":"01JZK3AB","start":"2026-07-06T09:00:00+09:00","stop":"2026-07-06T10:30:00+09:00","tags":["writing","client-a"],"note":"ブログ下書き"}
26
+ ```
27
+ - Times are **local time + UTC offset** (ISO 8601) — never normalize to UTC. Week membership is judged by local date.
28
+ - `id` is a self-implemented sortable **mini-ULID** (timestamp + randomness); commands accept prefix matches.
29
+ - Tags are positional args (`tt start writing client-a`); a quoted `'#tag'` is accepted with `#` stripped. Note goes via `-m`.
30
+
31
+ **v1 command set (0005):** `start`, `stop`, `status`, `resume`, `add`, `edit`, `rm`, `cancel`, `log`, `report`, `export`. Explicitly **out of scope for v1**: goals/targets, focus timer, timeline UI, plan.
32
+
33
+ **report vs export (0006):** `report` is a per-tag summary table for the terminal (multi-tag events count their full duration under *each* tag, so the tag column can exceed the total row, which is computed from real event time). `export` emits row-level data, default **TSV**, columns `date/start/stop/hours/tags/note`. Hours are **decimal** (1.50), unrounded unless `--round`. All output is **plain text — no rich formatting anywhere**. No clipboard integration (pipe to clip.exe/pbcopy instead).
34
+
35
+ **Daily preset (0007):** `tt export --daily [--date 7/6]` emits exactly 3 TSV columns (summary / AM hours / PM hours), **no header by default**, aggregated per (tag-set + note) per day, split mechanically at noon (`--noon` to change), pro-rated across the boundary. Summary = note if present, else space-joined tags.
36
+
37
+ **Naming (0008):** PyPI/import/repo name `weektag`, console command `tt` via `[project.scripts] tt = "weektag.cli:main"`.
38
+
39
+ ## Stack & constraints (0009)
40
+
41
+ - **typer** is the only runtime dependency (bundled rich/shellingham included, but rich decoration is unused).
42
+ - Python **3.11+**.
43
+ - Shell completion is a v1 requirement, including **dynamic tag completion** (candidates gathered from recent week files via typer autocompletion callbacks).
44
+ - Current time: `datetime.now().astimezone()` (works on Windows without tzdata).
45
+ - No config file in v1 — env var + flags only.
46
+
47
+ ## Development (0010)
48
+
49
+ - **src layout** (`src/weektag/`), **hatchling** backend, everything in `pyproject.toml`.
50
+ - Tooling: **uv** (env/lock), **ruff** (lint + format), **pytest + freezegun** (deterministic time-based tests). Dev deps separated from runtime deps.
51
+ - This checkout lives under OneDrive, which breaks uv's default hardlinking — run uv with `UV_LINK_MODE=copy` (e.g. `UV_LINK_MODE=copy uv sync`).
52
+ - Commands:
53
+ - `uv sync` — set up environment
54
+ - `uv run pytest` — run tests; single test: `uv run pytest tests/test_x.py::test_name`
55
+ - `uv run ruff check .` / `uv run ruff format .`
56
+ - `uv run tt ...` — run the CLI locally
57
+ - CI: GitHub Actions matrix ubuntu/macos/windows × Python 3.11–3.13 on every push/PR.
58
+ - Publishing: PyPI **Trusted Publishing** (OIDC) triggered by pushing a git tag. No API tokens.
59
+ - License MIT. README in English with a `README.ja.md` alongside.
60
+
61
+ ## Testing focus
62
+
63
+ Bugs are expected to concentrate in time handling — write freezegun-pinned tests for: ISO week boundaries, the W53 ISO-week-year mismatch (e.g. 2027-01-01 belongs to `2026-W53.jsonl`), noon splitting/pro-rating, timezone offsets, and midnight-spanning events. Windows behavior (paths, `os.replace` atomicity, console output) is verified in CI, not locally.
weektag-0.0.1/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Takehiro M.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
weektag-0.0.1/PKG-INFO ADDED
@@ -0,0 +1,130 @@
1
+ Metadata-Version: 2.4
2
+ Name: weektag
3
+ Version: 0.0.1
4
+ Summary: Tag-based CLI time tracker with agent-readable weekly JSONL storage
5
+ Project-URL: Repository, https://github.com/takeknock/weektag
6
+ Author: takeknock
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Keywords: cli,jsonl,tags,time-tracking
10
+ Classifier: Environment :: Console
11
+ Classifier: Operating System :: OS Independent
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Requires-Python: >=3.11
16
+ Requires-Dist: typer>=0.12
17
+ Description-Content-Type: text/markdown
18
+
19
+ # weektag
20
+
21
+ Tag-based CLI time tracker with agent-readable weekly JSONL storage.
22
+
23
+ [日本語版 README](README.ja.md)
24
+
25
+ `weektag` records what you work on as start/stop intervals with flat tags, stores them
26
+ as plain JSONL files split by ISO week, and turns them into weekly reports or
27
+ TSV/CSV you can paste straight into Excel. The files are the whole database:
28
+ `cat`, `grep`, `jq`, and coding agents (Claude Code etc.) can read them with no
29
+ preprocessing — and hand-editing them is officially supported.
30
+
31
+ ```console
32
+ $ tt start writing client-a -m "blog draft"
33
+ started writing client-a "blog draft" at 09:00 [KZ3M2A7Q]
34
+
35
+ $ tt status
36
+ running: writing client-a "blog draft" (started 09:00, 1.50 h elapsed) [KZ3M2A7Q]
37
+
38
+ $ tt stop
39
+ stopped writing client-a "blog draft" (1.50 h)
40
+ ```
41
+
42
+ ## Install
43
+
44
+ ```console
45
+ pipx install weektag # or: uv tool install weektag
46
+ ```
47
+
48
+ The installed command is `tt` (the package name `tt` was taken on PyPI).
49
+ Requires Python 3.11+.
50
+
51
+ ## Commands
52
+
53
+ ```
54
+ tt start <tags...> [-m NOTE] [--at 9:00] # start (auto-stops a running task)
55
+ tt stop [--at 10:30] # stop
56
+ tt status # running task + elapsed time
57
+ tt resume # restart previous task (same tags/note)
58
+ tt add 9:00-10:30 <tags...> [-m NOTE] # add a past interval
59
+ tt edit <id-prefix> [--start] [--stop] [--tags] [-m]
60
+ tt rm <id-prefix> # delete a record
61
+ tt cancel # discard the running task
62
+ tt log [--week 2026-W27] # raw log with ids (entry point for edit)
63
+ tt report [--week 2026-W27 | --last] # per-tag weekly summary
64
+ tt export [--format csv] [-o FILE] [--no-header]
65
+ tt export --daily [--date 7/6] [--noon 13:00] [--round 0.25] [--header]
66
+ ```
67
+
68
+ Only one task runs at a time: `tt start` while another task is running stops it
69
+ first. Forgot to start or stop? `add` / `edit` / `rm` fix the record afterwards.
70
+
71
+ Shell completion (bash / zsh / fish), including dynamic tag completion from your
72
+ recent records:
73
+
74
+ ```console
75
+ tt --install-completion
76
+ ```
77
+
78
+ ## Data format
79
+
80
+ One JSON object per line, one file per ISO week (Monday start), in
81
+ `~/.local/share/weektag/events/` (override with `WEEKTAG_DATA_DIR`;
82
+ `XDG_DATA_HOME` is honored):
83
+
84
+ ```json
85
+ {"id":"KZ3M2A7Q","start":"2026-07-06T09:00:00+09:00","stop":"2026-07-06T10:30:00+09:00","tags":["writing","client-a"],"note":"blog draft"}
86
+ ```
87
+
88
+ - A running task is simply a record without a `stop` key.
89
+ - Times are local time with UTC offset; week membership follows the local date
90
+ of `start`. Week-spanning records are not split.
91
+ - The week files are the only source of truth — no hidden state, no index, no
92
+ database. Edit them by hand or with an agent whenever you like.
93
+
94
+ ### Note on ISO week years
95
+
96
+ Files use ISO 8601 week numbering, which can differ from the calendar year at
97
+ year boundaries: a record on 2027-01-01 lives in `2026-W53.jsonl`. Commands
98
+ resolve this correctly; it only matters when you browse the files by hand.
99
+
100
+ ## Excel workflow
101
+
102
+ `tt export` prints TSV rows (`date start stop hours tags note`) with decimal
103
+ hours (`1.50`), so a paste into Excel splits into columns and `SUM` just works.
104
+
105
+ `tt export --daily` is a preset for daily-report sheets: exactly three columns
106
+ (summary / AM hours / PM hours), aggregated per (tag set + note), split at noon
107
+ (`--noon` to change), no header by default so you can append to an existing
108
+ table day after day. There is no clipboard integration — pipe instead:
109
+
110
+ ```console
111
+ tt export --daily | clip # Windows
112
+ tt export --daily | pbcopy # macOS
113
+ tt export --daily | xclip -sel c
114
+ ```
115
+
116
+ ## Command name collision
117
+
118
+ The `tt-time-tracker` package also installs a `tt` command. pipx / uv isolate
119
+ the environments, so only the PATH entry can collide. If you use both, rename
120
+ one with a shell alias, e.g. `alias wt=tt`.
121
+
122
+ ## Development
123
+
124
+ ```console
125
+ uv sync
126
+ uv run pytest
127
+ uv run ruff check . && uv run ruff format --check .
128
+ ```
129
+
130
+ MIT license.
@@ -0,0 +1,111 @@
1
+ # weektag
2
+
3
+ タグ式のCLIタイムトラッカー。記録はエージェント可読な週別JSONLに保存。
4
+
5
+ [English README](README.md)
6
+
7
+ `weektag` は作業を start/stop の区間としてフラットなタグ付きで記録し、ISO週ごとの
8
+ プレーンな JSONL ファイルに保存します。週次レポートや、Excel にそのまま貼れる
9
+ TSV/CSV に変換できます。ファイルがデータベースのすべてであり、`cat` / `grep` /
10
+ `jq`、そして Claude Code などのコーディングエージェントが前処理なしで読めます。
11
+ 手編集も正式サポートです。
12
+
13
+ ```console
14
+ $ tt start writing client-a -m "ブログ下書き"
15
+ started writing client-a "ブログ下書き" at 09:00 [KZ3M2A7Q]
16
+
17
+ $ tt status
18
+ running: writing client-a "ブログ下書き" (started 09:00, 1.50 h elapsed) [KZ3M2A7Q]
19
+
20
+ $ tt stop
21
+ stopped writing client-a "ブログ下書き" (1.50 h)
22
+ ```
23
+
24
+ ## インストール
25
+
26
+ ```console
27
+ pipx install weektag # または: uv tool install weektag
28
+ ```
29
+
30
+ インストールされるコマンドは `tt` です(PyPI の `tt` は取得済みのため配布名は
31
+ `weektag`)。Python 3.11 以上が必要です。
32
+
33
+ ## コマンド
34
+
35
+ ```
36
+ tt start <tags...> [-m メモ] [--at 9:00] # 開始(実行中があれば自動stop)
37
+ tt stop [--at 10:30] # 停止
38
+ tt status # 実行中タスクと経過時間
39
+ tt resume # 直前タスクを同タグ・同メモで再開
40
+ tt add 9:00-10:30 <tags...> [-m メモ] # 後追いの区間追加
41
+ tt edit <id前方一致> [--start] [--stop] [--tags] [-m]
42
+ tt rm <id前方一致> # 削除
43
+ tt cancel # 実行中を記録せず破棄
44
+ tt log [--week 2026-W27] # id付き生ログ(editの入口)
45
+ tt report [--week 2026-W27 | --last] # タグ別の週次集計
46
+ tt export [--format csv] [-o FILE] [--no-header]
47
+ tt export --daily [--date 7/6] [--noon 13:00] [--round 0.25] [--header]
48
+ ```
49
+
50
+ 同時に実行できるタスクは常に1本だけです。実行中に `tt start` すると前のタスクを
51
+ 止めてから開始します。打ち忘れ・止め忘れは `add` / `edit` / `rm` で後から直せます。
52
+
53
+ シェル補完(bash / zsh / fish)。直近の記録からのタグ動的補完つき:
54
+
55
+ ```console
56
+ tt --install-completion
57
+ ```
58
+
59
+ ## データ形式
60
+
61
+ 1行=1 JSONオブジェクト、1ファイル=1 ISO週(月曜始まり)。保存先は
62
+ `~/.local/share/weektag/events/`(`WEEKTAG_DATA_DIR` で変更可、
63
+ `XDG_DATA_HOME` にも対応):
64
+
65
+ ```json
66
+ {"id":"KZ3M2A7Q","start":"2026-07-06T09:00:00+09:00","stop":"2026-07-06T10:30:00+09:00","tags":["writing","client-a"],"note":"ブログ下書き"}
67
+ ```
68
+
69
+ - 実行中タスクは `stop` キーを持たないレコードです。
70
+ - 時刻はローカル時刻+UTCオフセット。週の帰属は `start` のローカル日付で決まり、
71
+ 週を跨ぐレコードも分割しません。
72
+ - 週ファイルが唯一の真実です。隠れた状態ファイル・インデックス・DBはありません。
73
+ 手やエージェントでいつでも編集できます。
74
+
75
+ ### ISO週年についての注意
76
+
77
+ ファイル名は ISO 8601 週番号なので、年末年始で暦年とズレることがあります。
78
+ 例:2027-01-01 のレコードは `2026-W53.jsonl` に入ります。コマンドは正しく
79
+ 解決するので、手でファイルを探すときだけ気にしてください。
80
+
81
+ ## Excel との連携
82
+
83
+ `tt export` は十進時間(`1.50`)の TSV(`date start stop hours tags note`)を
84
+ 出力するので、Excel に貼ると列が自動で分かれ、SUM がそのまま効きます。
85
+
86
+ `tt export --daily` は日報転記用プリセットです:3列だけ(概要 / 午前実績 /
87
+ 午後実績)、その日の「タグ集合+メモ」ごとに集約、正午で機械分割(`--noon` で
88
+ 変更可)、既存の表に日々貼るためヘッダーは既定で出しません。予定列は出力しない
89
+ ので、右端の予定列を上書きしません。クリップボード連携は内蔵せず、パイプで:
90
+
91
+ ```console
92
+ tt export --daily | clip # Windows
93
+ tt export --daily | pbcopy # macOS
94
+ tt export --daily | xclip -sel c
95
+ ```
96
+
97
+ ## コマンド名の衝突
98
+
99
+ `tt-time-tracker` パッケージも `tt` コマンドをインストールします。pipx / uv では
100
+ 環境自体は隔離され、PATH 上でのみ衝突します。両方使う場合はシェルエイリアスで
101
+ どちらかを改名してください(例:`alias wt=tt`)。
102
+
103
+ ## 開発
104
+
105
+ ```console
106
+ uv sync
107
+ uv run pytest
108
+ uv run ruff check . && uv run ruff format --check .
109
+ ```
110
+
111
+ MIT ライセンス。