@sonde/agent 0.2.5 → 0.2.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/.turbo/turbo-build.log +1 -1
- package/.turbo/turbo-test.log +14 -14
- package/CHANGELOG.md +10 -0
- package/dist/cli/packs.d.ts +6 -0
- package/dist/cli/packs.d.ts.map +1 -1
- package/dist/cli/packs.js +42 -8
- package/dist/cli/packs.js.map +1 -1
- package/dist/cli/packs.test.js +56 -1
- package/dist/cli/packs.test.js.map +1 -1
- package/dist/config.d.ts +13 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +55 -0
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +72 -5
- package/dist/index.js.map +1 -1
- package/dist/tui/installer/StepComplete.d.ts.map +1 -1
- package/dist/tui/installer/StepComplete.js +10 -1
- package/dist/tui/installer/StepComplete.js.map +1 -1
- package/dist/tui/manager/ManagerApp.d.ts +2 -1
- package/dist/tui/manager/ManagerApp.d.ts.map +1 -1
- package/dist/tui/manager/ManagerApp.js +3 -2
- package/dist/tui/manager/ManagerApp.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/packs.test.ts +65 -0
- package/src/cli/packs.ts +56 -10
- package/src/config.ts +57 -0
- package/src/index.ts +92 -5
- package/src/tui/installer/StepComplete.tsx +12 -1
- package/src/tui/manager/ManagerApp.tsx +4 -2
- package/tsconfig.tsbuildinfo +1 -1
package/src/index.ts
CHANGED
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
import { spawn } from 'node:child_process';
|
|
3
4
|
import os from 'node:os';
|
|
4
|
-
import {
|
|
5
|
+
import { packRegistry } from '@sonde/packs';
|
|
6
|
+
import { buildEnabledPacks, handlePacksCommand } from './cli/packs.js';
|
|
5
7
|
import { checkForUpdate, performUpdate } from './cli/update.js';
|
|
6
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
type AgentConfig,
|
|
10
|
+
getConfigPath,
|
|
11
|
+
loadConfig,
|
|
12
|
+
removePidFile,
|
|
13
|
+
saveConfig,
|
|
14
|
+
stopRunningAgent,
|
|
15
|
+
writePidFile,
|
|
16
|
+
} from './config.js';
|
|
7
17
|
import { AgentConnection, type ConnectionEvents, enrollWithHub } from './runtime/connection.js';
|
|
8
18
|
import { ProbeExecutor } from './runtime/executor.js';
|
|
9
19
|
import { checkNotRoot } from './runtime/privilege.js';
|
|
10
20
|
import { buildPatterns } from './runtime/scrubber.js';
|
|
21
|
+
import { createSystemChecker, scanForSoftware } from './system/scanner.js';
|
|
11
22
|
import { VERSION } from './version.js';
|
|
12
23
|
|
|
13
24
|
const args = process.argv.slice(2);
|
|
@@ -25,6 +36,8 @@ function printUsage(): void {
|
|
|
25
36
|
console.log(' install Interactive guided setup (enroll + scan + packs)');
|
|
26
37
|
console.log(' enroll Enroll this agent with a hub');
|
|
27
38
|
console.log(' start Start the agent (TUI by default, --headless for daemon)');
|
|
39
|
+
console.log(' stop Stop the background agent');
|
|
40
|
+
console.log(' restart Restart the agent in background');
|
|
28
41
|
console.log(' status Show agent status');
|
|
29
42
|
console.log(' packs Manage packs (list, scan, install, uninstall)');
|
|
30
43
|
console.log(' update Check for and install agent updates');
|
|
@@ -61,7 +74,10 @@ function createRuntime(events: ConnectionEvents): Runtime {
|
|
|
61
74
|
process.exit(1);
|
|
62
75
|
}
|
|
63
76
|
|
|
64
|
-
const
|
|
77
|
+
const enabledPacks = buildEnabledPacks(
|
|
78
|
+
packRegistry, config.disabledPacks ?? [],
|
|
79
|
+
);
|
|
80
|
+
const executor = new ProbeExecutor(enabledPacks, undefined, buildPatterns(config.scrubPatterns));
|
|
65
81
|
const connection = new AgentConnection(config, executor, events);
|
|
66
82
|
|
|
67
83
|
return { config, executor, connection };
|
|
@@ -120,6 +136,20 @@ async function cmdEnroll(): Promise<void> {
|
|
|
120
136
|
config.enrollmentToken = undefined;
|
|
121
137
|
saveConfig(config);
|
|
122
138
|
|
|
139
|
+
// Auto-detect packs
|
|
140
|
+
const manifests = [...packRegistry.values()].map((p) => p.manifest);
|
|
141
|
+
const checker = createSystemChecker();
|
|
142
|
+
const scanResults = scanForSoftware(manifests, checker);
|
|
143
|
+
const detectedNames = scanResults
|
|
144
|
+
.filter((r) => r.detected)
|
|
145
|
+
.map((r) => r.packName);
|
|
146
|
+
const allNames = manifests.map((m) => m.name);
|
|
147
|
+
const enabledNames = ['system', ...detectedNames.filter((n) => n !== 'system')];
|
|
148
|
+
const disabledNames = allNames.filter((n) => !enabledNames.includes(n));
|
|
149
|
+
|
|
150
|
+
config.disabledPacks = disabledNames;
|
|
151
|
+
saveConfig(config);
|
|
152
|
+
|
|
123
153
|
console.log('Agent enrolled successfully.');
|
|
124
154
|
console.log(` Hub: ${hubUrl}`);
|
|
125
155
|
console.log(` Name: ${agentName}`);
|
|
@@ -129,6 +159,14 @@ async function cmdEnroll(): Promise<void> {
|
|
|
129
159
|
console.log(' mTLS: Client certificate issued and saved');
|
|
130
160
|
}
|
|
131
161
|
console.log('');
|
|
162
|
+
console.log('Pack detection:');
|
|
163
|
+
for (const name of enabledNames) {
|
|
164
|
+
console.log(` ✓ ${name}`);
|
|
165
|
+
}
|
|
166
|
+
for (const name of disabledNames) {
|
|
167
|
+
console.log(` ✗ ${name} (not detected)`);
|
|
168
|
+
}
|
|
169
|
+
console.log('');
|
|
132
170
|
console.log('Run "sonde start" to connect.');
|
|
133
171
|
}
|
|
134
172
|
|
|
@@ -160,23 +198,66 @@ function cmdStart(): void {
|
|
|
160
198
|
console.log('');
|
|
161
199
|
|
|
162
200
|
connection.start();
|
|
201
|
+
writePidFile(process.pid);
|
|
163
202
|
process.stdin.unref();
|
|
164
203
|
|
|
165
204
|
const shutdown = () => {
|
|
166
205
|
console.log('\nShutting down...');
|
|
167
206
|
connection.stop();
|
|
207
|
+
removePidFile();
|
|
168
208
|
process.exit(0);
|
|
169
209
|
};
|
|
170
210
|
process.on('SIGINT', shutdown);
|
|
171
211
|
process.on('SIGTERM', shutdown);
|
|
172
212
|
}
|
|
173
213
|
|
|
214
|
+
function spawnBackgroundAgent(): number {
|
|
215
|
+
const child = spawn(process.execPath, [process.argv[1]!, 'start', '--headless'], {
|
|
216
|
+
detached: true,
|
|
217
|
+
stdio: 'ignore',
|
|
218
|
+
});
|
|
219
|
+
child.unref();
|
|
220
|
+
return child.pid!;
|
|
221
|
+
}
|
|
222
|
+
|
|
174
223
|
async function cmdManager(): Promise<void> {
|
|
224
|
+
stopRunningAgent();
|
|
225
|
+
|
|
226
|
+
let detached = false;
|
|
175
227
|
const { render } = await import('ink');
|
|
176
228
|
const { createElement } = await import('react');
|
|
177
229
|
const { ManagerApp } = await import('./tui/manager/ManagerApp.js');
|
|
178
|
-
|
|
230
|
+
|
|
231
|
+
const onDetach = () => {
|
|
232
|
+
detached = true;
|
|
233
|
+
spawnBackgroundAgent();
|
|
234
|
+
};
|
|
235
|
+
|
|
236
|
+
const { waitUntilExit } = render(
|
|
237
|
+
createElement(ManagerApp, { createRuntime, onDetach }),
|
|
238
|
+
);
|
|
179
239
|
await waitUntilExit();
|
|
240
|
+
|
|
241
|
+
if (detached) {
|
|
242
|
+
console.log('Agent detached to background.');
|
|
243
|
+
console.log(' sonde stop — stop the background agent');
|
|
244
|
+
console.log(' sonde start — reattach the TUI');
|
|
245
|
+
console.log(' sonde restart — restart in background');
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function cmdStop(): void {
|
|
250
|
+
if (stopRunningAgent()) {
|
|
251
|
+
console.log('Agent stopped.');
|
|
252
|
+
} else {
|
|
253
|
+
console.log('No running agent found.');
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function cmdRestart(): void {
|
|
258
|
+
stopRunningAgent();
|
|
259
|
+
const pid = spawnBackgroundAgent();
|
|
260
|
+
console.log(`Agent restarted in background (PID: ${pid}).`);
|
|
180
261
|
}
|
|
181
262
|
|
|
182
263
|
function cmdStatus(): void {
|
|
@@ -187,7 +268,7 @@ function cmdStatus(): void {
|
|
|
187
268
|
return;
|
|
188
269
|
}
|
|
189
270
|
|
|
190
|
-
console.log(
|
|
271
|
+
console.log(`Sonde Agent v${VERSION}`);
|
|
191
272
|
console.log(` Name: ${config.agentName}`);
|
|
192
273
|
console.log(` Hub: ${config.hubUrl}`);
|
|
193
274
|
console.log(` Agent ID: ${config.agentId ?? '(not yet assigned)'}`);
|
|
@@ -246,6 +327,12 @@ switch (command) {
|
|
|
246
327
|
});
|
|
247
328
|
}
|
|
248
329
|
break;
|
|
330
|
+
case 'stop':
|
|
331
|
+
cmdStop();
|
|
332
|
+
break;
|
|
333
|
+
case 'restart':
|
|
334
|
+
cmdRestart();
|
|
335
|
+
break;
|
|
249
336
|
case 'status':
|
|
250
337
|
cmdStatus();
|
|
251
338
|
break;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
import { packRegistry } from '@sonde/packs';
|
|
1
2
|
import type { PackManifest } from '@sonde/shared';
|
|
2
3
|
import { Box, Text, useApp, useInput } from 'ink';
|
|
3
4
|
import Spinner from 'ink-spinner';
|
|
4
5
|
import { useEffect, useState } from 'react';
|
|
6
|
+
import { buildEnabledPacks } from '../../cli/packs.js';
|
|
5
7
|
import { type AgentConfig, saveConfig } from '../../config.js';
|
|
6
8
|
import { enrollWithHub } from '../../runtime/connection.js';
|
|
7
9
|
import { ProbeExecutor } from '../../runtime/executor.js';
|
|
@@ -19,14 +21,23 @@ export function StepComplete({ hubConfig, selectedPacks }: StepCompleteProps): J
|
|
|
19
21
|
const [error, setError] = useState('');
|
|
20
22
|
|
|
21
23
|
useEffect(() => {
|
|
24
|
+
const selectedNames = new Set(selectedPacks.map((p) => p.name));
|
|
25
|
+
const disabledPacks = [...packRegistry.keys()]
|
|
26
|
+
.filter((name) => !selectedNames.has(name));
|
|
22
27
|
const config: AgentConfig = {
|
|
23
28
|
hubUrl: hubConfig.hubUrl,
|
|
24
29
|
apiKey: hubConfig.apiKey,
|
|
25
30
|
agentName: hubConfig.agentName,
|
|
31
|
+
disabledPacks: disabledPacks.length > 0
|
|
32
|
+
? disabledPacks
|
|
33
|
+
: undefined,
|
|
26
34
|
};
|
|
27
35
|
saveConfig(config);
|
|
28
36
|
|
|
29
|
-
const
|
|
37
|
+
const enabledPacks = buildEnabledPacks(
|
|
38
|
+
packRegistry, disabledPacks,
|
|
39
|
+
);
|
|
40
|
+
const executor = new ProbeExecutor(enabledPacks);
|
|
30
41
|
|
|
31
42
|
enrollWithHub(config, executor)
|
|
32
43
|
.then(({ agentId: id, apiKey: mintedKey }) => {
|
|
@@ -26,11 +26,12 @@ interface Runtime {
|
|
|
26
26
|
|
|
27
27
|
interface ManagerAppProps {
|
|
28
28
|
createRuntime: (events: ConnectionEvents) => Runtime;
|
|
29
|
+
onDetach?: () => void;
|
|
29
30
|
}
|
|
30
31
|
|
|
31
32
|
const MAX_ACTIVITY = 50;
|
|
32
33
|
|
|
33
|
-
export function ManagerApp({ createRuntime }: ManagerAppProps): JSX.Element {
|
|
34
|
+
export function ManagerApp({ createRuntime, onDetach }: ManagerAppProps): JSX.Element {
|
|
34
35
|
const { exit } = useApp();
|
|
35
36
|
const [view, setView] = useState<View>('status');
|
|
36
37
|
const [connected, setConnected] = useState(false);
|
|
@@ -91,6 +92,7 @@ export function ManagerApp({ createRuntime }: ManagerAppProps): JSX.Element {
|
|
|
91
92
|
break;
|
|
92
93
|
case 'q':
|
|
93
94
|
runtimeRef.current?.connection.stop();
|
|
95
|
+
onDetach?.();
|
|
94
96
|
exit();
|
|
95
97
|
break;
|
|
96
98
|
}
|
|
@@ -150,7 +152,7 @@ export function ManagerApp({ createRuntime }: ManagerAppProps): JSX.Element {
|
|
|
150
152
|
a:audit
|
|
151
153
|
</Text>
|
|
152
154
|
<Text> </Text>
|
|
153
|
-
<Text color="gray">q:
|
|
155
|
+
<Text color="gray">q:detach</Text>
|
|
154
156
|
</Box>
|
|
155
157
|
</Box>
|
|
156
158
|
);
|