webbee 0.1.0__tar.gz → 0.1.2__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 (37) hide show
  1. webbee-0.1.2/CHANGELOG.md +39 -0
  2. {webbee-0.1.0 → webbee-0.1.2}/PKG-INFO +9 -5
  3. {webbee-0.1.0 → webbee-0.1.2}/README.md +7 -3
  4. {webbee-0.1.0 → webbee-0.1.2}/pyproject.toml +2 -2
  5. webbee-0.1.2/src/webbee/__init__.py +1 -0
  6. {webbee-0.1.0 → webbee-0.1.2}/src/webbee/cli.py +1 -1
  7. {webbee-0.1.0 → webbee-0.1.2}/src/webbee/render.py +15 -0
  8. {webbee-0.1.0 → webbee-0.1.2}/src/webbee/repl.py +12 -1
  9. {webbee-0.1.0 → webbee-0.1.2}/tests/test_render.py +9 -0
  10. {webbee-0.1.0 → webbee-0.1.2}/tests/test_repl.py +17 -1
  11. webbee-0.1.0/CHANGELOG.md +0 -18
  12. webbee-0.1.0/src/webbee/__init__.py +0 -1
  13. {webbee-0.1.0 → webbee-0.1.2}/.github/workflows/publish.yml +0 -0
  14. {webbee-0.1.0 → webbee-0.1.2}/.gitignore +0 -0
  15. {webbee-0.1.0 → webbee-0.1.2}/LICENSE +0 -0
  16. {webbee-0.1.0 → webbee-0.1.2}/install.sh +0 -0
  17. {webbee-0.1.0 → webbee-0.1.2}/src/webbee/account.py +0 -0
  18. {webbee-0.1.0 → webbee-0.1.2}/src/webbee/banner_art.py +0 -0
  19. {webbee-0.1.0 → webbee-0.1.2}/src/webbee/commands.py +0 -0
  20. {webbee-0.1.0 → webbee-0.1.2}/src/webbee/config.py +0 -0
  21. {webbee-0.1.0 → webbee-0.1.2}/src/webbee/events.py +0 -0
  22. {webbee-0.1.0 → webbee-0.1.2}/src/webbee/session.py +0 -0
  23. {webbee-0.1.0 → webbee-0.1.2}/src/webbee/tools.py +0 -0
  24. {webbee-0.1.0 → webbee-0.1.2}/src/webbee/tui.py +0 -0
  25. {webbee-0.1.0 → webbee-0.1.2}/src/webbee/update.py +0 -0
  26. {webbee-0.1.0 → webbee-0.1.2}/tests/__init__.py +0 -0
  27. {webbee-0.1.0 → webbee-0.1.2}/tests/test_account.py +0 -0
  28. {webbee-0.1.0 → webbee-0.1.2}/tests/test_cli.py +0 -0
  29. {webbee-0.1.0 → webbee-0.1.2}/tests/test_commands.py +0 -0
  30. {webbee-0.1.0 → webbee-0.1.2}/tests/test_config.py +0 -0
  31. {webbee-0.1.0 → webbee-0.1.2}/tests/test_events.py +0 -0
  32. {webbee-0.1.0 → webbee-0.1.2}/tests/test_packaging.py +0 -0
  33. {webbee-0.1.0 → webbee-0.1.2}/tests/test_session.py +0 -0
  34. {webbee-0.1.0 → webbee-0.1.2}/tests/test_tools.py +0 -0
  35. {webbee-0.1.0 → webbee-0.1.2}/tests/test_tui.py +0 -0
  36. {webbee-0.1.0 → webbee-0.1.2}/tests/test_update.py +0 -0
  37. {webbee-0.1.0 → webbee-0.1.2}/tests/test_version.py +0 -0
