@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 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}`);
@@ -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.end(JSON.stringify(payload));
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) => { 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
- try { resolve(JSON.parse(data)); }
23
- catch { resolve({ error: data || 'Empty response' }); }
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: npx @seamnet/client guardian start`));
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();
@@ -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', sanitized, 'Enter'], { stdio: 'ignore', timeout: 5000 });
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) => { data += chunk; });
145
- conn.on('end', async () => {
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
- const res = await handleRequest(req);
149
- conn.end(JSON.stringify(res));
150
- } catch (e) {
151
- try { conn.end(JSON.stringify({ error: e.message })); } catch {}
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, () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@seamnet/client",
3
- "version": "0.3.4",
3
+ "version": "0.3.6",
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"