ciscollm-cli 1.3.3 → 1.3.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/README.md +19 -25
- package/dist/cli/commands/daemonCommand.d.ts +4 -0
- package/dist/cli/commands/daemonCommand.js +68 -0
- package/dist/cli/commands/daemonCommand.js.map +1 -0
- package/dist/cli/commands/monitorCommand.js +17 -1
- package/dist/cli/commands/monitorCommand.js.map +1 -1
- package/dist/cli/commands/runCommand.d.ts +1 -3
- package/dist/cli/commands/runCommand.js +177 -470
- package/dist/cli/commands/runCommand.js.map +1 -1
- package/dist/cli/ui/interactiveWizard.d.ts +1 -0
- package/dist/cli/ui/interactiveWizard.js +429 -0
- package/dist/cli/ui/interactiveWizard.js.map +1 -0
- package/dist/cli/ui/ui.js +0 -5
- package/dist/cli/ui/ui.js.map +1 -1
- package/dist/core/agent/AgentLoop.d.ts +15 -3
- package/dist/core/agent/AgentLoop.js +196 -67
- package/dist/core/agent/AgentLoop.js.map +1 -1
- package/dist/core/agent/AutoRemediationEngine.d.ts +14 -0
- package/dist/core/agent/AutoRemediationEngine.js +75 -0
- package/dist/core/agent/AutoRemediationEngine.js.map +1 -0
- package/dist/core/agent/DigitalTwin.d.ts +10 -0
- package/dist/core/agent/DigitalTwin.js +41 -0
- package/dist/core/agent/DigitalTwin.js.map +1 -0
- package/dist/core/agent/IntentTranslator.d.ts +8 -0
- package/dist/core/agent/IntentTranslator.js +63 -0
- package/dist/core/agent/IntentTranslator.js.map +1 -0
- package/dist/core/agent/MemoryManager.d.ts +14 -0
- package/dist/core/agent/MemoryManager.js +89 -0
- package/dist/core/agent/MemoryManager.js.map +1 -0
- package/dist/core/agent/MultiAgentCoordinator.js +0 -2
- package/dist/core/agent/MultiAgentCoordinator.js.map +1 -1
- package/dist/core/agent/NetworkPlanner.d.ts +9 -0
- package/dist/core/agent/NetworkPlanner.js +111 -0
- package/dist/core/agent/NetworkPlanner.js.map +1 -0
- package/dist/core/agent/PromptEngine.d.ts +1 -1
- package/dist/core/agent/PromptEngine.js +23 -13
- package/dist/core/agent/PromptEngine.js.map +1 -1
- package/dist/core/guardrails/NetworkAudit.js +1 -1
- package/dist/core/guardrails/NetworkAudit.js.map +1 -1
- package/dist/core/plugins/PluginManager.d.ts +17 -0
- package/dist/core/plugins/PluginManager.js +108 -0
- package/dist/core/plugins/PluginManager.js.map +1 -0
- package/dist/core/rollback/TransactionManager.js +0 -5
- package/dist/core/rollback/TransactionManager.js.map +1 -1
- package/dist/index.js +36 -61
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/llm/LLMClient.d.ts +1 -0
- package/dist/infrastructure/llm/LLMClient.js +33 -9
- package/dist/infrastructure/llm/LLMClient.js.map +1 -1
- package/dist/infrastructure/protocols/SshSession.d.ts +1 -0
- package/dist/infrastructure/protocols/SshSession.js +5 -4
- package/dist/infrastructure/protocols/SshSession.js.map +1 -1
- package/dist/infrastructure/protocols/TelnetSession.d.ts +1 -0
- package/dist/infrastructure/protocols/TelnetSession.js +5 -1
- package/dist/infrastructure/protocols/TelnetSession.js.map +1 -1
- package/dist/server/devices/ASADevice.d.ts +17 -0
- package/dist/server/devices/ASADevice.js +160 -0
- package/dist/server/devices/ASADevice.js.map +1 -0
- package/dist/server/devices/BaseDevice.d.ts +11 -0
- package/dist/server/devices/BaseDevice.js +19 -0
- package/dist/server/devices/BaseDevice.js.map +1 -0
- package/dist/server/devices/IOSDevice.d.ts +100 -0
- package/dist/server/devices/IOSDevice.js +1561 -0
- package/dist/server/devices/IOSDevice.js.map +1 -0
- package/dist/server/devices/LinuxServerDevice.d.ts +8 -0
- package/dist/server/devices/LinuxServerDevice.js +71 -0
- package/dist/server/devices/LinuxServerDevice.js.map +1 -0
- package/dist/server/devices/PCDevice.d.ts +20 -0
- package/dist/server/devices/PCDevice.js +86 -0
- package/dist/server/devices/PCDevice.js.map +1 -0
- package/dist/server/devices/RouterDevice.d.ts +4 -0
- package/dist/server/devices/RouterDevice.js +11 -0
- package/dist/server/devices/RouterDevice.js.map +1 -0
- package/dist/server/devices/SwitchDevice.d.ts +4 -0
- package/dist/server/devices/SwitchDevice.js +11 -0
- package/dist/server/devices/SwitchDevice.js.map +1 -0
- package/dist/server/devices/WLCDevice.d.ts +15 -0
- package/dist/server/devices/WLCDevice.js +88 -0
- package/dist/server/devices/WLCDevice.js.map +1 -0
- package/dist/server/index.js +47 -22
- package/dist/server/index.js.map +1 -1
- package/dist/server/shell-simulator.js +1 -2
- package/dist/server/shell-simulator.js.map +1 -1
- package/dist/server/ssh.d.ts +2 -1
- package/dist/server/ssh.js +22 -9
- package/dist/server/ssh.js.map +1 -1
- package/dist/server/telnet.d.ts +3 -2
- package/dist/server/telnet.js +10 -42
- package/dist/server/telnet.js.map +1 -1
- package/dist/shared/bootBanner.d.ts +1 -0
- package/dist/shared/bootBanner.js +93 -0
- package/dist/shared/bootBanner.js.map +1 -0
- package/dist/shared/constants.js +1 -1
- package/dist/shared/constants.js.map +1 -1
- package/package.json +1 -1
- package/dist/cli/commands/dashboardCommand.d.ts +0 -1
- package/dist/cli/commands/dashboardCommand.js +0 -16
- package/dist/cli/commands/dashboardCommand.js.map +0 -1
- package/dist/cli/commands/shellCommand.d.ts +0 -1
- package/dist/cli/commands/shellCommand.js +0 -44
- package/dist/cli/commands/shellCommand.js.map +0 -1
- package/dist/infrastructure/protocols/CmlSession.d.ts +0 -26
- package/dist/infrastructure/protocols/CmlSession.js +0 -448
- package/dist/infrastructure/protocols/CmlSession.js.map +0 -1
- package/dist/infrastructure/protocols/NetconfSession.d.ts +0 -74
- package/dist/infrastructure/protocols/NetconfSession.js +0 -553
- package/dist/infrastructure/protocols/NetconfSession.js.map +0 -1
- package/dist/server/dashboard.d.ts +0 -3
- package/dist/server/dashboard.js +0 -1149
- package/dist/server/dashboard.js.map +0 -1
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.BOOT_BANNER = void 0;
|
|
4
|
+
exports.BOOT_BANNER = `
|
|
5
|
+
Initializing Hardware ...
|
|
6
|
+
|
|
7
|
+
System integrity status: 00000610
|
|
8
|
+
Rom image verified correctly
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
System Bootstrap, Version 15.4(3r)S5, RELEASE SOFTWARE
|
|
12
|
+
Copyright (c) 1994-2015 by cisco Systems, Inc.
|
|
13
|
+
|
|
14
|
+
Current image running: Boot ROM0
|
|
15
|
+
|
|
16
|
+
Last reset cause: LocalSoft
|
|
17
|
+
Cisco ISR4321/K9 platform with 4194304 Kbytes of main memory
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
no valid BOOT image found
|
|
22
|
+
Final autoboot attempt from default boot device...
|
|
23
|
+
File size is 0x1d0580a0
|
|
24
|
+
Located isr4300-universalk9.03.16.05.S.155-3.S5-ext.SPA.bin
|
|
25
|
+
Image size 486899872 inode num 12, bks cnt 102567 blk size 8*512
|
|
26
|
+
##########################################################################################################################
|
|
27
|
+
Boot image size = 486899872 (0x1d0580a0) bytes
|
|
28
|
+
|
|
29
|
+
Package header rev 1 structure detected
|
|
30
|
+
Calculating SHA-1 hash...done
|
|
31
|
+
validate_package: SHA-1 hash:
|
|
32
|
+
calculated 83acd4f8:dc03c892:f243621c:06872286:6c9f0cf5
|
|
33
|
+
expected 83acd4f8:dc03c892:f243621c:06872286:6c9f0cf5
|
|
34
|
+
|
|
35
|
+
RSA Signed RELEASE Image Signature Verification Successful.
|
|
36
|
+
Package Load Test Latency : 6390 msec
|
|
37
|
+
Image validated
|
|
38
|
+
%IOSXEBOOT-4-BOOT_SRC: (rp/0): mounting /boot/super.iso to /tmp/sw/isos
|
|
39
|
+
|
|
40
|
+
Restricted Rights Legend
|
|
41
|
+
Use, duplication, or disclosure by the Government is
|
|
42
|
+
subject to restrictions as set forth in subparagraph
|
|
43
|
+
(c) of the Commercial Computer Software - Restricted
|
|
44
|
+
Rights clause at FAR sec. 52.227-19 and subparagraph
|
|
45
|
+
(c) (1) (ii) of the Rights in Technical Data and Computer
|
|
46
|
+
Software clause at DFARS sec. 252.227-7013.
|
|
47
|
+
cisco Systems, Inc.
|
|
48
|
+
170 West Tasman Drive
|
|
49
|
+
San Jose, California 95134-1706
|
|
50
|
+
|
|
51
|
+
Cisco IOS Software, ISR Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 15.5(3)S5, RELEASE SOFTWARE (fc2)
|
|
52
|
+
Technical Support: http://www.cisco.com/techsupport
|
|
53
|
+
Copyright (c) 1986-2017 by Cisco Systems, Inc.
|
|
54
|
+
Compiled Thu 19-Jan-17 11:24 by mcpre
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
Cisco IOS - XE software, Copyright(c) 2005 - 2017 by cisco Systems, Inc.
|
|
59
|
+
All rights reserved.Certain components of Cisco IOS - XE software are
|
|
60
|
+
licensed under the GNU General Public License("GPL") Version 2.0.The
|
|
61
|
+
software code licensed under GPL Version 2.0 is free software that comes
|
|
62
|
+
with ABSOLUTELY NO WARRANTY.You can redistribute and / or modify such
|
|
63
|
+
GPL code under the terms of GPL Version 2.0.For more details, see the
|
|
64
|
+
documentation or "License Notice" file accompanying the IOS - XE software,
|
|
65
|
+
or the applicable URL provided on the flyer accompanying the IOS - XE
|
|
66
|
+
software.
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
This product contains cryptographic features and is subject to United
|
|
71
|
+
States and local country laws governing import, export, transfer and
|
|
72
|
+
use. Delivery of Cisco cryptographic products does not imply
|
|
73
|
+
third-party authority to import, export, distribute or use encryption.
|
|
74
|
+
Importers, exporters, distributors and users are responsible for
|
|
75
|
+
compliance with U.S. and local country laws. By using this product you
|
|
76
|
+
agree to comply with applicable laws and regulations. If you are unable
|
|
77
|
+
to comply with U.S. and local laws, return this product immediately.
|
|
78
|
+
|
|
79
|
+
A summary of U.S. laws governing Cisco cryptographic products may be found at:
|
|
80
|
+
http://www.cisco.com/wwl/export/crypto/tool/stqrg.html
|
|
81
|
+
|
|
82
|
+
If you require further assistance please contact us by sending email to
|
|
83
|
+
export@cisco.com.
|
|
84
|
+
|
|
85
|
+
cisco ISR4321/K9 (1RU) processor with 1687137K/6147K bytes of memory.
|
|
86
|
+
Processor board ID FLM2041W2HD
|
|
87
|
+
2 Gigabit Ethernet interfaces
|
|
88
|
+
32768K bytes of non-volatile configuration memory.
|
|
89
|
+
4194304K bytes of physical memory.
|
|
90
|
+
3223551K bytes of flash memory at bootflash:.
|
|
91
|
+
|
|
92
|
+
`;
|
|
93
|
+
//# sourceMappingURL=bootBanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bootBanner.js","sourceRoot":"","sources":["../../src/shared/bootBanner.ts"],"names":[],"mappings":";;;AAAa,QAAA,WAAW,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwF1B,CAAC"}
|
package/dist/shared/constants.js
CHANGED
|
@@ -14,7 +14,7 @@ exports.IOS_ERROR_PATTERNS = [
|
|
|
14
14
|
{ type: 'CommandRejected', regex: /% Command rejected/i },
|
|
15
15
|
{ type: 'AccessDenied', regex: /% Permission denied/i }
|
|
16
16
|
];
|
|
17
|
-
exports.PROMPT_REGEX = /(?:^|[\r\n])\s*([A-Za-z0-9_\-@\.:\(\)/\\\[]
|
|
17
|
+
exports.PROMPT_REGEX = /(?:^|[\r\n])\s*([A-Za-z0-9_\-@\.:\(\)/\\\[]+\s*(?:>|#|\$|\]))\s*$/;
|
|
18
18
|
exports.MORE_REGEX = /(?:--\s*More\s*--|---\s*\(more\)\s*---|---- More ----|Press any key to continue|Press SPACE to continue)/i;
|
|
19
19
|
exports.DEFAULT_PROTECTED_INTERFACES = [
|
|
20
20
|
'GigabitEthernet0/0',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/shared/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,kBAAkB,GAAG;IAC9B,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa;IACpD,aAAa,EAAE,iBAAiB,EAAE,oBAAoB;CACzD,CAAC;AAEW,QAAA,kBAAkB,GAAG;IAC9B,EAAE,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,sBAAsB,EAAE;IAC3D,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,uBAAuB,EAAE;IAC7D,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,8BAA8B,EAAE;IAC/D,EAAE,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,yBAAyB,EAAE;IAC5D,EAAE,IAAI,EAAE,uBAAuB,EAAE,KAAK,EAAE,4BAA4B,EAAE;IACtE,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,qBAAqB,EAAE;IACzD,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,sBAAsB,EAAE;CAC1D,CAAC;AAGW,QAAA,YAAY,GAAG,
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/shared/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,kBAAkB,GAAG;IAC9B,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa;IACpD,aAAa,EAAE,iBAAiB,EAAE,oBAAoB;CACzD,CAAC;AAEW,QAAA,kBAAkB,GAAG;IAC9B,EAAE,IAAI,EAAE,kBAAkB,EAAE,KAAK,EAAE,sBAAsB,EAAE;IAC3D,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,uBAAuB,EAAE;IAC7D,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,8BAA8B,EAAE;IAC/D,EAAE,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,yBAAyB,EAAE;IAC5D,EAAE,IAAI,EAAE,uBAAuB,EAAE,KAAK,EAAE,4BAA4B,EAAE;IACtE,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,qBAAqB,EAAE;IACzD,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,sBAAsB,EAAE;CAC1D,CAAC;AAGW,QAAA,YAAY,GAAG,mEAAmE,CAAC;AAGnF,QAAA,UAAU,GAAG,2GAA2G,CAAC;AAIzH,QAAA,4BAA4B,GAAG;IACxC,oBAAoB;IACpB,oBAAoB;IACpB,oBAAoB;IACpB,OAAO;CACV,CAAC"}
|
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function dashboardAction(options: any): void;
|
|
@@ -1,16 +0,0 @@
|
|
|
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.dashboardAction = dashboardAction;
|
|
7
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
-
const MultiAgentCoordinator_1 = require("../../core/agent/MultiAgentCoordinator");
|
|
9
|
-
const dashboard_1 = require("../../server/dashboard");
|
|
10
|
-
function dashboardAction(options) {
|
|
11
|
-
const port = parseInt(options.port, 10);
|
|
12
|
-
const coordinator = new MultiAgentCoordinator_1.MultiAgentCoordinator();
|
|
13
|
-
(0, dashboard_1.startDashboardServer)(coordinator, port);
|
|
14
|
-
console.log(chalk_1.default.yellow('Standalone mode: Visualizing historical records and active topology when connected.'));
|
|
15
|
-
}
|
|
16
|
-
//# sourceMappingURL=dashboardCommand.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"dashboardCommand.js","sourceRoot":"","sources":["../../../src/cli/commands/dashboardCommand.ts"],"names":[],"mappings":";;;;;AAIA,0CAKC;AATD,kDAA0B;AAC1B,kFAA+E;AAC/E,sDAA8D;AAE9D,SAAgB,eAAe,CAAC,OAAY;IACxC,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACxC,MAAM,WAAW,GAAG,IAAI,6CAAqB,EAAE,CAAC;IAChD,IAAA,gCAAoB,EAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IACxC,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,MAAM,CAAC,qFAAqF,CAAC,CAAC,CAAC;AACrH,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function shellAction(): void;
|
|
@@ -1,44 +0,0 @@
|
|
|
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.shellAction = shellAction;
|
|
7
|
-
const readline_1 = __importDefault(require("readline"));
|
|
8
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
-
const shell_simulator_1 = require("../../server/shell-simulator");
|
|
10
|
-
function shellAction() {
|
|
11
|
-
const simulator = new shell_simulator_1.ShellSimulator();
|
|
12
|
-
console.clear();
|
|
13
|
-
console.log(chalk_1.default.bold.yellow('============================================================'));
|
|
14
|
-
console.log(chalk_1.default.bold.yellow(' Cisco IOS Interactive Mock Shell Simulator (v1.1.0)'));
|
|
15
|
-
console.log(chalk_1.default.bold.yellow('============================================================'));
|
|
16
|
-
const welcomeBanner = `\r\nCisco IOS Software, C2960 Software (C2960-LANBASEK9-M), Version 15.0(2)SE4, RELEASE SOFTWARE (fc1)\r\nTechnical Support: http://www.cisco.com/techsupport\r\nCopyright (c) 1986-2013 by Cisco Systems, Inc.\r\nCompiled Wed 26-Jun-13 02:49 by prod_rel_team\r\n\r\n`;
|
|
17
|
-
console.log(welcomeBanner);
|
|
18
|
-
const rl = readline_1.default.createInterface({ input: process.stdin, output: process.stdout });
|
|
19
|
-
const promptUser = () => {
|
|
20
|
-
rl.question(simulator.getPrompt(), (line) => {
|
|
21
|
-
const cmd = line.trim();
|
|
22
|
-
if (cmd.toLowerCase() === 'exit' && simulator.mode === 'USER_EXEC') {
|
|
23
|
-
console.log('Connection closed by foreign host.');
|
|
24
|
-
rl.close();
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
try {
|
|
28
|
-
const output = simulator.execute(cmd);
|
|
29
|
-
if (output) {
|
|
30
|
-
console.log(output);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
catch (err) {
|
|
34
|
-
console.log(`% Error: ${err.message}`);
|
|
35
|
-
}
|
|
36
|
-
promptUser();
|
|
37
|
-
});
|
|
38
|
-
};
|
|
39
|
-
promptUser();
|
|
40
|
-
rl.on('close', () => {
|
|
41
|
-
process.exit(0);
|
|
42
|
-
});
|
|
43
|
-
}
|
|
44
|
-
//# sourceMappingURL=shellCommand.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"shellCommand.js","sourceRoot":"","sources":["../../../src/cli/commands/shellCommand.ts"],"names":[],"mappings":";;;;;AAIA,kCAsCC;AA1CD,wDAAgC;AAChC,kDAA0B;AAC1B,kEAA8D;AAE9D,SAAgB,WAAW;IACvB,MAAM,SAAS,GAAG,IAAI,gCAAc,EAAE,CAAC;IAEvC,OAAO,CAAC,KAAK,EAAE,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,MAAM,CAAC,8DAA8D,CAAC,CAAC,CAAC;IAC/F,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,MAAM,CAAC,wDAAwD,CAAC,CAAC,CAAC;IACzF,OAAO,CAAC,GAAG,CAAC,eAAK,CAAC,IAAI,CAAC,MAAM,CAAC,8DAA8D,CAAC,CAAC,CAAC;IAC/F,MAAM,aAAa,GAAG,0QAA0Q,CAAC;IACjS,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAE3B,MAAM,EAAE,GAAG,kBAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAEtF,MAAM,UAAU,GAAG,GAAG,EAAE;QACpB,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,CAAC,IAAY,EAAE,EAAE;YAChD,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YACxB,IAAI,GAAG,CAAC,WAAW,EAAE,KAAK,MAAM,IAAI,SAAS,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBACjE,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;gBAClD,EAAE,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO;YACX,CAAC;YAED,IAAI,CAAC;gBACD,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBACtC,IAAI,MAAM,EAAE,CAAC;oBACT,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBACxB,CAAC;YACL,CAAC;YAAC,OAAO,GAAQ,EAAE,CAAC;gBAChB,OAAO,CAAC,GAAG,CAAC,YAAY,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YAC3C,CAAC;YACD,UAAU,EAAE,CAAC;QACjB,CAAC,CAAC,CAAC;IACP,CAAC,CAAC;IAEF,UAAU,EAAE,CAAC;IAEb,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QAChB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { BaseSession } from './BaseSession';
|
|
2
|
-
export declare class CmlSession extends BaseSession {
|
|
3
|
-
private apiUrl;
|
|
4
|
-
private username?;
|
|
5
|
-
private password?;
|
|
6
|
-
private token;
|
|
7
|
-
private activeLabId;
|
|
8
|
-
private ownedLab;
|
|
9
|
-
private activeNode;
|
|
10
|
-
private sshClient;
|
|
11
|
-
private sshStream;
|
|
12
|
-
constructor(apiUrl: string, username?: string | undefined, password?: string | undefined);
|
|
13
|
-
private request;
|
|
14
|
-
connect(): Promise<void>;
|
|
15
|
-
private provisionNode;
|
|
16
|
-
private waitForNodeBoot;
|
|
17
|
-
private findBestRunningNode;
|
|
18
|
-
private openSsh;
|
|
19
|
-
execute(command: string, timeoutMs?: number): Promise<string>;
|
|
20
|
-
private execViaSsh;
|
|
21
|
-
private getCmlStatus;
|
|
22
|
-
private listLabs;
|
|
23
|
-
private switchNode;
|
|
24
|
-
private getTopology;
|
|
25
|
-
disconnect(): Promise<void>;
|
|
26
|
-
}
|
|
@@ -1,448 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
-
var ownKeys = function(o) {
|
|
20
|
-
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
-
var ar = [];
|
|
22
|
-
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
-
return ar;
|
|
24
|
-
};
|
|
25
|
-
return ownKeys(o);
|
|
26
|
-
};
|
|
27
|
-
return function (mod) {
|
|
28
|
-
if (mod && mod.__esModule) return mod;
|
|
29
|
-
var result = {};
|
|
30
|
-
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
-
__setModuleDefault(result, mod);
|
|
32
|
-
return result;
|
|
33
|
-
};
|
|
34
|
-
})();
|
|
35
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
36
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
37
|
-
};
|
|
38
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
-
exports.CmlSession = void 0;
|
|
40
|
-
const BaseSession_1 = require("./BaseSession");
|
|
41
|
-
const chalk_1 = __importDefault(require("chalk"));
|
|
42
|
-
const https = __importStar(require("https"));
|
|
43
|
-
const net = __importStar(require("net"));
|
|
44
|
-
const PREFERRED_NODE_DEFS = ['iosv', 'iol-xe', 'csr1000v', 'cat8000v', 'iosxrv9000'];
|
|
45
|
-
const NODE_BOOT_TIMEOUT_MS = 5 * 60 * 1000;
|
|
46
|
-
const NODE_BOOT_POLL_MS = 8000;
|
|
47
|
-
class CmlSession extends BaseSession_1.BaseSession {
|
|
48
|
-
apiUrl;
|
|
49
|
-
username;
|
|
50
|
-
password;
|
|
51
|
-
token = null;
|
|
52
|
-
activeLabId = null;
|
|
53
|
-
ownedLab = false;
|
|
54
|
-
activeNode = null;
|
|
55
|
-
sshClient = null;
|
|
56
|
-
sshStream = null;
|
|
57
|
-
constructor(apiUrl, username, password) {
|
|
58
|
-
super();
|
|
59
|
-
this.apiUrl = apiUrl;
|
|
60
|
-
this.username = username;
|
|
61
|
-
this.password = password;
|
|
62
|
-
this.state = {
|
|
63
|
-
currentMode: 'PRIVILEGED_EXEC',
|
|
64
|
-
hostname: 'cml-sandbox',
|
|
65
|
-
prompt: 'cml-sandbox#'
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
async request(method, path, body) {
|
|
69
|
-
const base = this.apiUrl.replace(/\/$/, '');
|
|
70
|
-
const url = new URL(`${base}/api/v0${path}`);
|
|
71
|
-
return new Promise((resolve, reject) => {
|
|
72
|
-
const payload = body ? JSON.stringify(body) : undefined;
|
|
73
|
-
const headers = {
|
|
74
|
-
'Content-Type': 'application/json',
|
|
75
|
-
'Accept': 'application/json'
|
|
76
|
-
};
|
|
77
|
-
if (this.token)
|
|
78
|
-
headers['Authorization'] = `Bearer ${this.token}`;
|
|
79
|
-
if (payload)
|
|
80
|
-
headers['Content-Length'] = Buffer.byteLength(payload).toString();
|
|
81
|
-
const opts = {
|
|
82
|
-
hostname: url.hostname,
|
|
83
|
-
port: Number(url.port) || 443,
|
|
84
|
-
path: url.pathname + url.search,
|
|
85
|
-
method,
|
|
86
|
-
headers,
|
|
87
|
-
rejectUnauthorized: true
|
|
88
|
-
};
|
|
89
|
-
const req = https.request(opts, (res) => {
|
|
90
|
-
let data = '';
|
|
91
|
-
res.on('data', (c) => (data += c));
|
|
92
|
-
res.on('end', () => {
|
|
93
|
-
if (res.statusCode && res.statusCode >= 400) {
|
|
94
|
-
return reject(new Error(`CML API Error ${res.statusCode} on ${method} ${path}: ${data}`));
|
|
95
|
-
}
|
|
96
|
-
try {
|
|
97
|
-
resolve(data ? JSON.parse(data) : {});
|
|
98
|
-
}
|
|
99
|
-
catch {
|
|
100
|
-
resolve(data);
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
});
|
|
104
|
-
req.on('error', (e) => reject(e));
|
|
105
|
-
if (payload)
|
|
106
|
-
req.write(payload);
|
|
107
|
-
req.end();
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
async connect() {
|
|
111
|
-
const base = this.apiUrl.replace(/\/$/, '');
|
|
112
|
-
console.log(chalk_1.default.cyan(`❯ Connecting to Cisco Modeling Labs at ${chalk_1.default.bold(base)}...`));
|
|
113
|
-
const raw = await this.request('POST', '/authenticate', {
|
|
114
|
-
username: this.username || 'admin',
|
|
115
|
-
password: this.password || ''
|
|
116
|
-
});
|
|
117
|
-
this.token = typeof raw === 'string' ? raw : raw.token || String(raw);
|
|
118
|
-
console.log(chalk_1.default.green(`[+] Authenticated as ${chalk_1.default.bold(this.username || 'admin')}`));
|
|
119
|
-
console.log(chalk_1.default.cyan(`❯ Scanning CML for running labs and nodes...`));
|
|
120
|
-
const labIds = await this.request('GET', '/labs');
|
|
121
|
-
const runningNode = await this.findBestRunningNode(labIds || []);
|
|
122
|
-
if (runningNode) {
|
|
123
|
-
this.activeNode = runningNode;
|
|
124
|
-
this.activeLabId = runningNode.labId;
|
|
125
|
-
this.ownedLab = false;
|
|
126
|
-
this.state.hostname = runningNode.label;
|
|
127
|
-
this.state.prompt = `${runningNode.label}#`;
|
|
128
|
-
console.log(chalk_1.default.green(`[+] Found running node: ${chalk_1.default.bold(runningNode.label)} ` +
|
|
129
|
-
`[${runningNode.nodeDefinition}] in lab "${runningNode.labTitle}"`));
|
|
130
|
-
if (runningNode.mgmtIp) {
|
|
131
|
-
try {
|
|
132
|
-
await this.openSsh(runningNode.mgmtIp, runningNode.mgmtPort || 22);
|
|
133
|
-
console.log(chalk_1.default.green(`[+] SSH reachable at ${runningNode.label} (${runningNode.mgmtIp})`));
|
|
134
|
-
}
|
|
135
|
-
catch {
|
|
136
|
-
this.sshStream = null;
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
else {
|
|
141
|
-
const node = await this.provisionNode();
|
|
142
|
-
this.activeNode = node;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
async provisionNode() {
|
|
146
|
-
console.log(chalk_1.default.cyan(`❯ No running nodes found — provisioning a new Cisco node on CML...`));
|
|
147
|
-
const availDefs = await this.request('GET', '/simplified_node_definitions').catch(() => []);
|
|
148
|
-
const defIds = (availDefs || []).map((d) => d.id);
|
|
149
|
-
const chosenDef = PREFERRED_NODE_DEFS.find(d => defIds.includes(d)) || defIds[0];
|
|
150
|
-
if (!chosenDef) {
|
|
151
|
-
throw new Error('No node definitions available on this CML server.');
|
|
152
|
-
}
|
|
153
|
-
console.log(chalk_1.default.cyan(`❯ Creating sandbox lab with node type: ${chalk_1.default.bold(chosenDef)}...`));
|
|
154
|
-
const labRes = await this.request('POST', '/labs', {
|
|
155
|
-
title: `ciscollm-${chosenDef}-${Date.now()}`,
|
|
156
|
-
description: 'Auto-provisioned by ciscollm-cli.'
|
|
157
|
-
});
|
|
158
|
-
this.activeLabId = labRes.id;
|
|
159
|
-
this.ownedLab = true;
|
|
160
|
-
const nodeRes = await this.request('POST', `/labs/${this.activeLabId}/nodes`, {
|
|
161
|
-
label: `${chosenDef}-0`,
|
|
162
|
-
node_definition: chosenDef,
|
|
163
|
-
x: 0,
|
|
164
|
-
y: 0
|
|
165
|
-
});
|
|
166
|
-
const nodeId = nodeRes.id;
|
|
167
|
-
console.log(chalk_1.default.cyan(`❯ Starting lab ${this.activeLabId}...`));
|
|
168
|
-
await this.request('PUT', `/labs/${this.activeLabId}/start`);
|
|
169
|
-
const node = await this.waitForNodeBoot(this.activeLabId, nodeId, chosenDef);
|
|
170
|
-
console.log(chalk_1.default.green(`[+] Node ${chalk_1.default.bold(node.label)} is ${chalk_1.default.bold(node.state)} and ready.`));
|
|
171
|
-
return node;
|
|
172
|
-
}
|
|
173
|
-
async waitForNodeBoot(labId, nodeId, defId) {
|
|
174
|
-
const deadline = Date.now() + NODE_BOOT_TIMEOUT_MS;
|
|
175
|
-
let dots = 0;
|
|
176
|
-
process.stdout.write(chalk_1.default.cyan(`❯ Waiting for node to boot`));
|
|
177
|
-
while (Date.now() < deadline) {
|
|
178
|
-
const node = await this.request('GET', `/labs/${labId}/nodes/${nodeId}`);
|
|
179
|
-
const state = node.state || '';
|
|
180
|
-
if (state === 'BOOTED') {
|
|
181
|
-
process.stdout.write(`\n`);
|
|
182
|
-
const lab = await this.request('GET', `/labs/${labId}`);
|
|
183
|
-
const cmlNode = {
|
|
184
|
-
id: nodeId,
|
|
185
|
-
label: node.label || defId,
|
|
186
|
-
state,
|
|
187
|
-
nodeDefinition: defId,
|
|
188
|
-
labId,
|
|
189
|
-
labTitle: lab.title || labId
|
|
190
|
-
};
|
|
191
|
-
this.state.hostname = cmlNode.label;
|
|
192
|
-
this.state.prompt = `${cmlNode.label}#`;
|
|
193
|
-
return cmlNode;
|
|
194
|
-
}
|
|
195
|
-
dots++;
|
|
196
|
-
process.stdout.write(chalk_1.default.dim('.'));
|
|
197
|
-
await new Promise(r => setTimeout(r, NODE_BOOT_POLL_MS));
|
|
198
|
-
}
|
|
199
|
-
process.stdout.write(`\n`);
|
|
200
|
-
throw new Error(`Node did not reach BOOTED state within ${NODE_BOOT_TIMEOUT_MS / 60000} minutes.`);
|
|
201
|
-
}
|
|
202
|
-
async findBestRunningNode(labIds) {
|
|
203
|
-
const candidates = [];
|
|
204
|
-
for (const labId of labIds) {
|
|
205
|
-
try {
|
|
206
|
-
const lab = await this.request('GET', `/labs/${labId}`);
|
|
207
|
-
if (!lab || lab.state === 'STOPPED')
|
|
208
|
-
continue;
|
|
209
|
-
const nodeIds = await this.request('GET', `/labs/${labId}/nodes`);
|
|
210
|
-
if (!nodeIds || nodeIds.length === 0)
|
|
211
|
-
continue;
|
|
212
|
-
for (const nodeId of nodeIds) {
|
|
213
|
-
try {
|
|
214
|
-
const node = await this.request('GET', `/labs/${labId}/nodes/${nodeId}`);
|
|
215
|
-
if (!node || node.state === 'STOPPED' || node.state === 'DEFINED_ON_CORE') {
|
|
216
|
-
continue;
|
|
217
|
-
}
|
|
218
|
-
const candidate = {
|
|
219
|
-
id: nodeId,
|
|
220
|
-
label: node.label || nodeId,
|
|
221
|
-
state: node.state || 'UNKNOWN',
|
|
222
|
-
nodeDefinition: node.node_definition || 'unknown',
|
|
223
|
-
labId,
|
|
224
|
-
labTitle: lab.title || labId
|
|
225
|
-
};
|
|
226
|
-
try {
|
|
227
|
-
const l3 = await this.request('GET', `/labs/${labId}/nodes/${nodeId}/layer3_addresses`);
|
|
228
|
-
if (l3 && typeof l3 === 'object') {
|
|
229
|
-
const addresses = Object.values(l3);
|
|
230
|
-
for (const iface of addresses) {
|
|
231
|
-
if (iface?.ip4 && iface.ip4.length > 0) {
|
|
232
|
-
const ip = iface.ip4[0].split('/')[0];
|
|
233
|
-
candidate.mgmtIp = ip;
|
|
234
|
-
break;
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
catch { }
|
|
240
|
-
candidates.push(candidate);
|
|
241
|
-
}
|
|
242
|
-
catch { }
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
catch { }
|
|
246
|
-
}
|
|
247
|
-
if (candidates.length === 0)
|
|
248
|
-
return null;
|
|
249
|
-
const sorted = candidates.sort((a, b) => {
|
|
250
|
-
const stateScore = (s) => s === 'BOOTED' ? 3 : s === 'STARTED' ? 2 : s === 'DEFINED_ON_CORE' ? 1 : 0;
|
|
251
|
-
const sd = stateScore(b.state) - stateScore(a.state);
|
|
252
|
-
if (sd !== 0)
|
|
253
|
-
return sd;
|
|
254
|
-
return (b.mgmtIp ? 1 : 0) - (a.mgmtIp ? 1 : 0);
|
|
255
|
-
});
|
|
256
|
-
return sorted[0];
|
|
257
|
-
}
|
|
258
|
-
openSsh(host, port) {
|
|
259
|
-
return new Promise((resolve, reject) => {
|
|
260
|
-
const socket = new net.Socket();
|
|
261
|
-
const timeout = setTimeout(() => {
|
|
262
|
-
socket.destroy();
|
|
263
|
-
reject(new Error(`TCP connection to ${host}:${port} timed out`));
|
|
264
|
-
}, 4000);
|
|
265
|
-
socket.connect(port, host, () => {
|
|
266
|
-
clearTimeout(timeout);
|
|
267
|
-
socket.destroy();
|
|
268
|
-
resolve();
|
|
269
|
-
});
|
|
270
|
-
socket.on('error', (e) => {
|
|
271
|
-
clearTimeout(timeout);
|
|
272
|
-
reject(e);
|
|
273
|
-
});
|
|
274
|
-
});
|
|
275
|
-
}
|
|
276
|
-
async execute(command, timeoutMs = 8000) {
|
|
277
|
-
const lower = command.toLowerCase().trim();
|
|
278
|
-
if (lower === 'cml-status' || lower === 'cml status') {
|
|
279
|
-
return this.getCmlStatus();
|
|
280
|
-
}
|
|
281
|
-
if (lower === 'cml-labs' || lower === 'cml labs') {
|
|
282
|
-
return this.listLabs();
|
|
283
|
-
}
|
|
284
|
-
if (lower.startsWith('cml-node ') || lower.startsWith('cml node ')) {
|
|
285
|
-
const nodeLabel = command.split(' ').slice(1).join(' ');
|
|
286
|
-
return this.switchNode(nodeLabel);
|
|
287
|
-
}
|
|
288
|
-
if (lower === 'cml-topology' || lower === 'cml topology') {
|
|
289
|
-
return this.getTopology();
|
|
290
|
-
}
|
|
291
|
-
const prompt = this.state.prompt || `${this.state.hostname}#`;
|
|
292
|
-
console.log(`${chalk_1.default.blue('❯')} ${chalk_1.default.bold.yellow(prompt)} ${chalk_1.default.white(command)}`);
|
|
293
|
-
if (this.activeNode?.mgmtIp && this.sshStream === null) {
|
|
294
|
-
try {
|
|
295
|
-
const output = await this.execViaSsh(this.activeNode.mgmtIp, this.activeNode.mgmtPort || 22, command, timeoutMs);
|
|
296
|
-
if (output)
|
|
297
|
-
return output;
|
|
298
|
-
}
|
|
299
|
-
catch (e) {
|
|
300
|
-
console.log(chalk_1.default.dim(` [SSH fallback: ${e.message}]`));
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
if (this.activeLabId && this.activeNode) {
|
|
304
|
-
try {
|
|
305
|
-
const log = await this.request('GET', `/labs/${this.activeLabId}/nodes/${this.activeNode.id}/consoles/0/log`);
|
|
306
|
-
const lines = (log || '').trim().split('\n');
|
|
307
|
-
return lines.slice(-30).join('\n') || '';
|
|
308
|
-
}
|
|
309
|
-
catch {
|
|
310
|
-
return '';
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
return '';
|
|
314
|
-
}
|
|
315
|
-
execViaSsh(host, port, command, timeoutMs) {
|
|
316
|
-
return new Promise((resolve, reject) => {
|
|
317
|
-
const { spawn } = require('child_process');
|
|
318
|
-
const args = [
|
|
319
|
-
'-o', 'StrictHostKeyChecking=no',
|
|
320
|
-
'-o', 'UserKnownHostsFile=/dev/null',
|
|
321
|
-
'-o', `ConnectTimeout=${Math.ceil(timeoutMs / 1000)}`,
|
|
322
|
-
'-p', String(port),
|
|
323
|
-
`${this.username || 'admin'}@${host}`,
|
|
324
|
-
command
|
|
325
|
-
];
|
|
326
|
-
const proc = spawn('ssh', args, { env: process.env });
|
|
327
|
-
let out = '';
|
|
328
|
-
let err = '';
|
|
329
|
-
proc.stdout.on('data', (d) => { out += d.toString(); });
|
|
330
|
-
proc.stderr.on('data', (d) => { err += d.toString(); });
|
|
331
|
-
const timer = setTimeout(() => {
|
|
332
|
-
proc.kill();
|
|
333
|
-
resolve(out || '');
|
|
334
|
-
}, timeoutMs);
|
|
335
|
-
proc.on('close', () => {
|
|
336
|
-
clearTimeout(timer);
|
|
337
|
-
if (out)
|
|
338
|
-
resolve(out);
|
|
339
|
-
else if (err && !err.includes('Warning:'))
|
|
340
|
-
reject(new Error(err.trim()));
|
|
341
|
-
else
|
|
342
|
-
resolve('');
|
|
343
|
-
});
|
|
344
|
-
});
|
|
345
|
-
}
|
|
346
|
-
async getCmlStatus() {
|
|
347
|
-
if (!this.activeLabId) {
|
|
348
|
-
return JSON.stringify({ status: 'not_connected', mode: 'config-only' });
|
|
349
|
-
}
|
|
350
|
-
try {
|
|
351
|
-
const lab = await this.request('GET', `/labs/${this.activeLabId}`);
|
|
352
|
-
const stats = await this.request('GET', `/labs/${this.activeLabId}/simulation_stats`).catch(() => null);
|
|
353
|
-
return JSON.stringify({
|
|
354
|
-
status: lab.state,
|
|
355
|
-
lab_id: this.activeLabId,
|
|
356
|
-
title: lab.title,
|
|
357
|
-
node: this.activeNode
|
|
358
|
-
? { id: this.activeNode.id, label: this.activeNode.label, state: this.activeNode.state }
|
|
359
|
-
: null,
|
|
360
|
-
stats
|
|
361
|
-
}, null, 2);
|
|
362
|
-
}
|
|
363
|
-
catch (e) {
|
|
364
|
-
return JSON.stringify({ error: e.message });
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
async listLabs() {
|
|
368
|
-
try {
|
|
369
|
-
const labIds = await this.request('GET', '/labs');
|
|
370
|
-
const details = await Promise.all((labIds || []).map(async (id) => {
|
|
371
|
-
try {
|
|
372
|
-
const lab = await this.request('GET', `/labs/${id}`);
|
|
373
|
-
const nodes = await this.request('GET', `/labs/${id}/nodes`);
|
|
374
|
-
return { id, title: lab.title, state: lab.state, nodeCount: (nodes || []).length };
|
|
375
|
-
}
|
|
376
|
-
catch {
|
|
377
|
-
return { id, error: 'fetch_failed' };
|
|
378
|
-
}
|
|
379
|
-
}));
|
|
380
|
-
return JSON.stringify(details, null, 2);
|
|
381
|
-
}
|
|
382
|
-
catch (e) {
|
|
383
|
-
return JSON.stringify({ error: e.message });
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
async switchNode(label) {
|
|
387
|
-
if (!this.activeLabId)
|
|
388
|
-
return JSON.stringify({ error: 'no_lab_connected' });
|
|
389
|
-
try {
|
|
390
|
-
const result = await this.request('GET', `/labs/${this.activeLabId}/find/node/label/${encodeURIComponent(label)}`);
|
|
391
|
-
if (result && result.node_id) {
|
|
392
|
-
const node = await this.request('GET', `/labs/${this.activeLabId}/nodes/${result.node_id}`);
|
|
393
|
-
this.activeNode = {
|
|
394
|
-
id: result.node_id,
|
|
395
|
-
label: node.label,
|
|
396
|
-
state: node.state,
|
|
397
|
-
nodeDefinition: node.node_definition,
|
|
398
|
-
labId: this.activeLabId,
|
|
399
|
-
labTitle: ''
|
|
400
|
-
};
|
|
401
|
-
this.state.hostname = node.label;
|
|
402
|
-
this.state.prompt = `${node.label}#`;
|
|
403
|
-
return JSON.stringify({ switched_to: node.label, node_id: result.node_id });
|
|
404
|
-
}
|
|
405
|
-
return JSON.stringify({ error: `Node "${label}" not found` });
|
|
406
|
-
}
|
|
407
|
-
catch (e) {
|
|
408
|
-
return JSON.stringify({ error: e.message });
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
async getTopology() {
|
|
412
|
-
if (!this.activeLabId)
|
|
413
|
-
return JSON.stringify({ error: 'no_lab_connected' });
|
|
414
|
-
try {
|
|
415
|
-
const topology = await this.request('GET', `/labs/${this.activeLabId}/topology`);
|
|
416
|
-
return JSON.stringify(topology, null, 2);
|
|
417
|
-
}
|
|
418
|
-
catch (e) {
|
|
419
|
-
return JSON.stringify({ error: e.message });
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
async disconnect() {
|
|
423
|
-
if (this.activeLabId && this.ownedLab) {
|
|
424
|
-
try {
|
|
425
|
-
console.log(chalk_1.default.cyan(`❯ Deleting sandbox lab ${this.activeLabId}...`));
|
|
426
|
-
await this.request('DELETE', `/labs/${this.activeLabId}`);
|
|
427
|
-
console.log(chalk_1.default.green(`[+] Sandbox lab deleted cleanly.`));
|
|
428
|
-
}
|
|
429
|
-
catch (e) {
|
|
430
|
-
console.warn(chalk_1.default.yellow(`[!] Could not delete lab: ${e.message}`));
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
else if (this.activeLabId && !this.ownedLab) {
|
|
434
|
-
console.log(chalk_1.default.dim(` Leaving external lab ${this.activeLabId} intact (not owned by this session).`));
|
|
435
|
-
}
|
|
436
|
-
this.activeLabId = null;
|
|
437
|
-
if (this.token) {
|
|
438
|
-
try {
|
|
439
|
-
await this.request('DELETE', '/logout');
|
|
440
|
-
console.log(chalk_1.default.green(`[+] Logged out from CML successfully.`));
|
|
441
|
-
}
|
|
442
|
-
catch { }
|
|
443
|
-
this.token = null;
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
exports.CmlSession = CmlSession;
|
|
448
|
-
//# sourceMappingURL=CmlSession.js.map
|