@@ -0,0 +1,39 @@
1
+ # Changelog
2
+
3
+ ## 0.1.2
4
+
5
+ - **Device-code login (RFC 8628).** `/login` and `webbee login` now use the
6
+ device-authorization flow (via `imperal-mcp` 0.5.0): the terminal shows a
7
+ short code + `https://panel.imperal.io/device`; you approve in any browser
8
+ (even a phone), and the terminal polls until it's signed in. Works
9
+ identically on a local machine, over SSH, in WSL, or headless — no
10
+ `127.0.0.1` callback that a remote browser can never reach. Replaces the
11
+ loopback browser-login and the 0.1.1 executor workaround.
12
+ - The dock renders the sign-in code + URL into the action feed (a bare print is
13
+ invisible in the full-screen UI).
14
+ - Fix `__version__` so it tracks `pyproject.toml` (was pinned at 0.1.0).
15
+
16
+ ## 0.1.1
17
+
18
+ - Fix `/login` inside the REPL: it now runs the shared `imperal_mcp` auth flow
19
+ off the event loop, so the browser sign-in completes instead of failing with
20
+ "asyncio.run() cannot be called from a running event loop". (`webbee login`
21
+ from the shell already worked; this fixes the in-REPL command too — one auth
22
+ mechanism for every surface.)
23
+
24
+ ## 0.1.0
25
+
26
+ First public release.
27
+
28
+ - `webbee` — a coding agent in your terminal: reads, writes, and runs code in
29
+ the current directory; the brain runs in the Imperal Cloud on ICNLI. No model
30
+ keys on the machine.
31
+ - Full-screen dock: a scrollable, colored output pane with the input box and
32
+ toolbar pinned at the bottom.
33
+ - Consent modes — **default** (asks before anything it can't undo), **plan**
34
+ (read-only), **autopilot** (acts without asking); cycle with **Shift + TAB**.
35
+ Spending money always needs a browser approval.
36
+ - Reaches your connected Imperal apps (mail, notes, tasks, …) alongside the
37
+ local code tools.
38
+ - Slash commands: `/login` `/logout` `/mode` `/cost` `/status` `/clear` `/exit`.
39
+ - Live token/cost meter (session total) and update check.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: webbee
3
- Version: 0.1.0
3
+ Version: 0.1.2
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
@@ -24,7 +24,7 @@ Classifier: Topic :: Utilities
24
24
  Requires-Python: >=3.11
25
25
  Requires-Dist: httpx-sse>=0.4
26
26
  Requires-Dist: httpx>=0.27
27
- Requires-Dist: imperal-mcp>=0.4.0
27
+ Requires-Dist: imperal-mcp>=0.5.0
28
28
  Requires-Dist: imperal-sdk>=5.9.2
29
29
  Requires-Dist: prompt-toolkit>=3
30
30
  Requires-Dist: rich>=13.7
@@ -44,15 +44,19 @@ Webbee is the [Imperal Cloud](https://imperal.io) coding agent, in your terminal
44
44
  ## Install
45
45
 
46
46
  ```sh
47
- pipx install webbee # or: uv tool install webbee
47
+ pipx install webbee # recommended — or: uv tool install webbee
48
48
  ```
49
49
 
50
- No Python on the box? One line:
50
+ Plain `pip` works too, inside a virtualenv:
51
51
 
52
52
  ```sh
53
- curl -LsSf https://webbee.imperal.io/install.sh | sh
53
+ python3 -m venv .venv && . .venv/bin/activate && pip install webbee
54
54
  ```
55
55
 
56
+ > On Ubuntu/Debian a *global* `pip install` is blocked by the system (that's
57
+ > [PEP 668](https://peps.python.org/pep-0668/), not webbee) — use `pipx` or a
58
+ > venv. No Python on the box? `curl -LsSf https://webbee.imperal.io/install.sh | sh`.
59
+
56
60
  ## Use
57
61
 
58
62
  ```sh
@@ -12,15 +12,19 @@ Webbee is the [Imperal Cloud](https://imperal.io) coding agent, in your terminal
12
12
  ## Install
13
13
 
14
14
  ```sh
15
- pipx install webbee # or: uv tool install webbee
15
+ pipx install webbee # recommended — or: uv tool install webbee
16
16
  ```
17
17
 
18
- No Python on the box? One line:
18
+ Plain `pip` works too, inside a virtualenv:
19
19
 
20
20
  ```sh
21
- curl -LsSf https://webbee.imperal.io/install.sh | sh
21
+ python3 -m venv .venv && . .venv/bin/activate && pip install webbee
22
22
  ```
23
23
 
24
+ > On Ubuntu/Debian a *global* `pip install` is blocked by the system (that's
25
+ > [PEP 668](https://peps.python.org/pep-0668/), not webbee) — use `pipx` or a
26
+ > venv. No Python on the box? `curl -LsSf https://webbee.imperal.io/install.sh | sh`.
27
+
24
28
  ## Use
25
29
 
26
30
  ```sh
@@ -1,13 +1,13 @@
1
1
  [project]
2
2
  name = "webbee"
3
- version = "0.1.0"
3
+ version = "0.1.2"
4
4
  description = "Webbee 🐝 — the Imperal Cloud coding agent in your terminal"
5
5
  readme = "README.md"
6
6
  license = "MIT"
7
7
  license-files = ["LICENSE"]
8
8
  requires-python = ">=3.11"
9
9
  authors = [{ name = "Imperal, Inc.", email = "hello@imperal.io" }]
10
- dependencies = ["imperal-mcp>=0.4.0", "imperal-sdk>=5.9.2", "httpx>=0.27", "httpx-sse>=0.4", "rich>=13.7", "prompt_toolkit>=3"]
10
+ dependencies = ["imperal-mcp>=0.5.0", "imperal-sdk>=5.9.2", "httpx>=0.27", "httpx-sse>=0.4", "rich>=13.7", "prompt_toolkit>=3"]
11
11
  keywords = ["webbee", "imperal", "icnli", "coding-agent", "ai-agent", "cli", "terminal", "llm"]
12
12
  classifiers = [
13
13
  "Development Status :: 4 - Beta",
@@ -0,0 +1 @@
1
+ __version__ = "0.1.2"
@@ -22,7 +22,7 @@ def main(argv=None) -> None:
22
22
 
23
23
  if args.cmd == "login":
24
24
  from imperal_mcp import auth
25
- print(f"Logged in as {auth.login(cfg)}.")
25
+ print(f"Logged in as {asyncio.run(auth.login_device(cfg))}.")
26
26
  return
27
27
  if args.cmd == "logout":
28
28
  from imperal_mcp import auth
@@ -249,6 +249,21 @@ class RichSink:
249
249
  self.console.print(Panel(body, title="💳 This costs money", border_style="magenta"))
250
250
  self._nudge()
251
251
 
252
+ def login_prompt(self, user_code: str, url: str) -> None:
253
+ """Device-code sign-in: show the URL to open + the code to enter, as a
254
+ clear framed block. A bare print would be invisible in the full-screen
255
+ dock, so this renders into the feed; the terminal then polls silently
256
+ until you authorize in the browser."""
257
+ body = Text.assemble(
258
+ ("Open this URL in any browser (a phone is fine):\n", "white"),
259
+ (f" {url}\n\n", f"bold {_ACCENT}"),
260
+ ("and enter this code:\n", "white"),
261
+ (f" {user_code}\n\n", f"bold {_BEE}"),
262
+ ("Waiting for you to authorize…", "dim"),
263
+ )
264
+ self.console.print(Panel(body, title="🐝 Connect this terminal", border_style=_BEE))
265
+ self._nudge()
266
+
252
267
  def progress(self, text: str) -> None:
253
268
  if text:
254
269
  self.console.print(Text(" " + text, style="dim italic"))
@@ -65,7 +65,18 @@ async def run_repl(cfg, mode: str = "default", *, sink=None, read_line=input,
65
65
  if res.exit:
66
66
  return "exit"
67
67
  if res.action == "login":
68
- email = auth.login(cfg)
68
+ # ONE shared imperal_mcp mechanism: device-code flow (RFC 8628),
69
+ # async, so we await it directly on the dock's event loop (the
70
+ # /login turn runs as a background task, so the dock stays
71
+ # responsive while it polls). on_prompt renders the code + URL
72
+ # into the feed — a bare print would be invisible in the dock.
73
+ def _login_prompt(user_code, uri, uri_complete):
74
+ show = getattr(_sink, "login_prompt", None)
75
+ if show:
76
+ show(user_code, uri)
77
+ else:
78
+ _sink.note(f"Open {uri} and enter code: {user_code}")
79
+ email = await auth.login_device(cfg, on_prompt=_login_prompt)
69
80
  state["logged_in"] = True
70
81
  _sink.note(f"Signed in as {email}.")
71
82
  return "continue"
@@ -27,6 +27,15 @@ def test_tool_lines_render():
27
27
  assert "read_file" in out and "auth.py" in out
28
28
 
29
29
 
30
+ def test_login_prompt_shows_code_and_url():
31
+ s = _sink()
32
+ s.login_prompt("WDBK-7Q3M", "https://panel.imperal.io/device")
33
+ out = s.console.export_text()
34
+ assert "WDBK-7Q3M" in out
35
+ assert "panel.imperal.io/device" in out
36
+ assert not NO_CYRILLIC.search(out) # English UI only
37
+
38
+
30
39
  def test_ask_consent_relays_raw_input():
31
40
  console = Console(record=True, width=80)
32
41
  s = RichSink(console=console, live_enabled=False, input_fn=lambda p: " ага давай ", clock=lambda: 0.0)
@@ -41,7 +41,12 @@ class FakeAuth:
41
41
  async def ensure_access_token(self, cfg):
42
42
  if not self._in: raise self.NotLoggedInError("no creds")
43
43
  return "tok"
44
- def login(self, cfg, *, open_browser=True): self._in = True; return "u@imperal.io"
44
+ async def login_device(self, cfg, *, on_prompt=None, open_browser=True):
45
+ if on_prompt:
46
+ on_prompt("WDBK-7Q3M", "https://panel.imperal.io/device",
47
+ "https://panel.imperal.io/device?code=WDBK-7Q3M")
48
+ self._in = True
49
+ return "u@imperal.io"
45
50
  async def logout(self, cfg): self._in = False; self.logged_out = True
46
51
 
47
52
 
@@ -119,6 +124,17 @@ def test_login_command_calls_auth_and_logs_in():
119
124
  assert any(not NO_CYRILLIC.search(n) for n in sink.notes)
120
125
 
121
126
 
127
+ def test_login_uses_device_flow_and_renders_prompt():
128
+ # Device-code flow (RFC 8628): repl awaits auth.login_device directly (async,
129
+ # no executor) and on_prompt renders the code + URL into the feed before the
130
+ # poll completes. Confirms the prompt reaches the sink and login persists.
131
+ auth = FakeAuth(logged_in=False)
132
+ sink, agent = _run(read_line=_lines("/login", "/exit"), auth=auth)
133
+ assert auth._in is True
134
+ assert any("WDBK-7Q3M" in n and "panel.imperal.io/device" in n for n in sink.notes)
135
+ assert any("Signed in as u@imperal.io" in n for n in sink.notes)
136
+
137
+
122
138
  def test_mode_command_switches_agent_mode():
123
139
  sink, agent = _run(read_line=_lines("/mode autopilot", "/exit"))
124
140
  assert agent.mode == "autopilot"
webbee-0.1.0/CHANGELOG.md DELETED
@@ -1,18 +0,0 @@
1
- # Changelog
2
-
3
- ## 0.1.0
4
-
5
- First public release.
6
-
7
- - `webbee` — a coding agent in your terminal: reads, writes, and runs code in
8
- the current directory; the brain runs in the Imperal Cloud on ICNLI. No model
9
- keys on the machine.
10
- - Full-screen dock: a scrollable, colored output pane with the input box and
11
- toolbar pinned at the bottom.
12
- - Consent modes — **default** (asks before anything it can't undo), **plan**
13
- (read-only), **autopilot** (acts without asking); cycle with **Shift + TAB**.
14
- Spending money always needs a browser approval.
15
- - Reaches your connected Imperal apps (mail, notes, tasks, …) alongside the
16
- local code tools.
17
- - Slash commands: `/login` `/logout` `/mode` `/cost` `/status` `/clear` `/exit`.
18
- - Live token/cost meter (session total) and update check.
@@ -1 +0,0 @@
1
- __version__ = "0.1.0"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes