@openagents-org/agent-connector 0.2.7 → 0.2.8

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openagents-org/agent-connector",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "description": "Agent management CLI and library for OpenAgents — install, configure, and run AI coding agents",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Autostart — register agent-connector daemon as a system service.
3
+ *
4
+ * - macOS: launchd plist
5
+ * - Linux: systemd user unit
6
+ * - Windows: Task Scheduler XML
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+ const { execSync } = require('child_process');
14
+ const { whichBinary, IS_WINDOWS } = require('./paths');
15
+
16
+ const IS_MACOS = process.platform === 'darwin';
17
+ const IS_LINUX = process.platform === 'linux' && !IS_MACOS;
18
+ const HOME = process.env.HOME || process.env.USERPROFILE || '';
19
+
20
+ const SERVICE_LABEL = 'org.openagents.connector';
21
+
22
+ /**
23
+ * Enable autostart on login.
24
+ */
25
+ function enable(configDir) {
26
+ const nodeBin = whichBinary('node') || process.execPath;
27
+ const cliPath = path.resolve(__dirname, '..', 'bin', 'agent-connector.js');
28
+
29
+ if (IS_MACOS) return _enableMacOS(nodeBin, cliPath, configDir);
30
+ if (IS_LINUX) return _enableLinux(nodeBin, cliPath, configDir);
31
+ if (IS_WINDOWS) return _enableWindows(nodeBin, cliPath, configDir);
32
+ throw new Error(`Autostart not supported on ${process.platform}`);
33
+ }
34
+
35
+ /**
36
+ * Disable autostart.
37
+ */
38
+ function disable() {
39
+ if (IS_MACOS) return _disableMacOS();
40
+ if (IS_LINUX) return _disableLinux();
41
+ if (IS_WINDOWS) return _disableWindows();
42
+ throw new Error(`Autostart not supported on ${process.platform}`);
43
+ }
44
+
45
+ /**
46
+ * Check if autostart is enabled.
47
+ */
48
+ function isEnabled() {
49
+ if (IS_MACOS) {
50
+ const plistPath = path.join(HOME, 'Library', 'LaunchAgents', `${SERVICE_LABEL}.plist`);
51
+ return fs.existsSync(plistPath);
52
+ }
53
+ if (IS_LINUX) {
54
+ const unitPath = path.join(HOME, '.config', 'systemd', 'user', 'openagents-connector.service');
55
+ return fs.existsSync(unitPath);
56
+ }
57
+ if (IS_WINDOWS) {
58
+ try {
59
+ execSync(`schtasks /Query /TN "OpenAgents Connector"`, { stdio: 'pipe', timeout: 5000 });
60
+ return true;
61
+ } catch {
62
+ return false;
63
+ }
64
+ }
65
+ return false;
66
+ }
67
+
68
+ // ---- macOS: launchd ----
69
+
70
+ function _enableMacOS(nodeBin, cliPath, configDir) {
71
+ const plistDir = path.join(HOME, 'Library', 'LaunchAgents');
72
+ fs.mkdirSync(plistDir, { recursive: true });
73
+
74
+ const plistPath = path.join(plistDir, `${SERVICE_LABEL}.plist`);
75
+ const logPath = path.join(configDir, 'daemon.log');
76
+
77
+ const plist = `<?xml version="1.0" encoding="UTF-8"?>
78
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
79
+ <plist version="1.0">
80
+ <dict>
81
+ <key>Label</key>
82
+ <string>${SERVICE_LABEL}</string>
83
+ <key>ProgramArguments</key>
84
+ <array>
85
+ <string>${nodeBin}</string>
86
+ <string>${cliPath}</string>
87
+ <string>up</string>
88
+ <string>--foreground</string>
89
+ </array>
90
+ <key>RunAtLoad</key>
91
+ <true/>
92
+ <key>KeepAlive</key>
93
+ <true/>
94
+ <key>StandardOutPath</key>
95
+ <string>${logPath}</string>
96
+ <key>StandardErrorPath</key>
97
+ <string>${logPath}</string>
98
+ <key>EnvironmentVariables</key>
99
+ <dict>
100
+ <key>PATH</key>
101
+ <string>/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin</string>
102
+ </dict>
103
+ </dict>
104
+ </plist>`;
105
+
106
+ fs.writeFileSync(plistPath, plist, 'utf-8');
107
+ execSync(`launchctl load -w "${plistPath}"`, { stdio: 'pipe', timeout: 5000 });
108
+ return { enabled: true, path: plistPath };
109
+ }
110
+
111
+ function _disableMacOS() {
112
+ const plistPath = path.join(HOME, 'Library', 'LaunchAgents', `${SERVICE_LABEL}.plist`);
113
+ try {
114
+ execSync(`launchctl unload "${plistPath}"`, { stdio: 'pipe', timeout: 5000 });
115
+ } catch {}
116
+ try { fs.unlinkSync(plistPath); } catch {}
117
+ return { enabled: false };
118
+ }
119
+
120
+ // ---- Linux: systemd user unit ----
121
+
122
+ function _enableLinux(nodeBin, cliPath, configDir) {
123
+ const unitDir = path.join(HOME, '.config', 'systemd', 'user');
124
+ fs.mkdirSync(unitDir, { recursive: true });
125
+
126
+ const unitPath = path.join(unitDir, 'openagents-connector.service');
127
+
128
+ const unit = `[Unit]
129
+ Description=OpenAgents Connector Daemon
130
+ After=network.target
131
+
132
+ [Service]
133
+ Type=simple
134
+ ExecStart=${nodeBin} ${cliPath} up --foreground
135
+ Restart=on-failure
136
+ RestartSec=10
137
+ Environment=PATH=/usr/local/bin:/usr/bin:/bin
138
+
139
+ [Install]
140
+ WantedBy=default.target
141
+ `;
142
+
143
+ fs.writeFileSync(unitPath, unit, 'utf-8');
144
+ execSync('systemctl --user daemon-reload', { stdio: 'pipe', timeout: 5000 });
145
+ execSync('systemctl --user enable openagents-connector.service', { stdio: 'pipe', timeout: 5000 });
146
+ execSync('systemctl --user start openagents-connector.service', { stdio: 'pipe', timeout: 5000 });
147
+ return { enabled: true, path: unitPath };
148
+ }
149
+
150
+ function _disableLinux() {
151
+ try {
152
+ execSync('systemctl --user stop openagents-connector.service', { stdio: 'pipe', timeout: 5000 });
153
+ } catch {}
154
+ try {
155
+ execSync('systemctl --user disable openagents-connector.service', { stdio: 'pipe', timeout: 5000 });
156
+ } catch {}
157
+ const unitPath = path.join(HOME, '.config', 'systemd', 'user', 'openagents-connector.service');
158
+ try { fs.unlinkSync(unitPath); } catch {}
159
+ return { enabled: false };
160
+ }
161
+
162
+ // ---- Windows: Task Scheduler ----
163
+
164
+ function _enableWindows(nodeBin, cliPath, configDir) {
165
+ const taskName = 'OpenAgents Connector';
166
+ const cmd = `schtasks /Create /SC ONLOGON /TN "${taskName}" /TR "\\"${nodeBin}\\" \\"${cliPath}\\" up --foreground" /RL HIGHEST /F`;
167
+ execSync(cmd, { stdio: 'pipe', timeout: 10000 });
168
+ return { enabled: true, method: 'Task Scheduler' };
169
+ }
170
+
171
+ function _disableWindows() {
172
+ try {
173
+ execSync('schtasks /Delete /TN "OpenAgents Connector" /F', { stdio: 'pipe', timeout: 5000 });
174
+ } catch {}
175
+ return { enabled: false };
176
+ }
177
+
178
+ module.exports = { enable, disable, isEnabled };
package/src/cli.js CHANGED
@@ -327,6 +327,17 @@ async function cmdLogs(connector, flags, positional) {
327
327
  }
