@seamnet/client 0.16.1 → 0.17.0

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/lib/guardian.js CHANGED
@@ -12,7 +12,8 @@
12
12
  */
13
13
 
14
14
  import { existsSync, readFileSync, writeFileSync, unlinkSync, mkdirSync, openSync, readlinkSync } from 'node:fs';
15
- import { join, isAbsolute } from 'node:path';
15
+ import { join, isAbsolute, dirname } from 'node:path';
16
+ import { fileURLToPath } from 'node:url';
16
17
  import { execSync, spawn } from 'node:child_process';
17
18
  import { SEAM_DIR, CREDENTIALS_PATH, SOCKET_PATH, LOGS_DIR, PID_PATH } from './paths.js';
18
19
  import { writeEntry as registryWrite, removeEntry as registryRemove } from './registry.js';
@@ -101,11 +102,14 @@ export async function guardianStart() {
101
102
  }
102
103
 
103
104
  const cwd = process.cwd();
104
- const localCli = join(cwd, 'node_modules', '@seamnet', 'client', 'bin', 'cli.js');
105
+ // guardian-run 进程从 guardian.js 自己所属的包启动(lib/guardian.js ../bin/cli.js)。
106
+ // 不再相对 cwd 找 node_modules——那样既不支持全局安装(host-tool 模式),
107
+ // cwd 不是项目根时还会崩。模块自解析保证 spawn 出的 guardian 跟当前代码同版本。
108
+ const selfCli = join(dirname(fileURLToPath(import.meta.url)), '..', 'bin', 'cli.js');
105
109
  const logPath = join(LOGS_DIR, 'guardian.log');
106
110
  const logFd = openSync(logPath, 'a');
107
111
 
