dotbrain 0.4.3__tar.gz → 0.4.4__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.
- {dotbrain-0.4.3 → dotbrain-0.4.4}/PKG-INFO +1 -1
- {dotbrain-0.4.3 → dotbrain-0.4.4}/docs/cli-reference.md +3 -2
- {dotbrain-0.4.3 → dotbrain-0.4.4}/docs/getting-started.md +10 -6
- {dotbrain-0.4.3 → dotbrain-0.4.4}/pyproject.toml +1 -1
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/__init__.py +1 -1
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/cli.py +24 -12
- dotbrain-0.4.3/src/dotbrain/updater.py +0 -119
- {dotbrain-0.4.3 → dotbrain-0.4.4}/.gitignore +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/LICENSE +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/README.md +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/docs/README.md +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/docs/architecture.md +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/docs/beads-backend.md +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/docs/configuration.md +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/docs/glossary.md +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/docs/skills.md +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/docs/wiring.md +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/_cli_reference.py +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/adopter_repos.py +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/beads.py +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/bootstrap.py +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/brainspaces.py +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/config.py +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/doctor.py +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/hooks.py +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/migrate.py +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/paths.py +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/resource_loader.py +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/resources/__init__.py +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/resources/agents/claude/implementer.md +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/resources/agents/claude/investigator.md +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/resources/agents/claude/reviewer.md +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/resources/agents/claude/verifier.md +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/resources/agents/codex/implementer.toml +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/resources/agents/codex/investigator.toml +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/resources/agents/codex/reviewer.toml +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/resources/agents/codex/verifier.toml +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/resources/config.yaml +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/resources/core.yaml +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/resources/templates/brain/AGENTS.md +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/resources/templates/brain/DOTBRAIN.md +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/resources/templates/brain/adr/README.md +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/resources/templates/brain/designs/README.md +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/resources/templates/brain/docs/README.md +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/resources/templates/brain/project.yaml +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/resources/templates/gitignore +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/skills.py +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/subagents.py +0 -0
- {dotbrain-0.4.3 → dotbrain-0.4.4}/src/dotbrain/workflows.py +0 -0
|
@@ -22,7 +22,8 @@ Reference for the public `dotbrain` CLI.
|
|
|
22
22
|
│ links. │
|
|
23
23
|
│ doctor Read-only health check: machine readiness, project wiring, beads │
|
|
24
24
|
│ state drift. │
|
|
25
|
-
│ update
|
|
25
|
+
│ update Print the command that upgrades this CLI with the tool that │
|
|
26
|
+
│ installed it. │
|
|
26
27
|
│ wire Create or repair a project Brainspace and wire an adopter repo. │
|
|
27
28
|
│ refresh Refresh Brain/workspace files, repo links, beads state, and │
|
|
28
29
|
│ project skills. │
|
|
@@ -348,7 +349,7 @@ Reference for the public `dotbrain` CLI.
|
|
|
348
349
|
|
|
349
350
|
Usage: dotbrain update [OPTIONS]
|
|
350
351
|
|
|
351
|
-
|
|
352
|
+
Print the command that upgrades this CLI with the tool that installed it.
|
|
352
353
|
|
|
353
354
|
┌─ Options ────────────────────────────────────────────────────────────────────┐
|
|
354
355
|
│ --help -h Show this message and exit. │
|
|
@@ -179,16 +179,20 @@ codex plugin add dotbrain@dotbrain
|
|
|
179
179
|
Then refresh the CLI to match, either by asking your agent or by re-running the install command
|
|
180
180
|
from step 2 with the new tag.
|
|
181
181
|
|
|
182
|
-
To update only the released CLI,
|
|
182
|
+
To update only the released CLI, upgrade it with the tool that installed it:
|
|
183
183
|
|
|
184
184
|
```bash
|
|
185
|
-
dotbrain
|
|
185
|
+
uv tool install dotbrain@latest # uv
|
|
186
|
+
pipx upgrade dotbrain # pipx
|
|
187
|
+
python -m pip install --upgrade dotbrain # pip, using the Python dotbrain is installed in
|
|
186
188
|
```
|
|
187
189
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
190
|
+
With uv, use `dotbrain@latest` rather than `uv tool upgrade dotbrain`: an install pinned to one
|
|
191
|
+
version, such as the plugin installer's, stays on that version under `uv tool upgrade`. Not sure
|
|
192
|
+
which tool you used? `dotbrain update` prints the right command for your install.
|
|
193
|
+
|
|
194
|
+
Updating the CLI does not update plugins or private dotbrain data. Contributor checkouts remain
|
|
195
|
+
editable: update the checkout with Git instead.
|
|
192
196
|
|
|
193
197
|
## Edit Config Only When Needed
|
|
194
198
|
|
|
@@ -2,13 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import json
|
|
6
|
+
import subprocess
|
|
5
7
|
import sys
|
|
8
|
+
from importlib import metadata
|
|
6
9
|
from pathlib import Path
|
|
7
10
|
from typing import Optional
|
|
8
11
|
|
|
9
12
|
import typer
|
|
10
13
|
|
|
11
|
-
from dotbrain import __version__
|
|
14
|
+
from dotbrain import __version__
|
|
12
15
|
from dotbrain import doctor as doctor_mod
|
|
13
16
|
from dotbrain import adopter_repos, beads as beads_mod, bootstrap as bootstrap_mod, config, brainspaces, hooks, migrate, paths, resource_loader, skills, subagents, workflows
|
|
14
17
|
|
|
@@ -167,18 +170,27 @@ def doctor() -> None:
|
|
|
167
170
|
|
|
168
171
|
@app.command()
|
|
169
172
|
def update() -> None:
|
|
170
|
-
"""
|
|
173
|
+
"""Print the command that upgrades this CLI with the tool that installed it."""
|
|
174
|
+
typer.echo(_upgrade_hint())
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def _upgrade_hint() -> str:
|
|
171
178
|
try:
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
179
|
+
files = metadata.distribution("dotbrain").files or ()
|
|
180
|
+
record = next((f for f in files if f.name == "direct_url.json"), None)
|
|
181
|
+
direct_url = json.loads(record.read_text(encoding="utf-8")) if record else {}
|
|
182
|
+
except (metadata.PackageNotFoundError, OSError, ValueError):
|
|
183
|
+
direct_url = {}
|
|
184
|
+
if direct_url.get("dir_info", {}).get("editable"):
|
|
185
|
+
return "dotbrain is an editable install; update its checkout with git pull"
|
|
186
|
+
prefix = Path(sys.prefix)
|
|
187
|
+
if (prefix / "uv-receipt.toml").exists():
|
|
188
|
+
# @latest also clears the exact-version pin that `uv tool upgrade` would honor.
|
|
189
|
+
return "To update dotbrain, run: uv tool install dotbrain@latest"
|
|
190
|
+
if (prefix / "pipx_metadata.json").exists():
|
|
191
|
+
return "To update dotbrain, run: pipx upgrade dotbrain"
|
|
192
|
+
pip = subprocess.list2cmdline([sys.executable, "-m", "pip", "install", "--upgrade", "dotbrain"])
|
|
193
|
+
return f"To update dotbrain, run: {pip}"
|
|
182
194
|
|
|
183
195
|
|
|
184
196
|
@app.command()
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
"""Update released dotbrain CLI installations from PyPI."""
|
|
2
|
-
|
|
3
|
-
from __future__ import annotations
|
|
4
|
-
|
|
5
|
-
import json
|
|
6
|
-
import os
|
|
7
|
-
import re
|
|
8
|
-
import subprocess
|
|
9
|
-
from importlib import metadata
|
|
10
|
-
from typing import Any, Callable
|
|
11
|
-
from urllib.error import URLError
|
|
12
|
-
from urllib.request import Request, urlopen
|
|
13
|
-
|
|
14
|
-
PACKAGE = "dotbrain"
|
|
15
|
-
_PYPI_URL = f"https://pypi.org/pypi/{PACKAGE}/json"
|
|
16
|
-
_VERSION_RE = re.compile(r"^(\d+)\.(\d+)\.(\d+)$")
|
|
17
|
-
Fetch = Callable[[str], dict[str, Any]]
|
|
18
|
-
Run = Callable[..., subprocess.CompletedProcess[str]]
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
class UpdateError(RuntimeError):
|
|
22
|
-
"""The CLI could not safely update itself."""
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
def update_cli(current_version: str, *, fetch: Fetch | None = None,
|
|
26
|
-
run: Run = subprocess.run) -> str | None:
|
|
27
|
-
"""Install the latest stable release, returning its version or ``None`` when current."""
|
|
28
|
-
if _is_editable_install():
|
|
29
|
-
raise UpdateError("editable installs are updated from their checkout; use git pull there")
|
|
30
|
-
|
|
31
|
-
fetch = fetch or _fetch_json
|
|
32
|
-
target_version = _latest_version(fetch(_PYPI_URL))
|
|
33
|
-
if _version_parts(target_version) <= _version_parts(current_version):
|
|
34
|
-
return None
|
|
35
|
-
|
|
36
|
-
# The version comes from PyPI directly; uv's cached index may not list it yet.
|
|
37
|
-
command = ["uv", "tool", "install", "--force", "--refresh-package", PACKAGE,
|
|
38
|
-
f"{PACKAGE}=={target_version}"]
|
|
39
|
-
if _is_windows():
|
|
40
|
-
_defer_install(command)
|
|
41
|
-
return target_version
|
|
42
|
-
try:
|
|
43
|
-
result = run(command, check=False)
|
|
44
|
-
except FileNotFoundError as exc:
|
|
45
|
-
raise UpdateError("uv is not on PATH; install uv and retry") from exc
|
|
46
|
-
if result.returncode:
|
|
47
|
-
raise UpdateError(f"uv could not install {target_version}; the existing CLI was left unchanged")
|
|
48
|
-
return target_version
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
def _is_windows() -> bool:
|
|
52
|
-
return os.name == "nt"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def _defer_install(command: list[str]) -> None:
|
|
56
|
-
"""Run detached, after this Windows launcher releases its executable lock.
|
|
57
|
-
|
|
58
|
-
The child must not share this process's console: otherwise its output and
|
|
59
|
-
lifetime bleed into the caller's shell, and the prompt looks hung until the
|
|
60
|
-
install finishes. It gets a hidden console rather than none: a console-less
|
|
61
|
-
cmd makes Windows open a visible window for each console child it runs.
|
|
62
|
-
"""
|
|
63
|
-
script = f"ping -n 2 127.0.0.1 >NUL & {subprocess.list2cmdline(command)}"
|
|
64
|
-
subprocess.Popen(
|
|
65
|
-
["cmd", "/c", script],
|
|
66
|
-
stdin=subprocess.DEVNULL,
|
|
67
|
-
stdout=subprocess.DEVNULL,
|
|
68
|
-
stderr=subprocess.DEVNULL,
|
|
69
|
-
creationflags=getattr(subprocess, "CREATE_NO_WINDOW", 0)
|
|
70
|
-
| getattr(subprocess, "CREATE_NEW_PROCESS_GROUP", 0),
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
def _is_editable_install() -> bool:
|
|
75
|
-
try:
|
|
76
|
-
distribution = metadata.distribution("dotbrain")
|
|
77
|
-
except metadata.PackageNotFoundError:
|
|
78
|
-
return False
|
|
79
|
-
raw = next(
|
|
80
|
-
(
|
|
81
|
-
distribution.locate_file(path).read_text(encoding="utf-8")
|
|
82
|
-
for path in distribution.files or ()
|
|
83
|
-
if path.name == "direct_url.json"
|
|
84
|
-
),
|
|
85
|
-
None,
|
|
86
|
-
)
|
|
87
|
-
if not raw:
|
|
88
|
-
return False
|
|
89
|
-
try:
|
|
90
|
-
return bool(json.loads(raw).get("dir_info", {}).get("editable"))
|
|
91
|
-
except (ValueError, AttributeError):
|
|
92
|
-
return False
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
def _fetch_json(url: str) -> dict[str, Any]:
|
|
96
|
-
request = Request(url, headers={"Accept": "application/json", "User-Agent": "dotbrain"})
|
|
97
|
-
try:
|
|
98
|
-
with urlopen(request, timeout=10) as response: # noqa: S310 - fixed PyPI URL
|
|
99
|
-
data = json.load(response)
|
|
100
|
-
except (OSError, URLError, ValueError) as exc:
|
|
101
|
-
raise UpdateError("could not reach PyPI to check for updates") from exc
|
|
102
|
-
if not isinstance(data, dict):
|
|
103
|
-
raise UpdateError("PyPI returned an invalid update response")
|
|
104
|
-
return data
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
def _latest_version(release: dict[str, Any]) -> str:
|
|
108
|
-
info = release.get("info", {}) if isinstance(release.get("info"), dict) else {}
|
|
109
|
-
version = str(info.get("version", ""))
|
|
110
|
-
if not _VERSION_RE.fullmatch(version):
|
|
111
|
-
raise UpdateError("PyPI did not return a stable dotbrain release")
|
|
112
|
-
return version
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
def _version_parts(version: str) -> tuple[int, int, int]:
|
|
116
|
-
match = _VERSION_RE.fullmatch(version)
|
|
117
|
-
if not match:
|
|
118
|
-
raise UpdateError(f"unsupported installed version: {version}")
|
|
119
|
-
return tuple(int(part) for part in match.groups())
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|