agent-discogs 0.2.0__tar.gz → 0.3.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.
Files changed (52) hide show
  1. agent_discogs-0.3.0/PKG-INFO +171 -0
  2. agent_discogs-0.3.0/README.md +146 -0
  3. {agent_discogs-0.2.0 → agent_discogs-0.3.0}/pyproject.toml +16 -5
  4. {agent_discogs-0.2.0 → agent_discogs-0.3.0}/pyproject.toml.orig +23 -6
  5. agent_discogs-0.3.0/src/agent_discogs/__init__.py +555 -0
  6. agent_discogs-0.3.0/src/agent_discogs/account.py +153 -0
  7. agent_discogs-0.3.0/src/agent_discogs/client.py +74 -0
  8. agent_discogs-0.3.0/src/agent_discogs/collection.py +290 -0
  9. agent_discogs-0.3.0/src/agent_discogs/commands/cache.py +30 -0
  10. agent_discogs-0.3.0/src/agent_discogs/commands/completion.py +36 -0
  11. agent_discogs-0.3.0/src/agent_discogs/commands/get.py +1910 -0
  12. agent_discogs-0.3.0/src/agent_discogs/commands/search.py +540 -0
  13. {agent_discogs-0.2.0 → agent_discogs-0.3.0}/src/agent_discogs/commands/skills.py +8 -2
  14. {agent_discogs-0.2.0 → agent_discogs-0.3.0}/src/agent_discogs/commands/status.py +5 -4
  15. agent_discogs-0.3.0/src/agent_discogs/config.py +34 -0
  16. agent_discogs-0.3.0/src/agent_discogs/errors.py +418 -0
  17. agent_discogs-0.3.0/src/agent_discogs/formatting.py +1612 -0
  18. agent_discogs-0.3.0/src/agent_discogs/inventory.py +192 -0
  19. agent_discogs-0.3.0/src/agent_discogs/json_output.py +104 -0
  20. agent_discogs-0.3.0/src/agent_discogs/markup.py +262 -0
  21. agent_discogs-0.3.0/src/agent_discogs/pagination.py +346 -0
  22. agent_discogs-0.3.0/src/agent_discogs/projections.py +489 -0
  23. {agent_discogs-0.2.0 → agent_discogs-0.3.0}/src/agent_discogs/refs.py +2 -2
  24. agent_discogs-0.3.0/src/agent_discogs/sanitize.py +39 -0
  25. agent_discogs-0.3.0/src/agent_discogs/skills/core/SKILL.md +246 -0
  26. agent_discogs-0.3.0/src/agent_discogs/skills/core/references/commands.md +354 -0
  27. {agent_discogs-0.2.0 → agent_discogs-0.3.0}/src/agent_discogs/skills/core/references/discogs-domain.md +37 -4
  28. {agent_discogs-0.2.0 → agent_discogs-0.3.0}/src/agent_discogs/skills/core/references/pressings-guide.md +1 -1
  29. agent_discogs-0.3.0/src/agent_discogs/skills/core/references/search-patterns.md +94 -0
  30. agent_discogs-0.3.0/src/agent_discogs/style.py +101 -0
  31. agent_discogs-0.3.0/src/agent_discogs/trace.py +271 -0
  32. agent_discogs-0.3.0/src/agent_discogs/wantlist.py +71 -0
  33. agent_discogs-0.2.0/PKG-INFO +0 -260
  34. agent_discogs-0.2.0/README.md +0 -235
  35. agent_discogs-0.2.0/src/agent_discogs/__init__.py +0 -180
  36. agent_discogs-0.2.0/src/agent_discogs/client.py +0 -38
  37. agent_discogs-0.2.0/src/agent_discogs/commands/cache.py +0 -16
  38. agent_discogs-0.2.0/src/agent_discogs/commands/get.py +0 -794
  39. agent_discogs-0.2.0/src/agent_discogs/commands/search.py +0 -275
  40. agent_discogs-0.2.0/src/agent_discogs/errors.py +0 -175
  41. agent_discogs-0.2.0/src/agent_discogs/formatting.py +0 -741
  42. agent_discogs-0.2.0/src/agent_discogs/json_output.py +0 -66
  43. agent_discogs-0.2.0/src/agent_discogs/pagination.py +0 -196
  44. agent_discogs-0.2.0/src/agent_discogs/projections.py +0 -300
  45. agent_discogs-0.2.0/src/agent_discogs/skills/core/SKILL.md +0 -171
  46. agent_discogs-0.2.0/src/agent_discogs/skills/core/references/commands.md +0 -181
  47. agent_discogs-0.2.0/src/agent_discogs/skills/core/references/search-patterns.md +0 -72
  48. agent_discogs-0.2.0/src/agent_discogs/trace.py +0 -223
  49. {agent_discogs-0.2.0 → agent_discogs-0.3.0}/LICENSE.txt +0 -0
  50. {agent_discogs-0.2.0 → agent_discogs-0.3.0}/src/agent_discogs/__main__.py +0 -0
  51. {agent_discogs-0.2.0 → agent_discogs-0.3.0}/src/agent_discogs/commands/__init__.py +0 -0
  52. {agent_discogs-0.2.0 → agent_discogs-0.3.0}/src/agent_discogs/py.typed +0 -0
