ccq 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.
- ccq-0.1.0/LICENSE +21 -0
- ccq-0.1.0/PKG-INFO +150 -0
- ccq-0.1.0/README.md +128 -0
- ccq-0.1.0/pyproject.toml +63 -0
- ccq-0.1.0/src/ccq/__init__.py +3 -0
- ccq-0.1.0/src/ccq/cli.py +425 -0
- ccq-0.1.0/src/ccq/db.py +479 -0
- ccq-0.1.0/src/ccq/format.py +88 -0
- ccq-0.1.0/src/ccq/pricing.py +68 -0
- ccq-0.1.0/src/ccq/server.py +317 -0
ccq-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 saagpatel
|
|
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.
|
ccq-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ccq
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Query your own Claude Code agent history with DuckDB, read-only, straight over the JSONL transcripts.
|
|
5
|
+
Keywords: claude-code,duckdb,cli,jsonl,observability,agent-history
|
|
6
|
+
Author: saagpatel
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Operating System :: OS Independent
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Topic :: Utilities
|
|
15
|
+
Requires-Dist: duckdb>=1.1.0
|
|
16
|
+
Requires-Dist: click>=8.1.0
|
|
17
|
+
Requires-Python: >=3.12
|
|
18
|
+
Project-URL: Homepage, https://github.com/saagpatel/ccq
|
|
19
|
+
Project-URL: Repository, https://github.com/saagpatel/ccq
|
|
20
|
+
Project-URL: Issues, https://github.com/saagpatel/ccq/issues
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
|
|
23
|
+
# ccq — query your own Claude Code agent history
|
|
24
|
+
|
|
25
|
+
[](https://github.com/saagpatel/ccq/actions/workflows/ci.yml)
|
|
26
|
+
[](https://www.python.org/)
|
|
27
|
+
|
|
28
|
+
`ccq` makes your local Claude Code transcripts queryable. It runs **DuckDB directly
|
|
29
|
+
over the JSONL** at `~/.claude/projects/<project>/<session>.jsonl` — no copy, no ETL,
|
|
30
|
+
no database to maintain. The transcripts are only ever **read**, never written.
|
|
31
|
+
|
|
32
|
+
Ask it where your tokens go, which tools you lean on, where runs hit rate limits,
|
|
33
|
+
how much you delegate to subagents, and what happened inside any single session.
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
$ ccq cost --by model
|
|
37
|
+
model turns in_tok out_tok cost_usd
|
|
38
|
+
------------------------- ------ -------------- ----------- ---------
|
|
39
|
+
claude-opus-4-8 12,345 3,456,789,012 28,500,000 4,210.55
|
|
40
|
+
claude-sonnet-4-6 6,789 901,234,567 8,400,000 612.30
|
|
41
|
+
...
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Install
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
uv sync # create the venv + install deps
|
|
48
|
+
uv run ccq --help
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
(Or `uv tool install .` to put `ccq` on your PATH.)
|
|
52
|
+
|
|
53
|
+
## Commands
|
|
54
|
+
|
|
55
|
+
| Command | What it answers |
|
|
56
|
+
|---|---|
|
|
57
|
+
| `ccq sessions` | List sessions: project, span, message count, tokens, estimated cost. `--sort cost\|duration\|messages\|recent`, `--project`, `--since`, `-n`. |
|
|
58
|
+
| `ccq cost` | Cost rollups. `--by project\|model\|day\|session`. Main-loop only (see caveat). |
|
|
59
|
+
| `ccq tools` | Tool-use frequency. `--bash` breaks Bash calls down by leading command. |
|
|
60
|
+
| `ccq errors` | API errors / retries (429s, etc.) by project + status. `--list` for recent events. |
|
|
61
|
+
| `ccq agents` | Subagent (Agent tool) dispatches + token totals. `--by type\|model\|session\|project`. |
|
|
62
|
+
| `ccq session <id-prefix>` | One session's decision timeline: prompts, tool calls, errors, in order. |
|
|
63
|
+
| `ccq search <text>` | Full-text over your typed prompts and session titles → matching sessions. |
|
|
64
|
+
| `ccq sql "<SELECT…>"` | Run an arbitrary **read-only** query over the views (power surface). |
|
|
65
|
+
| `ccq serve` | Launch a local web dashboard (localhost only) with a read-only SQL box. |
|
|
66
|
+
| `ccq cache build\|status\|clear` | Manage the materialized snapshot that powers `--fast`. |
|
|
67
|
+
|
|
68
|
+
Every command takes `-f table|json|csv` and a global `--projects-dir` (defaults to
|
|
69
|
+
`~/.claude/projects`, handy for pointing at a backup).
|
|
70
|
+
|
|
71
|
+
## Fast mode
|
|
72
|
+
|
|
73
|
+
A live query rescans ~1 GB of JSONL each time (~1-3 s). For instant repeat queries,
|
|
74
|
+
materialize a snapshot once and pass `--fast` (`-F`):
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
ccq cache build # ~6 s, writes a ~100 MB snapshot to ~/.cache/ccq
|
|
78
|
+
ccq -F cost --by model # now ~0.1 s
|
|
79
|
+
ccq cache status # shows STALE once transcripts change; rebuild to refresh
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The snapshot lives under `$XDG_CACHE_HOME` (never in `~/.claude`), is opened
|
|
83
|
+
**read-only** at the engine level, and `--fast` builds it automatically on first use.
|
|
84
|
+
|
|
85
|
+
## Web viewer
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
ccq -F serve # http://127.0.0.1:8787 (Ctrl-C to stop)
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
A dashboard (cost by model, tools, errors, subagents, priciest sessions) plus a SQL
|
|
92
|
+
box that runs the same read-only-guarded queries. **Drill down:** click a project
|
|
93
|
+
chip to filter to that project, or a session id to see its full decision timeline.
|
|
94
|
+
Standard-library `http.server`, no extra dependencies, binds to localhost only.
|
|
95
|
+
|
|
96
|
+
## The query surface (`ccq sql`)
|
|
97
|
+
|
|
98
|
+
`sql` exposes these views — compose your own:
|
|
99
|
+
|
|
100
|
+
- **`sessions`** — one row per session: project, branch, span, `messages`, `models`, tokens, `cost_usd`.
|
|
101
|
+
- **`message_usage`** — one row per assistant turn: token breakdown + `cost_usd`.
|
|
102
|
+
- **`tool_calls`** — one row per tool invocation: `tool_name`, `tool_input` (JSON).
|
|
103
|
+
- **`errors`** — API error events: `status`, project, session, model.
|
|
104
|
+
- **`agents`** / **`agent_results`** — subagent dispatches joined to their `subagent_tokens`.
|
|
105
|
+
- **`prompts`** — searchable typed prompts + session titles.
|
|
106
|
+
- **`events`** — the raw per-line view everything else is built on.
|
|
107
|
+
- **`model_pricing`** — the per-model rate table used for costing.
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
ccq sql "SELECT project, round(sum(cost_usd),2) usd
|
|
111
|
+
FROM message_usage WHERE ts >= DATE '2026-06-01'
|
|
112
|
+
GROUP BY 1 ORDER BY usd DESC"
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
`sql` accepts a **single read-only statement** (SELECT/WITH/EXPLAIN/…). Writes,
|
|
116
|
+
`ATTACH`, `COPY`, `INSTALL`, and multi-statement input are refused. Tip: DuckDB
|
|
117
|
+
reserves words like `day`, `first`, `last` — quote them if used as aliases (`AS "day"`).
|
|
118
|
+
|
|
119
|
+
## How it works
|
|
120
|
+
|
|
121
|
+
`read_ndjson_objects('~/.claude/projects/*/*.jsonl')` loads each line as an opaque
|
|
122
|
+
`JSON` value (zero schema inference — the records are heterogeneous), and SQL views
|
|
123
|
+
extract the entities. Two things the transcripts taught us are baked in:
|
|
124
|
+
|
|
125
|
+
- Numeric fields use `TRY_CAST` (heterogeneous lines otherwise break a hard cast).
|
|
126
|
+
- Token-casting views read from a type-filtered subquery so the optimizer can't
|
|
127
|
+
reorder a cast ahead of the `type = 'assistant'` filter.
|
|
128
|
+
|
|
129
|
+
## Cost is estimated, and main-loop only
|
|
130
|
+
|
|
131
|
+
Transcripts store **token counts, not dollars**. `ccq` prices them with published
|
|
132
|
+
per-million-token rates (`src/ccq/pricing.py`) and the standard cache multipliers
|
|
133
|
+
(cache write 1.25×, cache read 0.10×). Two honest caveats:
|
|
134
|
+
|
|
135
|
+
1. **Estimates, not invoices** — unknown/`<synthetic>` models price to `$0`.
|
|
136
|
+
2. **Main-loop only** — a subagent's spend is **not** in the transcript. The only
|
|
137
|
+
signal that survives is `toolUseResult.totalTokens` (no input/output split, so it
|
|
138
|
+
can't be priced). `ccq agents` surfaces those token totals **separately**; they
|
|
139
|
+
are never folded into a dollar figure.
|
|
140
|
+
|
|
141
|
+
## Develop
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
uv run pytest # tests over synthetic fixtures
|
|
145
|
+
uv run ruff check . && uv run ruff format . # lint + format
|
|
146
|
+
uv run ty check src/ # type check
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Read-only on `~/.claude/projects` by contract — the test suite uses synthetic
|
|
150
|
+
fixtures and never reads your real history.
|
ccq-0.1.0/README.md
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# ccq — query your own Claude Code agent history
|
|
2
|
+
|
|
3
|
+
[](https://github.com/saagpatel/ccq/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.python.org/)
|
|
5
|
+
|
|
6
|
+
`ccq` makes your local Claude Code transcripts queryable. It runs **DuckDB directly
|
|
7
|
+
over the JSONL** at `~/.claude/projects/<project>/<session>.jsonl` — no copy, no ETL,
|
|
8
|
+
no database to maintain. The transcripts are only ever **read**, never written.
|
|
9
|
+
|
|
10
|
+
Ask it where your tokens go, which tools you lean on, where runs hit rate limits,
|
|
11
|
+
how much you delegate to subagents, and what happened inside any single session.
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
$ ccq cost --by model
|
|
15
|
+
model turns in_tok out_tok cost_usd
|
|
16
|
+
------------------------- ------ -------------- ----------- ---------
|
|
17
|
+
claude-opus-4-8 12,345 3,456,789,012 28,500,000 4,210.55
|
|
18
|
+
claude-sonnet-4-6 6,789 901,234,567 8,400,000 612.30
|
|
19
|
+
...
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
uv sync # create the venv + install deps
|
|
26
|
+
uv run ccq --help
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
(Or `uv tool install .` to put `ccq` on your PATH.)
|
|
30
|
+
|
|
31
|
+
## Commands
|
|
32
|
+
|
|
33
|
+
| Command | What it answers |
|
|
34
|
+
|---|---|
|
|
35
|
+
| `ccq sessions` | List sessions: project, span, message count, tokens, estimated cost. `--sort cost\|duration\|messages\|recent`, `--project`, `--since`, `-n`. |
|
|
36
|
+
| `ccq cost` | Cost rollups. `--by project\|model\|day\|session`. Main-loop only (see caveat). |
|
|
37
|
+
| `ccq tools` | Tool-use frequency. `--bash` breaks Bash calls down by leading command. |
|
|
38
|
+
| `ccq errors` | API errors / retries (429s, etc.) by project + status. `--list` for recent events. |
|
|
39
|
+
| `ccq agents` | Subagent (Agent tool) dispatches + token totals. `--by type\|model\|session\|project`. |
|
|
40
|
+
| `ccq session <id-prefix>` | One session's decision timeline: prompts, tool calls, errors, in order. |
|
|
41
|
+
| `ccq search <text>` | Full-text over your typed prompts and session titles → matching sessions. |
|
|
42
|
+
| `ccq sql "<SELECT…>"` | Run an arbitrary **read-only** query over the views (power surface). |
|
|
43
|
+
| `ccq serve` | Launch a local web dashboard (localhost only) with a read-only SQL box. |
|
|
44
|
+
| `ccq cache build\|status\|clear` | Manage the materialized snapshot that powers `--fast`. |
|
|
45
|
+
|
|
46
|
+
Every command takes `-f table|json|csv` and a global `--projects-dir` (defaults to
|
|
47
|
+
`~/.claude/projects`, handy for pointing at a backup).
|
|
48
|
+
|
|
49
|
+
## Fast mode
|
|
50
|
+
|
|
51
|
+
A live query rescans ~1 GB of JSONL each time (~1-3 s). For instant repeat queries,
|
|
52
|
+
materialize a snapshot once and pass `--fast` (`-F`):
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
ccq cache build # ~6 s, writes a ~100 MB snapshot to ~/.cache/ccq
|
|
56
|
+
ccq -F cost --by model # now ~0.1 s
|
|
57
|
+
ccq cache status # shows STALE once transcripts change; rebuild to refresh
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The snapshot lives under `$XDG_CACHE_HOME` (never in `~/.claude`), is opened
|
|
61
|
+
**read-only** at the engine level, and `--fast` builds it automatically on first use.
|
|
62
|
+
|
|
63
|
+
## Web viewer
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
ccq -F serve # http://127.0.0.1:8787 (Ctrl-C to stop)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
A dashboard (cost by model, tools, errors, subagents, priciest sessions) plus a SQL
|
|
70
|
+
box that runs the same read-only-guarded queries. **Drill down:** click a project
|
|
71
|
+
chip to filter to that project, or a session id to see its full decision timeline.
|
|
72
|
+
Standard-library `http.server`, no extra dependencies, binds to localhost only.
|
|
73
|
+
|
|
74
|
+
## The query surface (`ccq sql`)
|
|
75
|
+
|
|
76
|
+
`sql` exposes these views — compose your own:
|
|
77
|
+
|
|
78
|
+
- **`sessions`** — one row per session: project, branch, span, `messages`, `models`, tokens, `cost_usd`.
|
|
79
|
+
- **`message_usage`** — one row per assistant turn: token breakdown + `cost_usd`.
|
|
80
|
+
- **`tool_calls`** — one row per tool invocation: `tool_name`, `tool_input` (JSON).
|
|
81
|
+
- **`errors`** — API error events: `status`, project, session, model.
|
|
82
|
+
- **`agents`** / **`agent_results`** — subagent dispatches joined to their `subagent_tokens`.
|
|
83
|
+
- **`prompts`** — searchable typed prompts + session titles.
|
|
84
|
+
- **`events`** — the raw per-line view everything else is built on.
|
|
85
|
+
- **`model_pricing`** — the per-model rate table used for costing.
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
ccq sql "SELECT project, round(sum(cost_usd),2) usd
|
|
89
|
+
FROM message_usage WHERE ts >= DATE '2026-06-01'
|
|
90
|
+
GROUP BY 1 ORDER BY usd DESC"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`sql` accepts a **single read-only statement** (SELECT/WITH/EXPLAIN/…). Writes,
|
|
94
|
+
`ATTACH`, `COPY`, `INSTALL`, and multi-statement input are refused. Tip: DuckDB
|
|
95
|
+
reserves words like `day`, `first`, `last` — quote them if used as aliases (`AS "day"`).
|
|
96
|
+
|
|
97
|
+
## How it works
|
|
98
|
+
|
|
99
|
+
`read_ndjson_objects('~/.claude/projects/*/*.jsonl')` loads each line as an opaque
|
|
100
|
+
`JSON` value (zero schema inference — the records are heterogeneous), and SQL views
|
|
101
|
+
extract the entities. Two things the transcripts taught us are baked in:
|
|
102
|
+
|
|
103
|
+
- Numeric fields use `TRY_CAST` (heterogeneous lines otherwise break a hard cast).
|
|
104
|
+
- Token-casting views read from a type-filtered subquery so the optimizer can't
|
|
105
|
+
reorder a cast ahead of the `type = 'assistant'` filter.
|
|
106
|
+
|
|
107
|
+
## Cost is estimated, and main-loop only
|
|
108
|
+
|
|
109
|
+
Transcripts store **token counts, not dollars**. `ccq` prices them with published
|
|
110
|
+
per-million-token rates (`src/ccq/pricing.py`) and the standard cache multipliers
|
|
111
|
+
(cache write 1.25×, cache read 0.10×). Two honest caveats:
|
|
112
|
+
|
|
113
|
+
1. **Estimates, not invoices** — unknown/`<synthetic>` models price to `$0`.
|
|
114
|
+
2. **Main-loop only** — a subagent's spend is **not** in the transcript. The only
|
|
115
|
+
signal that survives is `toolUseResult.totalTokens` (no input/output split, so it
|
|
116
|
+
can't be priced). `ccq agents` surfaces those token totals **separately**; they
|
|
117
|
+
are never folded into a dollar figure.
|
|
118
|
+
|
|
119
|
+
## Develop
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
uv run pytest # tests over synthetic fixtures
|
|
123
|
+
uv run ruff check . && uv run ruff format . # lint + format
|
|
124
|
+
uv run ty check src/ # type check
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Read-only on `~/.claude/projects` by contract — the test suite uses synthetic
|
|
128
|
+
fixtures and never reads your real history.
|
ccq-0.1.0/pyproject.toml
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "ccq"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Query your own Claude Code agent history with DuckDB, read-only, straight over the JSONL transcripts."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
authors = [{ name = "saagpatel" }]
|
|
7
|
+
requires-python = ">=3.12"
|
|
8
|
+
license = "MIT"
|
|
9
|
+
license-files = ["LICENSE"]
|
|
10
|
+
keywords = ["claude-code", "duckdb", "cli", "jsonl", "observability", "agent-history"]
|
|
11
|
+
classifiers = [
|
|
12
|
+
"Development Status :: 4 - Beta",
|
|
13
|
+
"Environment :: Console",
|
|
14
|
+
"Intended Audience :: Developers",
|
|
15
|
+
"Operating System :: OS Independent",
|
|
16
|
+
"Programming Language :: Python :: 3.12",
|
|
17
|
+
"Topic :: Utilities",
|
|
18
|
+
]
|
|
19
|
+
dependencies = ["duckdb>=1.1.0", "click>=8.1.0"]
|
|
20
|
+
|
|
21
|
+
[project.urls]
|
|
22
|
+
Homepage = "https://github.com/saagpatel/ccq"
|
|
23
|
+
Repository = "https://github.com/saagpatel/ccq"
|
|
24
|
+
Issues = "https://github.com/saagpatel/ccq/issues"
|
|
25
|
+
|
|
26
|
+
[project.scripts]
|
|
27
|
+
ccq = "ccq.cli:main"
|
|
28
|
+
|
|
29
|
+
[dependency-groups]
|
|
30
|
+
dev = [{ include-group = "lint" }, { include-group = "test" }]
|
|
31
|
+
lint = ["ruff", "ty"]
|
|
32
|
+
test = ["pytest", "pytest-cov"]
|
|
33
|
+
|
|
34
|
+
[build-system]
|
|
35
|
+
requires = ["uv_build>=0.11.13,<0.12.0"]
|
|
36
|
+
build-backend = "uv_build"
|
|
37
|
+
|
|
38
|
+
[tool.ruff]
|
|
39
|
+
line-length = 100
|
|
40
|
+
target-version = "py312"
|
|
41
|
+
|
|
42
|
+
[tool.ruff.lint]
|
|
43
|
+
select = ["ALL"]
|
|
44
|
+
ignore = [
|
|
45
|
+
"D", # docstring rules - not enforcing full pydocstyle
|
|
46
|
+
"COM812", # trailing-comma conflict with formatter
|
|
47
|
+
"ISC001", # implicit-str-concat conflict with formatter
|
|
48
|
+
"S608", # SQL "injection" - SQL is internal; user SQL runs in a sealed read-only conn
|
|
49
|
+
"PLR0913", # too many arguments - CLI commands legitimately take several
|
|
50
|
+
]
|
|
51
|
+
|
|
52
|
+
[tool.ruff.lint.per-file-ignores]
|
|
53
|
+
"tests/*" = ["S101", "PLR2004", "INP001", "ERA001", "SLF001", "DTZ"] # asserts, magic vals, no __init__, comments, test internals, naive fixture datetimes
|
|
54
|
+
"src/ccq/cli.py" = ["FBT001"] # Click maps --flags to bool params
|
|
55
|
+
"src/ccq/db.py" = ["E501"] # embedded SQL reads better unwrapped
|
|
56
|
+
"src/ccq/server.py" = ["E501"] # embedded HTML/CSS reads better unwrapped
|
|
57
|
+
|
|
58
|
+
[tool.pytest.ini_options]
|
|
59
|
+
addopts = ["--cov=ccq", "--cov-report=term-missing"]
|
|
60
|
+
testpaths = ["tests"]
|
|
61
|
+
|
|
62
|
+
[tool.ty.environment]
|
|
63
|
+
python-version = "3.12"
|