webbee 0.6.6__tar.gz → 0.6.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.
- {webbee-0.6.6 → webbee-0.6.7}/CHANGELOG.md +6 -0
- {webbee-0.6.6 → webbee-0.6.7}/PKG-INFO +1 -1
- {webbee-0.6.6 → webbee-0.6.7}/pyproject.toml +1 -1
- webbee-0.6.7/src/webbee/__init__.py +1 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/boot.py +3 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/intel/watch.py +27 -5
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_intel_watch.py +26 -0
- webbee-0.6.6/src/webbee/__init__.py +0 -1
- {webbee-0.6.6 → webbee-0.6.7}/.github/workflows/publish.yml +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/.gitignore +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/LICENSE +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/README.md +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/install.sh +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/__main__.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/_launch.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/account.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/active_sessions.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/autoupdate.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/banner_art.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/browser.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/checkpoints.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/cli.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/clipboard.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/clipboard_read.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/clipboard_session.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/coding_context.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/commands.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/config.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/consent.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/details.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/events.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/frames.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/home.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/home_view.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/http.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/instance_lock.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/intel/__init__.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/intel/graph.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/intel/outline.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/intel/query.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/intel/service.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/intel/store.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/intel/vectors.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/media.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/modals.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/mode_store.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/native_files.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/native_read.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/newtab_mode.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/output_pane.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/pricing_constants.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/queue_panel.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/reflow.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/remote.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/render.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/repl.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/repo.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/selection.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/session.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/sessions.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/sizing.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/slots.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/steer.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/stream.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/tab_store.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/tabs.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/thread.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/tier_store.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/todo_panel.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/tokens.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/tools.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/tui.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/update.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/urlopen.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/wallet.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/src/webbee/worktrees.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/__init__.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/conftest.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_account.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_active_sessions.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_audit_2026_07_25_findings.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_autoupdate.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_checkpoints.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_cli.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_clipboard.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_clipboard_read.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_coding_context.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_commands.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_config.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_cpc_contract_stable.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_cpc_outline.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_cross_loop_token.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_details.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_events.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_freeze_fix.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_home.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_home_view.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_home_view_mouse.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_inspect_page.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_instance_lock.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_intel_chunker.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_intel_embed.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_intel_graph.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_intel_no_numpy.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_intel_query.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_intel_service.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_intel_store.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_intel_vectors.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_launch.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_marathon.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_modals_e2e.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_mode_store.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_native_files.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_newtab_mode.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_packaging.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_probe_cost.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_queue_manage_0337.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_reflow.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_render.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_repl.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_repo.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_resilient_http.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_session.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_sessions.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_sizing.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_slots.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_steer.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_stream.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_tab_bar_stability.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_tab_restore_0337.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_tabs.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_terminal_ux_0336.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_thread.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_tier_invalidation.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_tier_store.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_todo_panel.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_tokens.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_tools.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_tools_vision_websearch.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_tui.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_tui_hardening.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_update.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_update_badge_0340.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_urlopen.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_version.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_version_badge_corner.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_wallet.py +0 -0
- {webbee-0.6.6 → webbee-0.6.7}/tests/test_worktrees.py +0 -0
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.7
|
|
4
|
+
|
|
5
|
+
* **The OS's file-watch limit never crashes webbee**: on a large tree (Linux `fs.inotify.max_user_watches`, a repo with
|
|
6
|
+
`node_modules`) the live re-index polls the tree every 3 s instead of dying, and the watcher's end is always
|
|
7
|
+
collected -- no "Task exception was never retrieved" when webbee quits.
|
|
8
|
+
|
|
3
9
|
## 0.6.6
|
|
4
10
|
|
|
5
11
|
* **The upgrade's lock is the user's own**: it lives in webbee's data folder (only this user can write it), never in
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.6.7"
|
|
@@ -102,6 +102,9 @@ async def start_intel(cfg, workspace: str, intel_factory):
|
|
|
102
102
|
await asyncio.to_thread(svc.build)
|
|
103
103
|
from webbee.intel import watch
|
|
104
104
|
watcher_task = asyncio.ensure_future(watch.watch_workspace(svc.root, svc.apply_changes))
|
|
105
|
+
# its end is always collected: an exception is never printed when webbee quits ("Task exception was never
|
|
106
|
+
# retrieved", live 2026-10-25)
|
|
107
|
+
watcher_task.add_done_callback(lambda t: t.cancelled() or t.exception())
|
|
105
108
|
return svc, watcher_task
|
|
106
109
|
except Exception:
|
|
107
110
|
return None, None
|
|
@@ -17,14 +17,36 @@ def _ignored(path: str, root: str = "") -> bool:
|
|
|
17
17
|
return ignored_path(root, path)
|
|
18
18
|
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
# the OS's watch limit reached (Linux: fs.inotify.max_user_watches; live 2026-10-25 on a repo with node_modules: the
|
|
21
|
+
# watcher task died with "OS file watch limit reached" and its exception was printed when webbee quit): the tree is
|
|
22
|
+
# polled instead -- slower, never a crash
|
|
23
|
+
POLL_MS = 3000
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
async def watch_workspace(root: str, on_change, awatch=None) -> None:
|
|
21
27
|
"""Call on_change(set_of_relpaths) as files change. Fail-soft: if
|
|
22
|
-
watchfiles is unavailable, return immediately (no watcher)
|
|
28
|
+
watchfiles is unavailable, return immediately (no watcher); if the OS cannot
|
|
29
|
+
watch the tree, poll it; any other watch failure ends the watcher alone."""
|
|
30
|
+
if awatch is None:
|
|
31
|
+
try:
|
|
32
|
+
from watchfiles import awatch
|
|
33
|
+
except ImportError:
|
|
34
|
+
return
|
|
23
35
|
try:
|
|
24
|
-
|
|
25
|
-
except
|
|
36
|
+
await _follow(awatch(root), root, on_change)
|
|
37
|
+
except OSError as exc:
|
|
38
|
+
if "watch limit" not in str(exc) and "MaxFilesWatch" not in str(exc):
|
|
39
|
+
return
|
|
40
|
+
try:
|
|
41
|
+
await _follow(awatch(root, force_polling=True, poll_delay_ms=POLL_MS), root, on_change)
|
|
42
|
+
except Exception:
|
|
43
|
+
return
|
|
44
|
+
except Exception:
|
|
26
45
|
return
|
|
27
|
-
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
async def _follow(stream, root: str, on_change) -> None:
|
|
49
|
+
async for changes in stream:
|
|
28
50
|
rels = set()
|
|
29
51
|
for _chg, path in changes:
|
|
30
52
|
if _ignored(path, root):
|
|
@@ -75,3 +75,29 @@ def test_missing_watchfiles_extra_returns_immediately(monkeypatch, tmp_path):
|
|
|
75
75
|
monkeypatch.setattr(builtins, "__import__", _blocked_import)
|
|
76
76
|
# Must return (not hang/raise) when the optional extra isn't installed.
|
|
77
77
|
asyncio.run(watch.watch_workspace(str(tmp_path), lambda rels: None))
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def test_the_os_watch_limit_falls_back_to_polling_and_never_raises(tmp_path):
|
|
81
|
+
"""live 2026-10-25 (a repo with node_modules on Linux): "OS file watch limit reached" killed the watcher task and
|
|
82
|
+
its exception was printed when webbee quit -- the tree is polled instead."""
|
|
83
|
+
root = str(tmp_path)
|
|
84
|
+
calls, opened = [], []
|
|
85
|
+
|
|
86
|
+
def fake_awatch(_root, force_polling=False, poll_delay_ms=0):
|
|
87
|
+
opened.append(force_polling)
|
|
88
|
+
|
|
89
|
+
async def gen():
|
|
90
|
+
if not force_polling:
|
|
91
|
+
raise OSError('OS file watch limit reached. about ["/w"] (Error { kind: MaxFilesWatch })')
|
|
92
|
+
yield {("modified", os.path.join(root, "b.py"))}
|
|
93
|
+
return gen()
|
|
94
|
+
|
|
95
|
+
asyncio.run(watch.watch_workspace(root, calls.append, awatch=fake_awatch))
|
|
96
|
+
assert opened == [False, True] and calls == [{"b.py"}]
|
|
97
|
+
|
|
98
|
+
def broken(_root, **kw):
|
|
99
|
+
async def gen():
|
|
100
|
+
raise RuntimeError("anything else")
|
|
101
|
+
yield
|
|
102
|
+
return gen()
|
|
103
|
+
asyncio.run(watch.watch_workspace(root, calls.append, awatch=broken)) # ends quietly, never raises
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.6.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
|