@@ -0,0 +1,171 @@
1
+ Metadata-Version: 2.4
2
+ Name: agent-discogs
3
+ Version: 0.3.0
4
+ Summary: Token-efficient Discogs CLI for AI agents
5
+ Keywords: ai-agent,cli,discogs,discogs-api,music-database
6
+ Author: Jean-Marc Fontaine
7
+ Author-email: Jean-Marc Fontaine <jm@jmfontaine.net>
8
+ License-Expression: Apache-2.0
9
+ License-File: LICENSE.txt
10
+ Classifier: Programming Language :: Python :: 3 :: Only
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Classifier: Programming Language :: Python :: 3.13
15
+ Classifier: Programming Language :: Python :: 3.14
16
+ Classifier: Programming Language :: Python :: 3.15
17
+ Requires-Dist: click>=8.3.1
18
+ Requires-Dist: discogs-sdk>=0.8.1
19
+ Requires-Dist: pydantic>=2.12.5
20
+ Requires-Python: >=3.10
21
+ Project-URL: Homepage, https://github.com/jmfontaine/agent-discogs
22
+ Project-URL: Issues, https://github.com/jmfontaine/agent-discogs/issues
23
+ Project-URL: Repository, https://github.com/jmfontaine/agent-discogs
24
+ Description-Content-Type: text/markdown
25
+
26
+ # agent-discogs
27
+
28
+ A token-efficient Discogs CLI for AI agents that minimizes API calls.
29
+
30
+ ```bash
31
+ agent-discogs search "Nine Inch Nails"
32
+ agent-discogs get release @r352665 # ref from search output
33
+ agent-discogs tracks @r352665 # tracklist shortcut
34
+ agent-discogs price @r352665 # price guide shortcut
35
+ ```
36
+
37
+ ## Installation
38
+
39
+ ```bash
40
+ pipx install agent-discogs
41
+ ```
42
+
43
+ Or with [uv](https://docs.astral.sh/uv/):
44
+
45
+ ```bash
46
+ uv tool install agent-discogs
47
+ ```
48
+
49
+ Or with pip:
50
+
51
+ ```bash
52
+ pip install agent-discogs
53
+ ```
54
+
55
+ pipx, uv and pip need Python 3.10 or later.
56
+
57
+ ### Homebrew
58
+
59
+ ```bash
60
+ brew install jmfontaine/tap/agent-discogs
61
+ ```
62
+
63
+ The formula comes from the maintainer's [Homebrew](https://brew.sh/) tap. It installs the PyPI release into a virtualenv on Homebrew's own Python, whatever Python you have.
64
+
65
+ To tap once and then use the short name:
66
+
67
+ ```bash
68
+ brew tap jmfontaine/tap
69
+ brew install agent-discogs
70
+ ```
71
+
72
+ Or in a Brewfile:
73
+
74
+ ```ruby
75
+ tap "jmfontaine/tap"
76
+ brew "agent-discogs"
77
+ ```
78
+
79
+ A prebuilt bottle exists only for Apple Silicon Macs on macOS 26 or later. Everywhere else (Intel Macs, earlier macOS, Linux) Homebrew builds from source, which needs Rust (for pydantic-core; Homebrew installs it as a build dependency) and takes a few minutes.
80
+
81
+ `brew upgrade` installs a new release once the tap has picked it up from PyPI.
82
+
83
+ ### AI Coding Agent Skill
84
+
85
+ Install the skill so your AI coding agent can use agent-discogs automatically:
86
+
87
+ ```bash
88
+ npx skills add jmfontaine/agent-discogs
89
+ ```
90
+
91
+ The installed skill is a thin pointer; the usage guide itself ships inside the package and is served by `agent-discogs skills get core`, so agents always read instructions that match the version they run (see [skills](https://github.com/jmfontaine/agent-discogs/blob/main/docs/commands.md#skills)).
92
+
93
+ ## Authentication
94
+
95
+ Set your personal access token from [your Discogs developer settings](https://www.discogs.com/settings/developers):
96
+
97
+ ```bash
98
+ export DISCOGS_TOKEN="your-token-here"
99
+ ```
100
+
101
+ Credentials are required for price lookups, and Discogs' API documentation requires them for search too: unauthenticated searches currently get answers, but Discogs may refuse one with `auth_required`. Without any credentials the limit is 25 requests/minute; with a token, every command works at 60 requests/minute.
102
+
103
+ `price` needs one thing more than a token or OAuth credentials: Discogs only returns price suggestions to accounts that have filled out their [seller settings](https://www.discogs.com/settings/seller). Until you do, the endpoint answers 404 and `price` tells you so; every other command is unaffected.
104
+
105
+ The CLI sends whichever credentials discogs-sdk finds in the environment, in this order:
106
+
107
+ 1. `DISCOGS_TOKEN`;
108
+ 2. OAuth 1.0a (`DISCOGS_CONSUMER_KEY`, `DISCOGS_CONSUMER_SECRET`, `DISCOGS_ACCESS_TOKEN` and `DISCOGS_ACCESS_TOKEN_SECRET`, all four);
109
+ 3. a consumer key and secret alone (`DISCOGS_CONSUMER_KEY` and `DISCOGS_CONSUMER_SECRET`);
110
+ 4. otherwise none.
111
+
112
+ A consumer key and secret get 60 requests/minute but identify an app, not a user, so `price` needs a token or OAuth, and so do `--owned`, `--in-wantlist`, `get owned`, `get collection`, `get lists` and `get wantlist`, which read your own collection, lists and wantlist. `get inventory` alone works without credentials: Discogs shows anyone a seller's For Sale listings. `agent-discogs status` reports the mode in use.
113
+
114
+ > [!TIP]
115
+ > Use a `.env` file with [direnv](https://direnv.net/) to avoid exporting tokens manually in every shell.
116
+
117
+ ## Commands
118
+
119
+ ```bash
120
+ agent-discogs search release "The Downward Spiral" --year 1994
121
+ agent-discogs search artist "Nine Inch Nails" --limit 10
122
+ agent-discogs get artist @a3857
123
+ agent-discogs get versions @m3719 --country US --format Vinyl
124
+ agent-discogs get owned @r352665 @r847868
125
+ agent-discogs search release --artist "Nine Inch Nails" --year 1994 --limit 20 --owned
126
+ agent-discogs get collection --style Techno --format 12\" --max-requests 20
127
+ agent-discogs get wantlist --for-sale --max-price 20 --currency EUR --max-requests 60
128
+ agent-discogs get inventory <seller> --in-wantlist --condition VG+ --max-requests 60
129
+ agent-discogs get lists
130
+ agent-discogs get list 123
131
+ agent-discogs get release @r352665 --json
132
+ agent-discogs status
133
+ agent-discogs cache clear
134
+ agent-discogs skills get core
135
+ ```
136
+
137
+ Each command, its own flags and its text output are described in [Commands](https://github.com/jmfontaine/agent-discogs/blob/main/docs/commands.md). The global flags (`--cached`, `--fresh`, `--debug`, `--color`), the output modes (`--json`, `--full`) and the `--max-requests` cap have their own pages:
138
+
139
+ - `--json` and `--full`: [JSON output](https://github.com/jmfontaine/agent-discogs/blob/main/docs/json-output.md);
140
+ - `--cached`, `--fresh` and `--max-requests`: [Caching and request budget](https://github.com/jmfontaine/agent-discogs/blob/main/docs/caching-and-budget.md);
141
+ - `--debug`: [Debugging](https://github.com/jmfontaine/agent-discogs/blob/main/docs/debugging.md);
142
+ - `--color`: [Color](https://github.com/jmfontaine/agent-discogs/blob/main/docs/debugging.md#color); the default, `auto`, colors a terminal only, never a pipe.
143
+
144
+ For Tab completion in an interactive bash, zsh or fish shell, add `eval "$(agent-discogs completion zsh)"` (or `bash`) to the shell's startup file; see [Shell completion](https://github.com/jmfontaine/agent-discogs/blob/main/docs/commands.md#shell-completion) for fish.
145
+
146
+ ## Ref system
147
+
148
+ Output includes typed refs that encode the entity type and Discogs ID. Copy them into subsequent commands.
149
+
150
+ | Prefix | Type | Example |
151
+ |---|---|---|
152
+ | `@r` | Release | `@r352665` |
153
+ | `@a` | Artist | `@a3857` |
154
+ | `@m` | Master | `@m3719` |
155
+ | `@l` | Label | `@l647` |
156
+
157
+ Raw numeric IDs also work: `agent-discogs get release 352665`.
158
+
159
+ Smart resolution: `get versions @r352665` auto-resolves the release to its master.
160
+
161
+ ## Documentation
162
+
163
+ - [Commands](https://github.com/jmfontaine/agent-discogs/blob/main/docs/commands.md): `search` (filters, sorting, client-side scans, `--added-since`, `--owned`), `get` and its nouns (`get owned`, `get collection` and its filters, `get wantlist` and its `--for-sale` scan, `get inventory` and its grade, origin, price and `--in-wantlist` filters, `get lists` and `get list`), `tracks` / `price`, `status`, `cache`, `skills`, shell completion.
164
+ - [JSON output](https://github.com/jmfontaine/agent-discogs/blob/main/docs/json-output.md): projections, `--full`, the pagination envelope, `owned` rows, collection rows, wantlist rows and their `market`, inventory listings and their `wantlist` object, lists and their items, non-ASCII and control-character escaping.
165
+ - [Caching and request budget](https://github.com/jmfontaine/agent-discogs/blob/main/docs/caching-and-budget.md): `--cached` / `--fresh`, cache errors, rate limits, what each command costs, `--max-requests`.
166
+ - [Errors](https://github.com/jmfontaine/agent-discogs/blob/main/docs/errors.md): the error layout, error codes, and the 401, 429 and connection-error hints.
167
+ - [Debugging](https://github.com/jmfontaine/agent-discogs/blob/main/docs/debugging.md): the `--debug` panel, output encoding, how Discogs text is neutralized, and `--color`.
168
+
169
+ ## License
170
+
171
+ agent-discogs is licensed under the [Apache License 2.0](LICENSE.txt).
@@ -0,0 +1,146 @@
1
+ # agent-discogs
2
+
3
+ A token-efficient Discogs CLI for AI agents that minimizes API calls.
4
+
5
+ ```bash
6
+ agent-discogs search "Nine Inch Nails"
7
+ agent-discogs get release @r352665 # ref from search output
8
+ agent-discogs tracks @r352665 # tracklist shortcut
9
+ agent-discogs price @r352665 # price guide shortcut
10
+ ```
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ pipx install agent-discogs
16
+ ```
17
+
18
+ Or with [uv](https://docs.astral.sh/uv/):
19
+
20
+ ```bash
21
+ uv tool install agent-discogs
22
+ ```
23
+
24
+ Or with pip:
25
+
26
+ ```bash
27
+ pip install agent-discogs
28
+ ```
29
+
30
+ pipx, uv and pip need Python 3.10 or later.
31
+
32
+ ### Homebrew
33
+
34
+ ```bash
35
+ brew install jmfontaine/tap/agent-discogs
36
+ ```
37
+
38
+ The formula comes from the maintainer's [Homebrew](https://brew.sh/) tap. It installs the PyPI release into a virtualenv on Homebrew's own Python, whatever Python you have.
39
+
40
+ To tap once and then use the short name:
41
+
42
+ ```bash
43
+ brew tap jmfontaine/tap
44
+ brew install agent-discogs
45
+ ```
46
+
47
+ Or in a Brewfile:
48
+
49
+ ```ruby
50
+ tap "jmfontaine/tap"
51
+ brew "agent-discogs"
52
+ ```
53
+
54
+ A prebuilt bottle exists only for Apple Silicon Macs on macOS 26 or later. Everywhere else (Intel Macs, earlier macOS, Linux) Homebrew builds from source, which needs Rust (for pydantic-core; Homebrew installs it as a build dependency) and takes a few minutes.
55
+
56
+ `brew upgrade` installs a new release once the tap has picked it up from PyPI.
57
+
58
+ ### AI Coding Agent Skill
59
+
60
+ Install the skill so your AI coding agent can use agent-discogs automatically:
61
+
62
+ ```bash
63
+ npx skills add jmfontaine/agent-discogs
64
+ ```
65
+
66
+ The installed skill is a thin pointer; the usage guide itself ships inside the package and is served by `agent-discogs skills get core`, so agents always read instructions that match the version they run (see [skills](https://github.com/jmfontaine/agent-discogs/blob/main/docs/commands.md#skills)).
67
+
68
+ ## Authentication
69
+
70
+ Set your personal access token from [your Discogs developer settings](https://www.discogs.com/settings/developers):
71
+
72
+ ```bash
73
+ export DISCOGS_TOKEN="your-token-here"
74
+ ```
75
+
76
+ Credentials are required for price lookups, and Discogs' API documentation requires them for search too: unauthenticated searches currently get answers, but Discogs may refuse one with `auth_required`. Without any credentials the limit is 25 requests/minute; with a token, every command works at 60 requests/minute.
77
+
78
+ `price` needs one thing more than a token or OAuth credentials: Discogs only returns price suggestions to accounts that have filled out their [seller settings](https://www.discogs.com/settings/seller). Until you do, the endpoint answers 404 and `price` tells you so; every other command is unaffected.
79
+
80
+ The CLI sends whichever credentials discogs-sdk finds in the environment, in this order:
81
+
82
+ 1. `DISCOGS_TOKEN`;
83
+ 2. OAuth 1.0a (`DISCOGS_CONSUMER_KEY`, `DISCOGS_CONSUMER_SECRET`, `DISCOGS_ACCESS_TOKEN` and `DISCOGS_ACCESS_TOKEN_SECRET`, all four);
84
+ 3. a consumer key and secret alone (`DISCOGS_CONSUMER_KEY` and `DISCOGS_CONSUMER_SECRET`);
85
+ 4. otherwise none.
86
+
87
+ A consumer key and secret get 60 requests/minute but identify an app, not a user, so `price` needs a token or OAuth, and so do `--owned`, `--in-wantlist`, `get owned`, `get collection`, `get lists` and `get wantlist`, which read your own collection, lists and wantlist. `get inventory` alone works without credentials: Discogs shows anyone a seller's For Sale listings. `agent-discogs status` reports the mode in use.
88
+
89
+ > [!TIP]
90
+ > Use a `.env` file with [direnv](https://direnv.net/) to avoid exporting tokens manually in every shell.
91
+
92
+ ## Commands
93
+
94
+ ```bash
95
+ agent-discogs search release "The Downward Spiral" --year 1994
96
+ agent-discogs search artist "Nine Inch Nails" --limit 10
97
+ agent-discogs get artist @a3857
98
+ agent-discogs get versions @m3719 --country US --format Vinyl
99
+ agent-discogs get owned @r352665 @r847868
100
+ agent-discogs search release --artist "Nine Inch Nails" --year 1994 --limit 20 --owned
101
+ agent-discogs get collection --style Techno --format 12\" --max-requests 20
102
+ agent-discogs get wantlist --for-sale --max-price 20 --currency EUR --max-requests 60
103
+ agent-discogs get inventory <seller> --in-wantlist --condition VG+ --max-requests 60
104
+ agent-discogs get lists
105
+ agent-discogs get list 123
106
+ agent-discogs get release @r352665 --json
107
+ agent-discogs status
108
+ agent-discogs cache clear
109
+ agent-discogs skills get core
110
+ ```
111
+
112
+ Each command, its own flags and its text output are described in [Commands](https://github.com/jmfontaine/agent-discogs/blob/main/docs/commands.md). The global flags (`--cached`, `--fresh`, `--debug`, `--color`), the output modes (`--json`, `--full`) and the `--max-requests` cap have their own pages:
113
+
114
+ - `--json` and `--full`: [JSON output](https://github.com/jmfontaine/agent-discogs/blob/main/docs/json-output.md);
115
+ - `--cached`, `--fresh` and `--max-requests`: [Caching and request budget](https://github.com/jmfontaine/agent-discogs/blob/main/docs/caching-and-budget.md);
116
+ - `--debug`: [Debugging](https://github.com/jmfontaine/agent-discogs/blob/main/docs/debugging.md);
117
+ - `--color`: [Color](https://github.com/jmfontaine/agent-discogs/blob/main/docs/debugging.md#color); the default, `auto`, colors a terminal only, never a pipe.
118
+
119
+ For Tab completion in an interactive bash, zsh or fish shell, add `eval "$(agent-discogs completion zsh)"` (or `bash`) to the shell's startup file; see [Shell completion](https://github.com/jmfontaine/agent-discogs/blob/main/docs/commands.md#shell-completion) for fish.
120
+
121
+ ## Ref system
122
+
123
+ Output includes typed refs that encode the entity type and Discogs ID. Copy them into subsequent commands.
124
+
125
+ | Prefix | Type | Example |
126
+ |---|---|---|
127
+ | `@r` | Release | `@r352665` |
128
+ | `@a` | Artist | `@a3857` |
129
+ | `@m` | Master | `@m3719` |
130
+ | `@l` | Label | `@l647` |
131
+
132
+ Raw numeric IDs also work: `agent-discogs get release 352665`.
133
+
134
+ Smart resolution: `get versions @r352665` auto-resolves the release to its master.
135
+
136
+ ## Documentation
137
+
138
+ - [Commands](https://github.com/jmfontaine/agent-discogs/blob/main/docs/commands.md): `search` (filters, sorting, client-side scans, `--added-since`, `--owned`), `get` and its nouns (`get owned`, `get collection` and its filters, `get wantlist` and its `--for-sale` scan, `get inventory` and its grade, origin, price and `--in-wantlist` filters, `get lists` and `get list`), `tracks` / `price`, `status`, `cache`, `skills`, shell completion.
139
+ - [JSON output](https://github.com/jmfontaine/agent-discogs/blob/main/docs/json-output.md): projections, `--full`, the pagination envelope, `owned` rows, collection rows, wantlist rows and their `market`, inventory listings and their `wantlist` object, lists and their items, non-ASCII and control-character escaping.
140
+ - [Caching and request budget](https://github.com/jmfontaine/agent-discogs/blob/main/docs/caching-and-budget.md): `--cached` / `--fresh`, cache errors, rate limits, what each command costs, `--max-requests`.
141
+ - [Errors](https://github.com/jmfontaine/agent-discogs/blob/main/docs/errors.md): the error layout, error codes, and the 401, 429 and connection-error hints.
142
+ - [Debugging](https://github.com/jmfontaine/agent-discogs/blob/main/docs/debugging.md): the `--debug` panel, output encoding, how Discogs text is neutralized, and `--color`.
143
+
144
+ ## License
145
+
146
+ agent-discogs is licensed under the [Apache License 2.0](LICENSE.txt).
@@ -1,10 +1,10 @@
1
1
  [build-system]
2
2
  build-backend = "uv_build"
3
- requires = ["uv-build>=0.12.13,<0.13"]
3
+ requires = ["uv-build>=0.12.13,<0.14"]
4
4
 
5
5
  [project]
6
6
  name = "agent-discogs"
7
- version = "0.2.0"
7
+ version = "0.3.0"
8
8
  description = "Token-efficient Discogs CLI for AI agents"
9
9
  readme = "README.md"
10
10
  keywords = [
@@ -28,7 +28,7 @@ classifiers = [
28
28
  ]
29
29
  dependencies = [
30
30
  "click>=8.3.1",
31
- "discogs-sdk>=0.5.0",
31
+ "discogs-sdk>=0.8.1",
32
32
  "pydantic>=2.12.5",
33
33
  ]
34
34
 
@@ -47,6 +47,7 @@ agent-discogs = "agent_discogs:main"
47
47
  [dependency-groups]
48
48
  dev = [
49
49
  "deptry>=0.24",
50
+ "pre-commit>=4.6.2",
50
51
  "pyproject-fmt>=2.16.1",
51
52
  "pyright>=1.1.408",
52
53
  "ruff>=0.15.2",
@@ -107,7 +108,6 @@ select = [
107
108
  ignore = [
108
109
  "EM101",
109
110
  "EM102",
110
- "PLC0415",
111
111
  "PLR0911",
112
112
  "PLR0912",
113
113
  "PLR0913",
@@ -121,7 +121,6 @@ ignore = [
121
121
 
122
122
  [tool.ruff.lint.per-file-ignores]
123
123
  "tests/**" = [
124
- "ARG001",
125
124
  "ARG005",
126
125
  "PLR2004",
127
126
  "S101",
@@ -137,13 +136,25 @@ max_supported_python = "3.15"
137
136
  addopts = "-m 'not live'"
138
137
  markers = ["live: hits the real Discogs API; run with `just test-live` (needs DISCOGS_TOKEN)"]
139
138
 
139
+ [tool.coverage.run]
140
+ source = ["agent_discogs"]
141
+
142
+ [tool.coverage.report]
143
+ fail_under = 100
144
+
140
145
  [tool.deadcode]
141
146
  ignore-names = [
147
+ "_color_terminal",
148
+ "_fake_api",
149
+ "_isolate_env",
150
+ "_patch_clients",
142
151
  "_patch_get",
143
152
  "_patch_search",
144
153
  "_reset_singleton",
154
+ "_real_client",
145
155
  "_scoped_client",
146
156
  "format_help",
147
157
  "get_skill",
158
+ "pytest_plugins",
148
159
  "skill_path",
149
160
  ]
@@ -1,10 +1,10 @@
1
1
  [build-system]
2
2
  build-backend = "uv_build"
3
- requires = [ "uv-build>=0.12.13,<0.13" ]
3
+ requires = [ "uv-build>=0.12.13,<0.14" ]
4
4
 
5
5
  [project]
6
6
  name = "agent-discogs"
7
- version = "0.2.0"
7
+ version = "0.3.0"
8
8
  description = "Token-efficient Discogs CLI for AI agents"
9
9
  readme = "README.md"
10
10
  keywords = [ "ai-agent", "cli", "discogs", "discogs-api", "music-database" ]
@@ -21,7 +21,11 @@ classifiers = [
21
21
  "Programming Language :: Python :: 3.14",
22
22
  "Programming Language :: Python :: 3.15",
23
23
  ]
24
- dependencies = [ "click>=8.3.1", "discogs-sdk>=0.5.0", "pydantic>=2.12.5" ]
24
+ dependencies = [
25
+ "click>=8.3.1",
26
+ "discogs-sdk>=0.8.1",
27
+ "pydantic>=2.12.5",
28
+ ]
25
29
  urls.Homepage = "https://github.com/jmfontaine/agent-discogs"
26
30
  urls.Issues = "https://github.com/jmfontaine/agent-discogs/issues"
27
31
  urls.Repository = "https://github.com/jmfontaine/agent-discogs"
@@ -30,6 +34,7 @@ scripts.agent-discogs = "agent_discogs:main"
30
34
  [dependency-groups]
31
35
  dev = [
32
36
  "deptry>=0.24",
37
+ "pre-commit>=4.6.2",
33
38
  "pyproject-fmt>=2.16.1",
34
39
  "pyright>=1.1.408",
35
40
  "ruff>=0.15.2",
@@ -90,7 +95,6 @@ lint.select = [
90
95
  lint.ignore = [
91
96
  "EM101", # raw-string-in-exception - the test doubles that raise use one-off literals; naming them first adds a line and no clarity
92
97
  "EM102", # f-string-in-exception - refs.py and get.py interpolate the offending ref or noun, which is what makes the message actionable
93
- "PLC0415", # import-outside-top-level - errors.py and __init__.py import discogs_sdk lazily so --help and --version never pay to load it
94
98
  "PLR0911", # too-many-return-statements - format_error() returns one tailored message per SDK exception type
95
99
  "PLR0912", # too-many-branches - verbose release output walks a long list of independently optional Discogs fields
96
100
  "PLR0913", # too-many-arguments - click hands every command option to the callback as its own keyword argument
@@ -102,12 +106,11 @@ lint.ignore = [
102
106
  "TRY003", # raise-vanilla-args - these messages are read by agents, so they belong at the raise site rather than in an exception subclass
103
107
  ]
104
108
  lint.per-file-ignores."tests/**" = [
105
- "ARG001", # unused-function-argument - the fake _send() in test_pagination.py must accept params= because fetch_page passes it by keyword, then ignores it
106
109
  "ARG005", # unused-lambda-argument - the SimpleNamespace lambdas standing in for SDK methods take the real signature and use only part of it
107
110
  "PLR2004", # magic-value-comparison - assertions compare against literal Discogs IDs and counts, which read better inline than as named constants
108
111
  "S101", # assert - pytest expresses every assertion this way
109
112
  "S108", # hardcoded-temp-file - test_formatting.py only formats /tmp/test-cache into the status output; nothing is created or written there
110
- "SLF001", # private-member-access - test_client.py resets the module-level _client singleton around each test
113
+ "SLF001", # private-member-access - conftest.py's real_sdk resets the module-level client._client singleton, and tests read private state such as trace._trace
111
114
  ]
112
115
 
113
116
  [tool.pyproject-fmt]
@@ -120,13 +123,27 @@ ini_options.markers = [
120
123
  "live: hits the real Discogs API; run with `just test-live` (needs DISCOGS_TOKEN)",
121
124
  ]
122
125
 
126
+ # Line coverage only. Branch coverage would fail fail_under today on partial
127
+ # branches in cache.py (#18), formatting.py and projections.py.
128
+ [tool.coverage]
129
+ # Only the package: this also keeps out the test modules pytester writes under
130
+ # the basetemp, which its in-process runs would otherwise add to the report.
131
+ run.source = [ "agent_discogs" ]
132
+ report.fail_under = 100
133
+
123
134
  [tool.deadcode]
124
135
  ignore-names = [
136
+ "_color_terminal",
137
+ "_fake_api",
138
+ "_isolate_env",
139
+ "_patch_clients",
125
140
  "_patch_get",
126
141
  "_patch_search",
127
142
  "_reset_singleton",
143
+ "_real_client",
128
144
  "_scoped_client",
129
145
  "format_help",
130
146
  "get_skill", # click subcommands are registered by decorator, invisible to deadcode
147
+ "pytest_plugins", # pytest reads it from conftest.py, invisible to deadcode
131
148
  "skill_path",
132
149
  ]