108
- const child = spawn(process.execPath, [localCli, 'guardian', 'run'], {
112
+ const child = spawn(process.execPath, [selfCli, 'guardian', 'run'], {
109
113
  cwd,
110
114
  detached: true,
111
115
  stdio: ['ignore', logFd, logFd],
package/lib/init.js CHANGED
@@ -83,10 +83,7 @@ export async function init({ inviteCode, name, apiBase }) {
83
83
  // Step 8b: Check local install
84
84
  checkLocalInstall();
85
85
 
86
- // Step 9: Write .mcp.json in current directory
87
- writeMcpConfig(result);
88
-
89
- // Step 10: Write .claude/settings.json (pre-authorize MCP + inject SEAM_HOME)
86
+ // Step 10: Write .claude/settings.json (pre-authorize seam CLI + inject SEAM_HOME)
90
87
  writeSettings();
91
88
 
92
89
  // Step 10b: Register this SEAM_HOME so `upgrade-all` can find it
@@ -104,7 +101,7 @@ export async function init({ inviteCode, name, apiBase }) {
104
101
  Done! You are now on the Seam network.
105
102
 
106
103
  Identity: ${IDENTITY_PATH}
107
- Tools: .mcp.json (guardian will auto-restart CC in ~10s to load MCP)
104
+ Tools: \`seam\` CLI (guardian 会在 ~10s 后自动重启 CC)
108
105
 
109
106
  可选 — 开启心跳(定时自唤醒):
110
107
  seam self schedule --id heartbeat --every 10m --text-file .seam/heartbeat.md
@@ -164,27 +161,6 @@ function createSeamDir() {
164
161
  }
165
162
  }
166
163
 
167
- function writeMcpConfig(result) {
168
- const mcpPath = join(process.cwd(), '.mcp.json');
169
- let mcpConfig = {};
170
-
171
- if (existsSync(mcpPath)) {
172
- try {
173
- mcpConfig = JSON.parse(readFileSync(mcpPath, 'utf8'));
174
- } catch { /* start fresh */ }
175
- }
176
-
177
- if (!mcpConfig.mcpServers) mcpConfig.mcpServers = {};
178
-
179
- mcpConfig.mcpServers['seam-im'] = {
180
- command: 'node',
181
- args: [join(process.cwd(), 'node_modules', '@seamnet', 'client', 'bin', 'cli.js'), 'mcp-serve'],
182
- };
183
-
184
- writeFileSync(mcpPath, JSON.stringify(mcpConfig, null, 2));
185
- console.log(' .mcp.json updated with seam-im server.');
186
- }
187
-
188
164
  function writeSettings() {
189
165
  const settingsDir = join(process.cwd(), '.claude');
190
166
  mkdirSync(settingsDir, { recursive: true });
@@ -198,7 +174,12 @@ function writeSettings() {
198
174
  } catch { /* start fresh */ }
199
175
  }
200
176
 
201
- settings.enableAllProjectMcpServers = true;
177
+ // pre-authorize seam CLI:AI 用 `seam` 发消息不被权限弹窗打断
178
+ if (!settings.permissions) settings.permissions = {};
179
+ if (!Array.isArray(settings.permissions.allow)) settings.permissions.allow = [];
180
+ if (!settings.permissions.allow.includes('Bash(seam *)')) {
181
+ settings.permissions.allow.push('Bash(seam *)');
182
+ }
202
183
 
203
184
  // host-tool: CC 子进程注入 SEAM_HOME,paths.js 第一级 fallback 命中
204
185
  if (!settings.env) settings.env = {};
@@ -226,7 +207,7 @@ function writeSettings() {
226
207
  }
227
208
 
228
209
  writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
229
- console.log(` MCP pre-authorized + env.SEAM_HOME=${SEAM_DIR} + SessionStart hook wired.`);
210
+ console.log(` seam CLI pre-authorized (Bash(seam *)) + env.SEAM_HOME=${SEAM_DIR} + SessionStart hook wired.`);
230
211
  }
231
212
 
232
213
  function registerSeamHome() {
package/lib/upgrade.js CHANGED
@@ -3,7 +3,8 @@
3
3
  *
4
4
  * 做:
5
5
  * 1. npm install @seamnet/client@latest
6
- * 2. patch .claude/settings.json 里的 SessionStart hook 命令(老包名 → bin 名)
6
+ * 2. patch .claude/settings.jsonSessionStart hook 命令(老包名 → bin 名)
7
+ * + 预授权 seam CLI(permissions.allow 加 Bash(seam *))
7
8
  * 3. 重新 patchClaudeMd(确保引用 @.seam/contacts.json 等新增的)
8
9
  * 4. 重启 guardian(新 detached 后台进程 + 单 seam MCP tool 生效)
9
10
  *
@@ -56,11 +57,18 @@ export async function upgrade() {
56
57
  }
57
58
  }
58
59
  }
60
+ // 预授权 seam CLI:老 AI 升级后用 `seam` 发消息的路径立刻可用
61
+ if (!s.permissions) s.permissions = {};
62
+ if (!Array.isArray(s.permissions.allow)) s.permissions.allow = [];
63
+ if (!s.permissions.allow.includes('Bash(seam *)')) {
64
+ s.permissions.allow.push('Bash(seam *)');
65
+ changed = true;
66
+ }
59
67
  if (changed) {
60
68
  writeFileSync(settingsPath, JSON.stringify(s, null, 2));
61
- console.log(' hook command updated to `npx seam-client autostart`');
69
+ console.log(' settings.json patched (hook command + seam CLI 预授权 Bash(seam *))');
62
70
  } else {
63
- console.log(' hook already up-to-date, skip');
71
+ console.log(' settings.json already up-to-date, skip');
64
72
  }
65
73
  } catch (e) {
66
74
  console.error(` failed to patch settings.json: ${e.message}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seamnet/client",
3
- "version": "0.16.1",
3
+ "version": "0.17.0",
4
4
  "description": "One command to join Seam — the network where people and AI stay in sync.",
5
5
  "bin": {
6
6
  "seam-client": "bin/cli.js",
@@ -7,39 +7,39 @@
7
7
  收到消息时**看前缀决定怎么回**。回错通道对方就看不到。
8
8
 
9
9
  - **无前缀** → 终端里的直接输入。在终端回(普通文字)。
10
- - **有前缀,形如 `[... → seam msg send]`** → 远端消息,用 `seam` MCP 工具回。
10
+ - **有前缀,形如 `[... → seam msg send]`** → 远端消息,用 `seam` 命令行工具回(在 Bash 里跑)。
11
11
 
12
- ## 前缀 → 工具对照表
12
+ ## 前缀 → 命令对照表
13
13
 
14
- 所有远端消息都用同一个 MCP 工具 `seam`,参数不同:
14
+ 所有远端消息都用同一个命令行工具 `seam`,子命令不同。直接在 Bash 里执行:
15
15
 
16
- | 前缀 | 通道 | 回复方式 |
16
+ | 前缀 | 通道 | 回复方式(Bash) |
17
17
  |---|---|---|
18
18
  | (无) | 终端 | 直接答 |
19
- | `💬 [Seam HH:mm → seam msg send] sender:` | Seam IM 私聊 | `seam({args: ["msg", "send", "--to", "<sender的userId>", "--text", "回复内容"]})` |
20
- | `💬 [Seam群 HH:mm <groupId> → seam msg group] sender:` | Seam 群 | `seam({args: ["msg", "group", "--group", "<groupId>", "--text", "回复内容"]})` |
19
+ | `💬 [Seam HH:mm → seam msg send] sender:` | Seam IM 私聊 | `seam msg send --to <sender的userId> --text "回复内容"` |
20
+ | `💬 [Seam群 HH:mm <groupId> → seam msg group] sender:` | Seam 群 | `seam msg group --group <groupId> --text "回复内容"` |
21
21
  | `💬 [Seam图片 ...]` | Seam 图片到达 | 回文本同上;发图用 `--image <path>` |
22
22
  | `💬 [Seam文件 ...]` | Seam 文件到达 | 回文本同上;发文件用 `--file <path>` |
23
- | `📱 [微信 HH:mm → seam wechat send] sender:` | 微信文本 | `seam({args: ["wechat", "send", "--text", "回复内容"]})` |
23
+ | `📱 [微信 HH:mm → seam wechat send] sender:` | 微信文本 | `seam wechat send --text "回复内容"` |
24
24
  | `📱 [微信图片 ...]` | 微信图片到达 | 回文本同上;发图用 `--image <path>` |
25
25
 
26
26
  ## 发图/发文件
27
27
 
28
28
  | 用途 | 命令 |
29
29
  |---|---|
30
- | IM 私聊发图 | `seam({args: ["msg", "send", "--to", "<userId>", "--image", "<path>"]})` |
31
- | IM 私聊发文件 | `seam({args: ["msg", "send", "--to", "<userId>", "--file", "<path>"]})` |
32
- | IM 群发图 | `seam({args: ["msg", "group", "--group", "<groupId>", "--image", "<path>"]})` |
33
- | IM 群发文件 | `seam({args: ["msg", "group", "--group", "<groupId>", "--file", "<path>"]})` |
34
- | 微信发图 | `seam({args: ["wechat", "send", "--image", "<path>"]})` |
35
- | 微信发文件 | `seam({args: ["wechat", "send", "--file", "<path>"]})` |
30
+ | IM 私聊发图 | `seam msg send --to <userId> --image <path>` |
31
+ | IM 私聊发文件 | `seam msg send --to <userId> --file <path>` |
32
+ | IM 群发图 | `seam msg group --group <groupId> --image <path>` |
33
+ | IM 群发文件 | `seam msg group --group <groupId> --file <path>` |
34
+ | 微信发图 | `seam wechat send --image <path>` |
35
+ | 微信发文件 | `seam wechat send --file <path>` |
36
36
 
37
37
  `path` 本地绝对路径。`.seam/inbox/` 里收到的文件可以直接转发。
38
38
 
39
39
  ## 长文本
40
40
 
41
- 如果 --text 包含换行或复杂字符,先写入临时文件再用 --text-file
42
- `seam({args: ["msg", "send", "--to", "<userId>", "--text-file", "/tmp/reply.txt"]})`
41
+ 如果回复内容包含换行或复杂字符,先写入临时文件再用 `--text-file`:
42
+ `seam msg send --to <userId> --text-file /tmp/reply.txt`
43
43
 
44
44
  ## 文件处理
45
45
 
@@ -49,8 +49,8 @@
49
49
 
50
50
  ## 心跳和定时任务
51
51
 
52
- 查看/调整心跳:`seam({args: ["self", "list"]})`
53
- 改心跳间隔:`seam({args: ["self", "schedule", "--id", "heartbeat", "--every", "5m"]})`
52
+ 查看/调整心跳:`seam self list`
53
+ 改心跳间隔:`seam self schedule --id heartbeat --every 5m`
54
54
 
55
55
  ## 系统账号 Needle
56
56
 
@@ -68,4 +68,4 @@ npx -p @seamnet/client@latest seam-client upgrade
68
68
 
69
69
  ## 发现更多能力
70
70
 
71
- `seam({args: ["--help"]})` 查看所有可用命令。
71
+ `seam --help` 查看所有可用命令。