claude-simple 0.2.24 → 0.2.26

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,27 @@ 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
+ | 微信小程序 | `miniprogram/` — login, sessions, history and streaming chat over the same Hub APIs |
28
+
29
+ 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.
30
+
31
+ ```
32
+ cd app && flutter run
33
+ # Hub URL e.g. http://127.0.0.1:8080
34
+ ```
35
+
36
+ 微信小程序可直接使用微信开发者工具导入 `miniprogram/`。开发工具中可临时关闭合法域名校验;上线前需要将 Hub 的 HTTPS/WSS 域名分别加到 request/socket 合法域名。完整说明见 [`miniprogram/README.md`](miniprogram/README.md)。
37
+
17
38
  前端会探测 `GET /api/hub`:没有该接口即按单机模式工作,逻辑与多机无关。
18
39
 
19
40
  ```
@@ -70,6 +91,8 @@ npm install -g @openai/codex
70
91
  | `CURSOR_HOME` | `~/.cursor` | Cursor home (UI session journal) |
71
92
  | `JWT_SECRET` | persisted in `.credentials.json` | Override JWT signing key |
72
93
  | `AUTH_USERNAME` / `AUTH_PASSWORD` | — | Bootstrap first user from env |
94
+ | `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` |
95
+ | `ANTHROPIC_DEFAULT_*_MODEL` / `CLAUDE_CODE_SUBAGENT_MODEL` / `CLAUDE_CODE_EFFORT_LEVEL` | — | Merged into the Claude spawn env (`effort` e.g. `max`) |
73
96
 
74
97
  Edge-only env (when connecting to a hub):
75
98
 
@@ -140,7 +163,7 @@ Top bar **✦ Agent** — OpenAI-compatible tool agent (DeepSeek / OpenAI / loca
140
163
  | **代码** | `write_file` + `run_command` 生成并运行(有危险命令拦截) |
141
164
  | **VLM** | 粘贴/选图 → 上传为 `[imgN](路径)` 文本引用;需要时 `analyze_images`;`thread_id` 支持多轮追问 |
142
165
 
143
- API Key 存在服务端 `.ai_config.json`(已 gitignore)。配置入口:Agent 面板 ⚙。
166
+ Meta Agent 由 **Hub** 托管;API Key、VLM Key、配置和会话数据都保存在 Hub 的持久化数据目录,不下发给 Edge 或 App(且不写入 Git)。配置接口只返回是否已配置,绝不回显 Key 明文。Hub 重启会中断进行中的 SSE,但不会删除已落盘的 Meta 会话或 VLM thread。
144
167
 
145
168
  **Session 持久化(同一 sessionId;多图 = 多个 VLM thread 文件)**
146
169
 
@@ -158,7 +181,7 @@ API Key 存在服务端 `.ai_config.json`(已 gitignore)。配置入口:Ag
158
181
 
159
182
  删除会话会整目录删除。旧版 `session.json`、`vlm.jsonl`、`vlm/*.json`、全局 `.ai/vlm/` 会自动迁移。
160
183
 
161
- Meta Agent 的实现入口:`src/agents/meta-agent.js`、`src/app.js`(`/api/ai/*`)与 `public/agent-panel.js`。
184
+ Meta Agent 的 API 由 Hub 提供;旧版 Node/Edge 实现路径仅供迁移和历史参考。
162
185
 
163
186
  ## Multi-machine (optional)
164
187
 
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();