muse-cli 0.3.0__tar.gz → 0.3.1__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.
- {muse_cli-0.3.0 → muse_cli-0.3.1}/PKG-INFO +1 -1
- {muse_cli-0.3.0 → muse_cli-0.3.1}/src/muse_cli/__init__.py +1 -1
- {muse_cli-0.3.0 → muse_cli-0.3.1}/src/muse_cli/cli.py +52 -11
- {muse_cli-0.3.0 → muse_cli-0.3.1}/.gitignore +0 -0
- {muse_cli-0.3.0 → muse_cli-0.3.1}/LICENSE +0 -0
- {muse_cli-0.3.0 → muse_cli-0.3.1}/README.md +0 -0
- {muse_cli-0.3.0 → muse_cli-0.3.1}/docs/PROTOCOL.md +0 -0
- {muse_cli-0.3.0 → muse_cli-0.3.1}/pyproject.toml +0 -0
- {muse_cli-0.3.0 → muse_cli-0.3.1}/skills/muse-cli/SKILL.md +0 -0
- {muse_cli-0.3.0 → muse_cli-0.3.1}/src/muse_cli/__main__.py +0 -0
- {muse_cli-0.3.0 → muse_cli-0.3.1}/src/muse_cli/desc0.bin +0 -0
- {muse_cli-0.3.0 → muse_cli-0.3.1}/src/muse_cli/desc1.bin +0 -0
- {muse_cli-0.3.0 → muse_cli-0.3.1}/src/muse_cli/gateway.py +0 -0
- {muse_cli-0.3.0 → muse_cli-0.3.1}/src/muse_cli/routes.json +0 -0
- {muse_cli-0.3.0 → muse_cli-0.3.1}/src/muse_cli/update.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: muse-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.1
|
|
4
4
|
Summary: Command-line client for your personal muse.ai AI agent: chat, automate, and manage side chats, feed, goals, ideas, and sessions from the terminal. No browser needed.
|
|
5
5
|
Project-URL: Homepage, https://github.com/nikships/muse-cli
|
|
6
6
|
Project-URL: Documentation, https://github.com/nikships/muse-cli#readme
|
|
@@ -82,7 +82,32 @@ def _parse_browser_doc(stdout):
|
|
|
82
82
|
return None
|
|
83
83
|
|
|
84
84
|
|
|
85
|
-
def
|
|
85
|
+
def _interpret_browser(returncode, stdout, stderr, require_json):
|
|
86
|
+
"""Turn one agent-browser invocation into data, or raise RuntimeError.
|
|
87
|
+
|
|
88
|
+
`tab <id>` confirms success with a human line (`✓ Title` plus the URL)
|
|
89
|
+
and exit 0. That is not a failure. A real failure is `success: false`
|
|
90
|
+
or a non-zero exit.
|
|
91
|
+
"""
|
|
92
|
+
doc = _parse_browser_doc(stdout) or _parse_browser_doc(stderr)
|
|
93
|
+
if isinstance(doc, dict) and doc.get("success") is False:
|
|
94
|
+
raise RuntimeError(str(doc.get("error") or "unknown error")[:400])
|
|
95
|
+
if isinstance(doc, dict):
|
|
96
|
+
data = doc.get("data")
|
|
97
|
+
if isinstance(data, dict):
|
|
98
|
+
return data
|
|
99
|
+
if isinstance(data, list):
|
|
100
|
+
return {"items": data}
|
|
101
|
+
if "cookies" in doc or "tabs" in doc:
|
|
102
|
+
return doc
|
|
103
|
+
return data if isinstance(data, dict) else (doc if doc.get("success") else {})
|
|
104
|
+
text = (stderr or stdout or "").strip()
|
|
105
|
+
if returncode == 0 and not require_json:
|
|
106
|
+
return {}
|
|
107
|
+
raise RuntimeError(text[:400] or f"exit {returncode}")
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _browser_run(argv, require_json=True):
|
|
86
111
|
"""Run agent-browser and return the JSON envelope's data.
|
|
87
112
|
|
|
88
113
|
On failure the tool prints {"success": false, "error": ...}. Some versions
|
|
@@ -90,13 +115,7 @@ def _browser_run(argv):
|
|
|
90
115
|
"""
|
|
91
116
|
import subprocess
|
|
92
117
|
r = subprocess.run(argv, capture_output=True, text=True)
|
|
93
|
-
|
|
94
|
-
if isinstance(doc, dict) and doc.get("success") is False:
|
|
95
|
-
raise RuntimeError(str(doc.get("error") or "unknown error")[:400])
|
|
96
|
-
if r.returncode != 0 or doc is None:
|
|
97
|
-
msg = (r.stderr or r.stdout or "").strip()
|
|
98
|
-
raise RuntimeError(msg[:400] or f"exit {r.returncode}")
|
|
99
|
-
return doc.get("data", {}) if isinstance(doc, dict) else doc
|
|
118
|
+
return _interpret_browser(r.returncode, r.stdout, r.stderr, require_json)
|
|
100
119
|
|
|
101
120
|
|
|
102
121
|
def _export_error_kind(err):
|
|
@@ -108,6 +127,9 @@ def _export_error_kind(err):
|
|
|
108
127
|
return "debug"
|
|
109
128
|
if err == "no muse.ai tab open in Chrome":
|
|
110
129
|
return "tab"
|
|
130
|
+
# A page title from agent-browser means Chrome already answered.
|
|
131
|
+
if "https://muse.ai" in e or e.startswith("✓") or e.startswith("connected to chrome"):
|
|
132
|
+
return "connected"
|
|
111
133
|
return "other"
|
|
112
134
|
|
|
113
135
|
|
|
@@ -173,6 +195,13 @@ def _print_export_failure(err):
|
|
|
173
195
|
print("Open https://muse.ai/, log in, leave that tab open, and run", file=sys.stderr)
|
|
174
196
|
print("`muse-cli auth export` again.", file=sys.stderr)
|
|
175
197
|
return
|
|
198
|
+
if kind == "connected":
|
|
199
|
+
print("Chrome is connected and the muse.ai tab is open.", file=sys.stderr)
|
|
200
|
+
print("Remote debugging is already on. The cookie read did not come back.", file=sys.stderr)
|
|
201
|
+
print("Run `muse-cli auth export` again. If Chrome asks, click Allow.", file=sys.stderr)
|
|
202
|
+
print(file=sys.stderr)
|
|
203
|
+
_print_hand_copy()
|
|
204
|
+
return
|
|
176
205
|
print(err, file=sys.stderr)
|
|
177
206
|
print(file=sys.stderr)
|
|
178
207
|
print("Check both of these, then run `muse-cli auth export` again:", file=sys.stderr)
|
|
@@ -201,10 +230,22 @@ def _browser_cookies():
|
|
|
201
230
|
and (t.get("id") or t.get("tabId"))]
|
|
202
231
|
if not muse_tabs:
|
|
203
232
|
return None, "no muse.ai tab open in Chrome"
|
|
204
|
-
|
|
233
|
+
tab_id = (muse_tabs[0].get("id") or muse_tabs[0].get("tabId")
|
|
234
|
+
or muse_tabs[0].get("targetId"))
|
|
235
|
+
# Switching tabs prints a human confirmation unless --json is set.
|
|
236
|
+
# Exit 0 is success either way; the cookies read is the next call.
|
|
237
|
+
_browser_run(base + ["tab", tab_id, "--json"], require_json=False)
|
|
205
238
|
data = _browser_run(base + ["cookies", "get", "--json"])
|
|
206
|
-
|
|
207
|
-
|
|
239
|
+
raw = []
|
|
240
|
+
if isinstance(data, list):
|
|
241
|
+
raw = data
|
|
242
|
+
elif isinstance(data, dict):
|
|
243
|
+
for key in ("cookies", "items"):
|
|
244
|
+
if isinstance(data.get(key), list):
|
|
245
|
+
raw = data[key]
|
|
246
|
+
break
|
|
247
|
+
jar = [c for c in raw if isinstance(c, dict) and "muse.ai" in (c.get("domain") or c.get("url") or "")]
|
|
248
|
+
return jar, None
|
|
208
249
|
except RuntimeError as e:
|
|
209
250
|
last_err = str(e)
|
|
210
251
|
# Missing debug port and a stuck daemon will not change on retry.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|