328
328
  }
329
329
 
330
+ async function cmdAutostart(connector, flags) {
331
+ const autostart = require('./autostart');
332
+ if (flags.disable) {
333
+ autostart.disable();
334
+ print('Autostart disabled.');
335
+ } else {
336
+ const result = autostart.enable(connector._config ? connector._config.configDir : require('path').join(require('os').homedir(), '.openagents'));
337
+ print(`Autostart enabled.${result.path ? ` Config: ${result.path}` : ''}`);
338
+ }
339
+ }
340
+
330
341
  async function cmdWorkspace(connector, flags, positional) {
331
342
  const sub = positional[0] || 'list';
332
343
  const subArgs = positional.slice(1);
@@ -461,6 +472,7 @@ Commands:
461
472
  connect <agent> <token> Connect agent to workspace
462
473
  disconnect <agent> Disconnect agent from workspace
463
474
  env <type> [--set K=V] View/set env vars for agent type
475
+ autostart [--disable] Enable/disable auto-start on login
464
476
  test-llm <type> Test LLM connection
465
477
  logs [agent] [--lines N] View daemon logs
466
478
  workspace create [name] Create a new workspace
@@ -502,6 +514,7 @@ async function main() {
502
514
  connect: () => cmdConnect(connector, flags, positional),
503
515
  disconnect: () => cmdDisconnect(connector, flags, positional),
504
516
  logs: () => cmdLogs(connector, flags, positional),
517
+ autostart: () => cmdAutostart(connector, flags),
505
518
  workspace: () => cmdWorkspace(connector, flags, positional),
506
519
  env: () => cmdEnv(connector, flags, positional),
507
520
  'test-llm': () => cmdTestLLM(connector, flags, positional),
package/src/installer.js CHANGED
@@ -235,13 +235,18 @@ class Installer {
235
235
  env.PATH = execDir + sep + (env.PATH || '');
236
236
  }
237
237
 
238
- // On Windows, force UTF-8 codepage to avoid GBK garbled output
239
- const shellCmd = process.platform === 'win32' ? `chcp 65001 >nul && ${cmd}` : cmd;
238
+ // On Windows, use cmd.exe explicitly with UTF-8 codepage
239
+ let shellCmd = cmd;
240
+ let shellOpt = true;
241
+ if (process.platform === 'win32') {
242
+ shellCmd = `cmd.exe /C "chcp 65001 >nul & ${cmd}"`;
243
+ shellOpt = false; // we're specifying the shell ourselves
244
+ }
240
245
 
241
246
  exec(shellCmd, {
242
247
  encoding: 'utf-8',
243
248
  timeout: timeoutMs,
244
- shell: true,
249
+ shell: shellOpt,
245
250
  env,
246
251
  }, (error, stdout, stderr) => {
247
252
  const output = ((stdout || '') + '\n' + (stderr || '')).trim();