hidden-moves-github-projects 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.
- hidden_moves_github_projects-0.1.0/LICENSE +21 -0
- hidden_moves_github_projects-0.1.0/PKG-INFO +193 -0
- hidden_moves_github_projects-0.1.0/README.md +165 -0
- hidden_moves_github_projects-0.1.0/pyproject.toml +52 -0
- hidden_moves_github_projects-0.1.0/pyproject.toml.orig +43 -0
- hidden_moves_github_projects-0.1.0/src/hidden_moves_github_projects/__init__.py +38 -0
- hidden_moves_github_projects-0.1.0/src/hidden_moves_github_projects/__main__.py +6 -0
- hidden_moves_github_projects-0.1.0/src/hidden_moves_github_projects/_normalize.py +204 -0
- hidden_moves_github_projects-0.1.0/src/hidden_moves_github_projects/_queries.py +69 -0
- hidden_moves_github_projects-0.1.0/src/hidden_moves_github_projects/client.py +187 -0
- hidden_moves_github_projects-0.1.0/src/hidden_moves_github_projects/errors.py +38 -0
- hidden_moves_github_projects-0.1.0/src/hidden_moves_github_projects/host.py +70 -0
- hidden_moves_github_projects-0.1.0/src/hidden_moves_github_projects/integration.py +43 -0
- hidden_moves_github_projects-0.1.0/src/hidden_moves_github_projects/models.py +130 -0
- hidden_moves_github_projects-0.1.0/src/hidden_moves_github_projects/snapshots.py +122 -0
- hidden_moves_github_projects-0.1.0/src/hidden_moves_github_projects/transport.py +32 -0
- hidden_moves_github_projects-0.1.0/src/hidden_moves_github_projects/write_host.py +69 -0
- hidden_moves_github_projects-0.1.0/src/hidden_moves_github_projects/write_integration.py +53 -0
- hidden_moves_github_projects-0.1.0/src/hidden_moves_github_projects/writes.py +327 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ella Inng
|
|
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,193 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hidden-moves-github-projects
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Read and explicitly edit GitHub Projects through typed Python operations.
|
|
5
|
+
Keywords: github,projects,graphql,capabilities
|
|
6
|
+
Author: Ella Inng
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Classifier: Development Status :: 3 - Alpha
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
15
|
+
Requires-Dist: backpack-store>=0.1,<0.2 ; extra == 'backpack'
|
|
16
|
+
Requires-Dist: hidden-moves-mcp>=0.1,<0.2 ; extra == 'host'
|
|
17
|
+
Requires-Dist: hidden-moves>=0.1,<0.2 ; extra == 'moves'
|
|
18
|
+
Maintainer: Outside Labs
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Project-URL: Homepage, https://github.com/outside-labs/hidden_moves
|
|
21
|
+
Project-URL: Source, https://github.com/outside-labs/hidden_moves
|
|
22
|
+
Project-URL: Issues, https://github.com/outside-labs/hidden_moves/issues
|
|
23
|
+
Project-URL: Documentation, https://github.com/outside-labs/hidden_moves/blob/main/packages/hidden-moves-github-projects/README.md
|
|
24
|
+
Provides-Extra: backpack
|
|
25
|
+
Provides-Extra: host
|
|
26
|
+
Provides-Extra: moves
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# GitHub Projects client
|
|
30
|
+
|
|
31
|
+
An experimental GraphQL client with concrete typed records and explicitly
|
|
32
|
+
selected write operations. The ordinary Python library uses only the standard
|
|
33
|
+
library and does not import Hidden Moves, MCP, or an API SDK. Capability integration
|
|
34
|
+
is an optional extra.
|
|
35
|
+
|
|
36
|
+
The PyPI distribution is `hidden-moves-github-projects` and the Python import is
|
|
37
|
+
`hidden_moves_github_projects`. The optional `backpack` extra requires
|
|
38
|
+
`backpack-store>=0.1,<0.2`.
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
python -m pip install hidden-moves-github-projects==0.1.0
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Its release route uses `v0.1.0-github-projects`, `release.yaml`, and environment
|
|
45
|
+
`pypi-github-projects`; see the
|
|
46
|
+
[release guide](https://github.com/outside-labs/hidden_moves/blob/main/docs/PYPI_RELEASES.md).
|
|
47
|
+
|
|
48
|
+
## Ordinary Python
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from hidden_moves_github_projects import ProjectsClient
|
|
52
|
+
|
|
53
|
+
# The application supplies its credential resolver; construction performs no I/O.
|
|
54
|
+
client = ProjectsClient(resolve_token, timeout=10)
|
|
55
|
+
project = client.get("example", "organization", 2)
|
|
56
|
+
fields = client.fields(project.id)
|
|
57
|
+
page = client.items(project.id, page_size=20, field_page_size=50)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`resolve_token` is an application-owned callable returning an authorized token.
|
|
61
|
+
Keep credentials outside source control and tool arguments. A successful Project
|
|
62
|
+
query verifies access; repository access alone does not establish Projects access.
|
|
63
|
+
Classic-token scopes and GitHub App permissions differ. See the
|
|
64
|
+
[GitHub Projects API guide](https://docs.github.com/en/issues/planning-and-tracking-with-projects/automating-your-project/using-the-api-to-manage-projects).
|
|
65
|
+
|
|
66
|
+
## Operations and identities
|
|
67
|
+
|
|
68
|
+
- `list(owner, owner_kind, cursor=None, page_size=50)` returns a Project page.
|
|
69
|
+
- `get(owner, owner_kind, number)` returns a Project record.
|
|
70
|
+
- `fields(project_id, cursor=None, page_size=50)` returns a field-definition page.
|
|
71
|
+
- `items(project_id, cursor=None, page_size=50, field_page_size=50)` returns an item page.
|
|
72
|
+
- `item_field_values(item_id, cursor=None, page_size=50)` continues nested values.
|
|
73
|
+
- `iter_item_pages(project_id, ..., max_pages=10)` explicitly iterates bounded pages.
|
|
74
|
+
|
|
75
|
+
Owner kind is `user` or `organization`. Node IDs are opaque strings. Project number,
|
|
76
|
+
Project node ID, item node ID, content node ID, and issue/PR number are separate
|
|
77
|
+
identities. Item content distinguishes issues, PRs, drafts, redaction, and unknown
|
|
78
|
+
types. Select options retain IDs/names; iteration definitions retain active and
|
|
79
|
+
completed iteration metadata.
|
|
80
|
+
|
|
81
|
+
## Paging and completeness
|
|
82
|
+
|
|
83
|
+
Each requested connection returns `page_info.has_next_page` and `end_cursor`.
|
|
84
|
+
Every page contains at most the requested 1–100 entries. A last page with an input
|
|
85
|
+
cursor still represents only that page. Nested item field values have independent
|
|
86
|
+
page information and `field_values_complete`; continue them with the item ID and
|
|
87
|
+
their own cursor. An iterator that reaches its page budget raises
|
|
88
|
+
`PaginationLimitError` instead of silently claiming to have read the board.
|
|
89
|
+
|
|
90
|
+
Text, number, date, single-select, and iteration values are normalized. Unsupported
|
|
91
|
+
value types remain visible as typed placeholders and diagnostics; their omitted
|
|
92
|
+
payloads make `field_values_complete=False`. Unknown field/content types and null
|
|
93
|
+
nodes also produce diagnostics. Issue assignees, labels, linked PRs, and repository
|
|
94
|
+
connections are not queried. No unbounded nested connection is silently returned.
|
|
95
|
+
|
|
96
|
+
## Transport and errors
|
|
97
|
+
|
|
98
|
+
The default transport makes one HTTPS POST per explicit read, uses a finite socket
|
|
99
|
+
timeout, reads at most a configured byte budget, closes the response, and refuses
|
|
100
|
+
redirects carrying credentials. An explicit HTTPS endpoint supports application-
|
|
101
|
+
configured enterprise API URLs. Inject a `Transport` for synthetic or custom HTTP
|
|
102
|
+
behavior; it receives a `urllib.request.Request` and the timeout/byte budget and
|
|
103
|
+
returns `HTTPResponse(status, body)`.
|
|
104
|
+
|
|
105
|
+
HTTP failures, GraphQL errors (including HTTP 200 with partial data), malformed or
|
|
106
|
+
oversized responses, unavailable resources, and iterator limits have separate error
|
|
107
|
+
types. Upstream error text and resolver/transport exception messages are sanitized.
|
|
108
|
+
Requests are not retried automatically. Clients do not resolve local login state
|
|
109
|
+
unless the application explicitly supplies such a resolver.
|
|
110
|
+
|
|
111
|
+
## Verification
|
|
112
|
+
|
|
113
|
+
```sh
|
|
114
|
+
PYTHONPATH=packages/hidden-moves-github-projects/src \
|
|
115
|
+
.venv/bin/python -m unittest discover -s packages/hidden-moves-github-projects/tests -p test_client.py
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Tests use synthetic response fixtures, an injected transport, and blocked side
|
|
119
|
+
effects. CI builds and installs the actual wheel across the family platform matrix.
|
|
120
|
+
Live read access and capability-host interoperability are separate proofs.
|
|
121
|
+
|
|
122
|
+
## Optional provider and local host
|
|
123
|
+
|
|
124
|
+
Install `[moves]` for the optional provider or `[host]` for the MCP executable.
|
|
125
|
+
For local development install the family packages together:
|
|
126
|
+
|
|
127
|
+
```sh
|
|
128
|
+
uv pip install --python .venv/bin/python . ./packages/hidden-moves-mcp \
|
|
129
|
+
./packages/hidden-moves-openai ./packages/hidden-moves-github-projects
|
|
130
|
+
hidden-moves --plugin github-projects moves show github.projects.items
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
The zero-argument `github-projects` entry-point factory never resolves credentials
|
|
134
|
+
or makes a request. It advertises target-bound `github.projects.list/get/fields/items`
|
|
135
|
+
with read-only, non-destructive, external annotations. Generic framework inspection
|
|
136
|
+
needs no token; account invocation needs an application-bound `ProjectsClient`.
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
from hidden_moves_github_projects import ProjectsClient
|
|
140
|
+
from hidden_moves_github_projects.host import build_catalog, resolve_gh_token
|
|
141
|
+
from hidden_moves_mcp import MCPAdapter
|
|
142
|
+
from hidden_moves_openai import FunctionToolAdapter
|
|
143
|
+
|
|
144
|
+
client = ProjectsClient(resolve_gh_token, timeout=10)
|
|
145
|
+
catalog = build_catalog(client, ["github.projects.items"])
|
|
146
|
+
mcp = MCPAdapter(catalog)
|
|
147
|
+
functions = FunctionToolAdapter(catalog)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
`resolve_gh_token` explicitly captures the existing `github.com` login from `gh`
|
|
151
|
+
when a read executes. It neither prints the token nor changes login/scopes. A
|
|
152
|
+
local MCP host can launch the installed executable:
|
|
153
|
+
|
|
154
|
+
```json
|
|
155
|
+
{
|
|
156
|
+
"command": "/absolute/path/to/environment/bin/hidden-moves-github-projects",
|
|
157
|
+
"args": ["--move", "github.projects.items", "--timeout", "10"]
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Only selected capabilities list or dispatch. The host supplies no arbitrary query,
|
|
162
|
+
shell, or Project-editing tool. The SDK owns stdio protocol and process cleanup.
|
|
163
|
+
This configured local application uses one local identity; a remote host requires
|
|
164
|
+
request-scoped authorization and credentials. Sync HTTP executes inline here;
|
|
165
|
+
concurrent remote hosting must provide its own offloading and resource strategy.
|
|
166
|
+
|
|
167
|
+
The consumer tests use a synthetic transport and compare ordinary Python, the
|
|
168
|
+
selected catalog, actual stdio MCP initialize/list/call, and offline function-tool
|
|
169
|
+
dispatch. Install the local family and run:
|
|
170
|
+
|
|
171
|
+
```sh
|
|
172
|
+
python -m unittest discover -s packages/hidden-moves-github-projects/tests
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Inspection, fixture tests, and offline function tools require no model API call.
|
|
176
|
+
# Optional local snapshots
|
|
177
|
+
|
|
178
|
+
The `backpack` extra enables an explicit Projects-to-Backpack bridge. Store dated
|
|
179
|
+
normalized Project/item DTOs with a local UUID and source provenance, then reopen
|
|
180
|
+
them without GitHub access. Fetch and persistence can be invoked separately; no
|
|
181
|
+
snapshot read updates a board or claims to be live. See the
|
|
182
|
+
[snapshot guide](../../docs/PROJECT_SNAPSHOTS.md) and run
|
|
183
|
+
`python examples/projects_snapshot_demo.py` from the repository for the offline
|
|
184
|
+
proof. Backpack remains an independent package with no mandatory runtime
|
|
185
|
+
dependencies.
|
|
186
|
+
# Optional bounded writes
|
|
187
|
+
|
|
188
|
+
The separate `ProjectsWriter` and `github-projects-write` provider support adding
|
|
189
|
+
an existing Issue/PR and setting a dynamically resolved single-select choice.
|
|
190
|
+
The host authorizes explicit Project IDs and selects writes separately from the
|
|
191
|
+
default read profile. See the [write guide](../../docs/PROJECT_WRITES.md) for
|
|
192
|
+
expected-value checks, verified/unverified receipts and the remaining disposable
|
|
193
|
+
fixture gate. There are no bulk, deletion or archive tools.
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# GitHub Projects client
|
|
2
|
+
|
|
3
|
+
An experimental GraphQL client with concrete typed records and explicitly
|
|
4
|
+
selected write operations. The ordinary Python library uses only the standard
|
|
5
|
+
library and does not import Hidden Moves, MCP, or an API SDK. Capability integration
|
|
6
|
+
is an optional extra.
|
|
7
|
+
|
|
8
|
+
The PyPI distribution is `hidden-moves-github-projects` and the Python import is
|
|
9
|
+
`hidden_moves_github_projects`. The optional `backpack` extra requires
|
|
10
|
+
`backpack-store>=0.1,<0.2`.
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
python -m pip install hidden-moves-github-projects==0.1.0
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Its release route uses `v0.1.0-github-projects`, `release.yaml`, and environment
|
|
17
|
+
`pypi-github-projects`; see the
|
|
18
|
+
[release guide](https://github.com/outside-labs/hidden_moves/blob/main/docs/PYPI_RELEASES.md).
|
|
19
|
+
|
|
20
|
+
## Ordinary Python
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from hidden_moves_github_projects import ProjectsClient
|
|
24
|
+
|
|
25
|
+
# The application supplies its credential resolver; construction performs no I/O.
|
|
26
|
+
client = ProjectsClient(resolve_token, timeout=10)
|
|
27
|
+
project = client.get("example", "organization", 2)
|
|
28
|
+
fields = client.fields(project.id)
|
|
29
|
+
page = client.items(project.id, page_size=20, field_page_size=50)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
`resolve_token` is an application-owned callable returning an authorized token.
|
|
33
|
+
Keep credentials outside source control and tool arguments. A successful Project
|
|
34
|
+
query verifies access; repository access alone does not establish Projects access.
|
|
35
|
+
Classic-token scopes and GitHub App permissions differ. See the
|
|
36
|
+
[GitHub Projects API guide](https://docs.github.com/en/issues/planning-and-tracking-with-projects/automating-your-project/using-the-api-to-manage-projects).
|
|
37
|
+
|
|
38
|
+
## Operations and identities
|
|
39
|
+
|
|
40
|
+
- `list(owner, owner_kind, cursor=None, page_size=50)` returns a Project page.
|
|
41
|
+
- `get(owner, owner_kind, number)` returns a Project record.
|
|
42
|
+
- `fields(project_id, cursor=None, page_size=50)` returns a field-definition page.
|
|
43
|
+
- `items(project_id, cursor=None, page_size=50, field_page_size=50)` returns an item page.
|
|
44
|
+
- `item_field_values(item_id, cursor=None, page_size=50)` continues nested values.
|
|
45
|
+
- `iter_item_pages(project_id, ..., max_pages=10)` explicitly iterates bounded pages.
|
|
46
|
+
|
|
47
|
+
Owner kind is `user` or `organization`. Node IDs are opaque strings. Project number,
|
|
48
|
+
Project node ID, item node ID, content node ID, and issue/PR number are separate
|
|
49
|
+
identities. Item content distinguishes issues, PRs, drafts, redaction, and unknown
|
|
50
|
+
types. Select options retain IDs/names; iteration definitions retain active and
|
|
51
|
+
completed iteration metadata.
|
|
52
|
+
|
|
53
|
+
## Paging and completeness
|
|
54
|
+
|
|
55
|
+
Each requested connection returns `page_info.has_next_page` and `end_cursor`.
|
|
56
|
+
Every page contains at most the requested 1–100 entries. A last page with an input
|
|
57
|
+
cursor still represents only that page. Nested item field values have independent
|
|
58
|
+
page information and `field_values_complete`; continue them with the item ID and
|
|
59
|
+
their own cursor. An iterator that reaches its page budget raises
|
|
60
|
+
`PaginationLimitError` instead of silently claiming to have read the board.
|
|
61
|
+
|
|
62
|
+
Text, number, date, single-select, and iteration values are normalized. Unsupported
|
|
63
|
+
value types remain visible as typed placeholders and diagnostics; their omitted
|
|
64
|
+
payloads make `field_values_complete=False`. Unknown field/content types and null
|
|
65
|
+
nodes also produce diagnostics. Issue assignees, labels, linked PRs, and repository
|
|
66
|
+
connections are not queried. No unbounded nested connection is silently returned.
|
|
67
|
+
|
|
68
|
+
## Transport and errors
|
|
69
|
+
|
|
70
|
+
The default transport makes one HTTPS POST per explicit read, uses a finite socket
|
|
71
|
+
timeout, reads at most a configured byte budget, closes the response, and refuses
|
|
72
|
+
redirects carrying credentials. An explicit HTTPS endpoint supports application-
|
|
73
|
+
configured enterprise API URLs. Inject a `Transport` for synthetic or custom HTTP
|
|
74
|
+
behavior; it receives a `urllib.request.Request` and the timeout/byte budget and
|
|
75
|
+
returns `HTTPResponse(status, body)`.
|
|
76
|
+
|
|
77
|
+
HTTP failures, GraphQL errors (including HTTP 200 with partial data), malformed or
|
|
78
|
+
oversized responses, unavailable resources, and iterator limits have separate error
|
|
79
|
+
types. Upstream error text and resolver/transport exception messages are sanitized.
|
|
80
|
+
Requests are not retried automatically. Clients do not resolve local login state
|
|
81
|
+
unless the application explicitly supplies such a resolver.
|
|
82
|
+
|
|
83
|
+
## Verification
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
PYTHONPATH=packages/hidden-moves-github-projects/src \
|
|
87
|
+
.venv/bin/python -m unittest discover -s packages/hidden-moves-github-projects/tests -p test_client.py
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Tests use synthetic response fixtures, an injected transport, and blocked side
|
|
91
|
+
effects. CI builds and installs the actual wheel across the family platform matrix.
|
|
92
|
+
Live read access and capability-host interoperability are separate proofs.
|
|
93
|
+
|
|
94
|
+
## Optional provider and local host
|
|
95
|
+
|
|
96
|
+
Install `[moves]` for the optional provider or `[host]` for the MCP executable.
|
|
97
|
+
For local development install the family packages together:
|
|
98
|
+
|
|
99
|
+
```sh
|
|
100
|
+
uv pip install --python .venv/bin/python . ./packages/hidden-moves-mcp \
|
|
101
|
+
./packages/hidden-moves-openai ./packages/hidden-moves-github-projects
|
|
102
|
+
hidden-moves --plugin github-projects moves show github.projects.items
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The zero-argument `github-projects` entry-point factory never resolves credentials
|
|
106
|
+
or makes a request. It advertises target-bound `github.projects.list/get/fields/items`
|
|
107
|
+
with read-only, non-destructive, external annotations. Generic framework inspection
|
|
108
|
+
needs no token; account invocation needs an application-bound `ProjectsClient`.
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
from hidden_moves_github_projects import ProjectsClient
|
|
112
|
+
from hidden_moves_github_projects.host import build_catalog, resolve_gh_token
|
|
113
|
+
from hidden_moves_mcp import MCPAdapter
|
|
114
|
+
from hidden_moves_openai import FunctionToolAdapter
|
|
115
|
+
|
|
116
|
+
client = ProjectsClient(resolve_gh_token, timeout=10)
|
|
117
|
+
catalog = build_catalog(client, ["github.projects.items"])
|
|
118
|
+
mcp = MCPAdapter(catalog)
|
|
119
|
+
functions = FunctionToolAdapter(catalog)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
`resolve_gh_token` explicitly captures the existing `github.com` login from `gh`
|
|
123
|
+
when a read executes. It neither prints the token nor changes login/scopes. A
|
|
124
|
+
local MCP host can launch the installed executable:
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
"command": "/absolute/path/to/environment/bin/hidden-moves-github-projects",
|
|
129
|
+
"args": ["--move", "github.projects.items", "--timeout", "10"]
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Only selected capabilities list or dispatch. The host supplies no arbitrary query,
|
|
134
|
+
shell, or Project-editing tool. The SDK owns stdio protocol and process cleanup.
|
|
135
|
+
This configured local application uses one local identity; a remote host requires
|
|
136
|
+
request-scoped authorization and credentials. Sync HTTP executes inline here;
|
|
137
|
+
concurrent remote hosting must provide its own offloading and resource strategy.
|
|
138
|
+
|
|
139
|
+
The consumer tests use a synthetic transport and compare ordinary Python, the
|
|
140
|
+
selected catalog, actual stdio MCP initialize/list/call, and offline function-tool
|
|
141
|
+
dispatch. Install the local family and run:
|
|
142
|
+
|
|
143
|
+
```sh
|
|
144
|
+
python -m unittest discover -s packages/hidden-moves-github-projects/tests
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Inspection, fixture tests, and offline function tools require no model API call.
|
|
148
|
+
# Optional local snapshots
|
|
149
|
+
|
|
150
|
+
The `backpack` extra enables an explicit Projects-to-Backpack bridge. Store dated
|
|
151
|
+
normalized Project/item DTOs with a local UUID and source provenance, then reopen
|
|
152
|
+
them without GitHub access. Fetch and persistence can be invoked separately; no
|
|
153
|
+
snapshot read updates a board or claims to be live. See the
|
|
154
|
+
[snapshot guide](../../docs/PROJECT_SNAPSHOTS.md) and run
|
|
155
|
+
`python examples/projects_snapshot_demo.py` from the repository for the offline
|
|
156
|
+
proof. Backpack remains an independent package with no mandatory runtime
|
|
157
|
+
dependencies.
|
|
158
|
+
# Optional bounded writes
|
|
159
|
+
|
|
160
|
+
The separate `ProjectsWriter` and `github-projects-write` provider support adding
|
|
161
|
+
an existing Issue/PR and setting a dynamically resolved single-select choice.
|
|
162
|
+
The host authorizes explicit Project IDs and selects writes separately from the
|
|
163
|
+
default read profile. See the [write guide](../../docs/PROJECT_WRITES.md) for
|
|
164
|
+
expected-value checks, verified/unverified receipts and the remaining disposable
|
|
165
|
+
fixture gate. There are no bulk, deletion or archive tools.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "hidden-moves-github-projects"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Read and explicitly edit GitHub Projects through typed Python operations."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
license-files = ["LICENSE"]
|
|
9
|
+
keywords = [
|
|
10
|
+
"github",
|
|
11
|
+
"projects",
|
|
12
|
+
"graphql",
|
|
13
|
+
"capabilities",
|
|
14
|
+
]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 3 - Alpha",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.13",
|
|
21
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
22
|
+
]
|
|
23
|
+
dependencies = []
|
|
24
|
+
|
|
25
|
+
[[project.authors]]
|
|
26
|
+
name = "Ella Inng"
|
|
27
|
+
|
|
28
|
+
[[project.maintainers]]
|
|
29
|
+
name = "Outside Labs"
|
|
30
|
+
|
|
31
|
+
[project.optional-dependencies]
|
|
32
|
+
moves = ["hidden-moves>=0.1,<0.2"]
|
|
33
|
+
host = ["hidden-moves-mcp>=0.1,<0.2"]
|
|
34
|
+
backpack = ["backpack-store>=0.1,<0.2"]
|
|
35
|
+
|
|
36
|
+
[project.entry-points."hidden_moves.moves"]
|
|
37
|
+
github-projects = "hidden_moves_github_projects.integration:provide_moves"
|
|
38
|
+
github-projects-write = "hidden_moves_github_projects.write_integration:provide_write_moves"
|
|
39
|
+
|
|
40
|
+
[project.scripts]
|
|
41
|
+
hidden-moves-github-projects = "hidden_moves_github_projects.host:main"
|
|
42
|
+
hidden-moves-github-projects-write = "hidden_moves_github_projects.write_host:main"
|
|
43
|
+
|
|
44
|
+
[project.urls]
|
|
45
|
+
Homepage = "https://github.com/outside-labs/hidden_moves"
|
|
46
|
+
Source = "https://github.com/outside-labs/hidden_moves"
|
|
47
|
+
Issues = "https://github.com/outside-labs/hidden_moves/issues"
|
|
48
|
+
Documentation = "https://github.com/outside-labs/hidden_moves/blob/main/packages/hidden-moves-github-projects/README.md"
|
|
49
|
+
|
|
50
|
+
[build-system]
|
|
51
|
+
requires = ["uv_build>=0.12.1,<0.13.0"]
|
|
52
|
+
build-backend = "uv_build"
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "hidden-moves-github-projects"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Read and explicitly edit GitHub Projects through typed Python operations."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
license-files = ["LICENSE"]
|
|
9
|
+
authors = [{ name = "Ella Inng" }]
|
|
10
|
+
maintainers = [{ name = "Outside Labs" }]
|
|
11
|
+
keywords = ["github", "projects", "graphql", "capabilities"]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 3 - Alpha",
|
|
14
|
+
"Intended Audience :: Developers",
|
|
15
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
16
|
+
"Programming Language :: Python :: 3.11",
|
|
17
|
+
"Programming Language :: Python :: 3.13",
|
|
18
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
19
|
+
]
|
|
20
|
+
dependencies = []
|
|
21
|
+
|
|
22
|
+
[project.optional-dependencies]
|
|
23
|
+
moves = ["hidden-moves>=0.1,<0.2"]
|
|
24
|
+
host = ["hidden-moves-mcp>=0.1,<0.2"]
|
|
25
|
+
backpack = ["backpack-store>=0.1,<0.2"]
|
|
26
|
+
|
|
27
|
+
[project.entry-points."hidden_moves.moves"]
|
|
28
|
+
github-projects = "hidden_moves_github_projects.integration:provide_moves"
|
|
29
|
+
github-projects-write = "hidden_moves_github_projects.write_integration:provide_write_moves"
|
|
30
|
+
|
|
31
|
+
[project.scripts]
|
|
32
|
+
hidden-moves-github-projects = "hidden_moves_github_projects.host:main"
|
|
33
|
+
hidden-moves-github-projects-write = "hidden_moves_github_projects.write_host:main"
|
|
34
|
+
|
|
35
|
+
[project.urls]
|
|
36
|
+
Homepage = "https://github.com/outside-labs/hidden_moves"
|
|
37
|
+
Source = "https://github.com/outside-labs/hidden_moves"
|
|
38
|
+
Issues = "https://github.com/outside-labs/hidden_moves/issues"
|
|
39
|
+
Documentation = "https://github.com/outside-labs/hidden_moves/blob/main/packages/hidden-moves-github-projects/README.md"
|
|
40
|
+
|
|
41
|
+
[build-system]
|
|
42
|
+
requires = ["uv_build>=0.12.1,<0.13.0"]
|
|
43
|
+
build-backend = "uv_build"
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Read typed GitHub Projects records without a registry or protocol dependency."""
|
|
2
|
+
|
|
3
|
+
from .client import ProjectsClient
|
|
4
|
+
from .errors import (
|
|
5
|
+
CredentialError,
|
|
6
|
+
GraphQLError,
|
|
7
|
+
HTTPStatusError,
|
|
8
|
+
NotFoundError,
|
|
9
|
+
PaginationLimitError,
|
|
10
|
+
ProjectsError,
|
|
11
|
+
ProtocolError,
|
|
12
|
+
TransportError,
|
|
13
|
+
)
|
|
14
|
+
from .models import (
|
|
15
|
+
Content,
|
|
16
|
+
Diagnostic,
|
|
17
|
+
FieldPage,
|
|
18
|
+
FieldValue,
|
|
19
|
+
FieldValuePage,
|
|
20
|
+
ItemPage,
|
|
21
|
+
Iteration,
|
|
22
|
+
OwnerKind,
|
|
23
|
+
PageInfo,
|
|
24
|
+
Project,
|
|
25
|
+
ProjectField,
|
|
26
|
+
ProjectItem,
|
|
27
|
+
ProjectPage,
|
|
28
|
+
SelectOption,
|
|
29
|
+
)
|
|
30
|
+
from .transport import HTTPResponse, Transport
|
|
31
|
+
|
|
32
|
+
__all__ = [
|
|
33
|
+
"Content", "CredentialError", "Diagnostic", "FieldPage", "FieldValue", "FieldValuePage",
|
|
34
|
+
"GraphQLError", "HTTPResponse", "HTTPStatusError", "ItemPage", "Iteration", "NotFoundError",
|
|
35
|
+
"OwnerKind", "PageInfo", "PaginationLimitError", "Project", "ProjectField", "ProjectItem",
|
|
36
|
+
"ProjectPage", "ProjectsClient", "ProjectsError", "ProtocolError", "SelectOption", "Transport",
|
|
37
|
+
"TransportError",
|
|
38
|
+
]
|