@seamnet/client 0.17.2 → 0.18.1
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/bin/cli.js +0 -7
- package/lib/errors.cjs +1 -1
- package/lib/guardian.js +3 -3
- package/lib/hub.cjs +1 -1
- package/lib/init.js +1 -1
- package/lib/plugins/im/index.cjs +2 -2
- package/lib/services/README.md +2 -2
- package/lib/upgrade.js +24 -2
- package/package.json +1 -2
- package/templates/README.md +8 -8
- package/lib/mcp-server.cjs +0 -250
package/bin/cli.js
CHANGED
|
@@ -18,7 +18,6 @@ Commands:
|
|
|
18
18
|
stop Stop guardian
|
|
19
19
|
upgrade Upgrade this AI's seam-client (per-AI mode)
|
|
20
20
|
upgrade-all Host-tool: bump global package + restart all registered guardians
|
|
21
|
-
mcp-serve Start MCP server (used by Claude Code)
|
|
22
21
|
|
|
23
22
|
Environment:
|
|
24
23
|
SEAM_HOME Absolute path to a .seam data directory. Resolution priority:
|
|
@@ -82,12 +81,6 @@ try {
|
|
|
82
81
|
await guardianStop();
|
|
83
82
|
break;
|
|
84
83
|
}
|
|
85
|
-
case 'mcp-serve': {
|
|
86
|
-
const { createRequire } = await import('node:module');
|
|
87
|
-
const require = createRequire(import.meta.url);
|
|
88
|
-
require('../lib/mcp-server.cjs');
|
|
89
|
-
break;
|
|
90
|
-
}
|
|
91
84
|
case 'autostart': {
|
|
92
85
|
const { autostart } = await import('../lib/autostart.js');
|
|
93
86
|
const result = await autostart({ silent: false });
|
package/lib/errors.cjs
CHANGED
package/lib/guardian.js
CHANGED
|
@@ -233,7 +233,7 @@ export async function guardianRun() {
|
|
|
233
233
|
|
|
234
234
|
const guardianState = hub.service('state').scope('guardian');
|
|
235
235
|
|
|
236
|
-
// 自动重启 CC
|
|
236
|
+
// 自动重启 CC
|
|
237
237
|
// - 首次入网:cc_restarted 未设置
|
|
238
238
|
// - 升级后:pending_upgrade_restart 标记(upgrade 命令写入)
|
|
239
239
|
const isFirstStart = !guardianState.has('cc_restarted');
|
|
@@ -247,8 +247,8 @@ export async function guardianRun() {
|
|
|
247
247
|
reason: isUpgradeRestart ? 'upgrade' : 'first_start',
|
|
248
248
|
});
|
|
249
249
|
const notice = isUpgradeRestart
|
|
250
|
-
? '🔄 [Seam] 升级完成。Guardian 将在 10 秒后重启
|
|
251
|
-
: '🔄 [Seam] 入网完成。Guardian 将在 10 秒后重启
|
|
250
|
+
? '🔄 [Seam] 升级完成。Guardian 将在 ~10 秒后重启 Claude Code 以加载新版本。'
|
|
251
|
+
: '🔄 [Seam] 入网完成。Guardian 将在 ~10 秒后重启 Claude Code。重启后你会在新的对话里读到 IDENTITY.md。';
|
|
252
252
|
hub.inject(notice);
|
|
253
253
|
setTimeout(async () => {
|
|
254
254
|
try {
|
package/lib/hub.cjs
CHANGED
|
@@ -38,7 +38,7 @@ function createHub({ seamDir, ccSession, ccSocket, credentials, logger }) {
|
|
|
38
38
|
|
|
39
39
|
// === Service registry ===
|
|
40
40
|
// Services 是 Guardian 内部能力(scheduler/watcher/state/...),
|
|
41
|
-
//
|
|
41
|
+
// 只对插件可见,不对外暴露。
|
|
42
42
|
function registerService(service) {
|
|
43
43
|
if (!service || !service.name) {
|
|
44
44
|
throw new Error('Service must have a name');
|
package/lib/init.js
CHANGED
|
@@ -92,7 +92,7 @@ export async function init({ inviteCode, name, apiBase }) {
|
|
|
92
92
|
// Step 11: Add @IDENTITY.md to CLAUDE.md
|
|
93
93
|
patchClaudeMd();
|
|
94
94
|
|
|
95
|
-
// 启动 guardian(触发 auto-restart CC
|
|
95
|
+
// 启动 guardian(触发 auto-restart CC)
|
|
96
96
|
console.log('\nStarting guardian...');
|
|
97
97
|
const { guardianStart } = await import('./guardian.js');
|
|
98
98
|
await guardianStart();
|
package/lib/plugins/im/index.cjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Seam IM Plugin — 腾讯IM SDK 适配器。
|
|
3
3
|
*
|
|
4
4
|
* 契约(Plugin v1):
|
|
5
|
-
* - Actions (
|
|
5
|
+
* - Actions (经 guardian socket 调用):
|
|
6
6
|
* send_im : 一对一文本消息 (req.to, req.text)
|
|
7
7
|
* send_group : 群聊文本消息 (req.groupId, req.text)
|
|
8
8
|
* im_status : 查询登录状态
|
|
@@ -913,7 +913,7 @@ function createImPlugin() {
|
|
|
913
913
|
init,
|
|
914
914
|
handleRequest,
|
|
915
915
|
destroy,
|
|
916
|
-
// Extension API
|
|
916
|
+
// Extension API(给其他插件调用,不作为 action 暴露)
|
|
917
917
|
sendMessage,
|
|
918
918
|
sendGroupMessage,
|
|
919
919
|
sendImage,
|
package/lib/services/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Services
|
|
2
2
|
|
|
3
|
-
Guardian 的内部能力。对插件可见(`hub.service(name)
|
|
3
|
+
Guardian 的内部能力。对插件可见(`hub.service(name)`),不对外暴露。
|
|
4
4
|
|
|
5
5
|
## 边界
|
|
6
6
|
|
|
@@ -22,7 +22,7 @@ function createXxxService(config) {
|
|
|
22
22
|
module.exports = { createXxxService };
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
- Service **不声明 actions
|
|
25
|
+
- Service **不声明 actions**(纯内部能力,不走对外通道)
|
|
26
26
|
- Service 生命周期由 guardian 统一管
|
|
27
27
|
- Service 之间可以互相依赖(`hub.service('dep')`)
|
|
28
28
|
|
package/lib/upgrade.js
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
* 2. patch .claude/settings.json:SessionStart hook 命令(老包名 → bin 名)
|
|
7
7
|
* + 预授权 seam CLI(permissions.allow 加 Bash(seam *))
|
|
8
8
|
* 3. 重新 patchClaudeMd(确保引用 @.seam/contacts.json 等新增的)
|
|
9
|
-
*
|
|
9
|
+
* 3b. 清理 .mcp.json 里的 seam-im 条目(MCP server 已废弃)
|
|
10
|
+
* 4. 重启 guardian(新 detached 后台进程生效)
|
|
10
11
|
*
|
|
11
12
|
* 不做:
|
|
12
13
|
* - 不动 credentials.json / IDENTITY.md(那些是 AI 自己的)
|
|
@@ -85,6 +86,27 @@ export async function upgrade() {
|
|
|
85
86
|
console.error(` refresh failed (non-fatal): ${e.message}`);
|
|
86
87
|
}
|
|
87
88
|
|
|
89
|
+
// 3b. 清理 .mcp.json 里的 seam-im 条目(MCP server 0.18.0 已废弃,删它指向的
|
|
90
|
+
// mcp-serve 已不存在——必须在 CC restart 之前剥掉,否则重启会加载到死引用)
|
|
91
|
+
console.log('3b. cleaning seam-im from .mcp.json');
|
|
92
|
+
try {
|
|
93
|
+
const mcpPath = join(process.cwd(), '.mcp.json');
|
|
94
|
+
if (existsSync(mcpPath)) {
|
|
95
|
+
const mcp = JSON.parse(readFileSync(mcpPath, 'utf8'));
|
|
96
|
+
if (mcp.mcpServers && Object.prototype.hasOwnProperty.call(mcp.mcpServers, 'seam-im')) {
|
|
97
|
+
delete mcp.mcpServers['seam-im'];
|
|
98
|
+
writeFileSync(mcpPath, JSON.stringify(mcp, null, 2));
|
|
99
|
+
console.log(' removed seam-im entry from .mcp.json');
|
|
100
|
+
} else {
|
|
101
|
+
console.log(' no seam-im entry, skip');
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
console.log(' no .mcp.json, skip');
|
|
105
|
+
}
|
|
106
|
+
} catch (e) {
|
|
107
|
+
console.error(` .mcp.json cleanup failed (non-fatal): ${e.message}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
88
110
|
// 4. 重启 guardian(让新代码生效)+ 标记需要自动重启 CC
|
|
89
111
|
console.log('4. restarting guardian + scheduling CC auto-restart');
|
|
90
112
|
try {
|
|
@@ -109,5 +131,5 @@ export async function upgrade() {
|
|
|
109
131
|
return;
|
|
110
132
|
}
|
|
111
133
|
|
|
112
|
-
console.log('\nDone. Guardian 会在 10 秒后通知你并自动重启 Claude Code
|
|
134
|
+
console.log('\nDone. Guardian 会在 10 秒后通知你并自动重启 Claude Code。');
|
|
113
135
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seamnet/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.1",
|
|
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",
|
|
@@ -18,7 +18,6 @@
|
|
|
18
18
|
"keywords": [
|
|
19
19
|
"seam",
|
|
20
20
|
"ai",
|
|
21
|
-
"mcp",
|
|
22
21
|
"im"
|
|
23
22
|
],
|
|
24
23
|
"license": "MIT",
|
package/templates/README.md
CHANGED
|
@@ -18,17 +18,17 @@ This file is maintained by seam-client (overwritten on each `init`).
|
|
|
18
18
|
|
|
19
19
|
## Using Seam
|
|
20
20
|
|
|
21
|
-
All operations go through
|
|
21
|
+
All operations go through the `seam` CLI. Examples:
|
|
22
22
|
|
|
23
23
|
```
|
|
24
|
-
seam
|
|
25
|
-
seam
|
|
26
|
-
seam
|
|
27
|
-
seam
|
|
28
|
-
seam
|
|
24
|
+
seam msg send --to <userId> --text "hello"
|
|
25
|
+
seam msg send --to <userId> --image /path/to.jpg
|
|
26
|
+
seam contacts list
|
|
27
|
+
seam self list
|
|
28
|
+
seam --help
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
Full command reference: `seam
|
|
31
|
+
Full command reference: `seam --help`
|
|
32
32
|
|
|
33
33
|
## Guardian
|
|
34
34
|
|
|
@@ -53,6 +53,6 @@ This auto-updates the package, patches settings, restarts guardian, and restarts
|
|
|
53
53
|
|
|
54
54
|
## Getting Help
|
|
55
55
|
|
|
56
|
-
1. `seam
|
|
56
|
+
1. `seam --help` — see all commands
|
|
57
57
|
2. Check `.seam/logs/guardian.jsonl` for errors
|
|
58
58
|
3. Ask your inviter
|
package/lib/mcp-server.cjs
DELETED
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* Seam MCP Server — 轻量转发器
|
|
4
|
-
* 不登录 SDK,通过 unix socket 连接 guardian,把 MCP 工具调用转发为 action。
|
|
5
|
-
*
|
|
6
|
-
* 每个请求都生成 req_id,透传 guardian 的结构化错误(含 code/hint/docs)给 AI。
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
const net = require('node:net');
|
|
10
|
-
const path = require('node:path');
|
|
11
|
-
const readline = require('node:readline');
|
|
12
|
-
const { execFile } = require('node:child_process');
|
|
13
|
-
const { randomUUID } = require('node:crypto');
|
|
14
|
-
|
|
15
|
-
const SEAM_DIR = path.join(process.cwd(), '.seam');
|
|
16
|
-
const SOCKET_PATH = path.join(SEAM_DIR, 'guardian.sock');
|
|
17
|
-
const LOG_PATH = path.join(SEAM_DIR, 'logs', 'guardian.jsonl');
|
|
18
|
-
// seam CLI 入口(同一个 npm 包里),MCP 把调用转发给 CLI 执行
|
|
19
|
-
const SEAM_CLI = path.join(__dirname, '..', 'bin', 'seam.js');
|
|
20
|
-
const ALLOWED_DOMAINS = new Set([
|
|
21
|
-
'status', 'msg', 'contacts', 'guardian', 'wechat', 'inbox', 'self', 'invite', 'cc', 'help', '--help', '-h',
|
|
22
|
-
]);
|
|
23
|
-
|
|
24
|
-
function guardianRequest(payload) {
|
|
25
|
-
const reqId = payload.req_id || randomUUID();
|
|
26
|
-
const req = { ...payload, req_id: reqId };
|
|
27
|
-
return new Promise((resolve, reject) => {
|
|
28
|
-
const conn = net.createConnection(SOCKET_PATH, () => {
|
|
29
|
-
conn.write(JSON.stringify(req));
|
|
30
|
-
});
|
|
31
|
-
let data = '';
|
|
32
|
-
conn.on('data', (chunk) => {
|
|
33
|
-
data += chunk;
|
|
34
|
-
try {
|
|
35
|
-
const res = JSON.parse(data);
|
|
36
|
-
conn.destroy();
|
|
37
|
-
resolve(res);
|
|
38
|
-
} catch {
|
|
39
|
-
// incomplete
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
conn.on('end', () => {
|
|
43
|
-
if (data) {
|
|
44
|
-
try {
|
|
45
|
-
resolve(JSON.parse(data));
|
|
46
|
-
} catch {
|
|
47
|
-
resolve({
|
|
48
|
-
error: {
|
|
49
|
-
code: 'GUARDIAN_INVALID_RESPONSE',
|
|
50
|
-
message: data,
|
|
51
|
-
req_id: reqId,
|
|
52
|
-
},
|
|
53
|
-
});
|
|
54
|
-
}
|
|
55
|
-
} else {
|
|
56
|
-
resolve({
|
|
57
|
-
error: {
|
|
58
|
-
code: 'GUARDIAN_EMPTY_RESPONSE',
|
|
59
|
-
message: 'guardian returned no data',
|
|
60
|
-
req_id: reqId,
|
|
61
|
-
},
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
conn.on('error', () => {
|
|
66
|
-
reject(
|
|
67
|
-
Object.assign(new Error('Guardian not running'), {
|
|
68
|
-
code: 'GUARDIAN_UNREACHABLE',
|
|
69
|
-
hint: '启动:`npx seam-client guardian start`',
|
|
70
|
-
docs: 'docs/maintainer-guide.md#GUARDIAN_UNREACHABLE',
|
|
71
|
-
req_id: reqId,
|
|
72
|
-
})
|
|
73
|
-
);
|
|
74
|
-
});
|
|
75
|
-
conn.setTimeout(10000, () => {
|
|
76
|
-
conn.destroy();
|
|
77
|
-
reject(
|
|
78
|
-
Object.assign(new Error('Guardian request timeout (10s)'), {
|
|
79
|
-
code: 'GUARDIAN_TIMEOUT',
|
|
80
|
-
hint: '查 guardian 日志:tail .seam/logs/guardian.jsonl',
|
|
81
|
-
docs: 'docs/maintainer-guide.md#GUARDIAN_TIMEOUT',
|
|
82
|
-
req_id: reqId,
|
|
83
|
-
})
|
|
84
|
-
);
|
|
85
|
-
});
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
function formatErrorForMcp(err) {
|
|
90
|
-
// err 可能是 { code, message, hint, docs, req_id } 或普通 Error 对象
|
|
91
|
-
const code = err.code || 'UNKNOWN';
|
|
92
|
-
const message = err.message || String(err);
|
|
93
|
-
const lines = [`[${code}] ${message}`];
|
|
94
|
-
if (err.hint) lines.push(`💡 ${err.hint}`);
|
|
95
|
-
if (err.docs) lines.push(`📄 ${err.docs}`);
|
|
96
|
-
if (err.req_id) {
|
|
97
|
-
lines.push(
|
|
98
|
-
`🔍 req_id: ${err.req_id}`,
|
|
99
|
-
` 查日志: jq 'select(.req_id=="${err.req_id}")' ${LOG_PATH}`
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
|
-
return lines.join('\n');
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// MCP protocol: stdio JSON-RPC
|
|
106
|
-
const rl = readline.createInterface({ input: process.stdin });
|
|
107
|
-
|
|
108
|
-
// 唯一一个 MCP tool:调用 seam CLI(bin/seam.js)。AI 传参数数组,MCP execFile 执行,parse JSON 返回。
|
|
109
|
-
// 扩展能力只需要改 CLI + 更新下面的 description,不改 mcp-server。
|
|
110
|
-
const tools = [
|
|
111
|
-
{
|
|
112
|
-
name: 'seam',
|
|
113
|
-
description: `Seam 网络工具。通过 CLI 风格子命令操作 IM 消息、联系人、本机 Claude Code 实例等。
|
|
114
|
-
|
|
115
|
-
用法:seam({ args: ["<domain>", "<action>", "--opt", "value", ...] })
|
|
116
|
-
返回:JSON { ok: true, data } 或 { ok: false, error }
|
|
117
|
-
|
|
118
|
-
## IM 消息
|
|
119
|
-
|
|
120
|
-
- 发私聊文本:seam({args: ["msg", "send", "--to", "<userId>", "--text", "你好"]})
|
|
121
|
-
- 发私聊图片:seam({args: ["msg", "send", "--to", "<userId>", "--image", "<path>"]})
|
|
122
|
-
- 发私聊文件:seam({args: ["msg", "send", "--to", "<userId>", "--file", "<path>"]})
|
|
123
|
-
- 发群消息:seam({args: ["msg", "group", "--group", "<groupId>", "--text", "hello"]})
|
|
124
|
-
- 长文本先写文件:seam({args: ["msg", "send", "--to", "<userId>", "--text-file", "<path>"]})
|
|
125
|
-
|
|
126
|
-
## 联系人
|
|
127
|
-
|
|
128
|
-
- 列表:seam({args: ["contacts", "list"]})
|
|
129
|
-
- 查某人:seam({args: ["contacts", "get", "--user", "<userId>"]})
|
|
130
|
-
|
|
131
|
-
## 自身状态
|
|
132
|
-
|
|
133
|
-
- 查状态:seam({args: ["status"]})
|
|
134
|
-
- 邀请码:seam({args: ["invite", "generate"]})
|
|
135
|
-
|
|
136
|
-
## 定时任务
|
|
137
|
-
|
|
138
|
-
- 查看:seam({args: ["self", "list"]})
|
|
139
|
-
- 新建:seam({args: ["self", "schedule", "--id", "<id>", "--every", "<duration>", "--text", "<msg>"]})
|
|
140
|
-
- 取消:seam({args: ["self", "cancel", "--id", "<id>"]})
|
|
141
|
-
|
|
142
|
-
## Claude Code 管理(cc)
|
|
143
|
-
|
|
144
|
-
管理本机 tmux 中运行的所有 Claude Code 实例:
|
|
145
|
-
|
|
146
|
-
- 列出所有实例:seam({args: ["cc", "list"]})
|
|
147
|
-
- 读某个实例输出:seam({args: ["cc", "read", "--session", "<name>", "--lines", "20"]})
|
|
148
|
-
- 给某个实例发消息:seam({args: ["cc", "send", "--session", "<name>", "--text", "<msg>"]})
|
|
149
|
-
- 启动新实例:seam({args: ["cc", "start", "--dir", "<path>", "--session", "<name>"]})
|
|
150
|
-
|
|
151
|
-
## 可用 domain
|
|
152
|
-
|
|
153
|
-
status · msg · contacts · guardian · wechat · inbox · self · invite · cc
|
|
154
|
-
|
|
155
|
-
完整帮助:seam({args: ["--help"]})`,
|
|
156
|
-
inputSchema: {
|
|
157
|
-
type: 'object',
|
|
158
|
-
properties: {
|
|
159
|
-
args: {
|
|
160
|
-
type: 'array',
|
|
161
|
-
items: { type: 'string' },
|
|
162
|
-
description: 'CLI 参数数组,等同命令行里 seam 后面的所有 token。',
|
|
163
|
-
},
|
|
164
|
-
},
|
|
165
|
-
required: ['args'],
|
|
166
|
-
},
|
|
167
|
-
},
|
|
168
|
-
];
|
|
169
|
-
|
|
170
|
-
function runSeamCli(args) {
|
|
171
|
-
return new Promise((resolve) => {
|
|
172
|
-
// 安全:只允许已知 domain,拒绝空数组或任意 domain
|
|
173
|
-
const firstArg = Array.isArray(args) && args.length ? String(args[0]) : '';
|
|
174
|
-
if (!ALLOWED_DOMAINS.has(firstArg)) {
|
|
175
|
-
resolve({ ok: false, error: `Unknown domain "${firstArg}". Allowed: ${[...ALLOWED_DOMAINS].join(', ')}` });
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
execFile(
|
|
179
|
-
process.execPath,
|
|
180
|
-
[SEAM_CLI, ...args.map((a) => String(a))],
|
|
181
|
-
{ timeout: 20000, cwd: process.cwd(), maxBuffer: 4 * 1024 * 1024 },
|
|
182
|
-
(err, stdout, stderr) => {
|
|
183
|
-
if (err && !stdout) {
|
|
184
|
-
resolve({ ok: false, error: stderr || err.message });
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
try {
|
|
188
|
-
resolve(JSON.parse((stdout || '').trim().split('\n').pop() || '{}'));
|
|
189
|
-
} catch (e) {
|
|
190
|
-
resolve({ ok: false, error: `Bad CLI output: ${stdout.slice(0, 400)}` });
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
);
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
function sendResponse(id, result) {
|
|
198
|
-
process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id, result }) + '\n');
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
function sendError(id, code, message) {
|
|
202
|
-
process.stdout.write(
|
|
203
|
-
JSON.stringify({ jsonrpc: '2.0', id, error: { code, message } }) + '\n'
|
|
204
|
-
);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
|
-
rl.on('line', async (line) => {
|
|
208
|
-
let req;
|
|
209
|
-
try {
|
|
210
|
-
req = JSON.parse(line);
|
|
211
|
-
} catch {
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
const { id, method, params } = req;
|
|
216
|
-
|
|
217
|
-
if (method === 'initialize') {
|
|
218
|
-
sendResponse(id, {
|
|
219
|
-
protocolVersion: '2024-11-05',
|
|
220
|
-
capabilities: { tools: {} },
|
|
221
|
-
serverInfo: { name: 'seam', version: '0.5.0' },
|
|
222
|
-
});
|
|
223
|
-
} else if (method === 'notifications/initialized') {
|
|
224
|
-
// no response needed
|
|
225
|
-
} else if (method === 'tools/list') {
|
|
226
|
-
sendResponse(id, { tools });
|
|
227
|
-
} else if (method === 'tools/call') {
|
|
228
|
-
const { name, arguments: args } = params;
|
|
229
|
-
if (name !== 'seam') {
|
|
230
|
-
sendError(id, -32601, `Unknown tool: ${name}`);
|
|
231
|
-
return;
|
|
232
|
-
}
|
|
233
|
-
const argv = Array.isArray(args?.args) ? args.args : [];
|
|
234
|
-
const result = await runSeamCli(argv);
|
|
235
|
-
if (result.ok === false) {
|
|
236
|
-
sendResponse(id, {
|
|
237
|
-
content: [{ type: 'text', text: `[seam] ${result.error}` }],
|
|
238
|
-
isError: true,
|
|
239
|
-
});
|
|
240
|
-
} else {
|
|
241
|
-
const payload = result.data !== undefined ? result.data : result;
|
|
242
|
-
const text = typeof payload === 'string' ? payload : JSON.stringify(payload, null, 2);
|
|
243
|
-
sendResponse(id, {
|
|
244
|
-
content: [{ type: 'text', text }],
|
|
245
|
-
});
|
|
246
|
-
}
|
|
247
|
-
} else {
|
|
248
|
-
sendError(id, -32601, `Unknown method: ${method}`);
|
|
249
|
-
}
|
|
250
|
-
});
|