timing-cli 0.1.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.
@@ -0,0 +1,45 @@
1
+ # Python-generated files
2
+ __pycache__/
3
+ *.py[oc]
4
+ build/
5
+ dist/
6
+ wheels/
7
+ *.egg-info
8
+
9
+ # Virtual environments
10
+ .venv
11
+
12
+ # IDE
13
+ .idea/
14
+ .vscode/
15
+ *.swp
16
+
17
+ # Testing
18
+ .coverage
19
+ htmlcov/
20
+ .pytest_cache/
21
+
22
+ # uv
23
+ uv.lock
24
+
25
+ # Claude Code
26
+ .claude
27
+
28
+ # Dolt database files (added by bd init)
29
+ .dolt/
30
+ *.db
31
+
32
+ # Beads JSONL export is local; Dolt is the source of truth.
33
+ .beads/issues.jsonl
34
+
35
+ # Beads runtime artifacts (run state, metrics)
36
+ .beads/runs/
37
+ .beads/export-state.json
38
+
39
+ # Session-close runner artifacts
40
+ .session-close-state.json
41
+ .session-close.lock
42
+
43
+ # Beads / Dolt files (added by bd init)
44
+ .beads-credential-key
45
+ .beads/proxieddb/
@@ -0,0 +1,17 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format is based on
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and this project adheres
5
+ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ### Added
10
+
11
+ - Initial scaffold of `timing-cli`.
12
+ - Read-only access to the local Timing.app SQLite database (`db.py`).
13
+ - Rule-based classification of app usage onto projects (`rules.py`).
14
+ - Aggregation of app usage into gap-merged time-entry suggestions (`analysis.py`).
15
+ - Timing Web API client for pushing time entries (`api.py`).
16
+ - Typer CLI: `info`, `projects`, `usage`, `summary`, `suggest`, `push`, `serve`.
17
+ - FastMCP server exposing local activity and entry creation to agents (`serve.py`).
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Malte Sussdorff
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.
@@ -0,0 +1,218 @@
1
+ Metadata-Version: 2.4
2
+ Name: timing-cli
3
+ Version: 0.1.0
4
+ Summary: CLI + MCP server for the Timing.app macOS time tracker - reads the local activity database and generates/pushes time entries via the Timing Web API
5
+ Project-URL: Homepage, https://github.com/sussdorff/timing-cli
6
+ Project-URL: Repository, https://github.com/sussdorff/timing-cli
7
+ Project-URL: Issues, https://github.com/sussdorff/timing-cli/issues
8
+ Project-URL: Changelog, https://github.com/sussdorff/timing-cli/blob/main/CHANGELOG.md
9
+ Author: Malte Sussdorff
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: cli,macos,mcp,productivity,time-tracking,timing
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: End Users/Desktop
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: MacOS
17
+ Classifier: Operating System :: MacOS :: MacOS X
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Office/Business
22
+ Classifier: Topic :: Utilities
23
+ Requires-Python: >=3.12
24
+ Requires-Dist: fastmcp>=2.0
25
+ Requires-Dist: httpx>=0.27.0
26
+ Requires-Dist: mcp>=1.23.0
27
+ Requires-Dist: pydantic>=2.0.0
28
+ Requires-Dist: rich>=13.0.0
29
+ Requires-Dist: typer>=0.15.0
30
+ Description-Content-Type: text/markdown
31
+
32
+ # timing-cli
33
+
34
+ A command-line interface **and MCP server** for [Timing.app](https://timingapp.com/)
35
+ on macOS. Unlike the Timing Web API — which cannot see your locally recorded app
36
+ usage — `timing-cli` reads Timing's **local activity database directly**
37
+ (read-only) and turns real app usage into aggregated time entries, which it can
38
+ then push back to Timing via the Web API.
39
+
40
+ Because it ships an embedded MCP server, agents (e.g. the Hermes personal agent)
41
+ can query your activity and create entries **without ever copying or exposing
42
+ the raw `SQLite.db`** — the server runs locally, next to the database.
43
+
44
+ > **Not affiliated with Timing.** Independent tool. It only ever *reads* the
45
+ > local database; all writes go through the official Web API.
46
+
47
+ ## What it does
48
+
49
+ - **Reads** the local Timing store (`~/Library/Application Support/info.eurocomp.Timing2/SQLite.db`)
50
+ read-only: automatic app activity, window titles, document paths, projects.
51
+ - **Classifies** unassigned activity onto projects with your own rules (Timing's
52
+ built-in predicate rules only cover ~15% of activity). It also reuses decoded
53
+ Timing project predicate rules from the local database when Timing did not
54
+ already assign a slice.
55
+ - **Aggregates** consecutive same-project slices into clean time blocks
56
+ (gap-merging + minimum-duration filtering).
57
+ - **Pushes** the resulting suggestions to Timing as real time entries via the
58
+ Web API (with a safe dry-run default).
59
+ - **Serves** all of this over MCP (`timing serve`) for agents.
60
+
61
+ ## Quickstart
62
+
63
+ ```bash
64
+ # Install (globally, via uv)
65
+ uv tool install timing-cli
66
+
67
+ # See what's in your local database
68
+ timing info
69
+
70
+ # Daily project summary and suggested entries (read-only)
71
+ timing summary --date 2026-07-05
72
+ timing suggest --date 2026-07-05
73
+
74
+ # Push suggestions to Timing (dry-run first, then --yes)
75
+ export TIMING_API_KEY=... # from https://web.timingapp.com/integrations/tokens
76
+ timing push --date 2026-07-05 # dry-run
77
+ timing push --date 2026-07-05 --yes # actually create entries
78
+
79
+ # Run the MCP server (for Hermes / other agents)
80
+ timing serve # stdio
81
+ export TIMING_MCP_TOKEN=...
82
+ timing serve --transport http # HTTP on 127.0.0.1:8321
83
+ ```
84
+
85
+ `timing push --yes` resolves every non-unassigned suggestion to a unique Web-API
86
+ project before creating anything. If a project is ambiguous or unmapped, the push
87
+ fails before the first write; add a `[project_mappings]` override. Re-running the
88
+ same push skips matching existing entries unless `--replace` is passed.
89
+
90
+ ## Commands
91
+
92
+ | Command | Description |
93
+ | --- | --- |
94
+ | `timing info` | Database location, recorded date range, token status |
95
+ | `timing projects [--remote] [--archived]` | List projects (local DB or Web API) |
96
+ | `timing usage [--date/--from/--to] [--project ID]` | Raw automatically tracked app usage |
97
+ | `timing summary [--date/--from/--to]` | Total time per project |
98
+ | `timing suggest [--date/--from/--to]` | Aggregated time-entry suggestions (read-only) |
99
+ | `timing push [--date/--from/--to] [--yes] [--replace]` | Create entries via Web API (dry-run by default) |
100
+ | `timing serve [--transport] [--host] [--port]` | Run the MCP server |
101
+
102
+ ## Daily workflow
103
+
104
+ ```bash
105
+ # 1. Inspect the day without writing anything.
106
+ timing summary --date 2026-07-05
107
+ timing suggest --date 2026-07-05
108
+
109
+ # 2. If push projects are unmapped, inspect remote project references.
110
+ export TIMING_API_KEY=...
111
+ timing projects --remote
112
+
113
+ # 3. Add missing [project_mappings] entries, then dry-run again.
114
+ timing push --date 2026-07-05
115
+
116
+ # 4. Create entries once the dry-run looks right.
117
+ timing push --date 2026-07-05 --yes
118
+ ```
119
+
120
+ Re-running step 4 for the same day skips matching existing entries. Use
121
+ `--replace` only when you deliberately want Timing's API to replace overlapping
122
+ entries in the target window.
123
+
124
+ ## Configuration
125
+
126
+ Optional config at `~/.config/timing-cli/config.toml`:
127
+
128
+ ```toml
129
+ # Override the database path if Timing lives elsewhere.
130
+ # db_path = "~/Library/Application Support/info.eurocomp.Timing2/SQLite.db"
131
+
132
+ api_base_url = "https://web.timingapp.com/api/v1"
133
+ # api_token = "..." # prefer the TIMING_API_KEY env var instead
134
+ # mcp_http_token = "..." # prefer the TIMING_MCP_TOKEN env var instead
135
+
136
+ min_block_seconds = 120 # drop aggregated blocks shorter than this
137
+ gap_merge_seconds = 300 # merge same-project slices split by a gap up to this
138
+
139
+ # Optional overrides from local Timing projects to Web-API project references.
140
+ # Keys can be a local id ("id:42"), a full title chain, or a leaf title.
141
+ [project_mappings]
142
+ "Client / Polaris" = "/projects/123"
143
+ "id:42" = "/projects/456"
144
+
145
+ # Classification rules: map unassigned activity onto projects.
146
+ # First match wins. `app`/`bundle_id` are case-insensitive substrings;
147
+ # `title`/`path` are regexes.
148
+ [[rules]]
149
+ project = "Polaris"
150
+ title = "polaris"
151
+
152
+ [[rules]]
153
+ project = "Cognovis"
154
+ path = "code/mira"
155
+ ```
156
+
157
+ ### Cognovis example
158
+
159
+ This is a real-world shape for Malte's local setup. Fill the Web-API project
160
+ references from `timing projects --remote`; local project ids can be discovered
161
+ with `timing projects`.
162
+
163
+ ```toml
164
+ api_base_url = "https://web.timingapp.com/api/v1"
165
+ min_block_seconds = 120
166
+ gap_merge_seconds = 300
167
+
168
+ [project_mappings]
169
+ "cognovis Verwaltung" = "/projects/REMOTE_COGNOVIS_VERWALTUNG"
170
+ "]project-open[" = "/projects/REMOTE_PROJECT_OPEN"
171
+ "Home Electronic" = "/projects/REMOTE_HOME_ELECTRONIC"
172
+
173
+ [[rules]]
174
+ project = "cognovis Verwaltung"
175
+ title = "(timing|collmex|paperless|invoice|rechnung)"
176
+
177
+ [[rules]]
178
+ project = "cognovis Verwaltung"
179
+ path = "code/(cli-tools|library)"
180
+
181
+ [[rules]]
182
+ project = "]project-open["
183
+ app = "Mail"
184
+ title = "project-open"
185
+ ```
186
+
187
+ Timing's own project predicates are loaded from the local `Project.predicate`
188
+ column automatically and applied after explicit config rules. Keep local rules
189
+ for repository paths, editor titles, and project-specific conventions that
190
+ Timing itself does not classify well.
191
+
192
+ ## MCP tools
193
+
194
+ `timing serve` exposes: `list_timing_projects`, `list_app_usage_tool`,
195
+ `daily_project_summary`, `suggest_time_entries`, `create_time_entry` (write),
196
+ `recorded_date_range`.
197
+
198
+ HTTP transport requires bearer-token authentication via `TIMING_MCP_TOKEN` or
199
+ `mcp_http_token` in the config. Stdio transport remains local and does not require
200
+ an MCP token.
201
+
202
+ ## Release
203
+
204
+ The repository includes a GitHub Actions release workflow at
205
+ `.github/workflows/release.yml`. Tag pushes run tests and lint only; published
206
+ GitHub releases or manual dispatches build the package and publish to PyPI using
207
+ Trusted Publishing. Configure a PyPI trusted publisher for the repository and
208
+ the `pypi` environment before running the publish job.
209
+
210
+ ## Requirements
211
+
212
+ - macOS with Timing.app installed
213
+ - Python 3.12+ (installed automatically by `uv tool install`)
214
+ - A Timing Web API token for pushing entries (read-only commands need no token)
215
+
216
+ ## License
217
+
218
+ MIT
@@ -0,0 +1,187 @@
1
+ # timing-cli
2
+
3
+ A command-line interface **and MCP server** for [Timing.app](https://timingapp.com/)
4
+ on macOS. Unlike the Timing Web API — which cannot see your locally recorded app
5
+ usage — `timing-cli` reads Timing's **local activity database directly**
6
+ (read-only) and turns real app usage into aggregated time entries, which it can
7
+ then push back to Timing via the Web API.
8
+
9
+ Because it ships an embedded MCP server, agents (e.g. the Hermes personal agent)
10
+ can query your activity and create entries **without ever copying or exposing
11
+ the raw `SQLite.db`** — the server runs locally, next to the database.
12
+
13
+ > **Not affiliated with Timing.** Independent tool. It only ever *reads* the
14
+ > local database; all writes go through the official Web API.
15
+
16
+ ## What it does
17
+
18
+ - **Reads** the local Timing store (`~/Library/Application Support/info.eurocomp.Timing2/SQLite.db`)
19
+ read-only: automatic app activity, window titles, document paths, projects.
20
+ - **Classifies** unassigned activity onto projects with your own rules (Timing's
21
+ built-in predicate rules only cover ~15% of activity). It also reuses decoded
22
+ Timing project predicate rules from the local database when Timing did not
23
+ already assign a slice.
24
+ - **Aggregates** consecutive same-project slices into clean time blocks
25
+ (gap-merging + minimum-duration filtering).
26
+ - **Pushes** the resulting suggestions to Timing as real time entries via the
27
+ Web API (with a safe dry-run default).
28
+ - **Serves** all of this over MCP (`timing serve`) for agents.
29
+
30
+ ## Quickstart
31
+
32
+ ```bash
33
+ # Install (globally, via uv)
34
+ uv tool install timing-cli
35
+
36
+ # See what's in your local database
37
+ timing info
38
+
39
+ # Daily project summary and suggested entries (read-only)
40
+ timing summary --date 2026-07-05
41
+ timing suggest --date 2026-07-05
42
+
43
+ # Push suggestions to Timing (dry-run first, then --yes)
44
+ export TIMING_API_KEY=... # from https://web.timingapp.com/integrations/tokens
45
+ timing push --date 2026-07-05 # dry-run
46
+ timing push --date 2026-07-05 --yes # actually create entries
47
+
48
+ # Run the MCP server (for Hermes / other agents)
49
+ timing serve # stdio
50
+ export TIMING_MCP_TOKEN=...
51
+ timing serve --transport http # HTTP on 127.0.0.1:8321
52
+ ```
53
+
54
+ `timing push --yes` resolves every non-unassigned suggestion to a unique Web-API
55
+ project before creating anything. If a project is ambiguous or unmapped, the push
56
+ fails before the first write; add a `[project_mappings]` override. Re-running the
57
+ same push skips matching existing entries unless `--replace` is passed.
58
+
59
+ ## Commands
60
+
61
+ | Command | Description |
62
+ | --- | --- |
63
+ | `timing info` | Database location, recorded date range, token status |
64
+ | `timing projects [--remote] [--archived]` | List projects (local DB or Web API) |
65
+ | `timing usage [--date/--from/--to] [--project ID]` | Raw automatically tracked app usage |
66
+ | `timing summary [--date/--from/--to]` | Total time per project |
67
+ | `timing suggest [--date/--from/--to]` | Aggregated time-entry suggestions (read-only) |
68
+ | `timing push [--date/--from/--to] [--yes] [--replace]` | Create entries via Web API (dry-run by default) |
69
+ | `timing serve [--transport] [--host] [--port]` | Run the MCP server |
70
+
71
+ ## Daily workflow
72
+
73
+ ```bash
74
+ # 1. Inspect the day without writing anything.
75
+ timing summary --date 2026-07-05
76
+ timing suggest --date 2026-07-05
77
+
78
+ # 2. If push projects are unmapped, inspect remote project references.
79
+ export TIMING_API_KEY=...
80
+ timing projects --remote
81
+
82
+ # 3. Add missing [project_mappings] entries, then dry-run again.
83
+ timing push --date 2026-07-05
84
+
85
+ # 4. Create entries once the dry-run looks right.
86
+ timing push --date 2026-07-05 --yes
87
+ ```
88
+
89
+ Re-running step 4 for the same day skips matching existing entries. Use
90
+ `--replace` only when you deliberately want Timing's API to replace overlapping
91
+ entries in the target window.
92
+
93
+ ## Configuration
94
+
95
+ Optional config at `~/.config/timing-cli/config.toml`:
96
+
97
+ ```toml
98
+ # Override the database path if Timing lives elsewhere.
99
+ # db_path = "~/Library/Application Support/info.eurocomp.Timing2/SQLite.db"
100
+
101
+ api_base_url = "https://web.timingapp.com/api/v1"
102
+ # api_token = "..." # prefer the TIMING_API_KEY env var instead
103
+ # mcp_http_token = "..." # prefer the TIMING_MCP_TOKEN env var instead
104
+
105
+ min_block_seconds = 120 # drop aggregated blocks shorter than this
106
+ gap_merge_seconds = 300 # merge same-project slices split by a gap up to this
107
+
108
+ # Optional overrides from local Timing projects to Web-API project references.
109
+ # Keys can be a local id ("id:42"), a full title chain, or a leaf title.
110
+ [project_mappings]
111
+ "Client / Polaris" = "/projects/123"
112
+ "id:42" = "/projects/456"
113
+
114
+ # Classification rules: map unassigned activity onto projects.
115
+ # First match wins. `app`/`bundle_id` are case-insensitive substrings;
116
+ # `title`/`path` are regexes.
117
+ [[rules]]
118
+ project = "Polaris"
119
+ title = "polaris"
120
+
121
+ [[rules]]
122
+ project = "Cognovis"
123
+ path = "code/mira"
124
+ ```
125
+
126
+ ### Cognovis example
127
+
128
+ This is a real-world shape for Malte's local setup. Fill the Web-API project
129
+ references from `timing projects --remote`; local project ids can be discovered
130
+ with `timing projects`.
131
+
132
+ ```toml
133
+ api_base_url = "https://web.timingapp.com/api/v1"
134
+ min_block_seconds = 120
135
+ gap_merge_seconds = 300
136
+
137
+ [project_mappings]
138
+ "cognovis Verwaltung" = "/projects/REMOTE_COGNOVIS_VERWALTUNG"
139
+ "]project-open[" = "/projects/REMOTE_PROJECT_OPEN"
140
+ "Home Electronic" = "/projects/REMOTE_HOME_ELECTRONIC"
141
+
142
+ [[rules]]
143
+ project = "cognovis Verwaltung"
144
+ title = "(timing|collmex|paperless|invoice|rechnung)"
145
+
146
+ [[rules]]
147
+ project = "cognovis Verwaltung"
148
+ path = "code/(cli-tools|library)"
149
+
150
+ [[rules]]
151
+ project = "]project-open["
152
+ app = "Mail"
153
+ title = "project-open"
154
+ ```
155
+
156
+ Timing's own project predicates are loaded from the local `Project.predicate`
157
+ column automatically and applied after explicit config rules. Keep local rules
158
+ for repository paths, editor titles, and project-specific conventions that
159
+ Timing itself does not classify well.
160
+
161
+ ## MCP tools
162
+
163
+ `timing serve` exposes: `list_timing_projects`, `list_app_usage_tool`,
164
+ `daily_project_summary`, `suggest_time_entries`, `create_time_entry` (write),
165
+ `recorded_date_range`.
166
+
167
+ HTTP transport requires bearer-token authentication via `TIMING_MCP_TOKEN` or
168
+ `mcp_http_token` in the config. Stdio transport remains local and does not require
169
+ an MCP token.
170
+
171
+ ## Release
172
+
173
+ The repository includes a GitHub Actions release workflow at
174
+ `.github/workflows/release.yml`. Tag pushes run tests and lint only; published
175
+ GitHub releases or manual dispatches build the package and publish to PyPI using
176
+ Trusted Publishing. Configure a PyPI trusted publisher for the repository and
177
+ the `pypi` environment before running the publish job.
178
+
179
+ ## Requirements
180
+
181
+ - macOS with Timing.app installed
182
+ - Python 3.12+ (installed automatically by `uv tool install`)
183
+ - A Timing Web API token for pushing entries (read-only commands need no token)
184
+
185
+ ## License
186
+
187
+ MIT
@@ -0,0 +1,51 @@
1
+ [changelog]
2
+ header = """
3
+ # Changelog
4
+
5
+ """
6
+ body = """
7
+ {% if version %}
8
+ ## [{{ version }}] - {{ timestamp | date(format="%Y-%m-%d") }}
9
+ {% else %}
10
+ ## [Unreleased]
11
+ {% endif %}
12
+
13
+ {% for group, commits in commits | group_by(attribute="group") %}
14
+ ### {{ group }}
15
+ {% for commit in commits %}
16
+ - {% if commit.scope %}**{{ commit.scope }}:** {% endif %}{{ commit.message | upper_first }}
17
+ {% endfor %}
18
+ {% endfor %}
19
+
20
+ """
21
+ trim = true
22
+
23
+ [git]
24
+ conventional_commits = true
25
+ filter_unconventional = false
26
+ split_commits = false
27
+ protect_breaking_commits = true
28
+ filter_commits = true
29
+ tag_pattern = "^(?:v)?(?:\\d{4}\\.\\d{1,2}\\.\\d{1,2}(?:\\.\\d+)?|\\d+\\.\\d+\\.\\d+)$"
30
+ skip_tags = ""
31
+ ignore_tags = ""
32
+ topo_order = false
33
+ sort_commits = "oldest"
34
+ commit_preprocessors = [
35
+ { pattern = "^Merge .*", replace = "" },
36
+ ]
37
+ commit_parsers = [
38
+ { message = "^feat", group = "Added" },
39
+ { message = "^fix", group = "Fixed" },
40
+ { message = "^perf", group = "Changed" },
41
+ { message = "^refactor", group = "Changed" },
42
+ { message = "^docs", group = "Documentation" },
43
+ { message = "^test", group = "Tests" },
44
+ { message = "^build", group = "Build" },
45
+ { message = "^ci", group = "Build" },
46
+ { message = "^chore", group = "Changed" },
47
+ { message = "^revert", group = "Changed" },
48
+ { message = "^bd sync:", skip = true },
49
+ { message = "^bd:", skip = true },
50
+ { message = ".*", group = "Changed" },
51
+ ]
@@ -0,0 +1,77 @@
1
+ [project]
2
+ name = "timing-cli"
3
+ version = "0.1.0"
4
+ description = "CLI + MCP server for the Timing.app macOS time tracker - reads the local activity database and generates/pushes time entries via the Timing Web API"
5
+ authors = [
6
+ { name = "Malte Sussdorff" },
7
+ ]
8
+ readme = "README.md"
9
+ requires-python = ">=3.12"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ keywords = ["timing", "time-tracking", "cli", "mcp", "macos", "productivity"]
13
+ classifiers = [
14
+ "Environment :: Console",
15
+ "Intended Audience :: End Users/Desktop",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Operating System :: MacOS",
18
+ "Operating System :: MacOS :: MacOS X",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3.12",
21
+ "Programming Language :: Python :: 3.13",
22
+ "Topic :: Office/Business",
23
+ "Topic :: Utilities",
24
+ ]
25
+ dependencies = [
26
+ "typer>=0.15.0",
27
+ "rich>=13.0.0",
28
+ "fastmcp>=2.0",
29
+ "mcp>=1.23.0",
30
+ "httpx>=0.27.0",
31
+ "pydantic>=2.0.0",
32
+ ]
33
+
34
+ [project.scripts]
35
+ timing = "timing_cli.cli:app"
36
+
37
+ [project.urls]
38
+ Homepage = "https://github.com/sussdorff/timing-cli"
39
+ Repository = "https://github.com/sussdorff/timing-cli"
40
+ Issues = "https://github.com/sussdorff/timing-cli/issues"
41
+ Changelog = "https://github.com/sussdorff/timing-cli/blob/main/CHANGELOG.md"
42
+
43
+ [build-system]
44
+ requires = ["hatchling"]
45
+ build-backend = "hatchling.build"
46
+
47
+ [tool.hatch.build.targets.wheel]
48
+ packages = ["timing_cli"]
49
+
50
+ [tool.hatch.build.targets.sdist]
51
+ include = [
52
+ "/timing_cli",
53
+ "/README.md",
54
+ "/CHANGELOG.md",
55
+ "/LICENSE",
56
+ "/cliff.toml",
57
+ ]
58
+
59
+ [dependency-groups]
60
+ dev = [
61
+ "git-cliff>=2.12.0",
62
+ "pytest>=8.0.0",
63
+ "pytest-cov>=6.0.0",
64
+ "ruff>=0.8.0",
65
+ "bandit>=1.8.0",
66
+ ]
67
+
68
+ [tool.ruff]
69
+ target-version = "py312"
70
+ line-length = 100
71
+
72
+ [tool.ruff.lint]
73
+ select = ["E", "F", "I", "UP", "B", "C4"]
74
+
75
+ [tool.pytest.ini_options]
76
+ testpaths = ["tests"]
77
+ addopts = "-v"
@@ -0,0 +1,3 @@
1
+ """timing-cli: read the local Timing.app database and generate/push time entries."""
2
+
3
+ __version__ = "0.1.0"