echoclaw-relay-agent 0.22.4 → 0.22.5

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/dist/cli.js CHANGED
@@ -97,6 +97,9 @@ function parseArgs(argv) {
97
97
  else if (arg === 'status') {
98
98
  command = 'status';
99
99
  }
100
+ else if (arg === 'restart') {
101
+ command = 'restart';
102
+ }
100
103
  else if (arg === 'uninstall') {
101
104
  command = 'uninstall';
102
105
  }
@@ -171,6 +174,7 @@ ${BOLD}EchoClaw Relay Agent${RESET}
171
174
  ${BOLD}Usage:${RESET}
172
175
  ${CYAN}echoclaw-relay setup <CODE>${RESET} Pair + install as system service (${BOLD}recommended${RESET})
173
176
  ${CYAN}echoclaw-relay status${RESET} Show service status
177
+ ${CYAN}echoclaw-relay restart${RESET} Restart system service
174
178
  ${CYAN}echoclaw-relay uninstall${RESET} Remove system service
175
179
 
176
180
  ${BOLD}Setup Options:${RESET}
@@ -423,6 +427,31 @@ async function runStatus() {
423
427
  }
424
428
  console.log();
425
429
  }
430
+ async function runRestart() {
431
+ printLogo();
432
+ const svc = await getServiceManager();
433
+ const st = await svc.status();
434
+ if (!st.installed) {
435
+ console.log(` ${RED}Service not installed.${RESET}`);
436
+ console.log(` Run ${CYAN}echoclaw-relay setup <CODE>${RESET} first.\n`);
437
+ process.exit(1);
438
+ }
439
+ console.log(` Restarting service...`);
440
+ await svc.restart();
441
+ // Brief wait for process to come up
442
+ await new Promise(r => setTimeout(r, 1500));
443
+ const after = await svc.status();
444
+ if (after.running) {
445
+ console.log(` ${GREEN}${BOLD}Service restarted successfully.${RESET}`);
446
+ if (after.pid)
447
+ console.log(` PID: ${after.pid}`);
448
+ }
449
+ else {
450
+ console.log(` ${YELLOW}Service restarted but may still be starting up.${RESET}`);
451
+ console.log(` Run ${CYAN}echoclaw-relay status${RESET} to check.`);
452
+ }
453
+ console.log();
454
+ }
426
455
  async function runUninstall() {
427
456
  printLogo();
428
457
  const svc = await getServiceManager();
@@ -745,6 +774,9 @@ async function main() {
745
774
  else if (opts.command === 'status') {
746
775
  await runStatus();
747
776
  }
777
+ else if (opts.command === 'restart') {
778
+ await runRestart();
779
+ }
748
780
  else if (opts.command === 'uninstall') {
749
781
  await runUninstall();
750
782
  }
@@ -10,6 +10,7 @@
10
10
  import type { ServiceManager, ServiceStatus, ServiceInstallOptions } from './platform.js';
11
11
  export declare class LaunchdService implements ServiceManager {
12
12
  install(relayServer: string, options?: ServiceInstallOptions): Promise<void>;
13
+ restart(): Promise<void>;
13
14
  uninstall(): Promise<void>;
14
15
  status(): Promise<ServiceStatus>;
15
16
  }
@@ -105,6 +105,14 @@ ${args.map(a => ` <string>${escapeXml(a)}</string>`).join('\n')}
105
105
  await fs.writeFile(PLIST_PATH, plist, 'utf-8');
106
106
  await bootstrapService();
107
107
  }
108
+ async restart() {
109
+ const st = await this.status();
110
+ if (!st.installed) {
111
+ throw new Error('Service not installed. Run setup first.');
112
+ }
113
+ await bootoutService();
114
+ await bootstrapService();
115
+ }
108
116
  async uninstall() {
109
117
  await bootoutService();
110
118
  try {
@@ -10,6 +10,7 @@ export interface ServiceInstallOptions {
10
10
  export interface ServiceManager {
11
11
  install(relayServer: string, options?: ServiceInstallOptions): Promise<void>;
12
12
  uninstall(): Promise<void>;
13
+ restart(): Promise<void>;
13
14
  status(): Promise<ServiceStatus>;
14
15
  }
15
16
  export interface ServiceStatus {
@@ -11,6 +11,7 @@
11
11
  import type { ServiceManager, ServiceStatus, ServiceInstallOptions } from './platform.js';
12
12
  export declare class SystemdService implements ServiceManager {
13
13
  install(relayServer: string, options?: ServiceInstallOptions): Promise<void>;
14
+ restart(): Promise<void>;
14
15
  uninstall(): Promise<void>;
15
16
  status(): Promise<ServiceStatus>;
16
17
  }
@@ -171,6 +171,13 @@ WantedBy=default.target
171
171
  console.log(` ⚠ loginctl enable-linger failed (may require sudo). Service will start on login.`);
172
172
  }
173
173
  }
174
+ async restart() {
175
+ const userSessionOk = await isUserSessionAvailable();
176
+ if (!userSessionOk) {
177
+ throw new Error('systemd user session not available. Try: sudo loginctl enable-linger $(whoami)');
178
+ }
179
+ await execFileAsync('systemctl', ['--user', 'restart', UNIT_NAME]);
180
+ }
174
181
  async uninstall() {
175
182
  try {
176
183
  await execFileAsync('systemctl', ['--user', 'disable', '--now', UNIT_NAME]);
@@ -7,6 +7,7 @@
7
7
  import type { ServiceManager, ServiceStatus, ServiceInstallOptions } from './platform.js';
8
8
  export declare class WindowsService implements ServiceManager {
9
9
  install(relayServer: string, options?: ServiceInstallOptions): Promise<void>;
10
+ restart(): Promise<void>;
10
11
  uninstall(): Promise<void>;
11
12
  status(): Promise<ServiceStatus>;
12
13
  }
@@ -128,6 +128,13 @@ export class WindowsService {
128
128
  }
129
129
  catch { /* may fail if already running */ }
130
130
  }
131
+ async restart() {
132
+ try {
133
+ await execFileAsync('schtasks', ['/End', '/TN', TASK_NAME]);
134
+ }
135
+ catch { /* not running */ }
136
+ await execFileAsync('schtasks', ['/Run', '/TN', TASK_NAME]);
137
+ }
131
138
  async uninstall() {
132
139
  try {
133
140
  await execFileAsync('schtasks', ['/End', '/TN', TASK_NAME]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "echoclaw-relay-agent",
3
- "version": "0.22.4",
3
+ "version": "0.22.5",
4
4
  "description": "EchoClaw Relay Connection — E2E encrypted relay transport, pairing, and session management",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",