webbee 0.7.6__tar.gz → 0.7.8__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.
- {webbee-0.7.6 → webbee-0.7.8}/CHANGELOG.md +14 -0
- {webbee-0.7.6 → webbee-0.7.8}/PKG-INFO +1 -1
- {webbee-0.7.6 → webbee-0.7.8}/install.sh +1 -1
- {webbee-0.7.6 → webbee-0.7.8}/pyproject.toml +1 -1
- webbee-0.7.8/src/webbee/__init__.py +1 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/autoupdate.py +37 -18
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_autoupdate.py +37 -15
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_packaging.py +1 -1
- webbee-0.7.6/src/webbee/__init__.py +0 -1
- {webbee-0.7.6 → webbee-0.7.8}/.github/workflows/publish.yml +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/.gitignore +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/LICENSE +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/README.md +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/__main__.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/_launch.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/account.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/active_sessions.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/banner_art.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/boot.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/browser.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/checkpoints.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/cli.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/clipboard.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/clipboard_read.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/clipboard_session.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/coding_context.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/commands.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/config.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/consent.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/details.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/events.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/frames.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/home.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/home_view.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/http.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/instance_lock.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/intel/__init__.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/intel/graph.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/intel/outline.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/intel/query.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/intel/service.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/intel/store.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/intel/tree.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/intel/vectors.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/intel/watch.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/media.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/modals.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/mode_store.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/native_files.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/native_read.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/newtab_mode.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/output_pane.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/pricing_constants.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/queue_panel.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/reflow.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/remote.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/render.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/repl.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/repo.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/selection.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/session.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/sessions.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/sizing.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/slots.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/steer.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/stream.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/tab_store.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/tabs.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/thread.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/tier_store.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/todo_panel.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/tokens.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/tools.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/tui.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/update.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/urlopen.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/wallet.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/src/webbee/worktrees.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/__init__.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/conftest.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_account.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_active_sessions.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_audit_2026_07_25_findings.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_checkpoints.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_checkpoints_nested_1030.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_cli.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_clipboard.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_clipboard_read.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_code_map_fresh.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_coding_context.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_commands.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_config.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_cpc_contract_stable.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_cpc_outline.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_cross_loop_token.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_details.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_events.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_freeze_fix.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_home.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_home_view.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_home_view_mouse.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_inspect_page.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_instance_lock.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_intel_any_folder.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_intel_cache_and_sync_worker.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_intel_checksum_tree.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_intel_chunker.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_intel_embed.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_intel_folder_1106.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_intel_graph.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_intel_no_numpy.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_intel_query.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_intel_service.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_intel_store.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_intel_vectors.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_intel_watch.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_launch.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_marathon.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_modals_e2e.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_mode_and_remote_0_6_8.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_mode_store.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_native_files.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_newtab_mode.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_probe_cost.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_queue_manage_0337.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_reflow.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_remote_code_reads.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_render.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_repl.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_repo.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_resilient_http.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_review_fixes_1030.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_session.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_session_review_1030.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_sessions.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_sizing.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_slots.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_steer.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_stream.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_tab_bar_stability.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_tab_restore_0337.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_tabs.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_terminal_ux_0336.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_thread.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_tier_invalidation.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_tier_store.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_todo_panel.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_tokens.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_tools.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_tools_eol_cancel_1030.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_tools_vision_websearch.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_tui.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_tui_hardening.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_update.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_update_badge_0340.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_urlopen.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_version.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_version_badge_corner.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_wallet.py +0 -0
- {webbee-0.7.6 → webbee-0.7.8}/tests/test_worktrees.py +0 -0
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.7.8
|
|
4
|
+
|
|
5
|
+
* The webbee beside the shell's imperal-mcp (its code tools) follows webbee's releases. Live: webbee 0.7.7 was out,
|
|
6
|
+
imperal-mcp had no new release, and its environment kept webbee 0.7.6 because only imperal-mcp's version was
|
|
7
|
+
compared.
|
|
8
|
+
|
|
9
|
+
## 0.7.7
|
|
10
|
+
|
|
11
|
+
* `pipx reinstall webbee` brings the newest release for real (live check of 0.7.6: it still gave 0.7.5).
|
|
12
|
+
* imperal-mcp is installed beside webbee without its code extra. The extra requires webbee, and on a reinstall
|
|
13
|
+
pipx (uv backend) took that webbee from PyPI over the git one while PyPI's index still showed the release before.
|
|
14
|
+
webbee's own dependencies already bring what the extra holds.
|
|
15
|
+
* An install recorded with that extra is moved once onto the corrected record.
|
|
16
|
+
|
|
3
17
|
## 0.7.6
|
|
4
18
|
|
|
5
19
|
* **Always the newest release, from git** (06.11: `pipx reinstall webbee` put back 0.6.7 while 0.7.5 was out).
|
|
@@ -16,7 +16,7 @@ GH="https://github.com/imperalcloud"
|
|
|
16
16
|
if command -v git >/dev/null 2>&1; then
|
|
17
17
|
echo "Installing webbee (newest release, from git)…"
|
|
18
18
|
uv tool install --force --refresh \
|
|
19
|
-
--with "imperal-mcp
|
|
19
|
+
--with "imperal-mcp @ git+$GH/imperal-mcp.git@stable" \
|
|
20
20
|
--with "imperal-sdk[universal-index] @ git+$GH/imperal-sdk.git@stable" \
|
|
21
21
|
"webbee @ git+$GH/webbee-code.git@stable"
|
|
22
22
|
else
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.7.8"
|
|
@@ -35,12 +35,18 @@ REPOS = {DIST: "https://github.com/imperalcloud/webbee-code.git",
|
|
|
35
35
|
NAMES = {DIST: DIST, MCP: MCP_SPEC, SDK: SDK_SPEC} # each with the extras its install needs
|
|
36
36
|
|
|
37
37
|
|
|
38
|
-
def git_spec(dist: str, ref: str = STABLE) -> str:
|
|
38
|
+
def git_spec(dist: str, ref: str = STABLE, extras: bool = True) -> str:
|
|
39
39
|
"""``dist`` (with its extras) from its repository at ``ref`` -- the ``stable`` branch unless a tag is named."""
|
|
40
|
-
return f"{NAMES[dist]} @ git+{REPOS[dist]}@{ref}"
|
|
40
|
+
return f"{NAMES[dist] if extras else dist} @ git+{REPOS[dist]}@{ref}"
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
MCP_GIT_SPEC = git_spec(MCP)
|
|
44
|
+
# imperal-mcp beside webbee goes WITHOUT its code extra: the extra requires webbee, and pipx (uv backend) installed
|
|
45
|
+
# that webbee from PyPI over the git one on a reinstall (live 2026-11-06: stable 0.7.6, `pipx reinstall` gave PyPI's
|
|
46
|
+
# 0.7.5). webbee's own dependencies already hold what the extra brings (tree-sitter, the sdk's index).
|
|
47
|
+
MCP_BESIDE_WEBBEE = git_spec(MCP, extras=False)
|
|
48
|
+
WEBBEE_ENV_SPECS = (git_spec(DIST), MCP_BESIDE_WEBBEE, git_spec(SDK)) # webbee's own environment
|
|
49
|
+
MCP_ENV_SPECS = (MCP_GIT_SPEC, git_spec(SDK), git_spec(DIST)) # the shell's imperal-mcp
|
|
44
50
|
PYPI = "https://pypi.org/pypi/{}/json"
|
|
45
51
|
OFF_ENV = "WEBBEE_NO_AUTOUPDATE" # 1: never upgrade at the start (CI, a pinned setup)
|
|
46
52
|
DONE_ENV = "WEBBEE_UPGRADED" # set on the restart after a self-upgrade: never twice in a row
|
|
@@ -124,9 +130,11 @@ def stable_version(dist: str, git, run=subprocess.run):
|
|
|
124
130
|
return None
|
|
125
131
|
|
|
126
132
|
|
|
127
|
-
def on_stable(tool: str, prefix: str,
|
|
133
|
+
def on_stable(tool: str, prefix: str, specs) -> bool:
|
|
128
134
|
"""What pipx / uv will install again for the environment at ``prefix`` (``pipx reinstall``, ``pipx upgrade``,
|
|
129
|
-
``uv tool upgrade``)
|
|
135
|
+
``uv tool upgrade``) is ``specs``, each by its repository's stable branch. pipx: each spec exactly as given (an
|
|
136
|
+
imperal-mcp recorded beside webbee WITH its code extra pulled webbee from PyPI on a reinstall); uv resolves the
|
|
137
|
+
record as one set, so its repository and branch suffice. Plain pip keeps no such record."""
|
|
130
138
|
try:
|
|
131
139
|
if tool == "pipx":
|
|
132
140
|
import json
|
|
@@ -134,11 +142,12 @@ def on_stable(tool: str, prefix: str, dists) -> bool:
|
|
|
134
142
|
meta = json.load(f)
|
|
135
143
|
recorded = [str((meta.get("main_package") or {}).get("package_or_url") or "")]
|
|
136
144
|
recorded += [str((p or {}).get("package_or_url") or "") for p in (meta.get("injected_packages") or {}).values()]
|
|
137
|
-
return all(
|
|
145
|
+
return all(s in recorded for s in specs)
|
|
138
146
|
if tool == "uv":
|
|
139
147
|
with open(os.path.join(prefix, "uv-receipt.toml"), encoding="utf-8") as f:
|
|
140
148
|
receipt = f.read()
|
|
141
|
-
|
|
149
|
+
urls = [s.split(" @ git+", 1)[-1].rsplit("@", 1)[0] for s in specs]
|
|
150
|
+
return all(f'git = "{u}?rev={STABLE}"' in receipt for u in urls)
|
|
142
151
|
except Exception:
|
|
143
152
|
return False
|
|
144
153
|
return True
|
|
@@ -201,7 +210,7 @@ def self_command(version: str, prefix: str = sys.prefix, executable: str = sys.e
|
|
|
201
210
|
beside it; ``record``: pipx writes its record anew (see ``_git_install``)."""
|
|
202
211
|
light = env.get(LIGHT_ENV)
|
|
203
212
|
if source == "git" and not light:
|
|
204
|
-
return _git_install(tool_of(prefix), git_spec(DIST, ref), [
|
|
213
|
+
return _git_install(tool_of(prefix), git_spec(DIST, ref), [MCP_BESIDE_WEBBEE, git_spec(SDK)], uv, pipx,
|
|
205
214
|
executable, DIST, record)
|
|
206
215
|
spec = _spec(DIST, DIST, version, wheel)
|
|
207
216
|
if light: # an old Python runs this release through its light install
|
|
@@ -234,16 +243,17 @@ def mcp_installed(which=safe_which, run=subprocess.run) -> dict:
|
|
|
234
243
|
real = os.path.realpath(exe)
|
|
235
244
|
py = os.path.join(os.path.dirname(real), "python.exe" if _WINDOWS else "python")
|
|
236
245
|
out = {"tool": tool_of(real), "python": py, "prefix": os.path.dirname(os.path.dirname(real)), "version": "",
|
|
237
|
-
"code": False}
|
|
246
|
+
"code": False, "webbee": ""}
|
|
238
247
|
# asked twice when it says "no code extra": a reinstall is never made on one odd answer (live 2026-10-25: right after
|
|
239
248
|
# another install the first answer said no webbee, the next ones yes)
|
|
240
249
|
for _ in range(2):
|
|
241
250
|
try:
|
|
242
251
|
got = run([py, "-c", _NO_CWD + "import importlib.metadata as m, importlib.util as u; "
|
|
243
|
-
"
|
|
252
|
+
"w = u.find_spec('webbee') is not None; "
|
|
253
|
+
"print(m.version('imperal-mcp'), w, m.version('webbee') if w else '')"],
|
|
244
254
|
capture_output=True, text=True, timeout=20)
|
|
245
|
-
version, code = (str(got.stdout or "").split() + ["", ""])[:
|
|
246
|
-
out.update(version=version, code=code == "True")
|
|
255
|
+
version, code, webbee = (str(got.stdout or "").split() + ["", "", ""])[:3]
|
|
256
|
+
out.update(version=version, code=code == "True", webbee=webbee)
|
|
247
257
|
except Exception:
|
|
248
258
|
pass
|
|
249
259
|
if out["code"] or not out["version"]:
|
|
@@ -251,14 +261,19 @@ def mcp_installed(which=safe_which, run=subprocess.run) -> dict:
|
|
|
251
261
|
return out
|
|
252
262
|
|
|
253
263
|
|
|
254
|
-
def mcp_command(inst: dict, newest, uv, pipx, wheel=None, source: str = "pypi"):
|
|
264
|
+
def mcp_command(inst: dict, newest, uv, pipx, wheel=None, source: str = "pypi", webbee_newest=None):
|
|
255
265
|
"""The one command that makes the shell's imperal-mcp the newest with its code extra -- by the tool that installed
|
|
256
266
|
it (uv, else pipx, for a new install) -- or None when it already is, or nothing can do it. ``source`` "git": from
|
|
257
267
|
the stable branches, imperal-sdk and webbee beside it, and an install recorded by a version is moved onto the
|
|
258
|
-
branch even when its version is the newest (what ``pipx reinstall`` / ``uv tool upgrade`` would put back).
|
|
268
|
+
branch even when its version is the newest (what ``pipx reinstall`` / ``uv tool upgrade`` would put back). The
|
|
269
|
+
webbee beside it (its code tools) follows webbee's own releases: one newer than it holds upgrades the environment
|
|
270
|
+
too (live 2026-11-06: webbee 0.7.7 out, imperal-mcp unchanged, its environment kept webbee 0.7.6)."""
|
|
259
271
|
git = source == "git"
|
|
260
|
-
recorded = bool(inst) and on_stable(inst.get("tool") or "", inst.get("prefix") or "",
|
|
261
|
-
|
|
272
|
+
recorded = bool(inst) and on_stable(inst.get("tool") or "", inst.get("prefix") or "", MCP_ENV_SPECS)
|
|
273
|
+
behind = git and bool(inst) and bool(inst.get("webbee")) and bool(webbee_newest) \
|
|
274
|
+
and _ver(inst.get("webbee")) < _ver(webbee_newest)
|
|
275
|
+
if inst and inst.get("version") and inst.get("version") == newest and inst.get("code") and (recorded or not git) \
|
|
276
|
+
and not behind:
|
|
262
277
|
return None
|
|
263
278
|
if inst and not inst.get("version"):
|
|
264
279
|
return None # it did not answer: a working install is never replaced blind
|
|
@@ -471,7 +486,7 @@ def upgrade_before_start(argv, current: str, say=print, fetch=latest, which=safe
|
|
|
471
486
|
git = None if light else which("git") # 3.7's pip builds no package from source: the light install stays on PyPI
|
|
472
487
|
newest, source = _newest(DIST, git, fetch, stable)
|
|
473
488
|
tool = tool_of(prefix)
|
|
474
|
-
recorded = source != "git" or on_stable(tool, prefix,
|
|
489
|
+
recorded = source != "git" or on_stable(tool, prefix, WEBBEE_ENV_SPECS)
|
|
475
490
|
# the same release recorded by a version: moved onto the branch (what pipx/uv would put back on a reinstall)
|
|
476
491
|
if newest and (_ver(newest) > _ver(current) or (not recorded and _ver(newest) == _ver(current))) \
|
|
477
492
|
and not env.get(DONE_ENV):
|
|
@@ -503,9 +518,13 @@ def upgrade_before_start(argv, current: str, say=print, fetch=latest, which=safe
|
|
|
503
518
|
say(f"🐝 webbee could not update itself -- run: {_show(cmd)}")
|
|
504
519
|
mcp_newest, mcp_source = _newest(MCP, git, fetch, stable)
|
|
505
520
|
inst = mcp_installed(which, run)
|
|
506
|
-
cmd = mcp_command(inst, mcp_newest, uv, pipx, wheel, source=mcp_source
|
|
521
|
+
cmd = mcp_command(inst, mcp_newest, uv, pipx, wheel, source=mcp_source,
|
|
522
|
+
webbee_newest=newest if source == "git" else None)
|
|
507
523
|
if cmd:
|
|
508
|
-
what = (f"imperal-mcp {inst.get('version') or '?'} -> {mcp_newest or 'source'}"
|
|
524
|
+
what = (f"imperal-mcp {inst.get('version') or '?'} -> {mcp_newest or 'source'}"
|
|
525
|
+
+ (f", webbee beside it {inst.get('webbee')} -> {newest}"
|
|
526
|
+
if source == "git" and inst.get("webbee") and _ver(inst.get("webbee")) < _ver(newest) else "")
|
|
527
|
+
if inst
|
|
509
528
|
else f"imperal-mcp {mcp_newest or 'from source'}") + (" (git, stable)" if mcp_source == "git" else "")
|
|
510
529
|
say(f"🐝 updating {what} ...")
|
|
511
530
|
if _run(cmd, run):
|
|
@@ -304,6 +304,7 @@ def test_an_upgrader_that_dies_during_the_wait_is_taken_over(tmp_path):
|
|
|
304
304
|
# ── owner 2026-11-06: always the newest, from git. Live: `pipx reinstall webbee` put back 0.6.7 while 0.7.5 was out --
|
|
305
305
|
# pipx had recorded 0.6.7's wheel address and reinstalls its record; the record is now the stable branch ──
|
|
306
306
|
WB, MCP_G, SDK_G = au.git_spec(au.DIST), au.git_spec(au.MCP), au.git_spec(au.SDK)
|
|
307
|
+
MCP_W = au.MCP_BESIDE_WEBBEE # beside webbee: no code extra (it would pull webbee from PyPI)
|
|
307
308
|
H_OLD, H_NEW, H_TAG = "a" * 40, "b" * 40, "c" * 40
|
|
308
309
|
|
|
309
310
|
|
|
@@ -332,6 +333,7 @@ def test_the_spec_is_the_branch_never_a_version():
|
|
|
332
333
|
assert MCP_G == "imperal-mcp[code] @ git+https://github.com/imperalcloud/imperal-mcp.git@stable"
|
|
333
334
|
assert SDK_G == "imperal-sdk[universal-index] @ git+https://github.com/imperalcloud/imperal-sdk.git@stable"
|
|
334
335
|
assert au.MCP_GIT_SPEC == MCP_G
|
|
336
|
+
assert MCP_W == "imperal-mcp @ git+https://github.com/imperalcloud/imperal-mcp.git@stable"
|
|
335
337
|
|
|
336
338
|
|
|
337
339
|
def _pipx_venv(tmp_path, main, injected=()):
|
|
@@ -346,36 +348,38 @@ def _pipx_venv(tmp_path, main, injected=()):
|
|
|
346
348
|
|
|
347
349
|
def test_what_pipx_and_uv_recorded_is_read(tmp_path):
|
|
348
350
|
pinned = _pipx_venv(tmp_path / "a", "webbee @ https://files.pythonhosted.org/x/webbee-0.6.7-py3-none-any.whl")
|
|
349
|
-
assert not au.on_stable("pipx", pinned, (
|
|
350
|
-
good = _pipx_venv(tmp_path / "b", WB, (
|
|
351
|
-
assert au.on_stable("pipx", good,
|
|
351
|
+
assert not au.on_stable("pipx", pinned, (WB,))
|
|
352
|
+
good = _pipx_venv(tmp_path / "b", WB, (MCP_W, SDK_G))
|
|
353
|
+
assert au.on_stable("pipx", good, au.WEBBEE_ENV_SPECS)
|
|
354
|
+
coded = _pipx_venv(tmp_path / "d", WB, (MCP_G, SDK_G)) # mcp WITH its code extra beside webbee
|
|
355
|
+
assert not au.on_stable("pipx", coded, au.WEBBEE_ENV_SPECS)
|
|
352
356
|
half = _pipx_venv(tmp_path / "c", WB) # its packages still from PyPI
|
|
353
|
-
assert not au.on_stable("pipx", half,
|
|
357
|
+
assert not au.on_stable("pipx", half, au.WEBBEE_ENV_SPECS)
|
|
354
358
|
uv = tmp_path / "uv" / "tools" / "imperal-mcp"
|
|
355
359
|
uv.mkdir(parents=True)
|
|
356
360
|
(uv / "uv-receipt.toml").write_text('[tool]\nrequirements = [{ name = "imperal-mcp", extras = ["code"], '
|
|
357
361
|
'specifier = "==0.9.5" }]\n')
|
|
358
|
-
assert not au.on_stable("uv", str(uv), (
|
|
362
|
+
assert not au.on_stable("uv", str(uv), (MCP_G,))
|
|
359
363
|
(uv / "uv-receipt.toml").write_text(
|
|
360
364
|
'[tool]\nrequirements = [\n'
|
|
361
365
|
' { name = "imperal-mcp", extras = ["code"], git = "https://github.com/imperalcloud/imperal-mcp.git?rev=stable" },\n'
|
|
362
366
|
' { name = "imperal-sdk", extras = ["universal-index"], git = "https://github.com/imperalcloud/imperal-sdk.git?rev=stable" },\n'
|
|
363
367
|
' { name = "webbee", git = "https://github.com/imperalcloud/webbee-code.git?rev=stable" },\n]\n')
|
|
364
|
-
assert au.on_stable("uv", str(uv),
|
|
365
|
-
assert not au.on_stable("pipx", str(tmp_path / "missing"), (
|
|
366
|
-
assert au.on_stable("pip", "/venv", (
|
|
368
|
+
assert au.on_stable("uv", str(uv), au.MCP_ENV_SPECS)
|
|
369
|
+
assert not au.on_stable("pipx", str(tmp_path / "missing"), (WB,)) # unreadable: moved, never assumed
|
|
370
|
+
assert au.on_stable("pip", "/venv", (WB,)) # plain pip keeps no record
|
|
367
371
|
|
|
368
372
|
|
|
369
373
|
def test_from_git_each_tool_installs_and_records_the_branch():
|
|
370
374
|
uv = au.self_command("0.7.5", prefix="/u/.local/share/uv/tools/webbee", env={}, uv="/bin/uv", source="git")
|
|
371
|
-
assert uv == ["/bin/uv", "tool", "install", "--force", "--refresh", "--with",
|
|
375
|
+
assert uv == ["/bin/uv", "tool", "install", "--force", "--refresh", "--with", MCP_W, "--with", SDK_G, WB]
|
|
372
376
|
px = au.self_command("0.7.5", prefix="/h/.local/pipx/venvs/webbee", env={}, pipx="/bin/pipx", source="git")
|
|
373
|
-
assert px == [["/bin/pipx", "install", "--force", WB], ["/bin/pipx", "inject", "--force", "webbee",
|
|
377
|
+
assert px == [["/bin/pipx", "install", "--force", WB], ["/bin/pipx", "inject", "--force", "webbee", MCP_W, SDK_G]]
|
|
374
378
|
kept = au.self_command("0.7.5", prefix="/h/.local/pipx/venvs/webbee", env={}, pipx="/bin/pipx", source="git",
|
|
375
379
|
record=False) # already on the branch: its own record
|
|
376
380
|
assert kept == ["/bin/pipx", "upgrade", "--include-injected", "webbee"]
|
|
377
381
|
pip = au.self_command("0.7.5", prefix="/v", executable="/v/bin/python", env={}, source="git")
|
|
378
|
-
assert pip == ["/v/bin/python", "-m", "pip", "install", "--upgrade", "--no-cache-dir", WB,
|
|
382
|
+
assert pip == ["/v/bin/python", "-m", "pip", "install", "--upgrade", "--no-cache-dir", WB, MCP_W, SDK_G]
|
|
379
383
|
light = au.self_command("0.7.5", env={au.LIGHT_ENV: "/usr/bin/python3.7"}, source="git", wheel=None)
|
|
380
384
|
assert light[-1] == "webbee==0.7.5" # 3.7 builds nothing from source: PyPI
|
|
381
385
|
|
|
@@ -389,12 +393,12 @@ def test_the_same_release_recorded_by_a_version_is_moved_onto_the_branch(tmp_pat
|
|
|
389
393
|
execv=lambda p, a: execd.append(a), lock_path=lambda: str(tmp_path / "upgrade.lock"),
|
|
390
394
|
stable=lambda d, git: stable(d), prefix=venv)
|
|
391
395
|
assert ["/bin/pipx", "install", "--force", WB] in run.calls
|
|
392
|
-
assert ["/bin/pipx", "inject", "--force", "webbee",
|
|
396
|
+
assert ["/bin/pipx", "inject", "--force", "webbee", MCP_W, SDK_G] in run.calls
|
|
393
397
|
assert execd and any("onto its release branch" in s for s in said)
|
|
394
398
|
|
|
395
399
|
|
|
396
400
|
def test_on_the_branch_and_newest_nothing_is_installed(tmp_path, monkeypatch):
|
|
397
|
-
venv = _pipx_venv(tmp_path, WB, (
|
|
401
|
+
venv = _pipx_venv(tmp_path, WB, (MCP_W, SDK_G))
|
|
398
402
|
exe = tmp_path / "pipx" / "venvs" / "imperal-mcp" / "bin" / "imperal-mcp"
|
|
399
403
|
exe.parent.mkdir(parents=True)
|
|
400
404
|
exe.write_text("")
|
|
@@ -411,7 +415,7 @@ def test_on_the_branch_and_newest_nothing_is_installed(tmp_path, monkeypatch):
|
|
|
411
415
|
|
|
412
416
|
|
|
413
417
|
def test_a_newer_release_on_the_branch_is_taken_by_the_install_s_own_record(tmp_path):
|
|
414
|
-
venv = _pipx_venv(tmp_path, WB, (
|
|
418
|
+
venv = _pipx_venv(tmp_path, WB, (MCP_W, SDK_G))
|
|
415
419
|
run, execd = _Run(), []
|
|
416
420
|
au.upgrade_before_start([], "0.7.4", say=lambda m: None, fetch=lambda d: 1 / 0, wheel=None,
|
|
417
421
|
which=_which({"pipx": "/bin/pipx", "git": "/bin/git"}), run=run, env={},
|
|
@@ -457,7 +461,7 @@ def test_the_steps_of_one_install_stop_at_the_first_that_fails():
|
|
|
457
461
|
|
|
458
462
|
def test_a_git_release_that_does_not_import_is_put_back_by_its_own_tag(tmp_path, monkeypatch):
|
|
459
463
|
_checks(monkeypatch, [False, False, True])
|
|
460
|
-
venv = _pipx_venv(tmp_path, WB, (
|
|
464
|
+
venv = _pipx_venv(tmp_path, WB, (MCP_W, SDK_G))
|
|
461
465
|
run, said = _Run(), []
|
|
462
466
|
au.upgrade_before_start([], "0.7.4", say=said.append, fetch=lambda d: 1 / 0, wheel=None,
|
|
463
467
|
which=_which({"pipx": "/bin/pipx", "git": "/bin/git"}), run=run, env={},
|
|
@@ -465,3 +469,21 @@ def test_a_git_release_that_does_not_import_is_put_back_by_its_own_tag(tmp_path,
|
|
|
465
469
|
stable=lambda d, git: "0.7.5", prefix=venv)
|
|
466
470
|
assert ["/bin/pipx", "install", "--force", au.git_spec("webbee", "v0.7.4")] in run.calls
|
|
467
471
|
assert any("put 0.7.4 back" in s for s in said)
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
def test_the_webbee_beside_imperal_mcp_follows_webbee_s_releases(tmp_path):
|
|
475
|
+
uv = tmp_path / "uv" / "tools" / "imperal-mcp"
|
|
476
|
+
uv.mkdir(parents=True)
|
|
477
|
+
(uv / "uv-receipt.toml").write_text("".join(
|
|
478
|
+
f'{{ name = "x", git = "{u}?rev=stable" }}\n' for u in au.REPOS.values()))
|
|
479
|
+
inst = {"tool": "uv", "python": str(uv / "bin" / "python"), "prefix": str(uv), "version": "0.9.5", "code": True,
|
|
480
|
+
"webbee": "0.7.6"}
|
|
481
|
+
assert au.mcp_command(inst, "0.9.5", "/bin/uv", None, source="git", webbee_newest="0.7.6") is None
|
|
482
|
+
assert au.mcp_command(inst, "0.9.5", "/bin/uv", None, source="git", webbee_newest="0.7.7") == [
|
|
483
|
+
"/bin/uv", "tool", "install", "--force", "--refresh", "--with", SDK_G, "--with", WB, MCP_G]
|
|
484
|
+
run = _Run(stdout="0.9.5 True 0.7.6")
|
|
485
|
+
exe = uv / "bin" / "imperal-mcp"
|
|
486
|
+
exe.parent.mkdir()
|
|
487
|
+
exe.write_text("")
|
|
488
|
+
got = au.mcp_installed(which=lambda n: str(exe), run=run)
|
|
489
|
+
assert got["webbee"] == "0.7.6" and got["code"] is True
|
|
@@ -35,7 +35,7 @@ def test_install_script_is_posix_and_uses_uv():
|
|
|
35
35
|
# must be the plain form.
|
|
36
36
|
# 2026-11-06: always the newest release, from git -- the three packages by their stable branch (never a version,
|
|
37
37
|
# so `uv tool upgrade` and a second run bring the newest); without git the plain form from PyPI
|
|
38
|
-
for spec in ('"webbee @ git+$GH/webbee-code.git@stable"', '"imperal-mcp
|
|
38
|
+
for spec in ('"webbee @ git+$GH/webbee-code.git@stable"', '"imperal-mcp @ git+$GH/imperal-mcp.git@stable"',
|
|
39
39
|
'"imperal-sdk[universal-index] @ git+$GH/imperal-sdk.git@stable"'):
|
|
40
40
|
assert spec in txt
|
|
41
41
|
assert 'uv tool install --force --refresh "webbee"' in txt
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.7.6"
|
|
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
|
|
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
|
|
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
|
|
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
|