@sonde/agent 0.2.6 → 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.
Files changed (47) hide show
  1. package/.turbo/turbo-build.log +6 -4
  2. package/.turbo/turbo-test.log +65 -23
  3. package/CHANGELOG.md +20 -0
  4. package/dist/cli/service.d.ts +12 -0
  5. package/dist/cli/service.d.ts.map +1 -0
  6. package/dist/cli/service.js +164 -0
  7. package/dist/cli/service.js.map +1 -0
  8. package/dist/cli/service.test.d.ts +2 -0
  9. package/dist/cli/service.test.d.ts.map +1 -0
  10. package/dist/cli/service.test.js +99 -0
  11. package/dist/cli/service.test.js.map +1 -0
  12. package/dist/cli/update.d.ts.map +1 -1
  13. package/dist/cli/update.js +11 -8
  14. package/dist/cli/update.js.map +1 -1
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +60 -12
  17. package/dist/index.js.map +1 -1
  18. package/dist/tui/installer/InstallerApp.d.ts.map +1 -1
  19. package/dist/tui/installer/InstallerApp.js +3 -1
  20. package/dist/tui/installer/InstallerApp.js.map +1 -1
  21. package/dist/tui/installer/StepService.d.ts +6 -0
  22. package/dist/tui/installer/StepService.d.ts.map +1 -0
  23. package/dist/tui/installer/StepService.js +49 -0
  24. package/dist/tui/installer/StepService.js.map +1 -0
  25. package/dist/tui/status/PackToggleView.d.ts +15 -0
  26. package/dist/tui/status/PackToggleView.d.ts.map +1 -0
  27. package/dist/tui/status/PackToggleView.js +30 -0
  28. package/dist/tui/status/PackToggleView.js.map +1 -0
  29. package/dist/tui/status/StatusApp.d.ts +6 -0
  30. package/dist/tui/status/StatusApp.d.ts.map +1 -0
  31. package/dist/tui/status/StatusApp.js +98 -0
  32. package/dist/tui/status/StatusApp.js.map +1 -0
  33. package/dist/tui/status/StatusInfoView.d.ts +13 -0
  34. package/dist/tui/status/StatusInfoView.d.ts.map +1 -0
  35. package/dist/tui/status/StatusInfoView.js +14 -0
  36. package/dist/tui/status/StatusInfoView.js.map +1 -0
  37. package/package.json +1 -1
  38. package/src/cli/service.test.ts +124 -0
  39. package/src/cli/service.ts +178 -0
  40. package/src/cli/update.ts +11 -8
  41. package/src/index.ts +71 -13
  42. package/src/tui/installer/InstallerApp.tsx +6 -2
  43. package/src/tui/installer/StepService.tsx +112 -0
  44. package/src/tui/status/PackToggleView.tsx +69 -0
  45. package/src/tui/status/StatusApp.tsx +167 -0
  46. package/src/tui/status/StatusInfoView.tsx +88 -0
  47. package/tsconfig.tsbuildinfo +1 -1
