@seamnet/client 0.3.4 → 0.3.6
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 +9 -1
- package/lib/mcp-server.cjs +18 -5
- package/lib/plugins/im.cjs +18 -9
- package/package.json +1 -1
package/lib/guardian.js
CHANGED
|
@@ -33,11 +33,17 @@ export async function guardianStart() {
|
|
|
33
33
|
// Ensure logs dir
|
|
34
34
|
if (!existsSync(LOGS_DIR)) mkdirSync(LOGS_DIR, { recursive: true });
|
|
35
35
|
|
|
36
|
+
// Detect CC's tmux session for message injection
|
|
37
|
+
let ccSession = '';
|
|
38
|
+
try {
|
|
39
|
+
ccSession = execSync("tmux display-message -p '#S'", { encoding: 'utf8' }).trim();
|
|
40
|
+
} catch {}
|
|
41
|
+
|
|
36
42
|
// Start guardian in tmux — use local node_modules path
|
|
37
43
|
const cwd = process.cwd();
|
|
38
44
|
const localCli = join(cwd, 'node_modules', '@seamnet', 'client', 'bin', 'cli.js');
|
|
39
45
|
execSync(
|
|
40
|
-
`tmux new-session -d -s ${sessionName} 'cd ${cwd} && node ${localCli} guardian run 2>&1 | tee -a ${join(LOGS_DIR, 'guardian.log')}'`,
|
|
46
|
+
`tmux new-session -d -s ${sessionName} 'cd ${cwd} && SEAM_CC_SESSION=${ccSession} node ${localCli} guardian run 2>&1 | tee -a ${join(LOGS_DIR, 'guardian.log')}'`,
|
|
41
47
|
{ stdio: 'inherit' }
|
|
42
48
|
);
|
|
43
49
|
|
|
@@ -60,10 +66,12 @@ export async function guardianRun() {
|
|
|
60
66
|
const { createRequire } = await import('node:module');
|
|
61
67
|
const require = createRequire(import.meta.url);
|
|
62
68
|
const { createImPlugin } = require('./plugins/im.cjs');
|
|
69
|
+
const ccSession = process.env.SEAM_CC_SESSION || '';
|
|
63
70
|
const imPlugin = await createImPlugin({
|
|
64
71
|
credentials: creds,
|
|
65
72
|
socketPath: SOCKET_PATH,
|
|
66
73
|
seamDir: SEAM_DIR,
|
|
74
|
+
ccSession,
|
|
67
75
|
});
|
|
68
76
|
|
|
69
77
|
console.log(`[guardian] Running. Socket: ${SOCKET_PATH}`);
|
package/lib/mcp-server.cjs
CHANGED
|
@@ -14,16 +14,29 @@ const SOCKET_PATH = path.join(SEAM_DIR, 'guardian.sock');
|
|
|
14
14
|
function guardianRequest(payload) {
|
|
15
15
|
return new Promise((resolve, reject) => {
|
|
16
16
|
const conn = net.createConnection(SOCKET_PATH, () => {
|
|
17
|
-
conn.
|
|
17
|
+
conn.write(JSON.stringify(payload)); // write, not end — keep connection open for response
|
|
18
18
|
});
|
|
19
19
|
let data = '';
|
|
20
|
-
conn.on('data', (chunk) => {
|
|
20
|
+
conn.on('data', (chunk) => {
|
|
21
|
+
data += chunk;
|
|
22
|
+
// Try to parse response
|
|
23
|
+
try {
|
|
24
|
+
const res = JSON.parse(data);
|
|
25
|
+
conn.destroy();
|
|
26
|
+
resolve(res);
|
|
27
|
+
} catch {
|
|
28
|
+
// Not complete yet
|
|
29
|
+
}
|
|
30
|
+
});
|
|
21
31
|
conn.on('end', () => {
|
|
22
|
-
|
|
23
|
-
|
|
32
|
+
if (data) {
|
|
33
|
+
try { resolve(JSON.parse(data)); } catch { resolve({ error: data }); }
|
|
34
|
+
} else {
|
|
35
|
+
resolve({ error: 'Empty response from guardian' });
|
|
36
|
+
}
|
|
24
37
|
});
|
|
25
38
|
conn.on('error', (e) => {
|
|
26
|
-
reject(new Error(`Guardian not running. Start it first:
|
|
39
|
+
reject(new Error(`Guardian not running. Start it first: node node_modules/@seamnet/client/bin/cli.js guardian start`));
|
|
27
40
|
});
|
|
28
41
|
conn.setTimeout(10000, () => {
|
|
29
42
|
conn.destroy();
|
package/lib/plugins/im.cjs
CHANGED
|
@@ -52,7 +52,7 @@ if (!Module.prototype._imPatched) {
|
|
|
52
52
|
};
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
function createImPlugin({ credentials, socketPath, seamDir }) {
|
|
55
|
+
function createImPlugin({ credentials, socketPath, seamDir, ccSession }) {
|
|
56
56
|
return new Promise((resolve) => {
|
|
57
57
|
const SDK_APP_ID = Number(credentials.sdkAppId);
|
|
58
58
|
const USER_ID = credentials.userId;
|
|
@@ -117,11 +117,15 @@ function createImPlugin({ credentials, socketPath, seamDir }) {
|
|
|
117
117
|
});
|
|
118
118
|
|
|
119
119
|
function injectToTerminal(text) {
|
|
120
|
+
if (!ccSession) {
|
|
121
|
+
console.error('[im-plugin] inject skipped: no CC session configured');
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
120
124
|
try {
|
|
121
125
|
const { execFileSync } = require('child_process');
|
|
122
|
-
// Use execFileSync to avoid shell injection — text is passed as argument, not shell-interpolated
|
|
123
126
|
const sanitized = text.replace(/[\x00-\x1f]/g, ' ').slice(0, 2000);
|
|
124
|
-
execFileSync('tmux', ['send-keys',
|
|
127
|
+
execFileSync('tmux', ['send-keys', '-t', ccSession, sanitized], { stdio: 'ignore', timeout: 5000 });
|
|
128
|
+
execFileSync('tmux', ['send-keys', '-t', ccSession, 'Enter'], { stdio: 'ignore', timeout: 5000 });
|
|
125
129
|
} catch (e) {
|
|
126
130
|
console.error(`[im-plugin] inject failed: ${e.message}`);
|
|
127
131
|
}
|
|
@@ -141,16 +145,21 @@ function createImPlugin({ credentials, socketPath, seamDir }) {
|
|
|
141
145
|
|
|
142
146
|
const server = net.createServer((conn) => {
|
|
143
147
|
let data = '';
|
|
144
|
-
conn.on('data', (chunk) => {
|
|
145
|
-
|
|
148
|
+
conn.on('data', (chunk) => {
|
|
149
|
+
data += chunk;
|
|
150
|
+
// Try to parse as complete JSON
|
|
146
151
|
try {
|
|
147
152
|
const req = JSON.parse(data);
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
153
|
+
handleRequest(req).then(res => {
|
|
154
|
+
conn.end(JSON.stringify(res));
|
|
155
|
+
}).catch(e => {
|
|
156
|
+
conn.end(JSON.stringify({ error: e.message }));
|
|
157
|
+
});
|
|
158
|
+
} catch {
|
|
159
|
+
// Not complete JSON yet, wait for more data
|
|
152
160
|
}
|
|
153
161
|
});
|
|
162
|
+
conn.on('error', () => {}); // Ignore connection errors
|
|
154
163
|
});
|
|
155
164
|
|
|
156
165
|
server.listen(socketPath, () => {
|