taskops-cli 0.3.2__py3-none-any.whl → 0.3.3__py3-none-any.whl
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.
- taskops/_version.py +1 -1
- taskops/cli/commands.py +21 -10
- {taskops_cli-0.3.2.dist-info → taskops_cli-0.3.3.dist-info}/METADATA +63 -8
- {taskops_cli-0.3.2.dist-info → taskops_cli-0.3.3.dist-info}/RECORD +6 -6
- {taskops_cli-0.3.2.dist-info → taskops_cli-0.3.3.dist-info}/WHEEL +1 -1
- {taskops_cli-0.3.2.dist-info → taskops_cli-0.3.3.dist-info}/entry_points.txt +0 -0
taskops/_version.py
CHANGED
taskops/cli/commands.py
CHANGED
|
@@ -15,7 +15,7 @@ from pathlib import Path
|
|
|
15
15
|
from . import enrol, watch
|
|
16
16
|
from .. import session, identity
|
|
17
17
|
from .._json import query
|
|
18
|
-
from ..board import DIR, find_root, open_board
|
|
18
|
+
from ..board import DIR, find_root, open_board, read_config
|
|
19
19
|
from ..store import log
|
|
20
20
|
from .._errors import TaskopsError
|
|
21
21
|
from ..gitwork import remote, install, claudefiles
|
|
@@ -58,13 +58,15 @@ def join( # noqa: PLR0913 — one command, one config; each flag is a way IN
|
|
|
58
58
|
invite: str = "",
|
|
59
59
|
github: bool = False,
|
|
60
60
|
) -> int:
|
|
61
|
-
"""Connect this repo to a board. Bare like every other verb
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
taskops join
|
|
66
|
-
taskops join
|
|
67
|
-
taskops join my-project --
|
|
61
|
+
"""Connect this repo to a board. Bare like every other verb: the address is
|
|
62
|
+
CARRIED by the clone, the key is discovered, and the recorded remote is the
|
|
63
|
+
fallback for a checkout that carries nothing:
|
|
64
|
+
|
|
65
|
+
taskops join a clone: board.json travels, done
|
|
66
|
+
taskops join --github same clone, first time: GitHub vouches
|
|
67
|
+
taskops join my-project --invite <id> first time by invite: enrols the key
|
|
68
|
+
taskops remote add https://host:8787 no carried address? record the host…
|
|
69
|
+
taskops join my-project …and name the board
|
|
68
70
|
taskops join my-project no key anywhere + public board: read-only
|
|
69
71
|
|
|
70
72
|
The name defaults exactly as `board create`'s does (recorded name, else the
|
|
@@ -93,8 +95,17 @@ def join( # noqa: PLR0913 — one command, one config; each flag is a way IN
|
|
|
93
95
|
root = find_root(here)
|
|
94
96
|
bare = "://" not in target
|
|
95
97
|
if bare:
|
|
96
|
-
|
|
97
|
-
|
|
98
|
+
# v1's whole ambition, restored (its join.py said it in one line: "a
|
|
99
|
+
# clone carries `.taskops/board.json`, so the second developer types
|
|
100
|
+
# two words"). The committed address is read FIRST, so a fresh clone
|
|
101
|
+
# joins with no URL and no `remote add` — the recorded remote is for
|
|
102
|
+
# the checkout that has no carried address, or a DIFFERENT board.
|
|
103
|
+
carried = str(read_config(root).get("url", ""))
|
|
104
|
+
if carried and target in ("", carried.rsplit("/", 1)[-1]):
|
|
105
|
+
target = carried
|
|
106
|
+
else:
|
|
107
|
+
host, name = remote_cli.named(target)
|
|
108
|
+
target = f"{host}/{name}"
|
|
98
109
|
base = target.partition("?")[0]
|
|
99
110
|
params = query(target)
|
|
100
111
|
invite = invite or params.get("invite", "")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: taskops-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: A shared work board for teams of coding agents, with a human who decides.
|
|
5
5
|
Project-URL: Repository, https://github.com/bernatch22/taskops
|
|
6
6
|
License-Expression: MIT
|
|
@@ -47,8 +47,9 @@ can be misread:
|
|
|
47
47
|
into it exactly once, to install it and register your key.
|
|
48
48
|
* **A board**: one directory on that host. Created from your laptop with
|
|
49
49
|
`taskops board create`.
|
|
50
|
-
* **A repo**: joined to one board.
|
|
51
|
-
|
|
50
|
+
* **A repo**: joined to one board. A clone carries the board's address
|
|
51
|
+
(`.taskops/board.json`, committed), so `taskops join` is the whole step;
|
|
52
|
+
`taskops remote add` covers a checkout that carries none.
|
|
52
53
|
* **Your agents**: they never touch any of this — they talk to the board through
|
|
53
54
|
the eleven MCP tools.
|
|
54
55
|
|
|
@@ -90,10 +91,11 @@ Joining a hosted one is bare, like every other verb — the host is recorded onc
|
|
|
90
91
|
and the key is discovered the way ssh discovers one:
|
|
91
92
|
|
|
92
93
|
```sh
|
|
93
|
-
taskops
|
|
94
|
-
taskops join
|
|
95
|
-
taskops join my-project --invite <id> # first time
|
|
96
|
-
taskops
|
|
94
|
+
taskops join # a clone: board.json carries the address, done
|
|
95
|
+
taskops join --github # same clone, first time: GitHub vouches for you
|
|
96
|
+
taskops join my-project --invite <id> # first time by invite: it enrols your key too
|
|
97
|
+
taskops remote add https://host:8787 # no carried address? record the host once…
|
|
98
|
+
taskops join my-project # …and name the board
|
|
97
99
|
taskops join my-project # no key + public board: read-only window
|
|
98
100
|
```
|
|
99
101
|
|
|
@@ -222,6 +224,59 @@ until an owner records it and cleared again with `--clear`. Only a board that
|
|
|
222
224
|
has been opted in answers `--github` at all; every other one is invite-only,
|
|
223
225
|
exactly as before.
|
|
224
226
|
|
|
227
|
+
### The whole flow, and why cloning is not enough
|
|
228
|
+
|
|
229
|
+
Cloning the repo gives you the board's ADDRESS — `.taskops/board.json` is
|
|
230
|
+
committed and travels with the code — but the host has never seen you: it is a
|
|
231
|
+
different server from GitHub, sharing no session and no cookie with it. So one
|
|
232
|
+
command — `taskops join --github`, no URL: the clone already carries it —
|
|
233
|
+
introduces you, once per checkout, and after that GitHub is not in the picture
|
|
234
|
+
at all.
|
|
235
|
+
|
|
236
|
+
```
|
|
237
|
+
GitHub the board HOST
|
|
238
|
+
<owner>/<repo>, private principals + allowed_signers
|
|
239
|
+
| |
|
|
240
|
+
1. git clone -> the code, and .taskops/board.json (the address).
|
|
241
|
+
remote.json is 0600 and gitignored: no credential travels.
|
|
242
|
+
| |
|
|
243
|
+
2. taskops join --github (the carried address) |
|
|
244
|
+
| |
|
|
245
|
+
|-- the CLI finds YOUR token: `gh auth token`, else $GITHUB_TOKEN,
|
|
246
|
+
| else a hidden prompt. Never a flag value — the shell writes those
|
|
247
|
+
| into ~/.zsh_history before the process starts.
|
|
248
|
+
| |
|
|
249
|
+
|-- POST /<board>/join/github ------------------>|
|
|
250
|
+
| { github_token, principal, pubkey } |
|
|
251
|
+
| |
|
|
252
|
+
| the host asks GitHub ONCE, with your token:
|
|
253
|
+
| "does this user have <need> on <owner>/<repo>?"
|
|
254
|
+
| |
|
|
255
|
+
| yes -> it writes exactly two rows: |
|
|
256
|
+
| principals: <you>, member
|
|
257
|
+
| allowed_signers: <you> ssh-ed25519 AAAA...
|
|
258
|
+
| no -> refused, without saying whether the repo exists
|
|
259
|
+
| |
|
|
260
|
+
3. the GitHub token dies with that request. It is on neither disk.
|
|
261
|
+
|
|
262
|
+
from here on GitHub never participates again:
|
|
263
|
+
|
|
264
|
+
every session: your key signs a challenge -> the host checks it
|
|
265
|
+
(~/.ssh/id_ed25519) against allowed_signers
|
|
266
|
+
-> a 12h session
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
The alternative — re-checking GitHub on every request — would mean the host
|
|
270
|
+
holding somebody else's token, or being handed one on each call. That is the
|
|
271
|
+
whole category of problem this removes: there is no token to steal because
|
|
272
|
+
there is none stored.
|
|
273
|
+
|
|
274
|
+
**One consequence, stated plainly: access is granted automatically and taken
|
|
275
|
+
back by hand.** Losing push on the repo does not close the board, because the
|
|
276
|
+
credential is no longer GitHub — it is the enrolled key. Remove it with
|
|
277
|
+
`taskops revoke --key SHA256:…`, which is the same verb an invite-enrolled key
|
|
278
|
+
takes.
|
|
279
|
+
|
|
225
280
|
No URL and no `--key` after `remote add`: the host is recorded in the checkout,
|
|
226
281
|
`board create` records the name, and the key is **discovered** the way ssh
|
|
227
282
|
discovers one — `~/.ssh/id_ed25519`, `id_ecdsa`, `id_rsa`, in that order.
|
|
@@ -4,7 +4,7 @@ taskops/_errors.py,sha256=hBN_ChWVY09f61wNoy2dZPkwhEAQEQF5JRanpENCrNA,1548
|
|
|
4
4
|
taskops/_ids.py,sha256=97FnOiBVKJ87zAgHj8ia-HZkKqkhx2J6jYeMFjcKq2s,2460
|
|
5
5
|
taskops/_json.py,sha256=8pBzo98KdOKvSV3y3f7H7MF9RNb7zriK3152j8hQCHs,1682
|
|
6
6
|
taskops/_locate.py,sha256=QmmglRfv8rhlqKQWvRdAaiqBdiU05Lxo-varGDSona0,4500
|
|
7
|
-
taskops/_version.py,sha256=
|
|
7
|
+
taskops/_version.py,sha256=c41JEarmRmSUDrwqGrSJhwQs-REk0YwuPsv9lHWoQ5k,138
|
|
8
8
|
taskops/_wire.py,sha256=NrzkgZ5_-vPwETdF2HM_4GgROSdp_L-4rgBbyx-86T0,5392
|
|
9
9
|
taskops/board.py,sha256=GtcEaJmApGdqXpYSDbSyW-UU3zT437LwQgLGbWOq6B8,7867
|
|
10
10
|
taskops/identity.py,sha256=pFNElIrYfbLHL6AFy6yKHvL_bL2gA6pV3rIr7Ugvusc,5351
|
|
@@ -14,7 +14,7 @@ taskops/cli/__init__.py,sha256=RyUqzo36ftkMDHiOlBBQpcBXE8iuvYVJLKNw8WZgDCw,150
|
|
|
14
14
|
taskops/cli/__main__.py,sha256=JZbVGIEQpWgl9VEyTpQL6ORQvj3ODt3ui19x1_0r3Rw,163
|
|
15
15
|
taskops/cli/admin.py,sha256=K04upZZUSms70NpwZ97e-vBSQb9qVeEVzOxprPvIpn8,4021
|
|
16
16
|
taskops/cli/claude.py,sha256=oMeageiJ_wfNloIjhDDHBKWV0RjnYo9Dd9htemlj_m4,9440
|
|
17
|
-
taskops/cli/commands.py,sha256=
|
|
17
|
+
taskops/cli/commands.py,sha256=DRBa0HsJVxHGo3dOWZm10T_jnCWEeMMdRdRpeXOejHU,9338
|
|
18
18
|
taskops/cli/enrol.py,sha256=BgyrjT6BebnJILYL4n1JIIE0BD8BHwB29z9nVLw8Pnw,5347
|
|
19
19
|
taskops/cli/grants.py,sha256=LGlDtJLkiMSaxbVvriDzezTQvSAuY2Dcx2J8dqhmghA,2892
|
|
20
20
|
taskops/cli/hooks.py,sha256=C7UREKPZ3DP0PF-fRB2MunfhB9kau7aqgpjhD6sfack,1996
|
|
@@ -129,7 +129,7 @@ taskops/verbs/report.py,sha256=WeeeP3C7jO_5DKxIGdvhuCgWVdEREaUIa2CCUv6dUMg,4563
|
|
|
129
129
|
taskops/verbs/review.py,sha256=L0E0jlW4r7qZU3aDZbW3IUbPUwF4ENMehpW6OUWVlJw,3522
|
|
130
130
|
taskops/verbs/take.py,sha256=HSQVbKCmWxF94pMHxpf9o0SUZZir2IHxwNBahg8Ku2I,4156
|
|
131
131
|
taskops/verbs/update.py,sha256=17HzEmWjr7sFIF11-fMbEI0vzHE9VlYCdokVpaszi7E,8014
|
|
132
|
-
taskops_cli-0.3.
|
|
133
|
-
taskops_cli-0.3.
|
|
134
|
-
taskops_cli-0.3.
|
|
135
|
-
taskops_cli-0.3.
|
|
132
|
+
taskops_cli-0.3.3.dist-info/METADATA,sha256=6qgUMO1b5jlIZ3vFIt5CaNGr6x74PPd_7xdYRL5WSI4,21052
|
|
133
|
+
taskops_cli-0.3.3.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
134
|
+
taskops_cli-0.3.3.dist-info/entry_points.txt,sha256=vXgZOPfyYUPtaXX8EVEQd7JkXRYU82Nf-gdwV3Gaik0,45
|
|
135
|
+
taskops_cli-0.3.3.dist-info/RECORD,,
|
|
File without changes
|