dulus-bar 0.3.2__tar.gz → 0.4.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.
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/PKG-INFO +4 -4
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/README.md +2 -2
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/dulus_bar/__init__.py +1 -1
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/dulus_bar/agents.py +15 -0
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/dulus_bar/main.py +16 -0
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/dulus_bar/native/macos.py +21 -2
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/dulus_bar/overlay.py +303 -114
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/dulus_bar/server.py +13 -0
- dulus_bar-0.4.2/dulus_bar/wrappers/__init__.py +12 -0
- dulus_bar-0.4.2/dulus_bar/wrappers/_resolve_dulus.py +32 -0
- dulus_bar-0.4.2/dulus_bar/wrappers/_ws_health.py +38 -0
- dulus_bar-0.4.2/dulus_bar/wrappers/agent_wrapper.py +32 -0
- dulus_bar-0.4.2/dulus_bar/wrappers/base_wrapper.py +487 -0
- dulus_bar-0.4.2/dulus_bar/wrappers/claude_wrapper.py +38 -0
- dulus_bar-0.4.2/dulus_bar/wrappers/dulus_wrapper.py +155 -0
- dulus_bar-0.4.2/dulus_bar/wrappers/paths.py +178 -0
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/dulus_bar.egg-info/PKG-INFO +4 -4
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/dulus_bar.egg-info/SOURCES.txt +8 -0
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/dulus_bar.egg-info/requires.txt +1 -1
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/pyproject.toml +2 -2
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/tests/test_server_hub.py +4 -3
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/LICENSE +0 -0
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/dulus_bar/__main__.py +0 -0
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/dulus_bar/assets/dulus-bird.png +0 -0
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/dulus_bar/macos_native.py +0 -0
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/dulus_bar/native/__init__.py +0 -0
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/dulus_bar/native/base.py +0 -0
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/dulus_bar/native/linux.py +0 -0
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/dulus_bar/native/windows.py +0 -0
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/dulus_bar.egg-info/dependency_links.txt +0 -0
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/dulus_bar.egg-info/entry_points.txt +0 -0
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/dulus_bar.egg-info/top_level.txt +0 -0
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/setup.cfg +0 -0
- {dulus_bar-0.3.2 → dulus_bar-0.4.2}/tests/test_macos_native.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dulus-bar
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: Dulus Bar — a cross-platform Dynamic Island for your AI agents (Windows / macOS / Linux)
|
|
5
5
|
Author-email: Dulus <dev@dulus.ai>
|
|
6
6
|
License: MIT
|
|
@@ -19,7 +19,7 @@ Classifier: Programming Language :: Python :: 3
|
|
|
19
19
|
Requires-Python: >=3.10
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
|
-
Requires-Dist:
|
|
22
|
+
Requires-Dist: PySide6>=6.4.0
|
|
23
23
|
Requires-Dist: websockets>=12.0
|
|
24
24
|
Requires-Dist: psutil>=5.9.0
|
|
25
25
|
Requires-Dist: pywin32>=306; sys_platform == "win32"
|
|
@@ -47,8 +47,8 @@ Dynamic: license-file
|
|
|
47
47
|
</p>
|
|
48
48
|
|
|
49
49
|
<p align="center">
|
|
50
|
-
<img src="assets/island
|
|
51
|
-
<br><sub><em>
|
|
50
|
+
<img src="https://raw.githubusercontent.com/Dulus-Ai/Dulus-bar/main/assets/island.png" alt="Dulus Bar — the floating island with a live agent and an Allow/Deny prompt" width="78%">
|
|
51
|
+
<br><sub><em>Live model + context per agent, and Allow / Deny right on the island — no diving back into a terminal.</em></sub>
|
|
52
52
|
</p>
|
|
53
53
|
|
|
54
54
|
---
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
18
|
<p align="center">
|
|
19
|
-
<img src="assets/island
|
|
20
|
-
<br><sub><em>
|
|
19
|
+
<img src="https://raw.githubusercontent.com/Dulus-Ai/Dulus-bar/main/assets/island.png" alt="Dulus Bar — the floating island with a live agent and an Allow/Deny prompt" width="78%">
|
|
20
|
+
<br><sub><em>Live model + context per agent, and Allow / Deny right on the island — no diving back into a terminal.</em></sub>
|
|
21
21
|
</p>
|
|
22
22
|
|
|
23
23
|
---
|
|
@@ -40,6 +40,13 @@ _AGENTS: List[AgentStyle] = [
|
|
|
40
40
|
AgentStyle("aider", "Aider", "✎", "#22c55e", ("aider",)),
|
|
41
41
|
AgentStyle("cline", "Cline", "◔", "#0ea5e9", ("cline", "roo")),
|
|
42
42
|
AgentStyle("ollama", "Ollama", "◍", "#000000", ("ollama", "llama")),
|
|
43
|
+
AgentStyle("opencode", "OpenCode", "◈", "#f97316", ("opencode",)),
|
|
44
|
+
AgentStyle("goose", "Goose", "🪿", "#8b5cf6", ("goose", "block goose")),
|
|
45
|
+
AgentStyle("amp", "Amp", "⚡︎", "#ff2d20", ("amp", "sourcegraph")),
|
|
46
|
+
AgentStyle("crush", "Crush", "♥", "#ec4899", ("crush", "charm")),
|
|
47
|
+
AgentStyle("auggie", "Auggie", "Ⓐ", "#0d9488", ("auggie", "augment")),
|
|
48
|
+
AgentStyle("continue", "Continue", "▶", "#ffde59", ("continue", "cn")),
|
|
49
|
+
AgentStyle("plandex", "Plandex", "⌘", "#84cc16", ("plandex",)),
|
|
43
50
|
]
|
|
44
51
|
|
|
45
52
|
_BY_ALIAS: Dict[str, AgentStyle] = {}
|
|
@@ -96,6 +103,14 @@ _LAUNCH_COMMANDS: Dict[str, Tuple[str, ...]] = {
|
|
|
96
103
|
"grok": ("grok",),
|
|
97
104
|
"copilot": ("copilot",),
|
|
98
105
|
"opencode": ("opencode",),
|
|
106
|
+
"goose": ("goose",),
|
|
107
|
+
"amp": ("amp",),
|
|
108
|
+
"crush": ("crush",),
|
|
109
|
+
"auggie": ("auggie",),
|
|
110
|
+
"continue": ("cn", "continue"),
|
|
111
|
+
"plandex": ("plandex",),
|
|
112
|
+
"kimi": ("kimi",),
|
|
113
|
+
"mistral": ("mistral", "codestral"),
|
|
99
114
|
}
|
|
100
115
|
|
|
101
116
|
|
|
@@ -87,7 +87,23 @@ def _run() -> None:
|
|
|
87
87
|
raise
|
|
88
88
|
|
|
89
89
|
|
|
90
|
+
def _is_already_running(host: str = "127.0.0.1", port: int = 17372) -> bool:
|
|
91
|
+
"""Check if a Dulus Bar WebSocket hub is already running."""
|
|
92
|
+
import socket
|
|
93
|
+
|
|
94
|
+
try:
|
|
95
|
+
with socket.create_connection((host, port), timeout=0.25):
|
|
96
|
+
return True
|
|
97
|
+
except Exception:
|
|
98
|
+
return False
|
|
99
|
+
|
|
100
|
+
|
|
90
101
|
def main():
|
|
102
|
+
# Single-instance guard: if Dulus Bar is already running, avoid opening duplicate overlays
|
|
103
|
+
if _is_already_running():
|
|
104
|
+
print("[dulusbar] Dulus Bar is already running (ws://127.0.0.1:17372 active).", file=sys.stderr)
|
|
105
|
+
return
|
|
106
|
+
|
|
91
107
|
# Escape the terminal on first launch (unless already detached, or the user
|
|
92
108
|
# forces a foreground run with DULUS_BAR_FOREGROUND=1 for debugging).
|
|
93
109
|
if (
|
|
@@ -165,21 +165,40 @@ class MacOSBackend(NativeBackend):
|
|
|
165
165
|
|
|
166
166
|
def open_terminal_running(self, command, title="", cwd=None) -> bool:
|
|
167
167
|
import shlex
|
|
168
|
+
import tempfile
|
|
168
169
|
|
|
169
170
|
parts = []
|
|
170
171
|
if cwd:
|
|
171
172
|
parts.append(f"cd {shlex.quote(str(cwd))}")
|
|
172
173
|
parts.append(" ".join(shlex.quote(str(c)) for c in command))
|
|
173
174
|
shell_cmd = " && ".join(parts)
|
|
175
|
+
# Write the command to a temp .sh and tell the terminal to run *that*.
|
|
176
|
+
# Inlining shell_cmd inside AppleScript double quotes breaks as soon as
|
|
177
|
+
# any path or argument contains a double quote or backslash — the
|
|
178
|
+
# terminal would open and immediately close, looking like "nothing
|
|
179
|
+
# started". A script file sidesteps AppleScript quoting entirely.
|
|
180
|
+
script_file = None
|
|
181
|
+
try:
|
|
182
|
+
fd, script_file = tempfile.mkstemp(prefix="dulus-bar-", suffix=".sh")
|
|
183
|
+
with os.fdopen(fd, "w") as f:
|
|
184
|
+
f.write("#!/bin/bash\n")
|
|
185
|
+
if title:
|
|
186
|
+
f.write(f"echo -ne '\\033]0;{title}\\007'\n")
|
|
187
|
+
f.write(shell_cmd + "\n")
|
|
188
|
+
os.chmod(script_file, 0o755)
|
|
189
|
+
except Exception:
|
|
190
|
+
script_file = None
|
|
191
|
+
|
|
192
|
+
run_line = f"bash {shlex.quote(script_file)}" if script_file else shell_cmd
|
|
174
193
|
# Prefer iTerm if present, else Terminal.
|
|
175
194
|
script_iterm = (
|
|
176
195
|
'tell application "iTerm"\n'
|
|
177
196
|
' create window with default profile\n'
|
|
178
|
-
f' tell current session of current window to write text "{
|
|
197
|
+
f' tell current session of current window to write text "{run_line}"\n'
|
|
179
198
|
' activate\n'
|
|
180
199
|
'end tell'
|
|
181
200
|
)
|
|
182
|
-
script_term = f'tell application "Terminal" to do script "{
|
|
201
|
+
script_term = f'tell application "Terminal" to do script "{run_line}"\ntell application "Terminal" to activate'
|
|
183
202
|
for script in (script_term, script_iterm):
|
|
184
203
|
try:
|
|
185
204
|
r = subprocess.run(["osascript", "-e", script], capture_output=True, timeout=5)
|