webbee 0.7.6__tar.gz → 0.7.7__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 (160) hide show
  1. {webbee-0.7.6 → webbee-0.7.7}/CHANGELOG.md +8 -0
  2. {webbee-0.7.6 → webbee-0.7.7}/PKG-INFO +1 -1
  3. {webbee-0.7.6 → webbee-0.7.7}/install.sh +1 -1
  4. {webbee-0.7.6 → webbee-0.7.7}/pyproject.toml +1 -1
  5. webbee-0.7.7/src/webbee/__init__.py +1 -0
  6. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/autoupdate.py +18 -9
  7. {webbee-0.7.6 → webbee-0.7.7}/tests/test_autoupdate.py +19 -15
  8. {webbee-0.7.6 → webbee-0.7.7}/tests/test_packaging.py +1 -1
  9. webbee-0.7.6/src/webbee/__init__.py +0 -1
  10. {webbee-0.7.6 → webbee-0.7.7}/.github/workflows/publish.yml +0 -0
  11. {webbee-0.7.6 → webbee-0.7.7}/.gitignore +0 -0
  12. {webbee-0.7.6 → webbee-0.7.7}/LICENSE +0 -0
  13. {webbee-0.7.6 → webbee-0.7.7}/README.md +0 -0
  14. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/__main__.py +0 -0
  15. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/_launch.py +0 -0
  16. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/account.py +0 -0
  17. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/active_sessions.py +0 -0
  18. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/banner_art.py +0 -0
  19. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/boot.py +0 -0
  20. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/browser.py +0 -0
  21. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/checkpoints.py +0 -0
  22. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/cli.py +0 -0
  23. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/clipboard.py +0 -0
  24. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/clipboard_read.py +0 -0
  25. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/clipboard_session.py +0 -0
  26. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/coding_context.py +0 -0
  27. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/commands.py +0 -0
  28. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/config.py +0 -0
  29. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/consent.py +0 -0
  30. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/details.py +0 -0
  31. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/events.py +0 -0
  32. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/frames.py +0 -0
  33. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/home.py +0 -0
  34. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/home_view.py +0 -0
  35. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/http.py +0 -0
  36. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/instance_lock.py +0 -0
  37. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/intel/__init__.py +0 -0
  38. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/intel/graph.py +0 -0
  39. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/intel/outline.py +0 -0
  40. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/intel/query.py +0 -0
  41. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/intel/service.py +0 -0
  42. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/intel/store.py +0 -0
  43. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/intel/tree.py +0 -0
  44. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/intel/vectors.py +0 -0
  45. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/intel/watch.py +0 -0
  46. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/media.py +0 -0
  47. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/modals.py +0 -0
  48. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/mode_store.py +0 -0
  49. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/native_files.py +0 -0
  50. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/native_read.py +0 -0
  51. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/newtab_mode.py +0 -0
  52. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/output_pane.py +0 -0
  53. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/pricing_constants.py +0 -0
  54. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/queue_panel.py +0 -0
  55. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/reflow.py +0 -0
  56. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/remote.py +0 -0
  57. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/render.py +0 -0
  58. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/repl.py +0 -0
  59. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/repo.py +0 -0
  60. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/selection.py +0 -0
  61. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/session.py +0 -0
  62. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/sessions.py +0 -0
  63. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/sizing.py +0 -0
  64. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/slots.py +0 -0
  65. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/steer.py +0 -0
  66. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/stream.py +0 -0
  67. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/tab_store.py +0 -0
  68. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/tabs.py +0 -0
  69. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/thread.py +0 -0
  70. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/tier_store.py +0 -0
  71. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/todo_panel.py +0 -0
  72. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/tokens.py +0 -0
  73. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/tools.py +0 -0
  74. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/tui.py +0 -0
  75. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/update.py +0 -0
  76. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/urlopen.py +0 -0
  77. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/wallet.py +0 -0
  78. {webbee-0.7.6 → webbee-0.7.7}/src/webbee/worktrees.py +0 -0
  79. {webbee-0.7.6 → webbee-0.7.7}/tests/__init__.py +0 -0
  80. {webbee-0.7.6 → webbee-0.7.7}/tests/conftest.py +0 -0
  81. {webbee-0.7.6 → webbee-0.7.7}/tests/test_account.py +0 -0
  82. {webbee-0.7.6 → webbee-0.7.7}/tests/test_active_sessions.py +0 -0
  83. {webbee-0.7.6 → webbee-0.7.7}/tests/test_audit_2026_07_25_findings.py +0 -0
  84. {webbee-0.7.6 → webbee-0.7.7}/tests/test_checkpoints.py +0 -0
  85. {webbee-0.7.6 → webbee-0.7.7}/tests/test_checkpoints_nested_1030.py +0 -0
  86. {webbee-0.7.6 → webbee-0.7.7}/tests/test_cli.py +0 -0
  87. {webbee-0.7.6 → webbee-0.7.7}/tests/test_clipboard.py +0 -0
  88. {webbee-0.7.6 → webbee-0.7.7}/tests/test_clipboard_read.py +0 -0
  89. {webbee-0.7.6 → webbee-0.7.7}/tests/test_code_map_fresh.py +0 -0
  90. {webbee-0.7.6 → webbee-0.7.7}/tests/test_coding_context.py +0 -0
  91. {webbee-0.7.6 → webbee-0.7.7}/tests/test_commands.py +0 -0
  92. {webbee-0.7.6 → webbee-0.7.7}/tests/test_config.py +0 -0
  93. {webbee-0.7.6 → webbee-0.7.7}/tests/test_cpc_contract_stable.py +0 -0
  94. {webbee-0.7.6 → webbee-0.7.7}/tests/test_cpc_outline.py +0 -0
  95. {webbee-0.7.6 → webbee-0.7.7}/tests/test_cross_loop_token.py +0 -0
  96. {webbee-0.7.6 → webbee-0.7.7}/tests/test_details.py +0 -0
  97. {webbee-0.7.6 → webbee-0.7.7}/tests/test_events.py +0 -0
  98. {webbee-0.7.6 → webbee-0.7.7}/tests/test_freeze_fix.py +0 -0
  99. {webbee-0.7.6 → webbee-0.7.7}/tests/test_home.py +0 -0
  100. {webbee-0.7.6 → webbee-0.7.7}/tests/test_home_view.py +0 -0
  101. {webbee-0.7.6 → webbee-0.7.7}/tests/test_home_view_mouse.py +0 -0
  102. {webbee-0.7.6 → webbee-0.7.7}/tests/test_inspect_page.py +0 -0
  103. {webbee-0.7.6 → webbee-0.7.7}/tests/test_instance_lock.py +0 -0
  104. {webbee-0.7.6 → webbee-0.7.7}/tests/test_intel_any_folder.py +0 -0
  105. {webbee-0.7.6 → webbee-0.7.7}/tests/test_intel_cache_and_sync_worker.py +0 -0
  106. {webbee-0.7.6 → webbee-0.7.7}/tests/test_intel_checksum_tree.py +0 -0
  107. {webbee-0.7.6 → webbee-0.7.7}/tests/test_intel_chunker.py +0 -0
  108. {webbee-0.7.6 → webbee-0.7.7}/tests/test_intel_embed.py +0 -0
  109. {webbee-0.7.6 → webbee-0.7.7}/tests/test_intel_folder_1106.py +0 -0
  110. {webbee-0.7.6 → webbee-0.7.7}/tests/test_intel_graph.py +0 -0
  111. {webbee-0.7.6 → webbee-0.7.7}/tests/test_intel_no_numpy.py +0 -0
  112. {webbee-0.7.6 → webbee-0.7.7}/tests/test_intel_query.py +0 -0
  113. {webbee-0.7.6 → webbee-0.7.7}/tests/test_intel_service.py +0 -0
  114. {webbee-0.7.6 → webbee-0.7.7}/tests/test_intel_store.py +0 -0
  115. {webbee-0.7.6 → webbee-0.7.7}/tests/test_intel_vectors.py +0 -0
  116. {webbee-0.7.6 → webbee-0.7.7}/tests/test_intel_watch.py +0 -0
  117. {webbee-0.7.6 → webbee-0.7.7}/tests/test_launch.py +0 -0
  118. {webbee-0.7.6 → webbee-0.7.7}/tests/test_marathon.py +0 -0
  119. {webbee-0.7.6 → webbee-0.7.7}/tests/test_modals_e2e.py +0 -0
  120. {webbee-0.7.6 → webbee-0.7.7}/tests/test_mode_and_remote_0_6_8.py +0 -0
  121. {webbee-0.7.6 → webbee-0.7.7}/tests/test_mode_store.py +0 -0
  122. {webbee-0.7.6 → webbee-0.7.7}/tests/test_native_files.py +0 -0
  123. {webbee-0.7.6 → webbee-0.7.7}/tests/test_newtab_mode.py +0 -0
  124. {webbee-0.7.6 → webbee-0.7.7}/tests/test_probe_cost.py +0 -0
  125. {webbee-0.7.6 → webbee-0.7.7}/tests/test_queue_manage_0337.py +0 -0
  126. {webbee-0.7.6 → webbee-0.7.7}/tests/test_reflow.py +0 -0
  127. {webbee-0.7.6 → webbee-0.7.7}/tests/test_remote_code_reads.py +0 -0
  128. {webbee-0.7.6 → webbee-0.7.7}/tests/test_render.py +0 -0
  129. {webbee-0.7.6 → webbee-0.7.7}/tests/test_repl.py +0 -0
  130. {webbee-0.7.6 → webbee-0.7.7}/tests/test_repo.py +0 -0
  131. {webbee-0.7.6 → webbee-0.7.7}/tests/test_resilient_http.py +0 -0
  132. {webbee-0.7.6 → webbee-0.7.7}/tests/test_review_fixes_1030.py +0 -0
  133. {webbee-0.7.6 → webbee-0.7.7}/tests/test_session.py +0 -0
  134. {webbee-0.7.6 → webbee-0.7.7}/tests/test_session_review_1030.py +0 -0
  135. {webbee-0.7.6 → webbee-0.7.7}/tests/test_sessions.py +0 -0
  136. {webbee-0.7.6 → webbee-0.7.7}/tests/test_sizing.py +0 -0
  137. {webbee-0.7.6 → webbee-0.7.7}/tests/test_slots.py +0 -0
  138. {webbee-0.7.6 → webbee-0.7.7}/tests/test_steer.py +0 -0
  139. {webbee-0.7.6 → webbee-0.7.7}/tests/test_stream.py +0 -0
  140. {webbee-0.7.6 → webbee-0.7.7}/tests/test_tab_bar_stability.py +0 -0
  141. {webbee-0.7.6 → webbee-0.7.7}/tests/test_tab_restore_0337.py +0 -0
  142. {webbee-0.7.6 → webbee-0.7.7}/tests/test_tabs.py +0 -0
  143. {webbee-0.7.6 → webbee-0.7.7}/tests/test_terminal_ux_0336.py +0 -0
  144. {webbee-0.7.6 → webbee-0.7.7}/tests/test_thread.py +0 -0
  145. {webbee-0.7.6 → webbee-0.7.7}/tests/test_tier_invalidation.py +0 -0
  146. {webbee-0.7.6 → webbee-0.7.7}/tests/test_tier_store.py +0 -0
  147. {webbee-0.7.6 → webbee-0.7.7}/tests/test_todo_panel.py +0 -0
  148. {webbee-0.7.6 → webbee-0.7.7}/tests/test_tokens.py +0 -0
  149. {webbee-0.7.6 → webbee-0.7.7}/tests/test_tools.py +0 -0
  150. {webbee-0.7.6 → webbee-0.7.7}/tests/test_tools_eol_cancel_1030.py +0 -0
  151. {webbee-0.7.6 → webbee-0.7.7}/tests/test_tools_vision_websearch.py +0 -0
  152. {webbee-0.7.6 → webbee-0.7.7}/tests/test_tui.py +0 -0
  153. {webbee-0.7.6 → webbee-0.7.7}/tests/test_tui_hardening.py +0 -0
  154. {webbee-0.7.6 → webbee-0.7.7}/tests/test_update.py +0 -0
  155. {webbee-0.7.6 → webbee-0.7.7}/tests/test_update_badge_0340.py +0 -0
  156. {webbee-0.7.6 → webbee-0.7.7}/tests/test_urlopen.py +0 -0
  157. {webbee-0.7.6 → webbee-0.7.7}/tests/test_version.py +0 -0
  158. {webbee-0.7.6 → webbee-0.7.7}/tests/test_version_badge_corner.py +0 -0
  159. {webbee-0.7.6 → webbee-0.7.7}/tests/test_wallet.py +0 -0
  160. {webbee-0.7.6 → webbee-0.7.7}/tests/test_worktrees.py +0 -0
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.7.7
4
+
5
+ * `pipx reinstall webbee` brings the newest release for real (live check of 0.7.6: it still gave 0.7.5).
6
+ * imperal-mcp is installed beside webbee without its code extra. The extra requires webbee, and on a reinstall
7
+ pipx (uv backend) took that webbee from PyPI over the git one while PyPI's index still showed the release before.
8
+ webbee's own dependencies already bring what the extra holds.
9
+ * An install recorded with that extra is moved once onto the corrected record.
10
+
3
11
  ## 0.7.6
4
12
 
5
13
  * **Always the newest release, from git** (06.11: `pipx reinstall webbee` put back 0.6.7 while 0.7.5 was out).
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: webbee
3
- Version: 0.7.6
3
+ Version: 0.7.7
4
4
  Summary: Webbee 🐝 — the Imperal Cloud coding agent in your terminal
5
5
  Project-URL: Homepage, https://imperal.io
6
6
  Project-URL: Documentation, https://docs.imperal.io
@@ -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[code] @ git+$GH/imperal-mcp.git@stable" \
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "webbee"
3
- version = "0.7.6"
3
+ version = "0.7.7"
4
4
  description = "Webbee 🐝 — the Imperal Cloud coding agent in your terminal"
5
5
  readme = "README.md"
6
6
  license = "GPL-3.0-or-later"
@@ -0,0 +1 @@
1
+ __version__ = "0.7.7"
@@ -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, dists) -> bool:
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``) names each of ``dists`` by its repository's stable branch. Plain pip keeps no such record."""
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(any(f"git+{REPOS[d]}@{STABLE}" in s for s in recorded) for d in dists)
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
- return all(f'git = "{REPOS[d]}?rev={STABLE}"' in receipt for d in dists)
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), [git_spec(MCP), git_spec(SDK)], uv, pipx,
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
@@ -257,7 +266,7 @@ def mcp_command(inst: dict, newest, uv, pipx, wheel=None, source: str = "pypi"):
257
266
  the stable branches, imperal-sdk and webbee beside it, and an install recorded by a version is moved onto the
258
267
  branch even when its version is the newest (what ``pipx reinstall`` / ``uv tool upgrade`` would put back)."""
259
268
  git = source == "git"
260
- recorded = bool(inst) and on_stable(inst.get("tool") or "", inst.get("prefix") or "", (MCP, SDK, DIST))
269
+ recorded = bool(inst) and on_stable(inst.get("tool") or "", inst.get("prefix") or "", MCP_ENV_SPECS)
261
270
  if inst and inst.get("version") and inst.get("version") == newest and inst.get("code") and (recorded or not git):
262
271
  return None
263
272
  if inst and not inst.get("version"):
@@ -471,7 +480,7 @@ def upgrade_before_start(argv, current: str, say=print, fetch=latest, which=safe
471
480
  git = None if light else which("git") # 3.7's pip builds no package from source: the light install stays on PyPI
472
481
  newest, source = _newest(DIST, git, fetch, stable)
473
482
  tool = tool_of(prefix)
474
- recorded = source != "git" or on_stable(tool, prefix, (DIST, MCP, SDK))
483
+ recorded = source != "git" or on_stable(tool, prefix, WEBBEE_ENV_SPECS)
475
484
  # the same release recorded by a version: moved onto the branch (what pipx/uv would put back on a reinstall)
476
485
  if newest and (_ver(newest) > _ver(current) or (not recorded and _ver(newest) == _ver(current))) \
477
486
  and not env.get(DONE_ENV):
@@ -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, ("webbee",))
350
- good = _pipx_venv(tmp_path / "b", WB, (MCP_G, SDK_G))
351
- assert au.on_stable("pipx", good, ("webbee", "imperal-mcp", "imperal-sdk"))
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, ("webbee", "imperal-mcp"))
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), ("imperal-mcp",))
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), ("imperal-mcp", "imperal-sdk", "webbee"))
365
- assert not au.on_stable("pipx", str(tmp_path / "missing"), ("webbee",)) # unreadable: moved, never assumed
366
- assert au.on_stable("pip", "/venv", ("webbee",)) # plain pip keeps no record
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", MCP_G, "--with", SDK_G, WB]
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", MCP_G, SDK_G]]
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, MCP_G, SDK_G]
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", MCP_G, SDK_G] in run.calls
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, (MCP_G, SDK_G))
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, (MCP_G, SDK_G))
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, (MCP_G, SDK_G))
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={},
@@ -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[code] @ git+$GH/imperal-mcp.git@stable"',
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