@@ -1,4 +1,6 @@
1
-
2
- > @sonde/agent@0.2.5 build
3
- > tsc
4
-
1
+
2
+ 
3
+ > @sonde/agent@0.2.7 build
4
+ > tsc
5
+
6
+ ⠙
@@ -1,23 +1,65 @@
1
-
2
- > @sonde/agent@0.2.5 test
3
- > vitest run
4
-
5
-
6
- RUN v2.1.9 /Users/joshowen/Library/CloudStorage/ProtonDrive-joshowen@protonmail.com-folder/AI/ClaudeCode/sonde/packages/agent
7
-
8
- ✓ src/cli/mcp-bridge.test.ts (5 tests) 3ms
9
- src/runtime/scrubber.test.ts (11 tests) 5ms
10
- src/runtime/audit.test.ts (5 tests) 6ms
11
- src/runtime/privilege.test.ts (4 tests) 29ms
12
- src/system/scanner.test.ts (10 tests) 4ms
13
- src/cli/update.test.ts (9 tests) 5ms
14
- src/runtime/attestation.test.ts (8 tests) 4ms
15
- src/cli/packs.test.ts (17 tests) 6ms
16
- src/runtime/executor.test.ts (7 tests) 7ms
17
- src/runtime/connection.test.ts (11 tests) 23ms
18
-
19
- Test Files 10 passed (10)
20
- Tests 87 passed (87)
21
- Start at 10:01:38
22
- Duration 2.99s (transform 2.29s, setup 0ms, collect 8.24s, tests 91ms, environment 1ms, prepare 4.29s)
23
-
1
+
2
+ 
3
+ > @sonde/agent@0.2.7 test
4
+ > vitest run
5
+
6
+ 
7
+  RUN  v2.1.9 /Users/joshowen/Library/CloudStorage/ProtonDrive-joshowen@protonmail.com-folder/AI/ClaudeCode/sonde/packages/agent
8
+
9
+ [?25l · src/cli/mcp-bridge.test.ts (5)
10
+ [?25l ✓ src/cli/mcp-bridge.test.ts (5)
11
+ [?25l[?25l[?25l[?25l · src/system/scanner.test.ts (10)
12
+ ✓ src/cli/mcp-bridge.test.ts (5)
13
+ [?25l[?25l ✓ src/system/scanner.test.ts (10)
14
+ ✓ src/cli/mcp-bridge.test.ts (5)
15
+ [?25l[?25l ✓ src/system/scanner.test.ts (10)
16
+ · src/cli/service.test.ts (11)
17
+ ✓ src/runtime/scrubber.test.ts (11)
18
+ · src/runtime/audit.test.ts (5)
19
+ · src/cli/update.test.ts (9)
20
+ ✓ src/cli/mcp-bridge.test.ts (5)
21
+ · src/runtime/privilege.test.ts (4)
22
+ [?25l ✓ src/system/scanner.test.ts (10)
23
+ ✓ src/cli/service.test.ts (11)
24
+ ✓ src/runtime/scrubber.test.ts (11)
25
+ ✓ src/runtime/audit.test.ts (5)
26
+ ✓ src/cli/update.test.ts (9)
27
+ ✓ src/cli/mcp-bridge.test.ts (5)
28
+ ✓ src/runtime/privilege.test.ts (4)
29
+ [?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l[?25l · src/runtime/connection.test.ts (11)
30
+ ✓ src/system/scanner.test.ts (10)
31
+ ✓ src/cli/service.test.ts (11)
32
+ ✓ src/runtime/scrubber.test.ts (11)
33
+ ✓ src/runtime/audit.test.ts (5)
34
+ ✓ src/cli/update.test.ts (9)
35
+ ✓ src/cli/mcp-bridge.test.ts (5)
36
+ ✓ src/runtime/privilege.test.ts (4)
37
+ [?25l[?25l · src/cli/packs.test.ts (17)
38
+ ✓ src/runtime/connection.test.ts (11)
39
+ ✓ src/system/scanner.test.ts (10)
40
+ ✓ src/cli/service.test.ts (11)
41
+ ✓ src/runtime/executor.test.ts (7)
42
+ ✓ src/runtime/scrubber.test.ts (11)
43
+ ✓ src/runtime/attestation.test.ts (8)
44
+ ✓ src/runtime/audit.test.ts (5)
45
+ ✓ src/cli/update.test.ts (9)
46
+ ✓ src/cli/mcp-bridge.test.ts (5)
47
+ ✓ src/runtime/privilege.test.ts (4)
48
+  ✓ src/runtime/attestation.test.ts (8)
49
+ ✓ src/runtime/audit.test.ts (5)
50
+ ✓ src/runtime/connection.test.ts (11)
51
+ ✓ src/runtime/executor.test.ts (7)
52
+ ✓ src/runtime/privilege.test.ts (4)
53
+ ✓ src/runtime/scrubber.test.ts (11)
54
+ ✓ src/system/scanner.test.ts (10)
55
+ ✓ src/cli/mcp-bridge.test.ts (5)
56
+ ✓ src/cli/packs.test.ts (17)
57
+ ✓ src/cli/service.test.ts (11)
58
+ ✓ src/cli/update.test.ts (9)
59
+
60
+  Test Files  11 passed (11)
61
+  Tests  98 passed (98)
62
+  Start at  11:17:47
63
+  Duration  2.39s (transform 2.87s, setup 0ms, collect 9.53s, tests 60ms, environment 1ms, prepare 2.75s)
64
+
65
+ [?25h[?25h⠙
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # @sonde/agent
2
2
 
3
+ ## 0.2.8
4
+
5
+ ### Patch Changes
6
+
7
+ - updates
8
+
9
+ - Updated dependencies []:
10
+ - @sonde/shared@0.1.5
11
+ - @sonde/packs@0.1.5
12
+
13
+ ## 0.2.7
14
+
15
+ ### Patch Changes
16
+
17
+ - updates
18
+
19
+ - Updated dependencies []:
20
+ - @sonde/shared@0.1.4
21
+ - @sonde/packs@0.1.4
22
+
3
23
  ## 0.2.6
4
24
 
5
25
  ### Patch Changes
@@ -0,0 +1,12 @@
1
+ export interface ServiceResult {
2
+ success: boolean;
3
+ message: string;
4
+ }
5
+ export declare function generateUnitFile(): string;
6
+ export declare function isServiceInstalled(): boolean;
7
+ export declare function getServiceStatus(): string;
8
+ export declare function installService(): ServiceResult;
9
+ export declare function uninstallService(): ServiceResult;
10
+ export declare function stopService(): ServiceResult;
11
+ export declare function restartService(): ServiceResult;
12
+ //# sourceMappingURL=service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/cli/service.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAaD,wBAAgB,gBAAgB,IAAI,MAAM,CAuBzC;AAED,wBAAgB,kBAAkB,IAAI,OAAO,CAG5C;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAYzC;AAED,wBAAgB,cAAc,IAAI,aAAa,CA4B9C;AAED,wBAAgB,gBAAgB,IAAI,aAAa,CA6BhD;AAED,wBAAgB,WAAW,IAAI,aAAa,CAsB3C;AAED,wBAAgB,cAAc,IAAI,aAAa,CAyB9C"}
@@ -0,0 +1,164 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ const UNIT_NAME = 'sonde-agent';
5
+ const UNIT_PATH = `/etc/systemd/system/${UNIT_NAME}.service`;
6
+ function isLinux() {
7
+ return process.platform === 'linux';
8
+ }
9
+ function resolveSondeBinary() {
10
+ return execFileSync('which', ['sonde'], {
11
+ encoding: 'utf-8',
12
+ timeout: 5_000,
13
+ }).trim();
14
+ }
15
+ export function generateUnitFile() {
16
+ const user = os.userInfo();
17
+ const sondeBin = resolveSondeBinary();
18
+ return `[Unit]
19
+ Description=Sonde Agent
20
+ After=network-online.target
21
+ Wants=network-online.target
22
+
23
+ [Service]
24
+ Type=simple
25
+ User=${user.username}
26
+ Environment=HOME=${user.homedir}
27
+ ExecStart=${sondeBin} start --headless
28
+ Restart=on-failure
29
+ RestartSec=5
30
+ StandardOutput=journal
31
+ StandardError=journal
32
+ SyslogIdentifier=${UNIT_NAME}
33
+
34
+ [Install]
35
+ WantedBy=multi-user.target
36
+ `;
37
+ }
38
+ export function isServiceInstalled() {
39
+ if (!isLinux())
40
+ return false;
41
+ return fs.existsSync(UNIT_PATH);
42
+ }
43
+ export function getServiceStatus() {
44
+ if (!isLinux())
45
+ return 'unsupported';
46
+ if (!isServiceInstalled())
47
+ return 'not-installed';
48
+ try {
49
+ return execFileSync('systemctl', ['is-active', UNIT_NAME], {
50
+ encoding: 'utf-8',
51
+ timeout: 5_000,
52
+ }).trim();
53
+ }
54
+ catch {
55
+ return 'inactive';
56
+ }
57
+ }
58
+ export function installService() {
59
+ if (!isLinux()) {
60
+ return {
61
+ success: false,
62
+ message: 'systemd services are only supported on Linux.',
63
+ };
64
+ }
65
+ try {
66
+ const unitContent = generateUnitFile();
67
+ execFileSync('sudo', ['tee', UNIT_PATH], {
68
+ input: unitContent,
69
+ stdio: ['pipe', 'pipe', 'pipe'],
70
+ timeout: 10_000,
71
+ });
72
+ execFileSync('sudo', ['systemctl', 'daemon-reload'], { stdio: 'pipe', timeout: 10_000 });
73
+ execFileSync('sudo', ['systemctl', 'enable', UNIT_NAME], { stdio: 'pipe', timeout: 10_000 });
74
+ execFileSync('sudo', ['systemctl', 'start', UNIT_NAME], { stdio: 'pipe', timeout: 10_000 });
75
+ return {
76
+ success: true,
77
+ message: `${UNIT_NAME} service installed and started.`,
78
+ };
79
+ }
80
+ catch (err) {
81
+ const msg = err instanceof Error ? err.message : String(err);
82
+ return { success: false, message: `Failed to install service: ${msg}` };
83
+ }
84
+ }
85
+ export function uninstallService() {
86
+ if (!isLinux()) {
87
+ return {
88
+ success: false,
89
+ message: 'systemd services are only supported on Linux.',
90
+ };
91
+ }
92
+ if (!isServiceInstalled()) {
93
+ return { success: false, message: 'Service is not installed.' };
94
+ }
95
+ try {
96
+ execFileSync('sudo', ['systemctl', 'stop', UNIT_NAME], { stdio: 'pipe', timeout: 10_000 });
97
+ execFileSync('sudo', ['systemctl', 'disable', UNIT_NAME], { stdio: 'pipe', timeout: 10_000 });
98
+ execFileSync('sudo', ['rm', '-f', UNIT_PATH], { stdio: 'pipe', timeout: 5_000 });
99
+ execFileSync('sudo', ['systemctl', 'daemon-reload'], { stdio: 'pipe', timeout: 10_000 });
100
+ return {
101
+ success: true,
102
+ message: `${UNIT_NAME} service removed.`,
103
+ };
104
+ }
105
+ catch (err) {
106
+ const msg = err instanceof Error ? err.message : String(err);
107
+ return {
108
+ success: false,
109
+ message: `Failed to uninstall service: ${msg}`,
110
+ };
111
+ }
112
+ }
113
+ export function stopService() {
114
+ if (!isLinux()) {
115
+ return {
116
+ success: false,
117
+ message: 'systemd services are only supported on Linux.',
118
+ };
119
+ }
120
+ try {
121
+ execFileSync('systemctl', ['stop', UNIT_NAME], { stdio: 'pipe', timeout: 10_000 });
122
+ return { success: true, message: `Stopped ${UNIT_NAME} service.` };
123
+ }
124
+ catch {
125
+ try {
126
+ execFileSync('sudo', ['systemctl', 'stop', UNIT_NAME], { stdio: 'inherit', timeout: 30_000 });
127
+ return { success: true, message: `Stopped ${UNIT_NAME} service.` };
128
+ }
129
+ catch {
130
+ return {
131
+ success: false,
132
+ message: `Could not stop service. Try: sudo systemctl stop ${UNIT_NAME}`,
133
+ };
134
+ }
135
+ }
136
+ }
137
+ export function restartService() {
138
+ if (!isLinux()) {
139
+ return {
140
+ success: false,
141
+ message: 'systemd services are only supported on Linux.',
142
+ };
143
+ }
144
+ try {
145
+ execFileSync('systemctl', ['restart', UNIT_NAME], { stdio: 'pipe', timeout: 10_000 });
146
+ return { success: true, message: `Restarted ${UNIT_NAME} service.` };
147
+ }
148
+ catch {
149
+ try {
150
+ execFileSync('sudo', ['systemctl', 'restart', UNIT_NAME], {
151
+ stdio: 'inherit',
152
+ timeout: 30_000,
153
+ });
154
+ return { success: true, message: `Restarted ${UNIT_NAME} service.` };
155
+ }
156
+ catch {
157
+ return {
158
+ success: false,
159
+ message: `Could not restart service. Try: sudo systemctl restart ${UNIT_NAME}`,
160
+ };
161
+ }
162
+ }
163
+ }
164
+ //# sourceMappingURL=service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/cli/service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=service.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.test.d.ts","sourceRoot":"","sources":["../../src/cli/service.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,99 @@
1
+ import { afterEach, describe, expect, it, vi } from 'vitest';
2
+ vi.mock('node:child_process', () => ({
3
+ execFileSync: vi.fn(),
4
+ }));
5
+ vi.mock('node:fs', () => ({
6
+ default: { existsSync: vi.fn() },
7
+ }));
8
+ vi.mock('node:os', () => ({
9
+ default: {
10
+ userInfo: () => ({
11
+ username: 'testuser',
12
+ homedir: '/home/testuser',
13
+ }),
14
+ },
15
+ }));
16
+ import { execFileSync } from 'node:child_process';
17
+ import fs from 'node:fs';
18
+ import { generateUnitFile, getServiceStatus, isServiceInstalled, } from './service.js';
19
+ const mockExec = vi.mocked(execFileSync);
20
+ const mockExists = vi.mocked(fs.existsSync);
21
+ describe('generateUnitFile', () => {
22
+ it('includes the current user and home directory', () => {
23
+ mockExec.mockReturnValueOnce('/usr/local/bin/sonde\n');
24
+ const unit = generateUnitFile();
25
+ expect(unit).toContain('User=testuser');
26
+ expect(unit).toContain('Environment=HOME=/home/testuser');
27
+ });
28
+ it('includes the resolved sonde binary path', () => {
29
+ mockExec.mockReturnValueOnce('/usr/local/bin/sonde\n');
30
+ const unit = generateUnitFile();
31
+ expect(unit).toContain('ExecStart=/usr/local/bin/sonde start --headless');
32
+ });
33
+ it('sets restart on failure with 5s delay', () => {
34
+ mockExec.mockReturnValueOnce('/usr/bin/sonde\n');
35
+ const unit = generateUnitFile();
36
+ expect(unit).toContain('Restart=on-failure');
37
+ expect(unit).toContain('RestartSec=5');
38
+ });
39
+ it('targets network-online', () => {
40
+ mockExec.mockReturnValueOnce('/usr/bin/sonde\n');
41
+ const unit = generateUnitFile();
42
+ expect(unit).toContain('After=network-online.target');
43
+ expect(unit).toContain('Wants=network-online.target');
44
+ });
45
+ });
46
+ describe('isServiceInstalled', () => {
47
+ const originalPlatform = process.platform;
48
+ afterEach(() => {
49
+ Object.defineProperty(process, 'platform', {
50
+ value: originalPlatform,
51
+ });
52
+ });
53
+ it('returns false on non-Linux platforms', () => {
54
+ Object.defineProperty(process, 'platform', { value: 'darwin' });
55
+ expect(isServiceInstalled()).toBe(false);
56
+ });
57
+ it('returns true when unit file exists on Linux', () => {
58
+ Object.defineProperty(process, 'platform', { value: 'linux' });
59
+ mockExists.mockReturnValueOnce(true);
60
+ expect(isServiceInstalled()).toBe(true);
61
+ });
62
+ it('returns false when unit file is missing on Linux', () => {
63
+ Object.defineProperty(process, 'platform', { value: 'linux' });
64
+ mockExists.mockReturnValueOnce(false);
65
+ expect(isServiceInstalled()).toBe(false);
66
+ });
67
+ });
68
+ describe('getServiceStatus', () => {
69
+ const originalPlatform = process.platform;
70
+ afterEach(() => {
71
+ Object.defineProperty(process, 'platform', {
72
+ value: originalPlatform,
73
+ });
74
+ });
75
+ it('returns unsupported on non-Linux', () => {
76
+ Object.defineProperty(process, 'platform', { value: 'darwin' });
77
+ expect(getServiceStatus()).toBe('unsupported');
78
+ });
79
+ it('returns not-installed when unit file missing', () => {
80
+ Object.defineProperty(process, 'platform', { value: 'linux' });
81
+ mockExists.mockReturnValueOnce(false);
82
+ expect(getServiceStatus()).toBe('not-installed');
83
+ });
84
+ it('returns active status from systemctl', () => {
85
+ Object.defineProperty(process, 'platform', { value: 'linux' });
86
+ mockExists.mockReturnValueOnce(true);
87
+ mockExec.mockReturnValueOnce('active\n');
88
+ expect(getServiceStatus()).toBe('active');
89
+ });
90
+ it('returns inactive when systemctl throws', () => {
91
+ Object.defineProperty(process, 'platform', { value: 'linux' });
92
+ mockExists.mockReturnValueOnce(true);
93
+ mockExec.mockImplementationOnce(() => {
94
+ throw new Error('exit code 3');
95
+ });
96
+ expect(getServiceStatus()).toBe('inactive');
97
+ });
98
+ });
99
+ //# sourceMappingURL=service.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.test.js","sourceRoot":"","sources":["../../src/cli/service.test.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/cli/update.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAUtD;AAED;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC;IAC9C,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;CAC1B,CAAC,CAmBD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CA2BzD"}
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/cli/update.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAUtD;AAED;;GAEG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC;IAC9C,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;CAC1B,CAAC,CAmBD;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,aAAa,EAAE,MAAM,GAAG,IAAI,CA6BzD"}
@@ -1,5 +1,6 @@
1
1
  import { execFileSync } from 'node:child_process';
2
2
  import { VERSION } from '../version.js';
3
+ import { isServiceInstalled, restartService } from './service.js';
3
4
  /**
4
5
  * Lightweight semver comparison: returns true if a < b.
5
6
  */
@@ -57,15 +58,17 @@ export function performUpdate(targetVersion) {
57
58
  throw new Error(`Version mismatch after install: expected ${targetVersion}, got ${output}`);
58
59
  }
59
60
  console.log(`Successfully updated to v${targetVersion}`);
60
- // Best-effort systemd restart
61
- try {
62
- execFileSync('systemctl', ['restart', 'sonde-agent'], {
63
- timeout: 10_000,
64
- });
65
- console.log('Restarted sonde-agent systemd service');
61
+ if (isServiceInstalled()) {
62
+ const result = restartService();
63
+ console.log(result.message);
66
64
  }
67
- catch {
68
- // systemd not available or service not installed — that's fine
65
+ else {
66
+ console.log('Restart the agent to use the new version:');
67
+ console.log(' sonde restart');
68
+ if (process.platform === 'linux') {
69
+ console.log('');
70
+ console.log('Tip: Run "sonde service install" to start on boot.');
71
+ }
69
72
  }
70
73
  }
71
74
  //# sourceMappingURL=update.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/cli/update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAExC;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,CAAS,EAAE,CAAS;IAC3C,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3B,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACtB,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACtB,IAAI,EAAE,GAAG,EAAE;YAAE,OAAO,IAAI,CAAC;QACzB,IAAI,EAAE,GAAG,EAAE;YAAE,OAAO,KAAK,CAAC;IAC5B,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc;IAKlC,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,gDAAgD,EAAE;QACxE,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;QACvC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;KACpC,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,sCAAsC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC;IACvE,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAyB,CAAC;IACxD,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC;IACnC,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,CAAC;IAED,OAAO;QACL,cAAc,EAAE,OAAO;QACvB,aAAa;QACb,eAAe,EAAE,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC;KAClD,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,aAAqB;IACjD,OAAO,CAAC,GAAG,CAAC,2BAA2B,aAAa,KAAK,CAAC,CAAC;IAC3D,YAAY,CAAC,KAAK,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,gBAAgB,aAAa,EAAE,CAAC,EAAE;QACtE,KAAK,EAAE,SAAS;QAChB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,+BAA+B;IAC/B,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,EAAE,CAAC,WAAW,CAAC,EAAE;QAClD,QAAQ,EAAE,OAAO;QACjB,OAAO,EAAE,KAAK;KACf,CAAC,CAAC,IAAI,EAAE,CAAC;IACV,IAAI,MAAM,KAAK,aAAa,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,4CAA4C,aAAa,SAAS,MAAM,EAAE,CAAC,CAAC;IAC9F,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,4BAA4B,aAAa,EAAE,CAAC,CAAC;IAEzD,8BAA8B;IAC9B,IAAI,CAAC;QACH,YAAY,CAAC,WAAW,EAAE,CAAC,SAAS,EAAE,aAAa,CAAC,EAAE;YACpD,OAAO,EAAE,MAAM;SAChB,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,uCAAuC,CAAC,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,+DAA+D;IACjE,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/cli/update.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAOA,OAAO,EACL,KAAK,WAAW,EAOjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,eAAe,EAAE,KAAK,gBAAgB,EAAiB,MAAM,yBAAyB,CAAC;AAChG,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AA4CtD,UAAU,OAAO;IACf,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,aAAa,CAAC;IACxB,UAAU,EAAE,eAAe,CAAC;CAC7B;AAED,iBAAS,aAAa,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAgBxD;AAwSD,OAAO,EAAE,aAAa,EAAE,CAAC;AACzB,YAAY,EAAE,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAeA,OAAO,EACL,KAAK,WAAW,EAOjB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,eAAe,EAAE,KAAK,gBAAgB,EAAiB,MAAM,yBAAyB,CAAC;AAChG,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AA6CtD,UAAU,OAAO;IACf,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,aAAa,CAAC;IACxB,UAAU,EAAE,eAAe,CAAC;CAC7B;AAED,iBAAS,aAAa,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAgBxD;AAyVD,OAAO,EAAE,aAAa,EAAE,CAAC;AACzB,YAAY,EAAE,OAAO,EAAE,CAAC"}
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import { spawn } from 'node:child_process';
3
3
  import os from 'node:os';
4
4
  import { packRegistry } from '@sonde/packs';
5
5
  import { buildEnabledPacks, handlePacksCommand } from './cli/packs.js';
6
+ import { getServiceStatus, installService, isServiceInstalled, restartService, stopService, uninstallService, } from './cli/service.js';
6
7
  import { checkForUpdate, performUpdate } from './cli/update.js';
7
8
  import { getConfigPath, loadConfig, removePidFile, saveConfig, stopRunningAgent, writePidFile, } from './config.js';
8
9
  import { AgentConnection, enrollWithHub } from './runtime/connection.js';
@@ -28,6 +29,7 @@ function printUsage() {
28
29
  console.log(' restart Restart the agent in background');
29
30
  console.log(' status Show agent status');
30
31
  console.log(' packs Manage packs (list, scan, install, uninstall)');
32
+ console.log(' service Manage systemd service (install, uninstall, status)');
31
33
  console.log(' update Check for and install agent updates');
32
34
  console.log(' mcp-bridge stdio MCP bridge (for Claude Code integration)');
33
35
  console.log('');
@@ -196,6 +198,11 @@ async function cmdManager() {
196
198
  }
197
199
  }
198
200
  function cmdStop() {
201
+ if (isServiceInstalled() && getServiceStatus() === 'active') {
202
+ const result = stopService();
203
+ console.log(result.message);
204
+ return;
205
+ }
199
206
  if (stopRunningAgent()) {
200
207
  console.log('Agent stopped.');
201
208
  }
@@ -204,22 +211,57 @@ function cmdStop() {
204
211
  }
205
212
  }
206
213
  function cmdRestart() {
214
+ if (isServiceInstalled() && getServiceStatus() === 'active') {
215
+ const result = restartService();
216
+ console.log(result.message);
217
+ return;
218
+ }
207
219
  stopRunningAgent();
208
220
  const pid = spawnBackgroundAgent();
209
221
  console.log(`Agent restarted in background (PID: ${pid}).`);
210
222
  }
211
- function cmdStatus() {
212
- const config = loadConfig();
213
- if (!config) {
214
- console.log('Status: Not enrolled');
215
- console.log(`Run "sonde enroll" to get started.`);
216
- return;
223
+ async function cmdStatus() {
224
+ const { render } = await import('ink');
225
+ const { createElement } = await import('react');
226
+ const { StatusApp } = await import('./tui/status/StatusApp.js');
227
+ const { waitUntilExit } = render(createElement(StatusApp, { respawnAgent: spawnBackgroundAgent }));
228
+ await waitUntilExit();
229
+ }
230
+ function handleServiceCommand(subArgs) {
231
+ const sub = subArgs[0];
232
+ switch (sub) {
233
+ case 'install': {
234
+ const result = installService();
235
+ console.log(result.message);
236
+ if (!result.success)
237
+ process.exit(1);
238
+ break;
239
+ }
240
+ case 'uninstall': {
241
+ const result = uninstallService();
242
+ console.log(result.message);
243
+ if (!result.success)
244
+ process.exit(1);
245
+ break;
246
+ }
247
+ case 'status': {
248
+ const status = getServiceStatus();
249
+ console.log(`sonde-agent service: ${status}`);
250
+ break;
251
+ }
252
+ default:
253
+ console.log('Usage: sonde service <command>');
254
+ console.log('');
255
+ console.log('Commands:');
256
+ console.log(' install Install systemd service (starts on boot)');
257
+ console.log(' uninstall Remove systemd service');
258
+ console.log(' status Show service status');
259
+ if (sub) {
260
+ console.error(`\nUnknown subcommand: ${sub}`);
261
+ process.exit(1);
262
+ }
263
+ break;
217
264
  }
218
- console.log(`Sonde Agent v${VERSION}`);
219
- console.log(` Name: ${config.agentName}`);
220
- console.log(` Hub: ${config.hubUrl}`);
221
- console.log(` Agent ID: ${config.agentId ?? '(not yet assigned)'}`);
222
- console.log(` Config: ${getConfigPath()}`);
223
265
  }
224
266
  async function cmdInstall() {
225
267
  const initialHubUrl = getArg('--hub');
@@ -281,11 +323,17 @@ switch (command) {
281
323
  cmdRestart();
282
324
  break;
283
325
  case 'status':
284
- cmdStatus();
326
+ cmdStatus().catch((err) => {
327
+ console.error(err.message);
328
+ process.exit(1);
329
+ });
285
330
  break;
286
331
  case 'packs':
287
332
  handlePacksCommand(args.slice(1));
288
333
  break;
334
+ case 'service':
335
+ handleServiceCommand(args.slice(1));
336
+ break;
289
337
  case 'update':
290
338
  cmdUpdate().catch((err) => {
291
339
  console.error(`Update failed: ${err.message}`);