ciscollm-cli 1.3.0 → 1.3.2
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/LICENSE +21 -21
- package/README.md +242 -242
- package/dist/cli/commands/dashboardCommand.d.ts +1 -0
- package/dist/cli/commands/dashboardCommand.js +16 -0
- package/dist/cli/commands/dashboardCommand.js.map +1 -0
- package/dist/cli/commands/monitorCommand.d.ts +4 -0
- package/dist/cli/commands/monitorCommand.js +132 -0
- package/dist/cli/commands/monitorCommand.js.map +1 -0
- package/dist/cli/commands/runCommand.d.ts +6 -0
- package/dist/cli/commands/runCommand.js +635 -0
- package/dist/cli/commands/runCommand.js.map +1 -0
- package/dist/cli/commands/serverCommand.d.ts +1 -0
- package/dist/cli/commands/serverCommand.js +11 -0
- package/dist/cli/commands/serverCommand.js.map +1 -0
- package/dist/cli/commands/shellCommand.d.ts +1 -0
- package/dist/cli/commands/shellCommand.js +44 -0
- package/dist/cli/commands/shellCommand.js.map +1 -0
- package/dist/core/agent/AgentLoop.d.ts +0 -4
- package/dist/core/agent/AgentLoop.js +1 -158
- package/dist/core/agent/AgentLoop.js.map +1 -1
- package/dist/core/agent/AutoHealer.d.ts +12 -0
- package/dist/core/agent/AutoHealer.js +129 -26
- package/dist/core/agent/AutoHealer.js.map +1 -1
- package/dist/core/agent/HierarchicalAgentManager.d.ts +1 -1
- package/dist/core/agent/HierarchicalAgentManager.js +21 -5
- package/dist/core/agent/HierarchicalAgentManager.js.map +1 -1
- package/dist/core/agent/PromptEngine.js +33 -68
- package/dist/core/agent/PromptEngine.js.map +1 -1
- package/dist/core/guardrails/AuditLogger.js +4 -4
- package/dist/core/guardrails/CommandFirewall.js +15 -0
- package/dist/core/guardrails/CommandFirewall.js.map +1 -1
- package/dist/index.js +24 -903
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/llm/LLMClient.js +102 -4
- package/dist/infrastructure/llm/LLMClient.js.map +1 -1
- package/dist/infrastructure/llm/ToolDefinitions.d.ts +0 -136
- package/dist/infrastructure/llm/ToolDefinitions.js +0 -102
- package/dist/infrastructure/llm/ToolDefinitions.js.map +1 -1
- package/dist/infrastructure/protocols/PlinkSerial.js +1 -1
- package/dist/infrastructure/protocols/PlinkSerial.js.map +1 -1
- package/dist/server/dashboard.js +1033 -1033
- package/dist/server/index.js +8 -8
- package/dist/server/shell-simulator.d.ts +28 -1
- package/dist/server/shell-simulator.js +599 -73
- package/dist/server/shell-simulator.js.map +1 -1
- package/dist/server/ssh.js +20 -20
- package/package.json +54 -54
|
@@ -0,0 +1,635 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.runAction = runAction;
|
|
7
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const fs_1 = require("fs");
|
|
10
|
+
const MultiAgentCoordinator_1 = require("../../core/agent/MultiAgentCoordinator");
|
|
11
|
+
const PlinkSerial_1 = require("../../infrastructure/protocols/PlinkSerial");
|
|
12
|
+
const SshSession_1 = require("../../infrastructure/protocols/SshSession");
|
|
13
|
+
const TelnetSession_1 = require("../../infrastructure/protocols/TelnetSession");
|
|
14
|
+
const LLMClient_1 = require("../../infrastructure/llm/LLMClient");
|
|
15
|
+
const AgentLoop_1 = require("../../core/agent/AgentLoop");
|
|
16
|
+
const ui_1 = require("../ui/ui");
|
|
17
|
+
const dashboard_1 = require("../../server/dashboard");
|
|
18
|
+
async function runAction(options, coordinatorWrapper, dashboardWrapper, cleanup) {
|
|
19
|
+
let provider = options.provider;
|
|
20
|
+
let localType = options.localType;
|
|
21
|
+
if (localType) {
|
|
22
|
+
localType = localType.toLowerCase().trim();
|
|
23
|
+
if (localType === 'llmstudio') {
|
|
24
|
+
localType = 'lmstudio';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
let apiKey = options.api_key || options.apiKey;
|
|
28
|
+
let model = options.model;
|
|
29
|
+
let endpoint = options.endpoint;
|
|
30
|
+
let protocol = options.protocol;
|
|
31
|
+
let com = options.com;
|
|
32
|
+
let baud = options.baud;
|
|
33
|
+
let host = options.host;
|
|
34
|
+
let port = options.port;
|
|
35
|
+
let username = options.username;
|
|
36
|
+
let privateKey;
|
|
37
|
+
if (options.privateKey) {
|
|
38
|
+
privateKey = (0, fs_1.readFileSync)(options.privateKey, 'utf8');
|
|
39
|
+
}
|
|
40
|
+
let netconfPassphrase = options.passphrase;
|
|
41
|
+
let password = options.envPassword
|
|
42
|
+
? (process.env.CISCOLLM_PASS || '')
|
|
43
|
+
: options.password;
|
|
44
|
+
let goal = options.goal;
|
|
45
|
+
let strictCommandRef = options.strictCommandRef === true;
|
|
46
|
+
let refTelemetry = options.refTelemetry !== false;
|
|
47
|
+
let nonInteractive = options.nonInteractive === true;
|
|
48
|
+
let rbacRole = options.rbacRole || 'admin';
|
|
49
|
+
let dashboardPort = options.dashboardPort ? parseInt(options.dashboardPort, 10) : 3000;
|
|
50
|
+
if (nonInteractive) {
|
|
51
|
+
process.env.CISCOLLM_NON_INTERACTIVE = 'true';
|
|
52
|
+
}
|
|
53
|
+
ui_1.logger.banner();
|
|
54
|
+
if (goal && !localType && provider === 'local') {
|
|
55
|
+
const { chosenLocalType } = await inquirer_1.default.prompt([
|
|
56
|
+
{
|
|
57
|
+
type: 'list',
|
|
58
|
+
name: 'chosenLocalType',
|
|
59
|
+
message: chalk_1.default.cyan('Select Local LLM Service:'),
|
|
60
|
+
choices: [
|
|
61
|
+
{ name: `${chalk_1.default.green('●')} Ollama ${chalk_1.default.dim('(http://127.0.0.1:11434/v1)')}`, value: 'ollama' },
|
|
62
|
+
{ name: `${chalk_1.default.magenta('●')} LM Studio ${chalk_1.default.dim('(http://127.0.0.1:1234/v1)')}`, value: 'lmstudio' },
|
|
63
|
+
{ name: `${chalk_1.default.yellow('●')} OpenRouter ${chalk_1.default.dim('(Cloud API)')}`, value: '__cloud__' }
|
|
64
|
+
],
|
|
65
|
+
default: 'ollama'
|
|
66
|
+
}
|
|
67
|
+
]);
|
|
68
|
+
if (chosenLocalType === '__cloud__') {
|
|
69
|
+
provider = 'cloud';
|
|
70
|
+
localType = undefined;
|
|
71
|
+
if (!apiKey) {
|
|
72
|
+
const { key } = await inquirer_1.default.prompt([{ type: 'password', name: 'key', message: 'OpenRouter API Key:' }]);
|
|
73
|
+
apiKey = key;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
localType = chosenLocalType;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (!localType)
|
|
81
|
+
localType = 'ollama';
|
|
82
|
+
if (!goal) {
|
|
83
|
+
const detectedComs = await PlinkSerial_1.PlinkSerialSession.listAvailableComPorts();
|
|
84
|
+
let currentStep = 'PROVIDER';
|
|
85
|
+
const history = [];
|
|
86
|
+
const answers = {
|
|
87
|
+
provider: provider || 'local',
|
|
88
|
+
localType: localType || 'ollama',
|
|
89
|
+
apiKey: apiKey || '',
|
|
90
|
+
model: model || '',
|
|
91
|
+
endpoint: endpoint || '',
|
|
92
|
+
protocol: protocol || 'serial',
|
|
93
|
+
com: com || '',
|
|
94
|
+
baud: baud || '9600',
|
|
95
|
+
host: host || '',
|
|
96
|
+
port: port || '',
|
|
97
|
+
username: username || '',
|
|
98
|
+
password: password || '',
|
|
99
|
+
goal: ''
|
|
100
|
+
};
|
|
101
|
+
const goForward = (nextStep) => {
|
|
102
|
+
history.push(currentStep);
|
|
103
|
+
currentStep = nextStep;
|
|
104
|
+
};
|
|
105
|
+
const goBack = () => {
|
|
106
|
+
if (history.length > 0) {
|
|
107
|
+
currentStep = history.pop();
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
ui_1.logger.warn('Already at the first step.');
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
const refreshConsole = () => {
|
|
114
|
+
console.clear();
|
|
115
|
+
ui_1.logger.banner();
|
|
116
|
+
if (detectedComs.length > 0) {
|
|
117
|
+
ui_1.logger.info('Detected active COM ports on system:');
|
|
118
|
+
for (const port of detectedComs) {
|
|
119
|
+
console.log(` ${chalk_1.default.yellow('•')} ${chalk_1.default.yellow(port)}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
console.log('');
|
|
123
|
+
};
|
|
124
|
+
while (currentStep !== 'CONFIRMATION') {
|
|
125
|
+
refreshConsole();
|
|
126
|
+
switch (currentStep) {
|
|
127
|
+
case 'PROVIDER': {
|
|
128
|
+
const ans = await inquirer_1.default.prompt([
|
|
129
|
+
{
|
|
130
|
+
type: 'list',
|
|
131
|
+
name: 'provider',
|
|
132
|
+
message: 'Select LLM Provider:',
|
|
133
|
+
choices: [
|
|
134
|
+
{ name: 'Local (Ollama / LM Studio)', value: 'local' },
|
|
135
|
+
{ name: 'Cloud (OpenRouter)', value: 'cloud' }
|
|
136
|
+
],
|
|
137
|
+
default: answers.provider
|
|
138
|
+
}
|
|
139
|
+
]);
|
|
140
|
+
answers.provider = ans.provider;
|
|
141
|
+
if (answers.provider === 'local') {
|
|
142
|
+
goForward('LOCAL_TYPE');
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
goForward('API_KEY');
|
|
146
|
+
}
|
|
147
|
+
break;
|
|
148
|
+
}
|
|
149
|
+
case 'LOCAL_TYPE': {
|
|
150
|
+
const ans = await inquirer_1.default.prompt([
|
|
151
|
+
{
|
|
152
|
+
type: 'list',
|
|
153
|
+
name: 'localType',
|
|
154
|
+
message: 'Select Local LLM Service:',
|
|
155
|
+
choices: [
|
|
156
|
+
{ name: 'Ollama', value: 'ollama' },
|
|
157
|
+
{ name: 'LM Studio', value: 'lmstudio' },
|
|
158
|
+
{ name: chalk_1.default.dim('< Go Back'), value: '__back__' }
|
|
159
|
+
],
|
|
160
|
+
default: answers.localType
|
|
161
|
+
}
|
|
162
|
+
]);
|
|
163
|
+
if (ans.localType === '__back__') {
|
|
164
|
+
goBack();
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
answers.localType = ans.localType;
|
|
168
|
+
goForward('MODEL');
|
|
169
|
+
}
|
|
170
|
+
break;
|
|
171
|
+
}
|
|
172
|
+
case 'API_KEY': {
|
|
173
|
+
const ans = await inquirer_1.default.prompt([
|
|
174
|
+
{
|
|
175
|
+
type: 'input',
|
|
176
|
+
name: 'apiKey',
|
|
177
|
+
message: 'Enter OpenRouter API Key (or type "back" to go back):',
|
|
178
|
+
default: answers.apiKey || undefined
|
|
179
|
+
}
|
|
180
|
+
]);
|
|
181
|
+
if (ans.apiKey.trim().toLowerCase() === 'back') {
|
|
182
|
+
goBack();
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
answers.apiKey = ans.apiKey;
|
|
186
|
+
goForward('MODEL');
|
|
187
|
+
}
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
case 'MODEL': {
|
|
191
|
+
const defaultModel = answers.model || (answers.provider === 'cloud'
|
|
192
|
+
? 'nvidia/nemotron-3-super-120b-a12b:free'
|
|
193
|
+
: 'qwen3.5:4b');
|
|
194
|
+
const ans = await inquirer_1.default.prompt([
|
|
195
|
+
{
|
|
196
|
+
type: 'input',
|
|
197
|
+
name: 'model',
|
|
198
|
+
message: 'Enter LLM Model Name (or type "back" to go back):',
|
|
199
|
+
default: defaultModel
|
|
200
|
+
}
|
|
201
|
+
]);
|
|
202
|
+
if (ans.model.trim().toLowerCase() === 'back') {
|
|
203
|
+
goBack();
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
answers.model = ans.model;
|
|
207
|
+
goForward('ENDPOINT');
|
|
208
|
+
}
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
case 'ENDPOINT': {
|
|
212
|
+
const defaultEndpoint = answers.endpoint || (answers.provider === 'cloud'
|
|
213
|
+
? 'https://openrouter.ai/api/v1'
|
|
214
|
+
: (answers.localType === 'lmstudio'
|
|
215
|
+
? 'http://127.0.0.1:1234/v1'
|
|
216
|
+
: 'http://127.0.0.1:11434/v1'));
|
|
217
|
+
const ans = await inquirer_1.default.prompt([
|
|
218
|
+
{
|
|
219
|
+
type: 'input',
|
|
220
|
+
name: 'endpoint',
|
|
221
|
+
message: 'Enter LLM API Endpoint URL (or type "back" to go back):',
|
|
222
|
+
default: defaultEndpoint
|
|
223
|
+
}
|
|
224
|
+
]);
|
|
225
|
+
if (ans.endpoint.trim().toLowerCase() === 'back') {
|
|
226
|
+
goBack();
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
answers.endpoint = ans.endpoint;
|
|
230
|
+
goForward('PROTOCOL');
|
|
231
|
+
}
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
case 'PROTOCOL': {
|
|
235
|
+
const ans = await inquirer_1.default.prompt([
|
|
236
|
+
{
|
|
237
|
+
type: 'list',
|
|
238
|
+
name: 'protocol',
|
|
239
|
+
message: 'Select Connection Protocol:',
|
|
240
|
+
choices: [
|
|
241
|
+
{ name: 'serial', value: 'serial' },
|
|
242
|
+
{ name: 'ssh', value: 'ssh' },
|
|
243
|
+
{ name: 'telnet', value: 'telnet' },
|
|
244
|
+
{ name: chalk_1.default.dim('< Go Back'), value: '__back__' }
|
|
245
|
+
],
|
|
246
|
+
default: answers.protocol
|
|
247
|
+
}
|
|
248
|
+
]);
|
|
249
|
+
if (ans.protocol === '__back__') {
|
|
250
|
+
goBack();
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
answers.protocol = ans.protocol;
|
|
254
|
+
if (answers.protocol === 'serial') {
|
|
255
|
+
goForward('SERIAL_COM');
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
goForward('IP_HOST');
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
case 'SERIAL_COM': {
|
|
264
|
+
if (detectedComs.length > 0) {
|
|
265
|
+
const choices = detectedComs.map(port => {
|
|
266
|
+
const match = /^(COM\d+)\b/i.exec(port);
|
|
267
|
+
const portValue = match ? match[1].toUpperCase() : port;
|
|
268
|
+
return { name: port, value: portValue };
|
|
269
|
+
});
|
|
270
|
+
choices.push({ name: 'Enter COM port(s) manually', value: '__manual__' });
|
|
271
|
+
choices.push({ name: chalk_1.default.dim('< Go Back'), value: '__back__' });
|
|
272
|
+
const ans = await inquirer_1.default.prompt([
|
|
273
|
+
{
|
|
274
|
+
type: 'checkbox',
|
|
275
|
+
name: 'coms',
|
|
276
|
+
message: 'Select COM Port(s) (Use Space to select, Enter to confirm):',
|
|
277
|
+
choices: choices,
|
|
278
|
+
validate: (input) => {
|
|
279
|
+
if (input.length === 0) {
|
|
280
|
+
return 'You must select at least one option.';
|
|
281
|
+
}
|
|
282
|
+
if (input.includes('__back__') && input.length > 1) {
|
|
283
|
+
return 'Cannot select "< Go Back" along with other ports.';
|
|
284
|
+
}
|
|
285
|
+
if (input.includes('__manual__') && input.length > 1) {
|
|
286
|
+
return 'Cannot select "Enter COM port(s) manually" along with other ports.';
|
|
287
|
+
}
|
|
288
|
+
return true;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
]);
|
|
292
|
+
if (ans.coms.includes('__back__')) {
|
|
293
|
+
goBack();
|
|
294
|
+
}
|
|
295
|
+
else if (ans.coms.includes('__manual__')) {
|
|
296
|
+
const manualAns = await inquirer_1.default.prompt([
|
|
297
|
+
{
|
|
298
|
+
type: 'input',
|
|
299
|
+
name: 'com',
|
|
300
|
+
message: 'Enter COM Port name(s) (comma-separated, e.g. COM3 or COM3,COM4):',
|
|
301
|
+
validate: (input) => input.trim().length > 0 ? true : 'COM port is required.'
|
|
302
|
+
}
|
|
303
|
+
]);
|
|
304
|
+
answers.com = manualAns.com;
|
|
305
|
+
goForward('SERIAL_BAUD');
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
answers.com = ans.coms.join(',');
|
|
309
|
+
goForward('SERIAL_BAUD');
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
const ans = await inquirer_1.default.prompt([
|
|
314
|
+
{
|
|
315
|
+
type: 'input',
|
|
316
|
+
name: 'com',
|
|
317
|
+
message: 'Enter COM Port name(s) (comma-separated, e.g. COM3 or COM3,COM4) (or type "back" to go back):',
|
|
318
|
+
default: answers.com || undefined,
|
|
319
|
+
validate: (input) => {
|
|
320
|
+
if (input.trim().toLowerCase() === 'back')
|
|
321
|
+
return true;
|
|
322
|
+
return input.trim().length > 0 ? true : 'COM port is required.';
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
]);
|
|
326
|
+
if (ans.com.trim().toLowerCase() === 'back') {
|
|
327
|
+
goBack();
|
|
328
|
+
}
|
|
329
|
+
else {
|
|
330
|
+
answers.com = ans.com;
|
|
331
|
+
goForward('SERIAL_BAUD');
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
break;
|
|
335
|
+
}
|
|
336
|
+
case 'SERIAL_BAUD': {
|
|
337
|
+
const ans = await inquirer_1.default.prompt([
|
|
338
|
+
{
|
|
339
|
+
type: 'list',
|
|
340
|
+
name: 'baud',
|
|
341
|
+
message: 'Select Serial Baud Rate:',
|
|
342
|
+
choices: [
|
|
343
|
+
'9600', '19200', '38400', '57600', '115200',
|
|
344
|
+
{ name: chalk_1.default.dim('< Go Back'), value: '__back__' }
|
|
345
|
+
],
|
|
346
|
+
default: answers.baud
|
|
347
|
+
}
|
|
348
|
+
]);
|
|
349
|
+
if (ans.baud === '__back__') {
|
|
350
|
+
goBack();
|
|
351
|
+
}
|
|
352
|
+
else {
|
|
353
|
+
answers.baud = ans.baud;
|
|
354
|
+
goForward('GOAL');
|
|
355
|
+
}
|
|
356
|
+
break;
|
|
357
|
+
}
|
|
358
|
+
case 'IP_HOST': {
|
|
359
|
+
const ans = await inquirer_1.default.prompt([
|
|
360
|
+
{
|
|
361
|
+
type: 'input',
|
|
362
|
+
name: 'host',
|
|
363
|
+
message: 'Enter Target IP address(es) / Hostname(s) (comma-separated) (or type "back" to go back):',
|
|
364
|
+
default: answers.host || undefined,
|
|
365
|
+
validate: (input) => {
|
|
366
|
+
if (input.trim().toLowerCase() === 'back')
|
|
367
|
+
return true;
|
|
368
|
+
return input.trim().length > 0 ? true : 'Host address is required.';
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
]);
|
|
372
|
+
if (ans.host.trim().toLowerCase() === 'back') {
|
|
373
|
+
goBack();
|
|
374
|
+
}
|
|
375
|
+
else {
|
|
376
|
+
answers.host = ans.host;
|
|
377
|
+
goForward('IP_PORT');
|
|
378
|
+
}
|
|
379
|
+
break;
|
|
380
|
+
}
|
|
381
|
+
case 'IP_PORT': {
|
|
382
|
+
const ans = await inquirer_1.default.prompt([
|
|
383
|
+
{
|
|
384
|
+
type: 'input',
|
|
385
|
+
name: 'port',
|
|
386
|
+
message: 'Enter Connection Port (leave empty for default) (or type "back" to go back):',
|
|
387
|
+
default: answers.port || undefined
|
|
388
|
+
}
|
|
389
|
+
]);
|
|
390
|
+
if (ans.port.trim().toLowerCase() === 'back') {
|
|
391
|
+
goBack();
|
|
392
|
+
}
|
|
393
|
+
else {
|
|
394
|
+
answers.port = ans.port;
|
|
395
|
+
goForward('IP_USER');
|
|
396
|
+
}
|
|
397
|
+
break;
|
|
398
|
+
}
|
|
399
|
+
case 'IP_USER': {
|
|
400
|
+
const ans = await inquirer_1.default.prompt([
|
|
401
|
+
{
|
|
402
|
+
type: 'input',
|
|
403
|
+
name: 'username',
|
|
404
|
+
message: 'Enter Device Username (leave empty if none) (or type "back" to go back):',
|
|
405
|
+
default: answers.username || undefined
|
|
406
|
+
}
|
|
407
|
+
]);
|
|
408
|
+
if (ans.username.trim().toLowerCase() === 'back') {
|
|
409
|
+
goBack();
|
|
410
|
+
}
|
|
411
|
+
else {
|
|
412
|
+
answers.username = ans.username;
|
|
413
|
+
goForward('IP_PASS');
|
|
414
|
+
}
|
|
415
|
+
break;
|
|
416
|
+
}
|
|
417
|
+
case 'IP_PASS': {
|
|
418
|
+
const ans = await inquirer_1.default.prompt([
|
|
419
|
+
{
|
|
420
|
+
type: 'password',
|
|
421
|
+
name: 'password',
|
|
422
|
+
message: 'Enter Device Password (or type "back" to go back):',
|
|
423
|
+
default: answers.password || undefined
|
|
424
|
+
}
|
|
425
|
+
]);
|
|
426
|
+
if (ans.password === 'back') {
|
|
427
|
+
goBack();
|
|
428
|
+
}
|
|
429
|
+
else {
|
|
430
|
+
answers.password = ans.password;
|
|
431
|
+
goForward('GOAL');
|
|
432
|
+
}
|
|
433
|
+
break;
|
|
434
|
+
}
|
|
435
|
+
case 'GOAL': {
|
|
436
|
+
const ans = await inquirer_1.default.prompt([
|
|
437
|
+
{
|
|
438
|
+
type: 'input',
|
|
439
|
+
name: 'goal',
|
|
440
|
+
message: 'Enter Execution Goal / Intent (or type "back" to go back):',
|
|
441
|
+
default: answers.goal || undefined,
|
|
442
|
+
validate: (input) => {
|
|
443
|
+
if (input.trim().toLowerCase() === 'back')
|
|
444
|
+
return true;
|
|
445
|
+
return input.trim().length > 0 ? true : 'Execution goal is required.';
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
]);
|
|
449
|
+
if (ans.goal.trim().toLowerCase() === 'back') {
|
|
450
|
+
goBack();
|
|
451
|
+
}
|
|
452
|
+
else {
|
|
453
|
+
answers.goal = ans.goal;
|
|
454
|
+
goForward('CONFIRMATION');
|
|
455
|
+
}
|
|
456
|
+
break;
|
|
457
|
+
}
|
|
458
|
+
case 'CONFIRMATION':
|
|
459
|
+
break;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
// Show configuration confirmation wizard summary
|
|
463
|
+
refreshConsole();
|
|
464
|
+
console.log(chalk_1.default.bold.yellow('=== CISCOLLM CONFIGURATION CONFIRMATION ==='));
|
|
465
|
+
console.log(`• Provider: ${chalk_1.default.green(answers.provider.toUpperCase())}`);
|
|
466
|
+
if (answers.provider === 'local') {
|
|
467
|
+
console.log(`• Local Type: ${chalk_1.default.green(answers.localType.toUpperCase())}`);
|
|
468
|
+
}
|
|
469
|
+
console.log(`• Model: ${chalk_1.default.green(answers.model || 'qwen3.5:4b')}`);
|
|
470
|
+
console.log(`• Endpoint URL: ${chalk_1.default.green(answers.endpoint)}`);
|
|
471
|
+
console.log(`• Protocol: ${chalk_1.default.green(answers.protocol.toUpperCase())}`);
|
|
472
|
+
if (answers.protocol === 'serial') {
|
|
473
|
+
console.log(`• COM Port(s): ${chalk_1.default.green(answers.com)}`);
|
|
474
|
+
console.log(`• Baud Rate: ${chalk_1.default.green(answers.baud)}`);
|
|
475
|
+
}
|
|
476
|
+
else {
|
|
477
|
+
console.log(`• Host IP(s): ${chalk_1.default.green(answers.host)}`);
|
|
478
|
+
console.log(`• Connection Port: ${chalk_1.default.green(answers.port || '(default)')}`);
|
|
479
|
+
console.log(`• Login Username: ${chalk_1.default.green(answers.username || '(none)')}`);
|
|
480
|
+
}
|
|
481
|
+
console.log(`• Execution Goal: ${chalk_1.default.cyan(answers.goal)}`);
|
|
482
|
+
console.log(chalk_1.default.bold.yellow('==========================================='));
|
|
483
|
+
const confirmAns = await inquirer_1.default.prompt([
|
|
484
|
+
{
|
|
485
|
+
type: 'list',
|
|
486
|
+
name: 'confirm',
|
|
487
|
+
message: 'Do you want to proceed with this configuration?',
|
|
488
|
+
choices: [
|
|
489
|
+
{ name: 'Yes, start execution', value: 'yes' },
|
|
490
|
+
{ name: 'Edit Execution Goal', value: 'edit_goal' },
|
|
491
|
+
{ name: 'Restart Wizard', value: 'restart' },
|
|
492
|
+
{ name: 'Cancel and Exit', value: 'cancel' }
|
|
493
|
+
]
|
|
494
|
+
}
|
|
495
|
+
]);
|
|
496
|
+
if (confirmAns.confirm === 'yes') {
|
|
497
|
+
provider = answers.provider;
|
|
498
|
+
localType = answers.localType;
|
|
499
|
+
apiKey = answers.apiKey;
|
|
500
|
+
model = answers.model;
|
|
501
|
+
endpoint = answers.endpoint;
|
|
502
|
+
protocol = answers.protocol;
|
|
503
|
+
com = answers.com;
|
|
504
|
+
baud = answers.baud;
|
|
505
|
+
host = answers.host;
|
|
506
|
+
port = answers.port;
|
|
507
|
+
username = answers.username;
|
|
508
|
+
password = answers.password;
|
|
509
|
+
goal = answers.goal;
|
|
510
|
+
}
|
|
511
|
+
else if (confirmAns.confirm === 'edit_goal') {
|
|
512
|
+
answers.goal = '';
|
|
513
|
+
currentStep = 'GOAL';
|
|
514
|
+
// Loop back to prompt goal
|
|
515
|
+
// Wait, we need to restart the wizard loop! Let's re-run this function or let the while loop run.
|
|
516
|
+
// Because currentStep is set to 'GOAL' and answers are preserved, calling runAction again is easiest.
|
|
517
|
+
options.goal = undefined;
|
|
518
|
+
return runAction(options, coordinatorWrapper, dashboardWrapper, cleanup);
|
|
519
|
+
}
|
|
520
|
+
else if (confirmAns.confirm === 'restart') {
|
|
521
|
+
options.goal = undefined;
|
|
522
|
+
return runAction({ ...options, provider: undefined, localType: undefined, model: undefined, endpoint: undefined, protocol: undefined, com: undefined, host: undefined, username: undefined, password: undefined }, coordinatorWrapper, dashboardWrapper, cleanup);
|
|
523
|
+
}
|
|
524
|
+
else {
|
|
525
|
+
ui_1.logger.info('Configuration wizard cancelled.');
|
|
526
|
+
process.exit(0);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
ui_1.logger.info(`Initializing system link in [${provider.toUpperCase()}] mode using ${protocol.toUpperCase()}...`);
|
|
530
|
+
ui_1.logger.info(`Command reference policy: strict=${strictCommandRef ? 'on' : 'off'}, telemetry=${refTelemetry ? 'on' : 'off'}`);
|
|
531
|
+
coordinatorWrapper.active = new MultiAgentCoordinator_1.MultiAgentCoordinator();
|
|
532
|
+
try {
|
|
533
|
+
dashboardWrapper.server = (0, dashboard_1.startDashboardServer)(coordinatorWrapper.active, dashboardPort);
|
|
534
|
+
}
|
|
535
|
+
catch (e) {
|
|
536
|
+
ui_1.logger.warn(`Failed to auto-start live Visual Control Dashboard: ${e.message}`);
|
|
537
|
+
}
|
|
538
|
+
try {
|
|
539
|
+
if (protocol === 'serial') {
|
|
540
|
+
if (!com) {
|
|
541
|
+
throw new Error('COM port (-c, --com) is required for serial protocol connections.');
|
|
542
|
+
}
|
|
543
|
+
const ports = com.split(',').map((p) => p.trim()).filter((p) => p.length > 0);
|
|
544
|
+
for (const port of ports) {
|
|
545
|
+
const session = new PlinkSerial_1.PlinkSerialSession(port, parseInt(baud, 10));
|
|
546
|
+
coordinatorWrapper.active.registerSession(port, session);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
else if (protocol === 'ssh') {
|
|
550
|
+
if (!host || !username) {
|
|
551
|
+
throw new Error('Host (--host) and Username (-u, --username) are required for SSH connections.');
|
|
552
|
+
}
|
|
553
|
+
const hosts = host.split(',').map((h) => h.trim()).filter((h) => h.length > 0);
|
|
554
|
+
for (const h of hosts) {
|
|
555
|
+
const session = new SshSession_1.SshSession({
|
|
556
|
+
host: h,
|
|
557
|
+
port: port ? parseInt(port, 10) : 22,
|
|
558
|
+
username: username,
|
|
559
|
+
password: password
|
|
560
|
+
});
|
|
561
|
+
coordinatorWrapper.active.registerSession(h, session);
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
else if (protocol === 'telnet') {
|
|
565
|
+
if (!host) {
|
|
566
|
+
throw new Error('Host (--host) is required for Telnet connections.');
|
|
567
|
+
}
|
|
568
|
+
const hosts = host.split(',').map((h) => h.trim()).filter((h) => h.length > 0);
|
|
569
|
+
for (const h of hosts) {
|
|
570
|
+
const session = new TelnetSession_1.TelnetSession({
|
|
571
|
+
host: h,
|
|
572
|
+
port: port ? parseInt(port, 10) : 23,
|
|
573
|
+
username: username,
|
|
574
|
+
password: password
|
|
575
|
+
});
|
|
576
|
+
coordinatorWrapper.active.registerSession(h, session);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
else {
|
|
580
|
+
throw new Error(`Unsupported connection protocol type: ${protocol}`);
|
|
581
|
+
}
|
|
582
|
+
if (provider === 'local' && !endpoint) {
|
|
583
|
+
if (localType === 'lmstudio') {
|
|
584
|
+
endpoint = 'http://127.0.0.1:1234/v1';
|
|
585
|
+
ui_1.logger.info(`LM Studio endpoint: ${chalk_1.default.cyan(endpoint)}`);
|
|
586
|
+
}
|
|
587
|
+
else {
|
|
588
|
+
endpoint = 'http://127.0.0.1:11434/v1';
|
|
589
|
+
ui_1.logger.info(`Ollama endpoint: ${chalk_1.default.cyan(endpoint)}`);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
const localAIClient = new LLMClient_1.LLMClient(provider, endpoint, model, apiKey, localType);
|
|
593
|
+
const llmSpinner = (0, ui_1.createSpinner)('Preflight check: validating LLM endpoint reachability...').start();
|
|
594
|
+
try {
|
|
595
|
+
await localAIClient.ensureReachable();
|
|
596
|
+
const setupOk = await localAIClient.setupModelIfNeeded(status => {
|
|
597
|
+
llmSpinner.text = `LLM preflight: ${status}`;
|
|
598
|
+
});
|
|
599
|
+
if (setupOk) {
|
|
600
|
+
llmSpinner.succeed('LLM endpoint is reachable and model is ready.');
|
|
601
|
+
}
|
|
602
|
+
else {
|
|
603
|
+
llmSpinner.warn('LLM endpoint is reachable (model auto-load skipped/not supported by this provider).');
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
catch (err) {
|
|
607
|
+
llmSpinner.fail('LLM endpoint preflight failed.');
|
|
608
|
+
throw err;
|
|
609
|
+
}
|
|
610
|
+
const connSpinner = (0, ui_1.createSpinner)('Connecting to target network devices...').start();
|
|
611
|
+
try {
|
|
612
|
+
await coordinatorWrapper.active.connectAll();
|
|
613
|
+
connSpinner.succeed('All hardware sessions synchronized successfully.');
|
|
614
|
+
}
|
|
615
|
+
catch (err) {
|
|
616
|
+
connSpinner.fail('Connection failed.');
|
|
617
|
+
throw err;
|
|
618
|
+
}
|
|
619
|
+
const agent = new AgentLoop_1.CiscoAgentLoop(localAIClient, coordinatorWrapper.active, {
|
|
620
|
+
strictReferenceMode: strictCommandRef,
|
|
621
|
+
referenceTelemetry: refTelemetry,
|
|
622
|
+
rbacRole: rbacRole
|
|
623
|
+
});
|
|
624
|
+
await agent.run(goal);
|
|
625
|
+
}
|
|
626
|
+
catch (err) {
|
|
627
|
+
ui_1.logger.critical(`Execution Error: ${err.message}`);
|
|
628
|
+
}
|
|
629
|
+
finally {
|
|
630
|
+
await cleanup();
|
|
631
|
+
ui_1.logger.info('Session Terminated. Pipelines detached.');
|
|
632
|
+
process.exit(0);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
//# sourceMappingURL=runCommand.js.map
|