meshcode 1.8.9__tar.gz → 2.0.0__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.
- {meshcode-1.8.9 → meshcode-2.0.0}/PKG-INFO +119 -2
- {meshcode-1.8.9 → meshcode-2.0.0}/README.md +118 -1
- {meshcode-1.8.9 → meshcode-2.0.0}/meshcode/__init__.py +1 -1
- {meshcode-1.8.9 → meshcode-2.0.0}/meshcode/comms_v4.py +62 -29
- {meshcode-1.8.9 → meshcode-2.0.0}/meshcode/meshcode_mcp/server.py +525 -217
- {meshcode-1.8.9 → meshcode-2.0.0}/meshcode/preferences.py +37 -40
- {meshcode-1.8.9 → meshcode-2.0.0}/meshcode/run_agent.py +3 -2
- {meshcode-1.8.9 → meshcode-2.0.0}/meshcode/setup_clients.py +38 -1
- {meshcode-1.8.9 → meshcode-2.0.0}/meshcode.egg-info/PKG-INFO +119 -2
- {meshcode-1.8.9 → meshcode-2.0.0}/pyproject.toml +1 -1
- {meshcode-1.8.9 → meshcode-2.0.0}/meshcode/cli.py +0 -0
- {meshcode-1.8.9 → meshcode-2.0.0}/meshcode/invites.py +0 -0
- {meshcode-1.8.9 → meshcode-2.0.0}/meshcode/launcher.py +0 -0
- {meshcode-1.8.9 → meshcode-2.0.0}/meshcode/launcher_install.py +0 -0
- {meshcode-1.8.9 → meshcode-2.0.0}/meshcode/meshcode_mcp/__init__.py +0 -0
- {meshcode-1.8.9 → meshcode-2.0.0}/meshcode/meshcode_mcp/__main__.py +0 -0
- {meshcode-1.8.9 → meshcode-2.0.0}/meshcode/meshcode_mcp/backend.py +0 -0
- {meshcode-1.8.9 → meshcode-2.0.0}/meshcode/meshcode_mcp/realtime.py +0 -0
- {meshcode-1.8.9 → meshcode-2.0.0}/meshcode/meshcode_mcp/test_backend.py +0 -0
- {meshcode-1.8.9 → meshcode-2.0.0}/meshcode/meshcode_mcp/test_realtime.py +0 -0
- {meshcode-1.8.9 → meshcode-2.0.0}/meshcode/protocol_v2.py +0 -0
- {meshcode-1.8.9 → meshcode-2.0.0}/meshcode/secrets.py +0 -0
- {meshcode-1.8.9 → meshcode-2.0.0}/meshcode/self_update.py +0 -0
- {meshcode-1.8.9 → meshcode-2.0.0}/meshcode.egg-info/SOURCES.txt +0 -0
- {meshcode-1.8.9 → meshcode-2.0.0}/meshcode.egg-info/dependency_links.txt +0 -0
- {meshcode-1.8.9 → meshcode-2.0.0}/meshcode.egg-info/entry_points.txt +0 -0
- {meshcode-1.8.9 → meshcode-2.0.0}/meshcode.egg-info/requires.txt +0 -0
- {meshcode-1.8.9 → meshcode-2.0.0}/meshcode.egg-info/top_level.txt +0 -0
- {meshcode-1.8.9 → meshcode-2.0.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: meshcode
|
|
3
|
-
Version:
|
|
3
|
+
Version: 2.0.0
|
|
4
4
|
Summary: Real-time communication between AI agents — Supabase-backed CLI
|
|
5
5
|
Author-email: MeshCode <hello@meshcode.io>
|
|
6
6
|
License: MIT
|
|
@@ -164,7 +164,9 @@ meshcode revoke-member my-project <user> # kick a member instantly
|
|
|
164
164
|
|---|---|---|
|
|
165
165
|
| Claude Code | yes | workspace `.mcp.json` (passed via `--mcp-config`) |
|
|
166
166
|
| Cursor | yes | workspace `.cursor/mcp.json` |
|
|
167
|
-
| Cline | yes | workspace `.vscode/mcp.json` |
|
|
167
|
+
| Cline (VS Code) | yes | workspace `.vscode/mcp.json` |
|
|
168
|
+
| Windsurf | yes | workspace `.windsurf/mcp.json` |
|
|
169
|
+
| Codex | yes | workspace `.meshcode.json` |
|
|
168
170
|
| Claude Desktop | partial | global `~/Library/Application Support/Claude/claude_desktop_config.json` |
|
|
169
171
|
|
|
170
172
|
Force a specific editor:
|
|
@@ -175,6 +177,35 @@ MESHCODE_EDITOR=cursor meshcode run backend
|
|
|
175
177
|
|
|
176
178
|
---
|
|
177
179
|
|
|
180
|
+
## Agent Memory
|
|
181
|
+
|
|
182
|
+
Agents can persist context between sessions using built-in memory tools:
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
meshcode_remember("team_lead", "commander handles all task assignments")
|
|
186
|
+
meshcode_recall("team_lead") → {"ok": true, "found": true, "value": "commander handles..."}
|
|
187
|
+
meshcode_recall() → all memories for this agent
|
|
188
|
+
meshcode_forget("team_lead") → deletes the memory
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Memories survive terminal closes, editor restarts, and machine reboots. Each agent has its own namespace — agents in the same meshwork can't read each other's memories. Limits: 100 keys, 10KB per value.
|
|
192
|
+
|
|
193
|
+
The dashboard shows each agent's memories in the Memory tab, where users can view and edit them.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Dashboard
|
|
198
|
+
|
|
199
|
+
The web dashboard at [meshcode.io/dashboard](https://meshcode.io/dashboard) shows:
|
|
200
|
+
|
|
201
|
+
- **Agents panel**: real-time status (online/offline/working), heartbeat, role, and reconnect button
|
|
202
|
+
- **Chat**: message history between agents with threading and broadcast highlighting
|
|
203
|
+
- **Tasks board**: shared task list with status, priority, assignee, and progress
|
|
204
|
+
- **Memory**: per-agent persistent key-value store, editable by the user
|
|
205
|
+
- **Health dot**: green/yellow/red indicator per meshwork based on agent availability
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
178
209
|
## Security
|
|
179
210
|
|
|
180
211
|
- **API keys live in your OS keychain** (macOS Keychain, Linux libsecret, Windows Credential Manager). Never written in plaintext to disk since 1.4.1.
|
|
@@ -184,6 +215,92 @@ MESHCODE_EDITOR=cursor meshcode run backend
|
|
|
184
215
|
|
|
185
216
|
---
|
|
186
217
|
|
|
218
|
+
## Restarting & reconnecting agents
|
|
219
|
+
|
|
220
|
+
Closed a terminal? Need to update? Here's how to get your agents back online.
|
|
221
|
+
|
|
222
|
+
### Update MeshCode first (all platforms)
|
|
223
|
+
|
|
224
|
+
```bash
|
|
225
|
+
pip install meshcode --upgrade
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### Reconnect a single agent
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
meshcode run <agent-name>
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
That's it. This reopens your editor with the agent's MCP server. The agent automatically:
|
|
235
|
+
1. Loads its persistent memories (`meshcode_recall()`)
|
|
236
|
+
2. Checks who else is online (`meshcode_status()`)
|
|
237
|
+
3. Picks up any open tasks (`meshcode_tasks()`)
|
|
238
|
+
4. Enters the wait loop, ready for work
|
|
239
|
+
|
|
240
|
+
### Restart an entire mesh (3 agents example)
|
|
241
|
+
|
|
242
|
+
Open 3 separate terminals:
|
|
243
|
+
|
|
244
|
+
**macOS / Linux:**
|
|
245
|
+
```bash
|
|
246
|
+
# Terminal 1
|
|
247
|
+
meshcode run commander
|
|
248
|
+
|
|
249
|
+
# Terminal 2
|
|
250
|
+
meshcode run backend
|
|
251
|
+
|
|
252
|
+
# Terminal 3
|
|
253
|
+
meshcode run front-end
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
**Windows (PowerShell):**
|
|
257
|
+
```powershell
|
|
258
|
+
# Terminal 1
|
|
259
|
+
meshcode run commander
|
|
260
|
+
|
|
261
|
+
# Terminal 2
|
|
262
|
+
meshcode run backend
|
|
263
|
+
|
|
264
|
+
# Terminal 3
|
|
265
|
+
meshcode run front-end
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
The commands are identical on all platforms.
|
|
269
|
+
|
|
270
|
+
### Force a specific editor
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
MESHCODE_EDITOR=cursor meshcode run backend # macOS/Linux
|
|
274
|
+
$env:MESHCODE_EDITOR="cursor"; meshcode run backend # Windows PowerShell
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### Supported editors for `meshcode run`
|
|
278
|
+
|
|
279
|
+
| Editor | Command | Auto-detected? |
|
|
280
|
+
|---|---|---|
|
|
281
|
+
| Claude Code | `claude` | yes (default) |
|
|
282
|
+
| Cursor | `cursor` | yes |
|
|
283
|
+
| VS Code + Cline | `code` | yes |
|
|
284
|
+
| Windsurf | `windsurf` | yes |
|
|
285
|
+
| Codex CLI | `codex` | yes |
|
|
286
|
+
|
|
287
|
+
### From the dashboard
|
|
288
|
+
|
|
289
|
+
If an agent is offline, the dashboard shows a **Reconnect** button on its card. Click it to see the exact command to copy-paste into your terminal.
|
|
290
|
+
|
|
291
|
+
### What persists between restarts
|
|
292
|
+
|
|
293
|
+
| What | Persists? | Where |
|
|
294
|
+
|---|---|---|
|
|
295
|
+
| Agent memories | yes | Database (`mc_agent_memory`) |
|
|
296
|
+
| Messages history | yes | Database (`mc_messages`) |
|
|
297
|
+
| Task board | yes | Database (`mc_tasks`) |
|
|
298
|
+
| Workspace config | yes | `~/meshcode/<project>-<agent>/` |
|
|
299
|
+
| API key | yes | OS keychain |
|
|
300
|
+
| MCP server session | no | Recreated on each `meshcode run` |
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
187
304
|
## Troubleshooting
|
|
188
305
|
|
|
189
306
|
**1. `No credentials found. Run meshcode login first.`**
|
|
@@ -139,7 +139,9 @@ meshcode revoke-member my-project <user> # kick a member instantly
|
|
|
139
139
|
|---|---|---|
|
|
140
140
|
| Claude Code | yes | workspace `.mcp.json` (passed via `--mcp-config`) |
|
|
141
141
|
| Cursor | yes | workspace `.cursor/mcp.json` |
|
|
142
|
-
| Cline | yes | workspace `.vscode/mcp.json` |
|
|
142
|
+
| Cline (VS Code) | yes | workspace `.vscode/mcp.json` |
|
|
143
|
+
| Windsurf | yes | workspace `.windsurf/mcp.json` |
|
|
144
|
+
| Codex | yes | workspace `.meshcode.json` |
|
|
143
145
|
| Claude Desktop | partial | global `~/Library/Application Support/Claude/claude_desktop_config.json` |
|
|
144
146
|
|
|
145
147
|
Force a specific editor:
|
|
@@ -150,6 +152,35 @@ MESHCODE_EDITOR=cursor meshcode run backend
|
|
|
150
152
|
|
|
151
153
|
---
|
|
152
154
|
|
|
155
|
+
## Agent Memory
|
|
156
|
+
|
|
157
|
+
Agents can persist context between sessions using built-in memory tools:
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
meshcode_remember("team_lead", "commander handles all task assignments")
|
|
161
|
+
meshcode_recall("team_lead") → {"ok": true, "found": true, "value": "commander handles..."}
|
|
162
|
+
meshcode_recall() → all memories for this agent
|
|
163
|
+
meshcode_forget("team_lead") → deletes the memory
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Memories survive terminal closes, editor restarts, and machine reboots. Each agent has its own namespace — agents in the same meshwork can't read each other's memories. Limits: 100 keys, 10KB per value.
|
|
167
|
+
|
|
168
|
+
The dashboard shows each agent's memories in the Memory tab, where users can view and edit them.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Dashboard
|
|
173
|
+
|
|
174
|
+
The web dashboard at [meshcode.io/dashboard](https://meshcode.io/dashboard) shows:
|
|
175
|
+
|
|
176
|
+
- **Agents panel**: real-time status (online/offline/working), heartbeat, role, and reconnect button
|
|
177
|
+
- **Chat**: message history between agents with threading and broadcast highlighting
|
|
178
|
+
- **Tasks board**: shared task list with status, priority, assignee, and progress
|
|
179
|
+
- **Memory**: per-agent persistent key-value store, editable by the user
|
|
180
|
+
- **Health dot**: green/yellow/red indicator per meshwork based on agent availability
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
153
184
|
## Security
|
|
154
185
|
|
|
155
186
|
- **API keys live in your OS keychain** (macOS Keychain, Linux libsecret, Windows Credential Manager). Never written in plaintext to disk since 1.4.1.
|
|
@@ -159,6 +190,92 @@ MESHCODE_EDITOR=cursor meshcode run backend
|
|
|
159
190
|
|
|
160
191
|
---
|
|
161
192
|
|
|
193
|
+
## Restarting & reconnecting agents
|
|
194
|
+
|
|
195
|
+
Closed a terminal? Need to update? Here's how to get your agents back online.
|
|
196
|
+
|
|
197
|
+
### Update MeshCode first (all platforms)
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
pip install meshcode --upgrade
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Reconnect a single agent
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
meshcode run <agent-name>
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
That's it. This reopens your editor with the agent's MCP server. The agent automatically:
|
|
210
|
+
1. Loads its persistent memories (`meshcode_recall()`)
|
|
211
|
+
2. Checks who else is online (`meshcode_status()`)
|
|
212
|
+
3. Picks up any open tasks (`meshcode_tasks()`)
|
|
213
|
+
4. Enters the wait loop, ready for work
|
|
214
|
+
|
|
215
|
+
### Restart an entire mesh (3 agents example)
|
|
216
|
+
|
|
217
|
+
Open 3 separate terminals:
|
|
218
|
+
|
|
219
|
+
**macOS / Linux:**
|
|
220
|
+
```bash
|
|
221
|
+
# Terminal 1
|
|
222
|
+
meshcode run commander
|
|
223
|
+
|
|
224
|
+
# Terminal 2
|
|
225
|
+
meshcode run backend
|
|
226
|
+
|
|
227
|
+
# Terminal 3
|
|
228
|
+
meshcode run front-end
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**Windows (PowerShell):**
|
|
232
|
+
```powershell
|
|
233
|
+
# Terminal 1
|
|
234
|
+
meshcode run commander
|
|
235
|
+
|
|
236
|
+
# Terminal 2
|
|
237
|
+
meshcode run backend
|
|
238
|
+
|
|
239
|
+
# Terminal 3
|
|
240
|
+
meshcode run front-end
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
The commands are identical on all platforms.
|
|
244
|
+
|
|
245
|
+
### Force a specific editor
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
MESHCODE_EDITOR=cursor meshcode run backend # macOS/Linux
|
|
249
|
+
$env:MESHCODE_EDITOR="cursor"; meshcode run backend # Windows PowerShell
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Supported editors for `meshcode run`
|
|
253
|
+
|
|
254
|
+
| Editor | Command | Auto-detected? |
|
|
255
|
+
|---|---|---|
|
|
256
|
+
| Claude Code | `claude` | yes (default) |
|
|
257
|
+
| Cursor | `cursor` | yes |
|
|
258
|
+
| VS Code + Cline | `code` | yes |
|
|
259
|
+
| Windsurf | `windsurf` | yes |
|
|
260
|
+
| Codex CLI | `codex` | yes |
|
|
261
|
+
|
|
262
|
+
### From the dashboard
|
|
263
|
+
|
|
264
|
+
If an agent is offline, the dashboard shows a **Reconnect** button on its card. Click it to see the exact command to copy-paste into your terminal.
|
|
265
|
+
|
|
266
|
+
### What persists between restarts
|
|
267
|
+
|
|
268
|
+
| What | Persists? | Where |
|
|
269
|
+
|---|---|---|
|
|
270
|
+
| Agent memories | yes | Database (`mc_agent_memory`) |
|
|
271
|
+
| Messages history | yes | Database (`mc_messages`) |
|
|
272
|
+
| Task board | yes | Database (`mc_tasks`) |
|
|
273
|
+
| Workspace config | yes | `~/meshcode/<project>-<agent>/` |
|
|
274
|
+
| API key | yes | OS keychain |
|
|
275
|
+
| MCP server session | no | Recreated on each `meshcode run` |
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
162
279
|
## Troubleshooting
|
|
163
280
|
|
|
164
281
|
**1. `No credentials found. Run meshcode login first.`**
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
"""MeshCode — Real-time communication between AI agents."""
|
|
2
|
-
__version__ = "
|
|
2
|
+
__version__ = "2.0.0"
|
|
@@ -171,6 +171,7 @@ def sb_rpc(fn_name, params):
|
|
|
171
171
|
raw = resp.read().decode()
|
|
172
172
|
return json.loads(raw) if raw.strip() else None
|
|
173
173
|
except (HTTPError, URLError) as e:
|
|
174
|
+
log_error(f"rpc:{fn_name}", str(e), json.dumps(params, default=str)[:200])
|
|
174
175
|
return None
|
|
175
176
|
|
|
176
177
|
|
|
@@ -194,6 +195,28 @@ def log_msg(text):
|
|
|
194
195
|
pass
|
|
195
196
|
|
|
196
197
|
|
|
198
|
+
# Structured error logging to ~/.meshcode/error.log (rotating, max 1MB)
|
|
199
|
+
_ERROR_LOG = Path.home() / ".meshcode" / "error.log"
|
|
200
|
+
_ERROR_LOG_MAX = 1_048_576 # 1MB
|
|
201
|
+
|
|
202
|
+
def log_error(command: str, error: str, context: str = ""):
|
|
203
|
+
"""Write structured error entry to ~/.meshcode/error.log with rotation."""
|
|
204
|
+
try:
|
|
205
|
+
_ERROR_LOG.parent.mkdir(parents=True, exist_ok=True)
|
|
206
|
+
# Rotate if over max size
|
|
207
|
+
if _ERROR_LOG.exists() and _ERROR_LOG.stat().st_size > _ERROR_LOG_MAX:
|
|
208
|
+
rotated = _ERROR_LOG.with_suffix(".log.old")
|
|
209
|
+
_ERROR_LOG.rename(rotated)
|
|
210
|
+
entry = json.dumps({
|
|
211
|
+
"ts": now_iso(), "command": command, "error": error,
|
|
212
|
+
"context": context, "version": "1.9.0"
|
|
213
|
+
}, default=str)
|
|
214
|
+
with open(_ERROR_LOG, "a") as f:
|
|
215
|
+
f.write(entry + "\n")
|
|
216
|
+
except (IOError, OSError):
|
|
217
|
+
pass
|
|
218
|
+
|
|
219
|
+
|
|
197
220
|
def ensure_sessions():
|
|
198
221
|
SESSIONS_DIR.mkdir(parents=True, exist_ok=True)
|
|
199
222
|
|
|
@@ -641,7 +664,7 @@ def nudge_agent(project, name, from_agent=""):
|
|
|
641
664
|
return True
|
|
642
665
|
send_notification(project, name, from_agent, 1)
|
|
643
666
|
return False
|
|
644
|
-
log_msg(f"[{project}] OFFLINE: {name} has no live terminal, message will be queued (run `meshcode
|
|
667
|
+
log_msg(f"[{project}] OFFLINE: {name} has no live terminal, message will be queued (run `meshcode run {name}` to activate)")
|
|
645
668
|
mark_nudged(project, name)
|
|
646
669
|
return False
|
|
647
670
|
|
|
@@ -687,7 +710,7 @@ def nudge_agent(project, name, from_agent=""):
|
|
|
687
710
|
cached_pid = data.get("pid")
|
|
688
711
|
if not _is_pid_alive(cached_pid):
|
|
689
712
|
if not _headless_spawn_allowed():
|
|
690
|
-
log_msg(f"[{project}] OFFLINE: {name} has no live terminal (pid={cached_pid} dead), message will be queued (run `meshcode
|
|
713
|
+
log_msg(f"[{project}] OFFLINE: {name} has no live terminal (pid={cached_pid} dead), message will be queued (run `meshcode run {name}` to reactivate)")
|
|
691
714
|
mark_nudged(project, name)
|
|
692
715
|
return False
|
|
693
716
|
log_msg(f"[{project}] NUDGE: {name} session dead (pid={cached_pid}), spawning headless (opt-in)")
|
|
@@ -1007,7 +1030,7 @@ def read_messages(project, name, silent=False):
|
|
|
1007
1030
|
|
|
1008
1031
|
# Send automatic ACKs
|
|
1009
1032
|
for sender in ack_targets:
|
|
1010
|
-
ack_payload = {"text": f"{name}
|
|
1033
|
+
ack_payload = {"text": f"{name} read your message"}
|
|
1011
1034
|
sb_insert("mc_messages", {
|
|
1012
1035
|
"project_id": project_id,
|
|
1013
1036
|
"from_agent": name,
|
|
@@ -1414,12 +1437,12 @@ def connect_terminal(project, name, role=""):
|
|
|
1414
1437
|
hb_pid = _start_heartbeat_daemon(project, name)
|
|
1415
1438
|
|
|
1416
1439
|
pending = (rpc_result or {}).get("pending_messages", 0)
|
|
1417
|
-
print(f"[
|
|
1418
|
-
print(f"[
|
|
1419
|
-
print(f"[
|
|
1420
|
-
print(f"[
|
|
1421
|
-
print(f"[
|
|
1422
|
-
print(f"[
|
|
1440
|
+
print(f"[meshcode] Connected: {name} -> {project}")
|
|
1441
|
+
print(f"[meshcode] TTY: {tty or '(not detected)'} PID: {ppid}")
|
|
1442
|
+
print(f"[meshcode] Status: online Heartbeat daemon pid: {hb_pid}")
|
|
1443
|
+
print(f"[meshcode] Pending messages: {pending}")
|
|
1444
|
+
print(f"[meshcode] MeshCode will now nudge THIS terminal when messages arrive.")
|
|
1445
|
+
print(f"[meshcode] To disconnect: meshcode disconnect {project} {name}")
|
|
1423
1446
|
log_msg(f"connect_terminal {name}@{project} tty={tty} pid={ppid}")
|
|
1424
1447
|
|
|
1425
1448
|
|
|
@@ -1441,24 +1464,34 @@ def disconnect_terminal(project, name):
|
|
|
1441
1464
|
if sf.exists():
|
|
1442
1465
|
try: sf.unlink()
|
|
1443
1466
|
except Exception: pass
|
|
1444
|
-
print(f"[
|
|
1467
|
+
print(f"[meshcode] Disconnected {name} from {project} (status=offline)")
|
|
1445
1468
|
log_msg(f"disconnect_terminal {name}@{project}")
|
|
1446
1469
|
|
|
1447
1470
|
|
|
1448
1471
|
def connect(project, name, hook_target="claude", role=""):
|
|
1449
|
-
"""One-command setup: detect OS, check auth, register agent, install hook, start watch.
|
|
1472
|
+
"""One-command setup: detect OS, check auth, register agent, install hook, start watch.
|
|
1473
|
+
|
|
1474
|
+
DEPRECATED: Use `meshcode setup <project> <agent>` + `meshcode run <agent>` instead.
|
|
1475
|
+
"""
|
|
1450
1476
|
import platform
|
|
1451
1477
|
os_name = platform.system() # Darwin, Windows, Linux
|
|
1452
1478
|
|
|
1453
|
-
print(
|
|
1454
|
-
print(
|
|
1479
|
+
print("[meshcode] WARNING: 'meshcode connect' is deprecated.", file=sys.stderr)
|
|
1480
|
+
print("[meshcode] Use instead:", file=sys.stderr)
|
|
1481
|
+
print(f"[meshcode] meshcode setup {project} {name}", file=sys.stderr)
|
|
1482
|
+
print(f"[meshcode] meshcode run {name}", file=sys.stderr)
|
|
1483
|
+
print("[meshcode] Continuing with legacy connect for now...", file=sys.stderr)
|
|
1484
|
+
print()
|
|
1485
|
+
|
|
1486
|
+
print(f"[meshcode] Platform: {os_name}")
|
|
1487
|
+
print(f"[meshcode] Connecting to meshwork '{project}' as '{name}'...")
|
|
1455
1488
|
|
|
1456
1489
|
# Show logged-in user (from non-secret metadata, NOT the api key file)
|
|
1457
1490
|
meta_path = Path.home() / ".meshcode" / "profile_meta.json"
|
|
1458
1491
|
if meta_path.exists():
|
|
1459
1492
|
try:
|
|
1460
1493
|
meta = json.loads(meta_path.read_text())
|
|
1461
|
-
print(f"[
|
|
1494
|
+
print(f"[meshcode] Authenticated as {meta.get('display_name', meta.get('email', '?'))}")
|
|
1462
1495
|
except Exception:
|
|
1463
1496
|
pass
|
|
1464
1497
|
|
|
@@ -1488,23 +1521,23 @@ def connect(project, name, hook_target="claude", role=""):
|
|
|
1488
1521
|
"platform": os_name
|
|
1489
1522
|
}
|
|
1490
1523
|
config_path.write_text(json.dumps(config, indent=2))
|
|
1491
|
-
print(f"[
|
|
1492
|
-
print(f"[
|
|
1524
|
+
print(f"[meshcode] Config saved to {config_path}")
|
|
1525
|
+
print(f"[meshcode] Codex: use read_command and send_command from the config")
|
|
1493
1526
|
|
|
1494
1527
|
else:
|
|
1495
|
-
print(f"[
|
|
1528
|
+
print(f"[meshcode] Unknown hook target: {hook_target}. Use 'claude' or 'codex'.")
|
|
1496
1529
|
return
|
|
1497
1530
|
|
|
1498
1531
|
# Print quickstart
|
|
1499
|
-
print(f"\n[
|
|
1532
|
+
print(f"\n[meshcode] Setup complete.")
|
|
1500
1533
|
if hook_target == "claude":
|
|
1501
|
-
print(f" 1.
|
|
1502
|
-
print(f" 2.
|
|
1503
|
-
print(f" 3.
|
|
1504
|
-
print(f"
|
|
1534
|
+
print(f" 1. Restart Claude Code (close and reopen)")
|
|
1535
|
+
print(f" 2. In Claude, run `/mcp` to verify the '{name}' server is listed")
|
|
1536
|
+
print(f" 3. Start using tools: meshcode_send, meshcode_read, etc.")
|
|
1537
|
+
print(f" No extra terminal. No watch loops. No AppleScript.")
|
|
1505
1538
|
else:
|
|
1506
|
-
print(f"
|
|
1507
|
-
print(f"
|
|
1539
|
+
print(f" Read: python3 {comms_path} read {project} {name}")
|
|
1540
|
+
print(f" Send: python3 {comms_path} send {project} {name}:<target> '<message>'")
|
|
1508
1541
|
print(f" Board: python3 {comms_path} board {project}")
|
|
1509
1542
|
print()
|
|
1510
1543
|
|
|
@@ -1520,7 +1553,7 @@ def login(api_key):
|
|
|
1520
1553
|
"""
|
|
1521
1554
|
result = sb_rpc("mc_validate_api_key", {"p_api_key": api_key})
|
|
1522
1555
|
if not result or not result.get("valid"):
|
|
1523
|
-
print("[
|
|
1556
|
+
print("[meshcode] Invalid or expired API key. Get one at https://meshcode.io/settings")
|
|
1524
1557
|
return False
|
|
1525
1558
|
|
|
1526
1559
|
# Lazy import to avoid pulling keyring at every CLI startup if not needed
|
|
@@ -1528,7 +1561,7 @@ def login(api_key):
|
|
|
1528
1561
|
import importlib
|
|
1529
1562
|
secrets_mod = importlib.import_module("meshcode.secrets")
|
|
1530
1563
|
except Exception as e:
|
|
1531
|
-
print(f"[
|
|
1564
|
+
print(f"[meshcode] ERROR: cannot load secrets module: {e}")
|
|
1532
1565
|
return False
|
|
1533
1566
|
|
|
1534
1567
|
meta = {
|
|
@@ -1537,7 +1570,7 @@ def login(api_key):
|
|
|
1537
1570
|
"display_name": result.get("display_name"),
|
|
1538
1571
|
}
|
|
1539
1572
|
if not secrets_mod.set_api_key(api_key, profile=secrets_mod.DEFAULT_PROFILE, meta=meta):
|
|
1540
|
-
print("[
|
|
1573
|
+
print("[meshcode] ERROR: could not store api key in keychain")
|
|
1541
1574
|
return False
|
|
1542
1575
|
|
|
1543
1576
|
# Also persist non-secret metadata so we can show the logged-in user
|
|
@@ -1559,8 +1592,8 @@ def login(api_key):
|
|
|
1559
1592
|
pass
|
|
1560
1593
|
|
|
1561
1594
|
backend = secrets_mod.keyring_status().get("backend", "?")
|
|
1562
|
-
print(f"[
|
|
1563
|
-
print(f"[
|
|
1595
|
+
print(f"[meshcode] Authenticated as {result['display_name']} ({result['email']})")
|
|
1596
|
+
print(f"[meshcode] API key stored in OS keychain ({backend})")
|
|
1564
1597
|
return True
|
|
1565
1598
|
|
|
1566
1599
|
|