muse-cli 0.2.0__tar.gz → 0.2.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.
- {muse_cli-0.2.0 → muse_cli-0.2.2}/PKG-INFO +115 -17
- {muse_cli-0.2.0 → muse_cli-0.2.2}/README.md +114 -16
- {muse_cli-0.2.0 → muse_cli-0.2.2}/docs/PROTOCOL.md +6 -3
- {muse_cli-0.2.0 → muse_cli-0.2.2}/skills/muse-cli/SKILL.md +84 -10
- {muse_cli-0.2.0 → muse_cli-0.2.2}/src/muse_cli/__init__.py +1 -1
- {muse_cli-0.2.0 → muse_cli-0.2.2}/src/muse_cli/cli.py +182 -42
- {muse_cli-0.2.0 → muse_cli-0.2.2}/.gitignore +0 -0
- {muse_cli-0.2.0 → muse_cli-0.2.2}/LICENSE +0 -0
- {muse_cli-0.2.0 → muse_cli-0.2.2}/pyproject.toml +0 -0
- {muse_cli-0.2.0 → muse_cli-0.2.2}/src/muse_cli/__main__.py +0 -0
- {muse_cli-0.2.0 → muse_cli-0.2.2}/src/muse_cli/desc0.bin +0 -0
- {muse_cli-0.2.0 → muse_cli-0.2.2}/src/muse_cli/desc1.bin +0 -0
- {muse_cli-0.2.0 → muse_cli-0.2.2}/src/muse_cli/gateway.py +0 -0
- {muse_cli-0.2.0 → muse_cli-0.2.2}/src/muse_cli/routes.json +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: muse-cli
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
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
|
|
@@ -66,27 +66,124 @@ A command-line client for your personal muse.ai AI agent: chat from the terminal
|
|
|
66
66
|
uv tool install muse-cli # or: pipx install muse-cli / pip install muse-cli
|
|
67
67
|
```
|
|
68
68
|
|
|
69
|
-
|
|
69
|
+
The command is `muse-cli`. The name `muse` belongs to Muse Code on many machines.
|
|
70
|
+
|
|
71
|
+
Want the agent skill too? The installer sets up the CLI and copies the skill
|
|
72
|
+
to `~/.agents/skills/muse-cli`:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
curl -fsSL https://raw.githubusercontent.com/nikships/muse-cli/main/install.sh | bash
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Upgrade with `uv tool upgrade muse-cli`, remove with `uv tool uninstall muse-cli`.
|
|
79
|
+
|
|
80
|
+
Logging in is a separate one-time step. Chrome shares its cookies after you
|
|
81
|
+
turn on remote debugging. Follow [Log in once](#log-in-once) before running
|
|
82
|
+
any other command.
|
|
83
|
+
|
|
84
|
+
## Log in once
|
|
85
|
+
|
|
86
|
+
muse-cli borrows the login you already have in Chrome, saves those cookies
|
|
87
|
+
to `~/.config/muse-cli/cookies.txt` (mode `600`, only your user can read it),
|
|
88
|
+
and after that talks to muse.ai directly. Access tokens are fetched fresh
|
|
89
|
+
on every command. When a command later says the cookies expired, repeat this
|
|
90
|
+
section.
|
|
91
|
+
|
|
92
|
+
Do the steps in order. Each one checks itself before you continue.
|
|
93
|
+
|
|
94
|
+
### 1. Install the cookie reader
|
|
95
|
+
|
|
96
|
+
`auth export` uses [agent-browser](https://github.com/vercel-labs/agent-browser)
|
|
97
|
+
to read Chrome's cookies. That package comes from npm, so you need Node.js first.
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
node --version # if this fails, install Node.js LTS from https://nodejs.org
|
|
101
|
+
# and open a new terminal
|
|
102
|
+
npm i -g agent-browser
|
|
103
|
+
agent-browser --version
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
`npm i -g` needs permission to write to npm's global bin directory. If it
|
|
107
|
+
errors with `EACCES`, pick one and use it from then on: configure an
|
|
108
|
+
[npm prefix you own](https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally),
|
|
109
|
+
or run the install with the same rights you use for other global npm tools.
|
|
110
|
+
Then check `command -v agent-browser` prints a path.
|
|
111
|
+
|
|
112
|
+
### 2. Let Chrome share cookies
|
|
113
|
+
|
|
114
|
+
Open **Google Chrome**, the same profile you use for muse.ai. Paste this in
|
|
115
|
+
the address bar:
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
chrome://inspect/#remote-debugging
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Turn on remote debugging. The checkbox reads **Allow remote debugging for
|
|
122
|
+
this browser instance**. Leave Chrome open.
|
|
123
|
+
|
|
124
|
+
Turn this on while Chrome is already open and muse.ai is loaded. The export
|
|
125
|
+
can see that window only after the switch is on. The page is in Chrome 144
|
|
126
|
+
and newer.
|
|
127
|
+
|
|
128
|
+
Stay in this window. Starting a second Chrome with
|
|
129
|
+
`--remote-debugging-port` opens a different profile, and that profile does
|
|
130
|
+
not have your muse.ai login.
|
|
131
|
+
|
|
132
|
+
### 3. Be logged in, on a muse.ai tab
|
|
133
|
+
|
|
134
|
+
In that same Chrome window, open https://muse.ai/ and log in. Leave the tab
|
|
135
|
+
open. The exporter reads whichever tab is active, so the muse.ai tab has to
|
|
136
|
+
be the one in front when you run the next command.
|
|
137
|
+
|
|
138
|
+
### 4. Save the login
|
|
70
139
|
|
|
71
140
|
```bash
|
|
72
|
-
# 1. Log in to https://muse.ai/ in Chrome
|
|
73
|
-
# 2. Export your session (one time; re-run when it expires):
|
|
74
141
|
muse-cli auth export
|
|
142
|
+
```
|
|
75
143
|
|
|
76
|
-
|
|
144
|
+
Chrome may ask to allow the debugging connection. Click **Allow**. If the
|
|
145
|
+
command already failed, run it again after you click Allow.
|
|
146
|
+
|
|
147
|
+
Success looks like this (the count varies):
|
|
148
|
+
|
|
149
|
+
```
|
|
150
|
+
saved 12 muse.ai cookies to /home/you/.config/muse-cli/cookies.txt
|
|
77
151
|
```
|
|
78
152
|
|
|
79
|
-
|
|
80
|
-
|
|
153
|
+
The command prints the fix on the failure itself. These are the ones it
|
|
154
|
+
recognizes:
|
|
155
|
+
|
|
156
|
+
| What it says | What to do |
|
|
157
|
+
| --- | --- |
|
|
158
|
+
| No running Chrome / remote debugging | The switch in step 2 is off. Turn it on in the Chrome you already have open, then run the command again. |
|
|
159
|
+
| No muse.ai tab | Step 3. Open https://muse.ai/ in that same window and leave the tab open. |
|
|
160
|
+
| No `hatch_sess` | The tab is open and you are logged out. Log in, then export again. The cookies file already on disk is left as it was. |
|
|
161
|
+
| `agent-browser` is not installed | Step 1. `node --version`, then `npm i -g agent-browser`, then a new terminal. |
|
|
162
|
+
| Daemon already running | A previous attempt is stuck. `agent-browser close`, then `muse-cli auth export`. |
|
|
163
|
+
|
|
164
|
+
### 5. Check the connection
|
|
81
165
|
|
|
82
166
|
```bash
|
|
83
|
-
|
|
167
|
+
muse-cli status
|
|
84
168
|
```
|
|
85
169
|
|
|
86
|
-
|
|
170
|
+
You get JSON with your VM id, how many chats you have, the unread count, and
|
|
171
|
+
your identity. That means install and login both worked.
|
|
87
172
|
|
|
88
|
-
|
|
89
|
-
|
|
173
|
+
### Copy cookies by hand
|
|
174
|
+
|
|
175
|
+
Use this when you don't have Node, or you don't want remote debugging on.
|
|
176
|
+
|
|
177
|
+
1. In Chrome, open https://muse.ai/ and log in.
|
|
178
|
+
2. Open DevTools (F12, or Ctrl+Shift+I) → **Application** → **Cookies** → `https://muse.ai`.
|
|
179
|
+
3. Copy the cookies onto one line. `hatch_sess` has to be there. Separate cookies with `; ` (semicolon, space). A Netscape cookie jar (what curl writes) and a JSON object such as `{"hatch_sess": "..."}` also work.
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
mkdir -p ~/.config/muse-cli
|
|
183
|
+
printf '%s\n' 'hatch_sess=the-value-from-devtools; other_cookie=other_value' > ~/.config/muse-cli/cookies.txt
|
|
184
|
+
chmod 600 ~/.config/muse-cli/cookies.txt
|
|
185
|
+
muse-cli status
|
|
186
|
+
```
|
|
90
187
|
|
|
91
188
|
## Usage
|
|
92
189
|
|
|
@@ -164,12 +261,13 @@ pyproject.toml
|
|
|
164
261
|
|
|
165
262
|
## Setup notes
|
|
166
263
|
|
|
167
|
-
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
-
|
|
172
|
-
|
|
264
|
+
- Login is the [Log in once](#log-in-once) section above. Cookies live at
|
|
265
|
+
`~/.config/muse-cli/cookies.txt` (mode 600). Access and gateway tokens are
|
|
266
|
+
fetched fresh on every run.
|
|
267
|
+
- `auth export` reads those cookies from Google Chrome through
|
|
268
|
+
[agent-browser](https://github.com/vercel-labs/agent-browser). Chrome has
|
|
269
|
+
to be open, with remote debugging on
|
|
270
|
+
(`chrome://inspect/#remote-debugging`) and a logged-in muse.ai tab in front.
|
|
173
271
|
- Respect muse.ai's terms and rate limits. Internal APIs are unversioned and
|
|
174
272
|
can change; if calls fail, re-derive from a fresh app bundle.
|
|
175
273
|
|
|
@@ -29,27 +29,124 @@ A command-line client for your personal muse.ai AI agent: chat from the terminal
|
|
|
29
29
|
uv tool install muse-cli # or: pipx install muse-cli / pip install muse-cli
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
The command is `muse-cli`. The name `muse` belongs to Muse Code on many machines.
|
|
33
|
+
|
|
34
|
+
Want the agent skill too? The installer sets up the CLI and copies the skill
|
|
35
|
+
to `~/.agents/skills/muse-cli`:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
curl -fsSL https://raw.githubusercontent.com/nikships/muse-cli/main/install.sh | bash
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Upgrade with `uv tool upgrade muse-cli`, remove with `uv tool uninstall muse-cli`.
|
|
42
|
+
|
|
43
|
+
Logging in is a separate one-time step. Chrome shares its cookies after you
|
|
44
|
+
turn on remote debugging. Follow [Log in once](#log-in-once) before running
|
|
45
|
+
any other command.
|
|
46
|
+
|
|
47
|
+
## Log in once
|
|
48
|
+
|
|
49
|
+
muse-cli borrows the login you already have in Chrome, saves those cookies
|
|
50
|
+
to `~/.config/muse-cli/cookies.txt` (mode `600`, only your user can read it),
|
|
51
|
+
and after that talks to muse.ai directly. Access tokens are fetched fresh
|
|
52
|
+
on every command. When a command later says the cookies expired, repeat this
|
|
53
|
+
section.
|
|
54
|
+
|
|
55
|
+
Do the steps in order. Each one checks itself before you continue.
|
|
56
|
+
|
|
57
|
+
### 1. Install the cookie reader
|
|
58
|
+
|
|
59
|
+
`auth export` uses [agent-browser](https://github.com/vercel-labs/agent-browser)
|
|
60
|
+
to read Chrome's cookies. That package comes from npm, so you need Node.js first.
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
node --version # if this fails, install Node.js LTS from https://nodejs.org
|
|
64
|
+
# and open a new terminal
|
|
65
|
+
npm i -g agent-browser
|
|
66
|
+
agent-browser --version
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`npm i -g` needs permission to write to npm's global bin directory. If it
|
|
70
|
+
errors with `EACCES`, pick one and use it from then on: configure an
|
|
71
|
+
[npm prefix you own](https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally),
|
|
72
|
+
or run the install with the same rights you use for other global npm tools.
|
|
73
|
+
Then check `command -v agent-browser` prints a path.
|
|
74
|
+
|
|
75
|
+
### 2. Let Chrome share cookies
|
|
76
|
+
|
|
77
|
+
Open **Google Chrome**, the same profile you use for muse.ai. Paste this in
|
|
78
|
+
the address bar:
|
|
79
|
+
|
|
80
|
+
```
|
|
81
|
+
chrome://inspect/#remote-debugging
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Turn on remote debugging. The checkbox reads **Allow remote debugging for
|
|
85
|
+
this browser instance**. Leave Chrome open.
|
|
86
|
+
|
|
87
|
+
Turn this on while Chrome is already open and muse.ai is loaded. The export
|
|
88
|
+
can see that window only after the switch is on. The page is in Chrome 144
|
|
89
|
+
and newer.
|
|
90
|
+
|
|
91
|
+
Stay in this window. Starting a second Chrome with
|
|
92
|
+
`--remote-debugging-port` opens a different profile, and that profile does
|
|
93
|
+
not have your muse.ai login.
|
|
94
|
+
|
|
95
|
+
### 3. Be logged in, on a muse.ai tab
|
|
96
|
+
|
|
97
|
+
In that same Chrome window, open https://muse.ai/ and log in. Leave the tab
|
|
98
|
+
open. The exporter reads whichever tab is active, so the muse.ai tab has to
|
|
99
|
+
be the one in front when you run the next command.
|
|
100
|
+
|
|
101
|
+
### 4. Save the login
|
|
33
102
|
|
|
34
103
|
```bash
|
|
35
|
-
# 1. Log in to https://muse.ai/ in Chrome
|
|
36
|
-
# 2. Export your session (one time; re-run when it expires):
|
|
37
104
|
muse-cli auth export
|
|
105
|
+
```
|
|
38
106
|
|
|
39
|
-
|
|
107
|
+
Chrome may ask to allow the debugging connection. Click **Allow**. If the
|
|
108
|
+
command already failed, run it again after you click Allow.
|
|
109
|
+
|
|
110
|
+
Success looks like this (the count varies):
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
saved 12 muse.ai cookies to /home/you/.config/muse-cli/cookies.txt
|
|
40
114
|
```
|
|
41
115
|
|
|
42
|
-
|
|
43
|
-
|
|
116
|
+
The command prints the fix on the failure itself. These are the ones it
|
|
117
|
+
recognizes:
|
|
118
|
+
|
|
119
|
+
| What it says | What to do |
|
|
120
|
+
| --- | --- |
|
|
121
|
+
| No running Chrome / remote debugging | The switch in step 2 is off. Turn it on in the Chrome you already have open, then run the command again. |
|
|
122
|
+
| No muse.ai tab | Step 3. Open https://muse.ai/ in that same window and leave the tab open. |
|
|
123
|
+
| No `hatch_sess` | The tab is open and you are logged out. Log in, then export again. The cookies file already on disk is left as it was. |
|
|
124
|
+
| `agent-browser` is not installed | Step 1. `node --version`, then `npm i -g agent-browser`, then a new terminal. |
|
|
125
|
+
| Daemon already running | A previous attempt is stuck. `agent-browser close`, then `muse-cli auth export`. |
|
|
126
|
+
|
|
127
|
+
### 5. Check the connection
|
|
44
128
|
|
|
45
129
|
```bash
|
|
46
|
-
|
|
130
|
+
muse-cli status
|
|
47
131
|
```
|
|
48
132
|
|
|
49
|
-
|
|
133
|
+
You get JSON with your VM id, how many chats you have, the unread count, and
|
|
134
|
+
your identity. That means install and login both worked.
|
|
50
135
|
|
|
51
|
-
|
|
52
|
-
|
|
136
|
+
### Copy cookies by hand
|
|
137
|
+
|
|
138
|
+
Use this when you don't have Node, or you don't want remote debugging on.
|
|
139
|
+
|
|
140
|
+
1. In Chrome, open https://muse.ai/ and log in.
|
|
141
|
+
2. Open DevTools (F12, or Ctrl+Shift+I) → **Application** → **Cookies** → `https://muse.ai`.
|
|
142
|
+
3. Copy the cookies onto one line. `hatch_sess` has to be there. Separate cookies with `; ` (semicolon, space). A Netscape cookie jar (what curl writes) and a JSON object such as `{"hatch_sess": "..."}` also work.
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
mkdir -p ~/.config/muse-cli
|
|
146
|
+
printf '%s\n' 'hatch_sess=the-value-from-devtools; other_cookie=other_value' > ~/.config/muse-cli/cookies.txt
|
|
147
|
+
chmod 600 ~/.config/muse-cli/cookies.txt
|
|
148
|
+
muse-cli status
|
|
149
|
+
```
|
|
53
150
|
|
|
54
151
|
## Usage
|
|
55
152
|
|
|
@@ -127,12 +224,13 @@ pyproject.toml
|
|
|
127
224
|
|
|
128
225
|
## Setup notes
|
|
129
226
|
|
|
130
|
-
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
-
|
|
135
|
-
|
|
227
|
+
- Login is the [Log in once](#log-in-once) section above. Cookies live at
|
|
228
|
+
`~/.config/muse-cli/cookies.txt` (mode 600). Access and gateway tokens are
|
|
229
|
+
fetched fresh on every run.
|
|
230
|
+
- `auth export` reads those cookies from Google Chrome through
|
|
231
|
+
[agent-browser](https://github.com/vercel-labs/agent-browser). Chrome has
|
|
232
|
+
to be open, with remote debugging on
|
|
233
|
+
(`chrome://inspect/#remote-debugging`) and a logged-in muse.ai tab in front.
|
|
136
234
|
- Respect muse.ai's terms and rate limits. Internal APIs are unversioned and
|
|
137
235
|
can change; if calls fail, re-derive from a fresh app bundle.
|
|
138
236
|
|
|
@@ -74,6 +74,9 @@ chat / feed / goals / ideas / sessions / ...
|
|
|
74
74
|
delete: `{method: "/api/session/<op>", session_id}`.
|
|
75
75
|
- `api.idea-cards.execute`: `{ideaCardId, mode: "full"}` plus path param.
|
|
76
76
|
- POSTs to muse.ai need browser `Sec-Fetch-*` headers or they return 403.
|
|
77
|
-
- `auth export`
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
- `auth export` reads cookies from the user's own Google Chrome through
|
|
78
|
+
agent-browser `--auto-connect`. Chrome 144+ shares that profile only after
|
|
79
|
+
remote debugging is enabled at `chrome://inspect/#remote-debugging`. The
|
|
80
|
+
export follows the active tab, so a muse.ai tab has to be focused first,
|
|
81
|
+
and it must never overwrite a working jar without a `hatch_sess` in the
|
|
82
|
+
new one. A freshly launched browser has no login; do not fall back to one.
|
|
@@ -32,22 +32,96 @@ muse-cli --help >/dev/null && echo cli-ok # proves the install + deps resolve
|
|
|
32
32
|
|
|
33
33
|
## 2. Auth
|
|
34
34
|
|
|
35
|
-
The
|
|
35
|
+
The CLI stores the user's muse.ai browser login at
|
|
36
|
+
`~/.config/muse-cli/cookies.txt` (mode 0600). Chrome hides those cookies
|
|
37
|
+
until remote debugging is on. Walk the user through the steps below and wait
|
|
38
|
+
for them. Do not run `muse-cli auth export` before they say the Chrome
|
|
39
|
+
switch is on and a logged-in muse.ai tab is open.
|
|
40
|
+
|
|
41
|
+
Access and gateway tokens are fetched fresh on every run; only cookies
|
|
42
|
+
persist. When a later command fails with `auth error`, the cookies expired:
|
|
43
|
+
repeat 2b (or 2c).
|
|
44
|
+
|
|
45
|
+
### 2a. Cookie reader
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
command -v node >/dev/null && node --version
|
|
49
|
+
command -v npm >/dev/null && npm --version
|
|
50
|
+
command -v agent-browser >/dev/null && agent-browser --version
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
If `agent-browser` is missing and `npm` works:
|
|
36
54
|
|
|
37
55
|
```bash
|
|
38
|
-
|
|
56
|
+
npm i -g agent-browser
|
|
57
|
+
agent-browser --version # must print a version
|
|
58
|
+
command -v agent-browser # must print a path
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`EACCES` from `npm i -g` means npm cannot write its global bin directory.
|
|
62
|
+
Stop and tell the user. They fix it with an npm prefix they own
|
|
63
|
+
(https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally)
|
|
64
|
+
or by installing with the same rights they use for other global npm tools.
|
|
65
|
+
Do not sudo unless they tell you to.
|
|
66
|
+
|
|
67
|
+
If `node` or `npm` is missing, stop. Tell them to install Node.js LTS from
|
|
68
|
+
https://nodejs.org, open a new terminal, and come back. Offer 2c if they
|
|
69
|
+
would rather not install Node.
|
|
70
|
+
|
|
71
|
+
### 2b. Chrome, then export
|
|
72
|
+
|
|
73
|
+
Tell the user to do all of this in the Google Chrome window they already
|
|
74
|
+
use for muse.ai. Needs Chrome 144 or newer. Wait until they confirm:
|
|
75
|
+
|
|
76
|
+
1. Address bar: `chrome://inspect/#remote-debugging`
|
|
77
|
+
2. Turn on remote debugging ("Allow remote debugging for this browser instance").
|
|
78
|
+
3. Open https://muse.ai/ and log in. Leave that tab in front. The export
|
|
79
|
+
reads the active tab.
|
|
80
|
+
|
|
81
|
+
Then:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
muse-cli auth export
|
|
39
85
|
test -s ~/.config/muse-cli/cookies.txt && echo auth-ok
|
|
40
86
|
```
|
|
41
87
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
if it is missing). No Chrome? Copy the `muse.ai` cookies by hand (DevTools →
|
|
45
|
-
Application → Cookies; needs `hatch_sess`) into
|
|
46
|
-
`~/.config/muse-cli/cookies.txt` as Netscape-jar or `name=value; ...` text.
|
|
88
|
+
If Chrome shows an Allow prompt, they click Allow. If the command failed
|
|
89
|
+
before that click, run it once more.
|
|
47
90
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
91
|
+
Success is a line like `saved N muse.ai cookies to ~/.config/muse-cli/cookies.txt`.
|
|
92
|
+
|
|
93
|
+
If it fails, the CLI prints the next step. Map it like this, and do not retry
|
|
94
|
+
in a loop:
|
|
95
|
+
|
|
96
|
+
- "No running Chrome" or "remote-debugging-port": the switch in step 2 is
|
|
97
|
+
off, or they are in a different Chrome. Send them back to the steps above.
|
|
98
|
+
Do not tell them to launch Chrome with `--remote-debugging-port`. That
|
|
99
|
+
opens another profile, and it does not have their muse.ai login.
|
|
100
|
+
- "no muse.ai tab": Chrome connected. They still need https://muse.ai/ open
|
|
101
|
+
and in front in that same window.
|
|
102
|
+
- "no hatch_sess" / "do not include hatch_sess": the tab is open and they
|
|
103
|
+
are logged out. The cookies file on disk was kept.
|
|
104
|
+
- "daemon already running": `agent-browser close`, then `muse-cli auth export` once.
|
|
105
|
+
- `agent-browser` not found: back to 2a.
|
|
106
|
+
|
|
107
|
+
### 2c. Copy cookies by hand
|
|
108
|
+
|
|
109
|
+
Use this when Node is unavailable, or the user does not want remote debugging on.
|
|
110
|
+
|
|
111
|
+
1. They are logged in at https://muse.ai/ in Chrome.
|
|
112
|
+
2. DevTools (F12) → Application → Cookies → `https://muse.ai`.
|
|
113
|
+
3. Write one line to `~/.config/muse-cli/cookies.txt`. `hatch_sess` is required.
|
|
114
|
+
Separate cookies with `; `:
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
hatch_sess=VALUE; other_name=other_value
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
A Netscape jar or `{"hatch_sess": "..."}` JSON also works.
|
|
121
|
+
|
|
122
|
+
4. `chmod 600 ~/.config/muse-cli/cookies.txt`
|
|
123
|
+
5. `test -s ~/.config/muse-cli/cookies.txt && echo auth-ok`, then `muse-cli status`.
|
|
124
|
+
Stop if status fails and report the error text.
|
|
51
125
|
|
|
52
126
|
## 3. Verify end to end
|
|
53
127
|
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
"""muse-cli: CLI for your personal muse.ai agent. No browser needed
|
|
1
|
+
"""muse-cli: CLI for your personal muse.ai agent. No browser needed after cookie export.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
1.
|
|
5
|
-
2.
|
|
3
|
+
One-time setup (also printed by `muse-cli auth export` when a step is missing):
|
|
4
|
+
1. npm i -g agent-browser
|
|
5
|
+
2. In Chrome, open chrome://inspect/#remote-debugging and turn remote debugging on.
|
|
6
|
+
3. Open https://muse.ai/ in that same window and log in. Leave the tab open.
|
|
7
|
+
4. muse-cli auth export # saves session cookies locally (chmod 600)
|
|
6
8
|
|
|
7
9
|
Then: muse-cli status | muse-cli threads | muse-cli history | muse-cli send "hello" | ...
|
|
8
10
|
"""
|
|
9
11
|
import argparse
|
|
10
12
|
import json
|
|
11
13
|
import os
|
|
14
|
+
import shutil
|
|
12
15
|
import sys
|
|
13
16
|
import time
|
|
14
17
|
|
|
@@ -43,8 +46,11 @@ def load_config():
|
|
|
43
46
|
|
|
44
47
|
def connect(cfg):
|
|
45
48
|
if not os.path.exists(cfg["cookies_file"]):
|
|
46
|
-
raise AuthError(
|
|
47
|
-
|
|
49
|
+
raise AuthError(
|
|
50
|
+
f"no cookies at {cfg['cookies_file']}. Run `muse-cli auth export` "
|
|
51
|
+
"and follow the steps it prints: turn on Chrome remote debugging at "
|
|
52
|
+
"chrome://inspect/#remote-debugging, open https://muse.ai/ in that "
|
|
53
|
+
"window, then export again.")
|
|
48
54
|
cookies = load_cookies(cfg["cookies_file"])
|
|
49
55
|
if not cookies.strip():
|
|
50
56
|
raise AuthError(f"cookies file {cfg['cookies_file']} is empty; run `muse-cli auth export`")
|
|
@@ -55,66 +61,175 @@ def out(obj):
|
|
|
55
61
|
print(json.dumps(obj, indent=2, ensure_ascii=False))
|
|
56
62
|
|
|
57
63
|
|
|
64
|
+
def _parse_browser_doc(stdout):
|
|
65
|
+
"""agent-browser prints a JSON envelope, sometimes after a warning line."""
|
|
66
|
+
text = (stdout or "").strip()
|
|
67
|
+
if not text:
|
|
68
|
+
return None
|
|
69
|
+
blobs = [text]
|
|
70
|
+
for line in reversed(text.splitlines()):
|
|
71
|
+
line = line.strip()
|
|
72
|
+
if line.startswith("{") and line not in blobs:
|
|
73
|
+
blobs.append(line)
|
|
74
|
+
for blob in blobs:
|
|
75
|
+
try:
|
|
76
|
+
doc = json.loads(blob)
|
|
77
|
+
except json.JSONDecodeError:
|
|
78
|
+
continue
|
|
79
|
+
if isinstance(doc, dict):
|
|
80
|
+
return doc
|
|
81
|
+
return None
|
|
82
|
+
|
|
83
|
+
|
|
58
84
|
def _browser_run(argv):
|
|
59
|
-
"""Run agent-browser
|
|
60
|
-
|
|
85
|
+
"""Run agent-browser and return the JSON envelope's data.
|
|
86
|
+
|
|
87
|
+
On failure the tool prints {"success": false, "error": ...}. Some versions
|
|
88
|
+
exit 0 anyway, some exit non-zero; trust the envelope when it is there.
|
|
89
|
+
"""
|
|
61
90
|
import subprocess
|
|
62
91
|
r = subprocess.run(argv, capture_output=True, text=True)
|
|
63
|
-
|
|
64
|
-
raise RuntimeError((r.stderr or r.stdout)[:200] or f"exit {r.returncode}")
|
|
65
|
-
try:
|
|
66
|
-
doc = json.loads(r.stdout)
|
|
67
|
-
except json.JSONDecodeError:
|
|
68
|
-
raise RuntimeError((r.stdout or r.stderr)[:200] or "empty output")
|
|
92
|
+
doc = _parse_browser_doc(r.stdout) or _parse_browser_doc(r.stderr)
|
|
69
93
|
if isinstance(doc, dict) and doc.get("success") is False:
|
|
70
|
-
raise RuntimeError(str(doc.get("error") or "unknown error")[:
|
|
94
|
+
raise RuntimeError(str(doc.get("error") or "unknown error")[:400])
|
|
95
|
+
if r.returncode != 0 or doc is None:
|
|
96
|
+
msg = (r.stderr or r.stdout or "").strip()
|
|
97
|
+
raise RuntimeError(msg[:400] or f"exit {r.returncode}")
|
|
71
98
|
return doc.get("data", {}) if isinstance(doc, dict) else doc
|
|
72
99
|
|
|
73
100
|
|
|
74
|
-
def
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
101
|
+
def _export_error_kind(err):
|
|
102
|
+
e = (err or "").lower()
|
|
103
|
+
if "daemon already running" in e:
|
|
104
|
+
return "daemon"
|
|
105
|
+
if ("no running chrome" in e or "remote-debugging" in e
|
|
106
|
+
or "auto-launch failed" in e or "auto-connect" in e):
|
|
107
|
+
return "debug"
|
|
108
|
+
if err == "no muse.ai tab open in Chrome":
|
|
109
|
+
return "tab"
|
|
110
|
+
return "other"
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _print_hand_copy():
|
|
114
|
+
print("Copy the login by hand instead:", file=sys.stderr)
|
|
115
|
+
print(" 1. In Chrome, open https://muse.ai/ and log in.", file=sys.stderr)
|
|
116
|
+
print(" 2. DevTools (F12) → Application → Cookies → https://muse.ai", file=sys.stderr)
|
|
117
|
+
print(" 3. Write one line to ~/.config/muse-cli/cookies.txt", file=sys.stderr)
|
|
118
|
+
print(" hatch_sess=VALUE; other_name=other_value", file=sys.stderr)
|
|
119
|
+
print(" hatch_sess is required. Separate cookies with '; '.", file=sys.stderr)
|
|
120
|
+
print(" 4. chmod 600 ~/.config/muse-cli/cookies.txt", file=sys.stderr)
|
|
121
|
+
print(" 5. muse-cli status", file=sys.stderr)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _print_chrome_debug_steps():
|
|
125
|
+
print("Turn on remote debugging so muse-cli can read the muse.ai cookies.", file=sys.stderr)
|
|
126
|
+
print("Do this in the Chrome window where you already use muse.ai:", file=sys.stderr)
|
|
127
|
+
print(file=sys.stderr)
|
|
128
|
+
print(" 1. Open chrome://inspect/#remote-debugging", file=sys.stderr)
|
|
129
|
+
print(" 2. Turn on remote debugging", file=sys.stderr)
|
|
130
|
+
print(' ("Allow remote debugging for this browser instance").', file=sys.stderr)
|
|
131
|
+
print(" 3. Open https://muse.ai/ and log in. Leave that tab open.", file=sys.stderr)
|
|
132
|
+
print(" 4. Run `muse-cli auth export` again.", file=sys.stderr)
|
|
133
|
+
print(" If Chrome asks to allow the connection, click Allow.", file=sys.stderr)
|
|
134
|
+
print(" If this command already failed, run it again after Allow.", file=sys.stderr)
|
|
135
|
+
print(file=sys.stderr)
|
|
136
|
+
print("Stay in that same window. A second Chrome started with", file=sys.stderr)
|
|
137
|
+
print("--remote-debugging-port is another profile and has no muse.ai login.", file=sys.stderr)
|
|
138
|
+
print(file=sys.stderr)
|
|
139
|
+
print("Success looks like:", file=sys.stderr)
|
|
140
|
+
print(f" saved N muse.ai cookies to {COOKIES_FILE}", file=sys.stderr)
|
|
141
|
+
print(file=sys.stderr)
|
|
142
|
+
_print_hand_copy()
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def _print_need_agent_browser():
|
|
146
|
+
print("agent-browser is not installed, so muse-cli cannot read Chrome's cookies.", file=sys.stderr)
|
|
147
|
+
print(file=sys.stderr)
|
|
148
|
+
print(" 1. Install Node.js LTS if `node --version` fails: https://nodejs.org", file=sys.stderr)
|
|
149
|
+
print(" 2. Open a new terminal, then:", file=sys.stderr)
|
|
150
|
+
print(" npm i -g agent-browser", file=sys.stderr)
|
|
151
|
+
print(" agent-browser --version", file=sys.stderr)
|
|
152
|
+
print(" 3. Run `muse-cli auth export` again and follow the Chrome steps it prints.", file=sys.stderr)
|
|
153
|
+
print(file=sys.stderr)
|
|
154
|
+
_print_hand_copy()
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _print_export_failure(err):
|
|
158
|
+
kind = _export_error_kind(err)
|
|
159
|
+
print("cookie export failed.", file=sys.stderr)
|
|
160
|
+
if kind == "daemon":
|
|
161
|
+
print("agent-browser is still running from an earlier attempt. Close it, then retry:", file=sys.stderr)
|
|
162
|
+
print(" agent-browser close", file=sys.stderr)
|
|
163
|
+
print(" muse-cli auth export", file=sys.stderr)
|
|
164
|
+
print(file=sys.stderr)
|
|
165
|
+
_print_chrome_debug_steps()
|
|
166
|
+
return
|
|
167
|
+
if kind == "debug":
|
|
168
|
+
_print_chrome_debug_steps()
|
|
169
|
+
return
|
|
170
|
+
if kind == "tab":
|
|
171
|
+
print("Chrome is connected, but no muse.ai tab is open.", file=sys.stderr)
|
|
172
|
+
print("Open https://muse.ai/, log in, leave that tab open, and run", file=sys.stderr)
|
|
173
|
+
print("`muse-cli auth export` again.", file=sys.stderr)
|
|
174
|
+
return
|
|
175
|
+
print(err, file=sys.stderr)
|
|
176
|
+
print(file=sys.stderr)
|
|
177
|
+
print("Check both of these, then run `muse-cli auth export` again:", file=sys.stderr)
|
|
178
|
+
print(" - chrome://inspect/#remote-debugging has remote debugging on", file=sys.stderr)
|
|
179
|
+
print(" - https://muse.ai/ is open in that same Chrome and you are logged in", file=sys.stderr)
|
|
180
|
+
print(file=sys.stderr)
|
|
181
|
+
_print_hand_copy()
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _browser_cookies():
|
|
185
|
+
"""Read muse.ai cookies from the user's Chrome via agent-browser.
|
|
186
|
+
|
|
187
|
+
Auto-connect attaches to the real profile. A fresh browser has no login,
|
|
188
|
+
so this never falls back to launching one.
|
|
189
|
+
"""
|
|
190
|
+
base = ["agent-browser", "--headed", "--auto-connect"]
|
|
78
191
|
last_err = "unknown error"
|
|
79
|
-
for
|
|
192
|
+
for attempt in range(3):
|
|
80
193
|
try:
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
_browser_run(base + ["tab", muse_tabs[0].get("id") or muse_tabs[0]["tabId"]])
|
|
194
|
+
# Cookies follow the active tab: focus a muse.ai tab first,
|
|
195
|
+
# else the export comes back empty even when logged in.
|
|
196
|
+
data = _browser_run(base + ["tab", "list", "--json"])
|
|
197
|
+
tabs = data.get("tabs", []) if isinstance(data, dict) else []
|
|
198
|
+
muse_tabs = [t for t in tabs
|
|
199
|
+
if isinstance(t, dict) and "muse.ai" in (t.get("url") or "")
|
|
200
|
+
and (t.get("id") or t.get("tabId"))]
|
|
201
|
+
if not muse_tabs:
|
|
202
|
+
return None, "no muse.ai tab open in Chrome"
|
|
203
|
+
_browser_run(base + ["tab", muse_tabs[0].get("id") or muse_tabs[0]["tabId"]])
|
|
92
204
|
data = _browser_run(base + ["cookies", "get", "--json"])
|
|
93
205
|
jar = data.get("cookies", []) if isinstance(data, dict) else []
|
|
94
206
|
return [c for c in jar if "muse.ai" in c.get("domain", "")], None
|
|
95
207
|
except RuntimeError as e:
|
|
96
208
|
last_err = str(e)
|
|
209
|
+
# Missing debug port and a stuck daemon will not change on retry.
|
|
210
|
+
if _export_error_kind(last_err) in ("debug", "daemon") or attempt == 2:
|
|
211
|
+
return None, last_err
|
|
97
212
|
time.sleep(2)
|
|
98
213
|
return None, last_err
|
|
99
214
|
|
|
100
215
|
|
|
101
216
|
def cmd_auth_export(_args):
|
|
102
217
|
os.makedirs(CONFIG_DIR, exist_ok=True)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
218
|
+
if shutil.which("agent-browser") is None:
|
|
219
|
+
_print_need_agent_browser()
|
|
220
|
+
sys.exit(1)
|
|
221
|
+
print("Reading muse.ai cookies from Chrome...", file=sys.stderr)
|
|
222
|
+
jar, err = _browser_cookies()
|
|
108
223
|
if jar is None:
|
|
109
|
-
|
|
110
|
-
print("is Chrome running with muse.ai open?", file=sys.stderr)
|
|
111
|
-
print("alternative: export cookies by hand, see README Setup.", file=sys.stderr)
|
|
224
|
+
_print_export_failure(err)
|
|
112
225
|
sys.exit(1)
|
|
113
226
|
# Never clobber a working login with an empty or logged-out jar.
|
|
114
227
|
if not any(c["name"] == "hatch_sess" for c in jar):
|
|
115
|
-
print("
|
|
116
|
-
|
|
228
|
+
print("Chrome answered, but the cookies do not include hatch_sess.", file=sys.stderr)
|
|
229
|
+
print("That cookie is set only after you log in at https://muse.ai/.", file=sys.stderr)
|
|
230
|
+
print("Log in, leave the muse.ai tab open, and run `muse-cli auth export` again.",
|
|
117
231
|
file=sys.stderr)
|
|
232
|
+
print(f"Left {COOKIES_FILE} unchanged.", file=sys.stderr)
|
|
118
233
|
sys.exit(1)
|
|
119
234
|
lines = ["# Netscape HTTP Cookie File"]
|
|
120
235
|
for c in jar:
|
|
@@ -471,7 +586,32 @@ def main():
|
|
|
471
586
|
sub = ap.add_subparsers(dest="cmd", required=True)
|
|
472
587
|
|
|
473
588
|
p = sub.add_parser("auth", help="auth helpers"); a = p.add_subparsers(dest="op", required=True)
|
|
474
|
-
|
|
589
|
+
export_help = (
|
|
590
|
+
"Copy your muse.ai login out of Google Chrome into\n"
|
|
591
|
+
"~/.config/muse-cli/cookies.txt (mode 600).\n"
|
|
592
|
+
"\n"
|
|
593
|
+
"Chrome shares those cookies only after remote debugging is on.\n"
|
|
594
|
+
"In the Chrome window you already use for muse.ai:\n"
|
|
595
|
+
"\n"
|
|
596
|
+
" 1. Open chrome://inspect/#remote-debugging\n"
|
|
597
|
+
" 2. Turn on remote debugging\n"
|
|
598
|
+
' ("Allow remote debugging for this browser instance")\n'
|
|
599
|
+
" 3. Open https://muse.ai/ and log in. Leave that tab open.\n"
|
|
600
|
+
" 4. Run this command. If Chrome asks to allow the connection,\n"
|
|
601
|
+
" click Allow, then run it again if it failed before the click.\n"
|
|
602
|
+
"\n"
|
|
603
|
+
"Requires agent-browser: npm i -g agent-browser\n"
|
|
604
|
+
"(install Node.js LTS from https://nodejs.org first if npm is missing).\n"
|
|
605
|
+
"\n"
|
|
606
|
+
"Stay in that same Chrome. Starting another Chrome with\n"
|
|
607
|
+
"--remote-debugging-port uses a different profile and has no muse.ai login."
|
|
608
|
+
)
|
|
609
|
+
a.add_parser(
|
|
610
|
+
"export",
|
|
611
|
+
help="copy the muse.ai login out of Chrome (remote debugging must be on)",
|
|
612
|
+
description=export_help,
|
|
613
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
614
|
+
).set_defaults(fn=cmd_auth_export)
|
|
475
615
|
|
|
476
616
|
sub.add_parser("status", help="VM, session count, unread, identity").set_defaults(fn=cmd_status)
|
|
477
617
|
p = sub.add_parser("threads", help="list chats and side chats")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|