claude-simple 0.2.23 → 0.2.25

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.
package/README.md CHANGED
@@ -14,6 +14,24 @@ Inspired by [cc-connect](https://github.com/chenhg5/cc-connect) agent adapters:
14
14
 
15
15
  **本地跑不需要中心端。** 单机默认就是 Standalone:UI + 后端 + agent 都在同一个 Node 进程里。
16
16
 
17
+ ### Multi-user, locks, port maps, Flutter
18
+
19
+ Design: [`docs/multiuser-portmap-design.md`](docs/multiuser-portmap-design.md).
20
+
21
+ | Piece | What it does |
22
+ |-------|----------------|
23
+ | Roles | `owner` / `admin` / `editor` / `viewer` — live role on mutating APIs |
24
+ | Locks | Lease locks (`POST /api/collab/locks`, heartbeat/release/break). 423 if held. Auto-claim 30s on unguarded writes |
25
+ | Port map | `POST /api/collab/routes` then visit `/r/{slug}/…` — Hub tunnels to edge `host:port` (loopback by default) |
26
+ | Flutter | `app/` — login, machines, locks, routes, users; local JSON cache + sync |
27
+
28
+ Hub stores users/locks/routes under `hub-data/`. Standalone uses `.collab.json` plus `.credentials.json` (`role` on each user). Invite users: `POST /api/collab/users` as admin/owner.
29
+
30
+ ```
31
+ cd app && flutter run
32
+ # Hub URL e.g. http://127.0.0.1:8080
33
+ ```
34
+
17
35
  前端会探测 `GET /api/hub`:没有该接口即按单机模式工作,逻辑与多机无关。
18
36
 
19
37
  ```
@@ -70,6 +88,8 @@ npm install -g @openai/codex
70
88
  | `CURSOR_HOME` | `~/.cursor` | Cursor home (UI session journal) |
71
89
  | `JWT_SECRET` | persisted in `.credentials.json` | Override JWT signing key |
72
90
  | `AUTH_USERNAME` / `AUTH_PASSWORD` | — | Bootstrap first user from env |
91
+ | `ANTHROPIC_BASE_URL` / `ANTHROPIC_AUTH_TOKEN` / `ANTHROPIC_MODEL` | — | Anthropic-compatible APIs (DeepSeek etc.). LaunchAgent does **not** inherit shell `export` — use Settings → Claude env, `~/.claude/settings.json` `env`, or `~/.claude-simple-edge/agent-env.json` |
92
+ | `ANTHROPIC_DEFAULT_*_MODEL` / `CLAUDE_CODE_SUBAGENT_MODEL` / `CLAUDE_CODE_EFFORT_LEVEL` | — | Merged into the Claude spawn env (`effort` e.g. `max`) |
73
93
 
74
94
  Edge-only env (when connecting to a hub):
75
95
 
package/client.js CHANGED
@@ -150,15 +150,32 @@ async function refreshSessionCatalog() {
150
150
  const key = catalogKey(session);
151
151
  if (session.sessionId) next[key] = session;
152
152
  }
153
- const before = syncState.catalog || {};
153
+ // Prefer the in-flight snapshot so a missing Hub ACK cannot re-diff
154
+ // against a stale committed catalog on every file watch.
155
+ const before = syncState.catalogPending?.next || syncState.catalog || {};
156
+ const fingerprint = (session) => {
157
+ if (!session) return '';
158
+ const { updatedAt, ...rest } = session;
159
+ return JSON.stringify(rest);
160
+ };
154
161
  const upserts = Object.entries(next)
155
- .filter(([key, value]) => JSON.stringify(before[key]) !== JSON.stringify(value))
162
+ .filter(([key, value]) => fingerprint(before[key]) !== fingerprint(value))
156
163
  .map(([, value]) => value);
157
164
  const removes = Object.keys(before).filter(key => !next[key]);
158
165
  if (upserts.length || removes.length) {
159
166
  // Keep the outgoing delta on disk until the Hub confirms it. Retrying
160
167
  // is safe because Hub-side upserts/removes are idempotent.
161
- const id = ++syncState.catalogSeq;
168
+ // If the Hub never ACKs (older hub, drop), do not mint a new seq or log
169
+ // on every fs watch — that flooded edge.out.log with "+1 -0".
170
+ const prev = syncState.catalogPending;
171
+ const same = prev
172
+ && JSON.stringify(prev.upserts) === JSON.stringify(upserts)
173
+ && JSON.stringify(prev.removes) === JSON.stringify(removes);
174
+ if (same) {
175
+ flushCatalogOutbox();
176
+ return;
177
+ }
178
+ const id = prev?.id || ++syncState.catalogSeq;
162
179
  syncState.catalogPending = { id, upserts, removes, next };
163
180
  void persistSyncState();
164
181
  flushCatalogOutbox();