ciscollm-cli 1.1.0 → 1.1.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/README.md +122 -279
- package/dist/core/agent/AgentLoop.d.ts +1 -0
- package/dist/core/agent/AgentLoop.js +126 -21
- package/dist/core/agent/AgentLoop.js.map +1 -1
- package/dist/core/rollback/TransactionManager.js +89 -92
- package/dist/core/rollback/TransactionManager.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/llm/LLMClient.d.ts +2 -1
- package/dist/infrastructure/llm/LLMClient.js +48 -18
- package/dist/infrastructure/llm/LLMClient.js.map +1 -1
- package/dist/infrastructure/protocols/PlinkSerial.js +11 -1
- package/dist/infrastructure/protocols/PlinkSerial.js.map +1 -1
- package/dist/infrastructure/protocols/SshSession.js +11 -2
- package/dist/infrastructure/protocols/SshSession.js.map +1 -1
- package/dist/infrastructure/protocols/TelnetSession.js +10 -1
- package/dist/infrastructure/protocols/TelnetSession.js.map +1 -1
- package/dist/server/shell-simulator.js +27 -0
- package/dist/server/shell-simulator.js.map +1 -1
- package/dist/shared/utils.d.ts +1 -0
- package/dist/shared/utils.js +46 -5
- package/dist/shared/utils.js.map +1 -1
- package/package.json +52 -52
- package/dist/infrastructure/protocols/MockSession.d.ts +0 -80
- package/dist/infrastructure/protocols/MockSession.js +0 -953
- package/dist/infrastructure/protocols/MockSession.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,279 +1,122 @@
|
|
|
1
|
-
# ciscollm-cli
|
|
2
|
-
|
|
3
|
-
`ciscollm-cli` is
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
* **
|
|
15
|
-
* **
|
|
16
|
-
* **
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
* **
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
###
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
###
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
### 1. `ciscollm run`
|
|
125
|
-
Execute network configuration or optimization tasks on target Cisco hardware.
|
|
126
|
-
|
|
127
|
-
```bash
|
|
128
|
-
ciscollm run [options]
|
|
129
|
-
```
|
|
130
|
-
|
|
131
|
-
| Option / Flag | Alias | Description | Default Value |
|
|
132
|
-
|---|---|---|---|
|
|
133
|
-
| `-g, --goal <intent>` | - | The goal of the configuration/troubleshooting task. If not specified, launches the Interactive Setup Wizard. | - |
|
|
134
|
-
| `--protocol <type>` | - | Connection protocol (`serial`, `ssh`, `telnet`, `mock`, `netconf`, `cml`). | `serial` |
|
|
135
|
-
| `--provider <type>` | - | LLM provider mode (`local`, `cloud`). | `local` |
|
|
136
|
-
| `--local-type <type>` | - | Local LLM server flavor (`ollama`, `lmstudio`). | `ollama` |
|
|
137
|
-
| `--model <name>` | - | Name of the LLM model to compile. | - |
|
|
138
|
-
| `--endpoint <url>` | - | The LLM API endpoint URL. | - |
|
|
139
|
-
| `--api-key <key>` | - | API key for the cloud provider (OpenRouter). | - |
|
|
140
|
-
| `-c, --com <ports>` | - | COM Port(s), comma-separated (e.g., `COM3` or `COM3,COM4`). | - |
|
|
141
|
-
| `-b, --baud <rate>` | - | Serial transmission baud rate. | `9600` |
|
|
142
|
-
| `--host <address>` | - | Target IP address or hostname (comma-separated for multi-device). | - |
|
|
143
|
-
| `--port <port>` | - | Target connection port. | - |
|
|
144
|
-
| `-u, --username <name>` | - | Device login username. | - |
|
|
145
|
-
| `-p, --password <pass>` | - | Device login password. | - |
|
|
146
|
-
| `--env-password` | - | Read the device password from the `CISCOLLM_PASS` environment variable. | `false` |
|
|
147
|
-
| `--private-key <path>` | - | SSH private key file path for SSH and NETCONF sessions. | - |
|
|
148
|
-
| `--passphrase <passphrase>` | - | Passphrase for the SSH private key file. | - |
|
|
149
|
-
| `--netconf-ready-timeout <ms>` | - | NETCONF SSH ready timeout in milliseconds. | `20000` |
|
|
150
|
-
| `--netconf-hello-timeout <ms>` | - | NETCONF hello exchange timeout in milliseconds. | `15000` |
|
|
151
|
-
| `--netconf-rpc-timeout <ms>` | - | NETCONF RPC response timeout in milliseconds. | `15000` |
|
|
152
|
-
| `--netconf-keepalive-interval <ms>` | - | NETCONF SSH keepalive interval in milliseconds. | `10000` |
|
|
153
|
-
| `--strict-command-ref` | - | Block commands not found in the `cf_command_ref.pdf` index. | `false` |
|
|
154
|
-
| `--no-ref-telemetry` | - | Disable command-reference warmup telemetry logs. | `false` |
|
|
155
|
-
| `--non-interactive` | - | Run without interactive prompts (auto-rejects dangerous commands). | `false` |
|
|
156
|
-
| `--rbac-role <role>` | - | Specify the Active Agent RBAC authorization role (`admin`, `read_only`). | `admin` |
|
|
157
|
-
| `--dashboard-port <port>` | - | Port to host the live Visual Control Dashboard server. | `3000` |
|
|
158
|
-
|
|
159
|
-
### 2. `ciscollm server`
|
|
160
|
-
Start the Cisco IOS Multi-Protocol Test Simulator (SSH, Telnet, NETCONF, and HTTP LLM Mock).
|
|
161
|
-
|
|
162
|
-
```bash
|
|
163
|
-
ciscollm server [options]
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
| Option / Flag | Description | Default Value |
|
|
167
|
-
|---|---|---|
|
|
168
|
-
| `--ssh-port <port>` | Port for the mock SSH & NETCONF server | `2222` |
|
|
169
|
-
| `--telnet-port <port>` | Port for the mock Telnet server | `2323` |
|
|
170
|
-
| `--http-port <port>` | Port for the mock HTTP LLM server | `11434` |
|
|
171
|
-
|
|
172
|
-
### 3. `ciscollm shell`
|
|
173
|
-
Launch the interactive stateful Cisco IOS mock shell simulator directly.
|
|
174
|
-
|
|
175
|
-
```bash
|
|
176
|
-
ciscollm shell
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
### 4. `ciscollm dashboard`
|
|
180
|
-
Start the visual control dashboard server standalone to inspect historical records and active topology.
|
|
181
|
-
|
|
182
|
-
```bash
|
|
183
|
-
ciscollm dashboard [options]
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
| Option / Flag | Description | Default Value |
|
|
187
|
-
|---|---|---|
|
|
188
|
-
| `--port <port>` | Port for the dashboard server | `3000` |
|
|
189
|
-
|
|
190
|
-
---
|
|
191
|
-
|
|
192
|
-
## 💡 Usage Examples
|
|
193
|
-
|
|
194
|
-
### 1. Launching the Interactive Setup Wizard
|
|
195
|
-
Start the interactive CLI configuration process:
|
|
196
|
-
```bash
|
|
197
|
-
ciscollm run
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
### 2. Running a Quick Mock Simulation
|
|
201
|
-
```bash
|
|
202
|
-
ciscollm run --protocol mock --goal "Configure GigabitEthernet0/1 with IP 192.168.2.1/24 and interface description 'LAN B'"
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
### 3. Local Model (Ollama)
|
|
206
|
-
```bash
|
|
207
|
-
ciscollm run --provider local --local-type ollama --endpoint http://127.0.0.1:11434/v1 --model qwen3.5-4b --protocol mock --goal "Show IP routing table"
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### 4. Cloud Inference via OpenRouter
|
|
211
|
-
```bash
|
|
212
|
-
ciscollm run --provider cloud --api-key YOUR_OPENROUTER_API_KEY --protocol mock --goal "Verify interface states"
|
|
213
|
-
```
|
|
214
|
-
|
|
215
|
-
### 5. Enforcing Strict Validation Mode
|
|
216
|
-
```bash
|
|
217
|
-
ciscollm run --strict-command-ref --protocol mock --goal "Configure router ospf 1 and advertise network 192.168.1.0/24"
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
### 6. NETCONF Session with SSH Key Auth
|
|
221
|
-
```bash
|
|
222
|
-
ciscollm run --protocol netconf --host 192.168.1.188 --port 830 --username admin --private-key C:\\Users\\me\\.ssh\\id_rsa --passphrase YOUR_PASSPHRASE --netconf-rpc-timeout 20000 --goal "Show running configuration"
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
### 7. NETCONF Session with Password from Environment
|
|
226
|
-
```bash
|
|
227
|
-
$env:CISCOLLM_PASS = '!@admin1234'
|
|
228
|
-
ciscollm run --protocol netconf --host 192.168.1.188 --username admin --env-password --goal "Show interface brief"
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
### 8. Starting the Multi-Protocol Test Simulator
|
|
232
|
-
Start the simulator server which handles SSH/Telnet connections and hosts a mock LLM endpoint:
|
|
233
|
-
```bash
|
|
234
|
-
ciscollm server --ssh-port 2222 --telnet-port 2323 --http-port 11434
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
### 9. Launching the Stateful Interactive Shell
|
|
238
|
-
Directly test and play with IOS commands:
|
|
239
|
-
```bash
|
|
240
|
-
ciscollm shell
|
|
241
|
-
```
|
|
242
|
-
|
|
243
|
-
### 10. Running the Dashboard Standalone
|
|
244
|
-
Inspect previous change runs, active state differences, or network topologies:
|
|
245
|
-
```bash
|
|
246
|
-
ciscollm dashboard --port 3000
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
---
|
|
250
|
-
|
|
251
|
-
## 💻 Development & Contribution
|
|
252
|
-
|
|
253
|
-
Follow these steps to set up the project locally for development:
|
|
254
|
-
|
|
255
|
-
### 1. Clone & Install Dependencies
|
|
256
|
-
```bash
|
|
257
|
-
git clone https://github.com/ThemeHackers/ciscollm-cli.git
|
|
258
|
-
cd ciscollm-cli
|
|
259
|
-
npm install
|
|
260
|
-
```
|
|
261
|
-
|
|
262
|
-
### 2. Build the Project
|
|
263
|
-
Compile the TypeScript code to target JavaScript inside `dist/`:
|
|
264
|
-
```bash
|
|
265
|
-
npm run build
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
### 3. Run Development Build
|
|
269
|
-
Run the CLI locally from source code:
|
|
270
|
-
```bash
|
|
271
|
-
npm start -- run --protocol mock --goal "Show running config"
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
### 4. Run Unit Tests
|
|
275
|
-
Validate features including the Command Firewall, Transaction Manager, and Error Analyzer:
|
|
276
|
-
```bash
|
|
277
|
-
npm run test
|
|
278
|
-
```
|
|
279
|
-
|
|
1
|
+
# ciscollm-cli
|
|
2
|
+
|
|
3
|
+
`ciscollm-cli` is an autonomous Cisco IOS automation agent CLI powered by LLM tool-calling. It allows network engineers to configure, troubleshoot, and simulate Cisco hardware safely and efficiently with strict safety guardrails.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🚀 Core Capabilities
|
|
8
|
+
|
|
9
|
+
1. **Intelligent Cisco Automation Swarm**
|
|
10
|
+
* Multi-agent coordination with role-based routing (Core, Distribution, Access).
|
|
11
|
+
* Supports both local models (Ollama, LM Studio) and cloud endpoints (OpenRouter).
|
|
12
|
+
|
|
13
|
+
2. **Enterprise-Grade Safety Guardrails**
|
|
14
|
+
* **Command Firewall**: Intercepts high-risk commands (e.g. disabling AAA, removing access groups, shutting management interfaces).
|
|
15
|
+
* **Dry-Run Validation**: Analyzes network topology beforehand to prevent accidental disruptions.
|
|
16
|
+
* **Strict Command Reference**: Restricts execution to valid Cisco IOS command sets indexed from `cf_command_ref.pdf`.
|
|
17
|
+
|
|
18
|
+
3. **Atomic Transactions & Recovery**
|
|
19
|
+
* **Atomic Replace**: Backs up configuration to flash and uses `configure replace` to restore state on failures.
|
|
20
|
+
* **Command Inversion Fallback**: Generates reverse commands (e.g. `shutdown` -> `no shutdown`) to recover state if flash storage is unavailable.
|
|
21
|
+
|
|
22
|
+
4. **Live Visualization & Audits**
|
|
23
|
+
* **Visual Control Dashboard**: A real-time SPA showing network topology maps, agent thinking logs, configuration diffs, and manual rollbacks.
|
|
24
|
+
* **State Diff Engine**: Displays colorized differences (green/red/yellow) in routing tables, VLANs, and interfaces.
|
|
25
|
+
* **Enterprise Audit Log**: Local, structured audit logging (`audit.log`) for compliance.
|
|
26
|
+
|
|
27
|
+
5. **Multi-Protocol Simulation & Adapters**
|
|
28
|
+
* Adapters for Serial (Plink), SSH, Telnet, NETCONF XML, and Cisco Modeling Labs (CML).
|
|
29
|
+
* Stateful mock IOS simulator server and local interactive shell (`ciscollm shell`).
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## 📦 Quick Start
|
|
34
|
+
|
|
35
|
+
### Installation
|
|
36
|
+
Install the global executable via `npm`:
|
|
37
|
+
```bash
|
|
38
|
+
npm install -g ciscollm-cli
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Starting the Simulator Server (For Testing)
|
|
42
|
+
Start the multi-protocol test server (SSH, Telnet, NETCONF, and Mock LLM endpoint):
|
|
43
|
+
```bash
|
|
44
|
+
ciscollm server --ssh-port 2222 --telnet-port 2323 --http-port 11434
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### Launching the Agent
|
|
48
|
+
Run the interactive setup wizard to configure the agent target and goals:
|
|
49
|
+
```bash
|
|
50
|
+
ciscollm run
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 🛠️ CLI Usage & Options
|
|
56
|
+
|
|
57
|
+
### `ciscollm run [options]`
|
|
58
|
+
Execute configuration or optimization tasks on target hardware.
|
|
59
|
+
|
|
60
|
+
| Option / Flag | Description | Default |
|
|
61
|
+
|---|---|---|
|
|
62
|
+
| `-g, --goal <intent>` | Configuration goal. Omit to launch the Interactive Setup Wizard. | - |
|
|
63
|
+
| `--protocol <type>` | Connection protocol (`serial`, `ssh`, `telnet`, `netconf`, `cml`). | `serial` |
|
|
64
|
+
| `--provider <type>` | LLM provider mode (`local`, `cloud`). | `local` |
|
|
65
|
+
| `--local-type <type>` | Local LLM service flavor (`ollama`, `lmstudio`). | `ollama` |
|
|
66
|
+
| `--model <name>` | LLM model name. | - |
|
|
67
|
+
| `--endpoint <url>` | LLM API server endpoint. | - |
|
|
68
|
+
| `--api-key <key>` | Cloud provider (OpenRouter) API key. | - |
|
|
69
|
+
| `-c, --com <ports>` | COM Port(s), comma-separated (e.g., `COM3,COM4`). | - |
|
|
70
|
+
| `--host <address>` | Target IP / hostnames, comma-separated. | - |
|
|
71
|
+
| `-u, --username <name>` | Login username. | - |
|
|
72
|
+
| `-p, --password <pass>` | Login password. | - |
|
|
73
|
+
| `--strict-command-ref` | Block commands not listed in `cf_command_ref.pdf`. | `false` |
|
|
74
|
+
| `--non-interactive` | Auto-reject high-risk commands instead of prompting for approval. | `false` |
|
|
75
|
+
| `--rbac-role <role>` | Authorization role (`admin`, `read_only`). | `admin` |
|
|
76
|
+
| `--dashboard-port <port>` | Live Visual Dashboard port. | `3000` |
|
|
77
|
+
|
|
78
|
+
### Other Commands
|
|
79
|
+
* `ciscollm server [options]` - Start mock SSH, Telnet, and LLM servers for sandbox testing.
|
|
80
|
+
* `ciscollm shell` - Launch a stateful interactive mock Cisco IOS command line directly.
|
|
81
|
+
* `ciscollm dashboard [--port <port>]` - Start the visual dashboard standalone.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## 💡 Quick Examples
|
|
86
|
+
|
|
87
|
+
#### 1. Configuring Interfaces via Local Simulation (SSH)
|
|
88
|
+
```bash
|
|
89
|
+
ciscollm run --protocol ssh --host 127.0.0.1 --port 2222 -u admin -p admin --goal "Configure GigabitEthernet0/1 with IP 192.168.2.1/24 and interface description 'LAN B'"
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
#### 2. Running local LLM (Ollama) against Simulation
|
|
93
|
+
```bash
|
|
94
|
+
ciscollm run --provider local --local-type ollama --endpoint http://127.0.0.1:11434/v1 --model qwen3.5:4b --protocol ssh --host 127.0.0.1 --port 2222 -u admin -p admin --goal "Show IP routing table"
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
#### 3. Strict Command Reference compliance
|
|
98
|
+
```bash
|
|
99
|
+
ciscollm run --strict-command-ref --protocol ssh --host 127.0.0.1 --port 2222 -u admin -p admin --goal "Configure router ospf 1 and advertise 192.168.1.0/24"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## 💻 Development
|
|
105
|
+
|
|
106
|
+
1. **Setup Workspace:**
|
|
107
|
+
```bash
|
|
108
|
+
git clone https://github.com/ThemeHackers/ciscollm-cli.git
|
|
109
|
+
cd ciscollm-cli
|
|
110
|
+
npm install
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
2. **Build and Run:**
|
|
114
|
+
```bash
|
|
115
|
+
npm run build
|
|
116
|
+
npm start -- run
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
3. **Run Unit Tests:**
|
|
120
|
+
```bash
|
|
121
|
+
npm run test
|
|
122
|
+
```
|
|
@@ -34,6 +34,7 @@ export declare class CiscoAgentLoop {
|
|
|
34
34
|
private resolveTargetDevice;
|
|
35
35
|
private classifyCommand;
|
|
36
36
|
private handleExecuteCommandCall;
|
|
37
|
+
private prefixLengthToMask;
|
|
37
38
|
private captureDeviceSnapshot;
|
|
38
39
|
private handleEnableIosShellCall;
|
|
39
40
|
private handleDefineShellVariableCall;
|
|
@@ -18,6 +18,7 @@ const AuditLogger_1 = require("../guardrails/AuditLogger");
|
|
|
18
18
|
const HierarchicalAgentManager_1 = require("./HierarchicalAgentManager");
|
|
19
19
|
const StateDiff_1 = require("../rollback/StateDiff");
|
|
20
20
|
const NetworkAudit_1 = require("../guardrails/NetworkAudit");
|
|
21
|
+
const utils_1 = require("../../shared/utils");
|
|
21
22
|
class CiscoAgentLoop {
|
|
22
23
|
llmClient;
|
|
23
24
|
coordinator;
|
|
@@ -462,7 +463,7 @@ class CiscoAgentLoop {
|
|
|
462
463
|
async handleExecuteCommandCall(call) {
|
|
463
464
|
let args;
|
|
464
465
|
try {
|
|
465
|
-
args =
|
|
466
|
+
args = (0, utils_1.safeJsonParse)(call.function.arguments);
|
|
466
467
|
}
|
|
467
468
|
catch (e) {
|
|
468
469
|
this.injectToolResponse(call.id, 'execute_ios_command', `Format Error: Invalid Tool Call arguments. Must be JSON.`);
|
|
@@ -634,32 +635,136 @@ class CiscoAgentLoop {
|
|
|
634
635
|
this.injectToolResponse(call.id, 'execute_ios_command', `Hardware Session Fault: ${error.message}`);
|
|
635
636
|
}
|
|
636
637
|
}
|
|
638
|
+
prefixLengthToMask(prefix) {
|
|
639
|
+
const mask = [];
|
|
640
|
+
for (let i = 0; i < 4; i++) {
|
|
641
|
+
const n = Math.min(prefix, 8);
|
|
642
|
+
mask.push(256 - Math.pow(2, 8 - n));
|
|
643
|
+
prefix -= n;
|
|
644
|
+
}
|
|
645
|
+
return mask.join('.');
|
|
646
|
+
}
|
|
637
647
|
async captureDeviceSnapshot(deviceId) {
|
|
638
648
|
const session = this.coordinator.getSession(deviceId);
|
|
639
649
|
if (!session)
|
|
640
650
|
return null;
|
|
641
|
-
|
|
642
|
-
const
|
|
643
|
-
const
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
651
|
+
try {
|
|
652
|
+
const state = session.getState();
|
|
653
|
+
const prefix = (state.currentMode === 'GLOBAL_CONFIG' || state.currentMode === 'INTERFACE_CONFIG') ? 'do ' : '';
|
|
654
|
+
let configText = '';
|
|
655
|
+
try {
|
|
656
|
+
configText = await session.execute(`${prefix}show running-config`);
|
|
657
|
+
}
|
|
658
|
+
catch (err) {
|
|
659
|
+
ui_1.logger.warn(`Failed to execute show running-config: ${err.message}`);
|
|
660
|
+
}
|
|
661
|
+
let routesText = '';
|
|
662
|
+
try {
|
|
663
|
+
routesText = await session.execute(`${prefix}show ip route`);
|
|
664
|
+
}
|
|
665
|
+
catch (err) {
|
|
666
|
+
ui_1.logger.warn(`Failed to execute show ip route: ${err.message}`);
|
|
667
|
+
}
|
|
668
|
+
let vlansText = '';
|
|
669
|
+
try {
|
|
670
|
+
vlansText = await session.execute(`${prefix}show vlan brief`);
|
|
671
|
+
}
|
|
672
|
+
catch (err) {
|
|
673
|
+
try {
|
|
674
|
+
vlansText = await session.execute(`${prefix}show vlan`);
|
|
675
|
+
}
|
|
676
|
+
catch {
|
|
677
|
+
// ignore
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
const interfaces = [];
|
|
681
|
+
if (configText) {
|
|
682
|
+
const lines = configText.split(/\r?\n/);
|
|
683
|
+
let currentInterface = null;
|
|
684
|
+
for (const line of lines) {
|
|
685
|
+
const trimmed = line.trim();
|
|
686
|
+
if (trimmed.startsWith('interface ')) {
|
|
687
|
+
const name = trimmed.substring(10).trim();
|
|
688
|
+
currentInterface = {
|
|
689
|
+
name,
|
|
690
|
+
ip: null,
|
|
691
|
+
subnet: null,
|
|
692
|
+
adminShutdown: false,
|
|
693
|
+
lineProtocolUp: true,
|
|
694
|
+
description: null
|
|
695
|
+
};
|
|
696
|
+
interfaces.push(currentInterface);
|
|
697
|
+
}
|
|
698
|
+
else if (currentInterface) {
|
|
699
|
+
if (trimmed.startsWith('ip address ')) {
|
|
700
|
+
const parts = trimmed.substring(11).trim().split(/\s+/);
|
|
701
|
+
if (parts.length >= 2) {
|
|
702
|
+
currentInterface.ip = parts[0];
|
|
703
|
+
currentInterface.subnet = parts[1];
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
else if (trimmed.startsWith('description ')) {
|
|
707
|
+
currentInterface.description = trimmed.substring(12).trim();
|
|
708
|
+
}
|
|
709
|
+
else if (trimmed === 'shutdown') {
|
|
710
|
+
currentInterface.adminShutdown = true;
|
|
711
|
+
currentInterface.lineProtocolUp = false;
|
|
712
|
+
}
|
|
713
|
+
else if (trimmed === 'no shutdown') {
|
|
714
|
+
currentInterface.adminShutdown = false;
|
|
715
|
+
currentInterface.lineProtocolUp = true;
|
|
716
|
+
}
|
|
717
|
+
else if (line.startsWith('!') || trimmed === 'end') {
|
|
718
|
+
currentInterface = null;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
const routes = [];
|
|
724
|
+
if (routesText) {
|
|
725
|
+
const routeLines = routesText.split(/\r?\n/);
|
|
726
|
+
for (const line of routeLines) {
|
|
727
|
+
const trimmed = line.trim();
|
|
728
|
+
const routeMatch = /^([C|S|R|B|O|D])\s+(\d{1,3}(?:\.\d{1,3}){3})\/(\d+)\s+(?:via\s+(\d{1,3}(?:\.\d{1,3}){3})|is\s+directly\s+connected,\s+(\S+))/i.exec(trimmed);
|
|
729
|
+
if (routeMatch) {
|
|
730
|
+
const network = routeMatch[2];
|
|
731
|
+
const prefixLen = parseInt(routeMatch[3], 10);
|
|
732
|
+
const nextHop = routeMatch[4] || null;
|
|
733
|
+
const mask = this.prefixLengthToMask(prefixLen);
|
|
734
|
+
routes.push({
|
|
735
|
+
network,
|
|
736
|
+
mask,
|
|
737
|
+
nextHop
|
|
738
|
+
});
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
const vlans = [];
|
|
743
|
+
if (vlansText) {
|
|
744
|
+
const vlanLines = vlansText.split(/\r?\n/);
|
|
745
|
+
for (const line of vlanLines) {
|
|
746
|
+
const trimmed = line.trim();
|
|
747
|
+
const vlanMatch = /^(\d+)\s+(\S+)/.exec(trimmed);
|
|
748
|
+
if (vlanMatch) {
|
|
749
|
+
const vid = parseInt(vlanMatch[1], 10);
|
|
750
|
+
if (!isNaN(vid) && !vlans.includes(vid)) {
|
|
751
|
+
vlans.push(vid);
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
}
|
|
653
755
|
}
|
|
654
756
|
return {
|
|
655
757
|
deviceId,
|
|
656
758
|
timestamp: new Date().toISOString(),
|
|
657
759
|
sessionState: session.getState(),
|
|
658
|
-
interfaces
|
|
659
|
-
routes
|
|
660
|
-
vlans
|
|
760
|
+
interfaces,
|
|
761
|
+
routes,
|
|
762
|
+
vlans
|
|
661
763
|
};
|
|
662
764
|
}
|
|
765
|
+
catch (e) {
|
|
766
|
+
ui_1.logger.warn(`Failed to capture CLI-based device snapshot for diff: ${e.message}`);
|
|
767
|
+
}
|
|
663
768
|
return {
|
|
664
769
|
deviceId,
|
|
665
770
|
timestamp: new Date().toISOString(),
|
|
@@ -672,7 +777,7 @@ class CiscoAgentLoop {
|
|
|
672
777
|
async handleEnableIosShellCall(call) {
|
|
673
778
|
let args;
|
|
674
779
|
try {
|
|
675
|
-
args =
|
|
780
|
+
args = (0, utils_1.safeJsonParse)(call.function.arguments);
|
|
676
781
|
}
|
|
677
782
|
catch (e) {
|
|
678
783
|
this.injectToolResponse(call.id, 'enable_ios_shell', `Format Error: Invalid Tool Call arguments. Must be JSON.`);
|
|
@@ -711,7 +816,7 @@ class CiscoAgentLoop {
|
|
|
711
816
|
async handleDefineShellVariableCall(call) {
|
|
712
817
|
let args;
|
|
713
818
|
try {
|
|
714
|
-
args =
|
|
819
|
+
args = (0, utils_1.safeJsonParse)(call.function.arguments);
|
|
715
820
|
}
|
|
716
821
|
catch (e) {
|
|
717
822
|
this.injectToolResponse(call.id, 'define_shell_variable', `Format Error: Invalid Tool Call arguments. Must be JSON.`);
|
|
@@ -741,7 +846,7 @@ class CiscoAgentLoop {
|
|
|
741
846
|
async handleExecuteShellLoopCall(call) {
|
|
742
847
|
let args;
|
|
743
848
|
try {
|
|
744
|
-
args =
|
|
849
|
+
args = (0, utils_1.safeJsonParse)(call.function.arguments);
|
|
745
850
|
}
|
|
746
851
|
catch (e) {
|
|
747
852
|
this.injectToolResponse(call.id, 'execute_shell_loop', `Format Error: Invalid Tool Call arguments. Must be JSON.`);
|
|
@@ -773,7 +878,7 @@ class CiscoAgentLoop {
|
|
|
773
878
|
async handleDefineShellFunctionCall(call) {
|
|
774
879
|
let args;
|
|
775
880
|
try {
|
|
776
|
-
args =
|
|
881
|
+
args = (0, utils_1.safeJsonParse)(call.function.arguments);
|
|
777
882
|
}
|
|
778
883
|
catch (e) {
|
|
779
884
|
this.injectToolResponse(call.id, 'define_shell_function', `Format Error: Invalid Tool Call arguments. Must be JSON.`);
|
|
@@ -804,7 +909,7 @@ class CiscoAgentLoop {
|
|
|
804
909
|
async handlePingTestCall(call) {
|
|
805
910
|
let args;
|
|
806
911
|
try {
|
|
807
|
-
args =
|
|
912
|
+
args = (0, utils_1.safeJsonParse)(call.function.arguments);
|
|
808
913
|
}
|
|
809
914
|
catch (e) {
|
|
810
915
|
this.injectToolResponse(call.id, 'ping_test', `Format Error: Invalid Tool Call arguments. Must be JSON.`);
|