ciscollm-cli 1.0.1 → 1.0.3
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 +169 -74
- package/dist/cli/ui/ui.d.ts +1 -0
- package/dist/cli/ui/ui.js +19 -4
- package/dist/cli/ui/ui.js.map +1 -1
- package/dist/core/agent/AgentLoop.d.ts +7 -0
- package/dist/core/agent/AgentLoop.js +177 -18
- package/dist/core/agent/AgentLoop.js.map +1 -1
- package/dist/core/agent/CommandReferenceEngine.d.ts +2 -0
- package/dist/core/agent/CommandReferenceEngine.js +73 -4
- package/dist/core/agent/CommandReferenceEngine.js.map +1 -1
- package/dist/core/agent/HierarchicalAgentManager.d.ts +11 -0
- package/dist/core/agent/HierarchicalAgentManager.js +70 -0
- package/dist/core/agent/HierarchicalAgentManager.js.map +1 -0
- package/dist/core/agent/MultiAgentCoordinator.d.ts +5 -1
- package/dist/core/agent/MultiAgentCoordinator.js +64 -5
- package/dist/core/agent/MultiAgentCoordinator.js.map +1 -1
- package/dist/core/agent/PromptEngine.d.ts +1 -1
- package/dist/core/agent/PromptEngine.js +64 -48
- package/dist/core/agent/PromptEngine.js.map +1 -1
- package/dist/core/guardrails/AuditLogger.d.ts +15 -0
- package/dist/core/guardrails/AuditLogger.js +66 -0
- package/dist/core/guardrails/AuditLogger.js.map +1 -0
- package/dist/core/guardrails/CommandFirewall.js +24 -0
- package/dist/core/guardrails/CommandFirewall.js.map +1 -1
- package/dist/core/guardrails/PreExecutionValidator.d.ts +9 -0
- package/dist/core/guardrails/PreExecutionValidator.js +58 -0
- package/dist/core/guardrails/PreExecutionValidator.js.map +1 -0
- package/dist/core/rollback/StateDiff.d.ts +47 -0
- package/dist/core/rollback/StateDiff.js +121 -0
- package/dist/core/rollback/StateDiff.js.map +1 -0
- package/dist/core/rollback/TransactionManager.d.ts +2 -0
- package/dist/core/rollback/TransactionManager.js +130 -54
- package/dist/core/rollback/TransactionManager.js.map +1 -1
- package/dist/core/topology/TopologyDiscovery.d.ts +5 -0
- package/dist/core/topology/TopologyDiscovery.js +54 -0
- package/dist/core/topology/TopologyDiscovery.js.map +1 -0
- package/dist/index.js +247 -31
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/llm/LLMClient.js +52 -2
- package/dist/infrastructure/llm/LLMClient.js.map +1 -1
- package/dist/infrastructure/protocols/BaseSession.js +1 -1
- package/dist/infrastructure/protocols/BaseSession.js.map +1 -1
- package/dist/infrastructure/protocols/CmlSession.d.ts +26 -0
- package/dist/infrastructure/protocols/CmlSession.js +448 -0
- package/dist/infrastructure/protocols/CmlSession.js.map +1 -0
- package/dist/infrastructure/protocols/MockSession.d.ts +33 -0
- package/dist/infrastructure/protocols/MockSession.js +433 -35
- package/dist/infrastructure/protocols/MockSession.js.map +1 -1
- package/dist/infrastructure/protocols/NetconfSession.d.ts +72 -0
- package/dist/infrastructure/protocols/NetconfSession.js +489 -0
- package/dist/infrastructure/protocols/NetconfSession.js.map +1 -0
- package/dist/infrastructure/protocols/PlinkSerial.js +112 -28
- package/dist/infrastructure/protocols/PlinkSerial.js.map +1 -1
- package/dist/infrastructure/protocols/SshSession.js +5 -5
- package/dist/infrastructure/protocols/SshSession.js.map +1 -1
- package/dist/infrastructure/protocols/TelnetSession.js +8 -8
- package/dist/infrastructure/protocols/TelnetSession.js.map +1 -1
- package/dist/shared/types.d.ts +12 -0
- package/package.json +5 -3
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.HierarchicalAgentManager = void 0;
|
|
4
|
+
class HierarchicalAgentManager {
|
|
5
|
+
static agents = [
|
|
6
|
+
{
|
|
7
|
+
role: 'CORE',
|
|
8
|
+
description: 'Handles core routing tables, dynamic routing protocols (OSPF, BGP, RIP), static routes, and IP SLAs.',
|
|
9
|
+
allowedPattern: [
|
|
10
|
+
/^(no\s+)?ip\s+route\s+/i,
|
|
11
|
+
/^(no\s+)?router\s+(ospf|bgp|rip|eigrp)/i,
|
|
12
|
+
/^(no\s+)?network\s+/i,
|
|
13
|
+
/^(no\s+)?neighbor\s+/i,
|
|
14
|
+
/^show\s+ip\s+route/i,
|
|
15
|
+
/^show\s+ip\s+ospf/i,
|
|
16
|
+
/^show\s+ip\s+bgp/i
|
|
17
|
+
]
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
role: 'DISTRIBUTION',
|
|
21
|
+
description: 'Handles VLAN databases, trunking protocols, authentication (AAA), ACL firewalls, and NAT mappings.',
|
|
22
|
+
allowedPattern: [
|
|
23
|
+
/^(no\s+)?vlan\s+\d+/i,
|
|
24
|
+
/^(no\s+)?access-list\s+/i,
|
|
25
|
+
/^(no\s+)?ip\s+access-list\s+/i,
|
|
26
|
+
/^(no\s+)?ip\s+access-group\s+/i,
|
|
27
|
+
/^(no\s+)?crypto\s+key\s+/i,
|
|
28
|
+
/^(no\s+)?aaa\s+/i,
|
|
29
|
+
/^(no\s+)?ip\s+nat\s+/i,
|
|
30
|
+
/^show\s+vlan/i,
|
|
31
|
+
/^show\s+access-lists/i
|
|
32
|
+
]
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
role: 'ACCESS',
|
|
36
|
+
description: 'Handles physical port assignments, loopbacks, speed/duplex, interface shut/no shut, port descriptions, and interface IPs.',
|
|
37
|
+
allowedPattern: [
|
|
38
|
+
/^(no\s+)?interface\s+/i,
|
|
39
|
+
/^(no\s+)?ip\s+address\s+/i,
|
|
40
|
+
/^(no\s+)?description\s+/i,
|
|
41
|
+
/^(no\s+)?shutdown/i,
|
|
42
|
+
/^(no\s+)?speed\s+/i,
|
|
43
|
+
/^(no\s+)?duplex\s+/i,
|
|
44
|
+
/^show\s+ip\s+interface/i,
|
|
45
|
+
/^show\s+interfaces/i
|
|
46
|
+
]
|
|
47
|
+
}
|
|
48
|
+
];
|
|
49
|
+
static routeCommand(command) {
|
|
50
|
+
const clean = command.trim();
|
|
51
|
+
for (const agent of this.agents) {
|
|
52
|
+
for (const pattern of agent.allowedPattern) {
|
|
53
|
+
if (pattern.test(clean)) {
|
|
54
|
+
return agent.role;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return 'ACCESS';
|
|
59
|
+
}
|
|
60
|
+
static getHierarchicalAgentPrompt() {
|
|
61
|
+
return `You are operating as a Hierarchical Network Swarm. Tasks are segregated into three agent layers:
|
|
62
|
+
- CORE AGENT (Core Routing, OSPF, BGP, Static Routes)
|
|
63
|
+
- DISTRIBUTION AGENT (VLANs, ACLs, Security policies, NAT)
|
|
64
|
+
- ACCESS AGENT (User ports, Interfaces, Speed/Duplex, IP Assignment)
|
|
65
|
+
|
|
66
|
+
Always specify in your thoughts which agent layer is executing the command (e.g. "[AccessAgent] Modifying interface GigabitEthernet0/1").`;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.HierarchicalAgentManager = HierarchicalAgentManager;
|
|
70
|
+
//# sourceMappingURL=HierarchicalAgentManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HierarchicalAgentManager.js","sourceRoot":"","sources":["../../../src/core/agent/HierarchicalAgentManager.ts"],"names":[],"mappings":";;;AAQA,MAAa,wBAAwB;IACzB,MAAM,CAAC,MAAM,GAAuB;QACxC;YACI,IAAI,EAAE,MAAM;YACZ,WAAW,EAAE,sGAAsG;YACnH,cAAc,EAAE;gBACZ,yBAAyB;gBACzB,yCAAyC;gBACzC,sBAAsB;gBACtB,uBAAuB;gBACvB,qBAAqB;gBACrB,oBAAoB;gBACpB,mBAAmB;aACtB;SACJ;QACD;YACI,IAAI,EAAE,cAAc;YACpB,WAAW,EAAE,oGAAoG;YACjH,cAAc,EAAE;gBACZ,sBAAsB;gBACtB,0BAA0B;gBAC1B,+BAA+B;gBAC/B,gCAAgC;gBAChC,2BAA2B;gBAC3B,kBAAkB;gBAClB,uBAAuB;gBACvB,eAAe;gBACf,uBAAuB;aAC1B;SACJ;QACD;YACI,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,2HAA2H;YACxI,cAAc,EAAE;gBACZ,wBAAwB;gBACxB,2BAA2B;gBAC3B,0BAA0B;gBAC1B,oBAAoB;gBACpB,oBAAoB;gBACpB,qBAAqB;gBACrB,yBAAyB;gBACzB,qBAAqB;aACxB;SACJ;KACJ,CAAC;IAGK,MAAM,CAAC,YAAY,CAAC,OAAe;QACtC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAE7B,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAC9B,KAAK,MAAM,OAAO,IAAI,KAAK,CAAC,cAAc,EAAE,CAAC;gBACzC,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;oBACtB,OAAO,KAAK,CAAC,IAAI,CAAC;gBACtB,CAAC;YACL,CAAC;QACL,CAAC;QAGD,OAAO,QAAQ,CAAC;IACpB,CAAC;IAGM,MAAM,CAAC,0BAA0B;QACpC,OAAO;;;;;0IAK2H,CAAC;IACvI,CAAC;;AAtEL,4DAuEC"}
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { BaseSession } from '../../infrastructure/protocols/BaseSession';
|
|
2
|
-
import { SessionState } from '../../shared/types';
|
|
2
|
+
import { NetworkTopology, SessionState } from '../../shared/types';
|
|
3
3
|
export declare class MultiAgentCoordinator {
|
|
4
4
|
private sessions;
|
|
5
|
+
private topology;
|
|
5
6
|
registerSession(deviceId: string, session: BaseSession): void;
|
|
6
7
|
connectAll(): Promise<void>;
|
|
7
8
|
executeCommand(deviceId: string, command: string): Promise<string>;
|
|
8
9
|
getSessions(): Map<string, BaseSession>;
|
|
9
10
|
getSession(deviceId: string): BaseSession | undefined;
|
|
10
11
|
getAllStates(): Record<string, SessionState>;
|
|
12
|
+
discoverTopology(): Promise<NetworkTopology>;
|
|
13
|
+
getTopology(): NetworkTopology;
|
|
14
|
+
private deduplicateLinks;
|
|
11
15
|
disconnectAll(): Promise<void>;
|
|
12
16
|
}
|
|
@@ -1,17 +1,27 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
exports.MultiAgentCoordinator = void 0;
|
|
7
|
+
const TopologyDiscovery_1 = require("../topology/TopologyDiscovery");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
4
9
|
class MultiAgentCoordinator {
|
|
5
10
|
sessions = new Map();
|
|
11
|
+
topology = {
|
|
12
|
+
discoveredAt: new Date(0).toISOString(),
|
|
13
|
+
nodes: [],
|
|
14
|
+
links: []
|
|
15
|
+
};
|
|
6
16
|
registerSession(deviceId, session) {
|
|
7
17
|
this.sessions.set(deviceId, session);
|
|
8
18
|
}
|
|
9
19
|
async connectAll() {
|
|
10
|
-
console.log(
|
|
20
|
+
console.log(chalk_1.default.cyan(`❯ Establishing parallel connections to ${this.sessions.size} target device(s)...`));
|
|
11
21
|
const promises = Array.from(this.sessions.entries()).map(async ([id, session]) => {
|
|
12
22
|
try {
|
|
13
23
|
await session.connect();
|
|
14
|
-
console.log(
|
|
24
|
+
console.log(chalk_1.default.green(`✔ Device "${id}" connected successfully.`));
|
|
15
25
|
}
|
|
16
26
|
catch (err) {
|
|
17
27
|
throw new Error(`Device "${id}" failed to connect: ${err.message}`);
|
|
@@ -39,15 +49,64 @@ class MultiAgentCoordinator {
|
|
|
39
49
|
}
|
|
40
50
|
return states;
|
|
41
51
|
}
|
|
52
|
+
async discoverTopology() {
|
|
53
|
+
const links = [];
|
|
54
|
+
const nodeSet = new Set(Array.from(this.sessions.keys()));
|
|
55
|
+
for (const [deviceId, session] of this.sessions.entries()) {
|
|
56
|
+
try {
|
|
57
|
+
const cdpOutput = await session.execute('show cdp neighbors');
|
|
58
|
+
const parsed = TopologyDiscovery_1.TopologyDiscovery.parseCdpNeighbors(deviceId, cdpOutput);
|
|
59
|
+
parsed.forEach(link => nodeSet.add(link.remoteDeviceId));
|
|
60
|
+
links.push(...parsed);
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
// CDP may be disabled; try LLDP in the same iteration.
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
const lldpOutput = await session.execute('show lldp neighbors');
|
|
67
|
+
const parsed = TopologyDiscovery_1.TopologyDiscovery.parseLldpNeighbors(deviceId, lldpOutput);
|
|
68
|
+
parsed.forEach(link => nodeSet.add(link.remoteDeviceId));
|
|
69
|
+
links.push(...parsed);
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// LLDP may be unavailable on some platforms.
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const dedupedLinks = this.deduplicateLinks(links);
|
|
76
|
+
this.topology = {
|
|
77
|
+
discoveredAt: new Date().toISOString(),
|
|
78
|
+
nodes: Array.from(nodeSet),
|
|
79
|
+
links: dedupedLinks
|
|
80
|
+
};
|
|
81
|
+
return this.topology;
|
|
82
|
+
}
|
|
83
|
+
getTopology() {
|
|
84
|
+
return this.topology;
|
|
85
|
+
}
|
|
86
|
+
deduplicateLinks(links) {
|
|
87
|
+
const seen = new Set();
|
|
88
|
+
const deduped = [];
|
|
89
|
+
for (const link of links) {
|
|
90
|
+
const endpointA = `${link.localDeviceId}|${link.localInterface}`;
|
|
91
|
+
const endpointB = `${link.remoteDeviceId}|${link.remoteInterface}`;
|
|
92
|
+
const normalized = [endpointA, endpointB].sort().join('<->');
|
|
93
|
+
if (seen.has(normalized)) {
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
seen.add(normalized);
|
|
97
|
+
deduped.push(link);
|
|
98
|
+
}
|
|
99
|
+
return deduped;
|
|
100
|
+
}
|
|
42
101
|
async disconnectAll() {
|
|
43
|
-
console.log('
|
|
102
|
+
console.log(chalk_1.default.cyan('❯ Terminating all connection channels...'));
|
|
44
103
|
for (const [id, session] of this.sessions.entries()) {
|
|
45
104
|
try {
|
|
46
105
|
await session.disconnect();
|
|
47
|
-
console.log(
|
|
106
|
+
console.log(chalk_1.default.green(`✔ Device "${id}" disconnected cleanly.`));
|
|
48
107
|
}
|
|
49
108
|
catch (err) {
|
|
50
|
-
console.
|
|
109
|
+
console.warn(chalk_1.default.yellow(`⚠ Device "${id}" failed to close cleanly: ${err.message}`));
|
|
51
110
|
}
|
|
52
111
|
}
|
|
53
112
|
this.sessions.clear();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultiAgentCoordinator.js","sourceRoot":"","sources":["../../../src/core/agent/MultiAgentCoordinator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"MultiAgentCoordinator.js","sourceRoot":"","sources":["../../../src/core/agent/MultiAgentCoordinator.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export declare class PromptEngine {
|
|
2
|
-
static getSystemPrompt(stateInfo: string, commandReferenceHints?: string, strictReferenceMode?: boolean): string;
|
|
2
|
+
static getSystemPrompt(stateInfo: string, commandReferenceHints?: string, strictReferenceMode?: boolean, topologyInfo?: string): string;
|
|
3
3
|
}
|
|
@@ -2,54 +2,70 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.PromptEngine = void 0;
|
|
4
4
|
class PromptEngine {
|
|
5
|
-
static getSystemPrompt(stateInfo, commandReferenceHints = 'Reference status: not loaded.', strictReferenceMode = false) {
|
|
6
|
-
return `You are a Senior Network Automation Engineer Agent executing operations on Cisco Enterprise Hardware (Switches & Routers).
|
|
7
|
-
Your objective is to accomplish the user's network configuration and troubleshooting goals safely, using step-by-step tool calls.
|
|
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
|
-
|
|
5
|
+
static getSystemPrompt(stateInfo, commandReferenceHints = 'Reference status: not loaded.', strictReferenceMode = false, topologyInfo = 'Topology not discovered yet.') {
|
|
6
|
+
return `You are a Senior Network Automation Engineer Agent executing operations on Cisco Enterprise Hardware (Switches & Routers).
|
|
7
|
+
Your objective is to accomplish the user's network configuration and troubleshooting goals safely, using step-by-step tool calls.
|
|
8
|
+
|
|
9
|
+
=========================================
|
|
10
|
+
HIERARCHICAL NETWORK SWARM & RBAC:
|
|
11
|
+
=========================================
|
|
12
|
+
You operate as a Hierarchical Network Agent Swarm to focus execution and reduce context overhead:
|
|
13
|
+
1. CORE AGENT: Manages core routing tables, dynamic routing protocols (OSPF, BGP, RIP), static routes, and IP SLAs.
|
|
14
|
+
2. DISTRIBUTION AGENT: Manages VLAN databases, trunking protocols, authentication (AAA), ACL firewalls, and NAT mappings.
|
|
15
|
+
3. ACCESS AGENT: Manages physical port assignments, speed/duplex, interface shut/no shut, port descriptions, and interface IPs.
|
|
16
|
+
Specify which layer is performing the action in your thoughts (e.g., "[CORE AGENT] Configuring static route").
|
|
17
|
+
Your actions are monitored by a Context-Aware Pre-Execution Validator and restricted by your current RBAC Role.
|
|
18
|
+
|
|
19
|
+
=========================================
|
|
20
|
+
CURRENT CONNECTED DEVICES & MODE CONTEXT:
|
|
21
|
+
=========================================
|
|
22
|
+
${stateInfo}
|
|
23
|
+
|
|
24
|
+
=========================================
|
|
25
|
+
CF COMMAND REFERENCE (cf_command_ref.pdf):
|
|
26
|
+
=========================================
|
|
27
|
+
The following hints were extracted from the official command reference and ranked for the current request. Prefer these exact command forms and syntax whenever relevant.
|
|
28
|
+
Strict reference enforcement: ${strictReferenceMode ? 'ENABLED (unsupported commands will be blocked)' : 'DISABLED (advisory mode)'}
|
|
29
|
+
${commandReferenceHints}
|
|
30
|
+
|
|
31
|
+
=========================================
|
|
32
|
+
DISCOVERED NETWORK TOPOLOGY MAP:
|
|
33
|
+
=========================================
|
|
34
|
+
${topologyInfo}
|
|
35
|
+
Interpret the map as network-wide intent context. Prefer plans that keep end-to-end reachability and avoid asymmetric intermediate states.
|
|
36
|
+
|
|
37
|
+
=========================================
|
|
38
|
+
CISCO IOS SHELL (IOS.sh) AUTOMATION GUIDE:
|
|
39
|
+
=========================================
|
|
40
|
+
1. Capabilities: The connected Cisco devices support Cisco IOS Shell. You can utilize:
|
|
41
|
+
- Variables: E.g., "TARGET_IP=10.0.1.5", and reference them as "$TARGET_IP" in commands.
|
|
42
|
+
- Loop Constructs: E.g., "for i in 1 2; do ping 10.0.1.$i; done" to check connectivity.
|
|
43
|
+
- Piping & Output Filtering: E.g., "| include GigabitEthernet" or "| grep ip" to filter CLI outputs.
|
|
44
|
+
- Functions: E.g., "my_ping() { ping 10.0.1.1; }" to bind commands.
|
|
45
|
+
2. Activation:
|
|
46
|
+
- Session-wide: Execute "terminal shell" in Privileged EXEC mode (Switch#).
|
|
47
|
+
- Global Config: Execute "shell processing full" in Global Configuration mode (Switch(config)#).
|
|
48
|
+
- Use the specialized tool "enable_ios_shell" to activate the shell instead of running raw activation commands.
|
|
49
|
+
|
|
50
|
+
=========================================
|
|
51
|
+
OPERATIONAL COMPLIANCE RULES:
|
|
52
|
+
=========================================
|
|
53
|
+
1. Navigational Awareness: Verify the current device access level (e.g., USER_EXEC ">", PRIVILEGED_EXEC "#", GLOBAL_CONFIG "(config)#", INTERFACE_CONFIG "(config-if)#"). Change modes appropriately before running commands (e.g., issue "enable", "configure terminal").
|
|
54
|
+
2. Multi-Device Scope: When multiple target devices are connected, you must specify the "device" parameter in all tool calls to designate the destination.
|
|
55
|
+
3. Chaining Constraint: Issue commands step-by-step. Do not combine multiple unrelated configuration actions into a single tool call.
|
|
56
|
+
4. Validation Discipline: Use at most one inspection pass before a configuration block. Do not repeat show commands unless the device state changed or a command failed. After the configuration block completes, verify once with an inspection command or a ping_test, then stop if the verification is clean.
|
|
57
|
+
5. Error Diagnostics: If a command fails or returns error markers (e.g., "% Unrecognized command", "% Invalid input"), stop. Do not repeat failed commands. Troubleshoot the cause (such as port state, interface context, or syntax) and correct it before retrying.
|
|
58
|
+
6. Language Policy: All reasoning blocks, arguments, tool calls, and output explanations must be written strictly in English.
|
|
59
|
+
|
|
60
|
+
=========================================
|
|
61
|
+
RESPONSE FORMAT PROTOCOL (CRITICAL):
|
|
62
|
+
=========================================
|
|
63
|
+
- You MUST always populate the "content" field of your response with a detailed, step-by-step Chain-of-Thought (CoT) reasoning block BEFORE proposing any tool calls.
|
|
64
|
+
- You MUST format your thoughts by explicitly structuring them into these three sections:
|
|
65
|
+
1. CURRENT STATE ANALYSIS: [What is the current device status, context, and access level?]
|
|
66
|
+
2. TECHNICAL PLAN: [What is the detailed sequential plan, variables, loops, or shell configurations needed to achieve the goal?]
|
|
67
|
+
3. NEXT ACTION DETAILS: [What specific tool are you calling right now, what arguments/commands are you sending, and why?]
|
|
68
|
+
- NEVER return an empty or whitespace-only "content" string when generating tool calls. The user must see your structured thoughts before execution occurs.
|
|
53
69
|
- When you are done and no additional tool call is required, your final response must be a direct user-facing outcome summary with concrete results and next actions (if any). Do not end with meta statements such as "I should" or "I will".`;
|
|
54
70
|
}
|
|
55
71
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PromptEngine.js","sourceRoot":"","sources":["../../../src/core/agent/PromptEngine.ts"],"names":[],"mappings":";;;AAAA,MAAa,YAAY;IACf,MAAM,CAAC,eAAe,CACvB,SAAiB,EACjB,wBAAgC,+BAA+B,EAC/D,sBAA+B,KAAK;
|
|
1
|
+
{"version":3,"file":"PromptEngine.js","sourceRoot":"","sources":["../../../src/core/agent/PromptEngine.ts"],"names":[],"mappings":";;;AAAA,MAAa,YAAY;IACf,MAAM,CAAC,eAAe,CACvB,SAAiB,EACjB,wBAAgC,+BAA+B,EAC/D,sBAA+B,KAAK,EACpC,eAAuB,8BAA8B;QAEtD,OAAO;;;;;;;;;;;;;;;;EAgBb,SAAS;;;;;;gCAMqB,mBAAmB,CAAC,CAAC,CAAC,gDAAgD,CAAC,CAAC,CAAC,0BAA0B;EACjI,qBAAqB;;;;;EAKrB,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+OAmCiO,CAAC;IAC5O,CAAC;CACJ;AAxED,oCAwEC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface AuditLogEntry {
|
|
2
|
+
timestamp: string;
|
|
3
|
+
deviceId: string;
|
|
4
|
+
role: string;
|
|
5
|
+
thought?: string;
|
|
6
|
+
command: string;
|
|
7
|
+
status: 'SUCCESS' | 'FAILED' | 'BLOCKED' | 'ROLLBACK';
|
|
8
|
+
outputSnippet?: string;
|
|
9
|
+
reason?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare class AuditLogger {
|
|
12
|
+
private static logFile;
|
|
13
|
+
static setLogFile(filePath: string): void;
|
|
14
|
+
static log(entry: AuditLogEntry): void;
|
|
15
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.AuditLogger = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
class AuditLogger {
|
|
40
|
+
static logFile = path.resolve(process.cwd(), 'audit.log');
|
|
41
|
+
static setLogFile(filePath) {
|
|
42
|
+
this.logFile = path.resolve(process.cwd(), filePath);
|
|
43
|
+
}
|
|
44
|
+
static log(entry) {
|
|
45
|
+
const formattedTimestamp = entry.timestamp || new Date().toISOString();
|
|
46
|
+
const outputCleaned = entry.outputSnippet
|
|
47
|
+
? entry.outputSnippet.replace(/\r?\n/g, ' ').substring(0, 100) + '...'
|
|
48
|
+
: '';
|
|
49
|
+
const thoughtCleaned = entry.thought
|
|
50
|
+
? entry.thought.replace(/\r?\n/g, ' ').substring(0, 150) + '...'
|
|
51
|
+
: '';
|
|
52
|
+
const logMessage = `[${formattedTimestamp}] [Device: ${entry.deviceId}] [Role: ${entry.role.toUpperCase()}] [Status: ${entry.status}]
|
|
53
|
+
Thought: ${thoughtCleaned || 'N/A'}
|
|
54
|
+
Command: "${entry.command}"
|
|
55
|
+
Result: ${outputCleaned || entry.reason || 'N/A'}
|
|
56
|
+
--------------------------------------------------------------------------------\n`;
|
|
57
|
+
try {
|
|
58
|
+
fs.appendFileSync(this.logFile, logMessage, 'utf8');
|
|
59
|
+
}
|
|
60
|
+
catch (e) {
|
|
61
|
+
console.error('[AuditLogger Error]: Failed to write to audit log:', e);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
exports.AuditLogger = AuditLogger;
|
|
66
|
+
//# sourceMappingURL=AuditLogger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuditLogger.js","sourceRoot":"","sources":["../../../src/core/guardrails/AuditLogger.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAyB;AACzB,2CAA6B;AAa7B,MAAa,WAAW;IACZ,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,WAAW,CAAC,CAAC;IAE3D,MAAM,CAAC,UAAU,CAAC,QAAgB;QACrC,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC;IACzD,CAAC;IAGM,MAAM,CAAC,GAAG,CAAC,KAAoB;QAClC,MAAM,kBAAkB,GAAG,KAAK,CAAC,SAAS,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACvE,MAAM,aAAa,GAAG,KAAK,CAAC,aAAa;YACrC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,KAAK;YACtE,CAAC,CAAC,EAAE,CAAC;QACT,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO;YAChC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,KAAK;YAChE,CAAC,CAAC,EAAE,CAAC;QAET,MAAM,UAAU,GAAG,IAAI,kBAAkB,cAAc,KAAK,CAAC,QAAQ,YAAY,KAAK,CAAC,IAAI,CAAC,WAAW,EAAE,cAAc,KAAK,CAAC,MAAM;aAC9H,cAAc,IAAI,KAAK;cACtB,KAAK,CAAC,OAAO;aACd,aAAa,IAAI,KAAK,CAAC,MAAM,IAAI,KAAK;mFACgC,CAAC;QAE5E,IAAI,CAAC;YACD,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;QACxD,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACT,OAAO,CAAC,KAAK,CAAC,oDAAoD,EAAE,CAAC,CAAC,CAAC;QAC3E,CAAC;IACL,CAAC;;AA5BL,kCA6BC"}
|
|
@@ -47,6 +47,24 @@ class CommandFirewall {
|
|
|
47
47
|
}
|
|
48
48
|
checkCommand(command, currentInterfaceContext) {
|
|
49
49
|
const normalized = command.toLowerCase().trim();
|
|
50
|
+
if (normalized.startsWith('no ip route 0.0.0.0') || normalized.startsWith('no ip route 0.0.0.0 0.0.0.0')) {
|
|
51
|
+
return {
|
|
52
|
+
dangerous: true,
|
|
53
|
+
reason: 'Attempting to remove the default static route (0.0.0.0/0) which may sever SSH/telnet connectivity.'
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
if (normalized.startsWith('no aaa new-model') || normalized.startsWith('crypto key zeroize')) {
|
|
57
|
+
return {
|
|
58
|
+
dangerous: true,
|
|
59
|
+
reason: 'Attempting to disable AAA security or zeroize crypto keys, which can lock out admin access.'
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
if (normalized.startsWith('no access-list') || normalized.startsWith('no ip access-group')) {
|
|
63
|
+
return {
|
|
64
|
+
dangerous: true,
|
|
65
|
+
reason: 'Attempting to remove or disable an access-list which could expose or lock the management interface.'
|
|
66
|
+
};
|
|
67
|
+
}
|
|
50
68
|
const matchedDestructive = constants_1.DESTRUCTIVE_TOKENS.find(token => normalized.startsWith(token) || normalized.includes(` ${token}`));
|
|
51
69
|
if (matchedDestructive) {
|
|
52
70
|
return {
|
|
@@ -89,6 +107,12 @@ class CommandFirewall {
|
|
|
89
107
|
p.startsWith(interfaceName));
|
|
90
108
|
}
|
|
91
109
|
async verifyWithHuman(command, reason) {
|
|
110
|
+
const isNonInteractive = process.env.CISCOLLM_NON_INTERACTIVE === 'true';
|
|
111
|
+
if (isNonInteractive) {
|
|
112
|
+
console.warn('\n' + chalk_1.default.bold.red(`⚠️ [GUARDRAIL BLOCK]: Non-interactive mode active. Automatically rejecting high-risk command: "${command}"`));
|
|
113
|
+
console.warn(`- Protection Rule Match: ${chalk_1.default.cyan(reason)}\n`);
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
92
116
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
93
117
|
return new Promise((resolve) => {
|
|
94
118
|
console.warn('\n' + chalk_1.default.bold.red('⚠️ [GUARDRAIL WARNING]: High-Risk Command Blocked'));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CommandFirewall.js","sourceRoot":"","sources":["../../../src/core/guardrails/CommandFirewall.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,mDAAqC;AACrC,kDAA0B;AAC1B,sDAA0F;AAE1F,MAAa,eAAe;IAChB,mBAAmB,CAAW;IAEtC,YAAY,sBAAgC,wCAA4B;QACpE,IAAI,CAAC,mBAAmB,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;IACpF,CAAC;IAGM,YAAY,CAAC,OAAe,EAAE,uBAAsC;QACvE,MAAM,UAAU,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;QAGhD,MAAM,kBAAkB,GAAG,8BAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CACvD,UAAU,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,KAAK,EAAE,CAAC,CACnE,CAAC;QACF,IAAI,kBAAkB,EAAE,CAAC;YACrB,OAAO;gBACH,SAAS,EAAE,IAAI;gBACf,MAAM,EAAE,kCAAkC,kBAAkB,IAAI;aACnE,CAAC;QACN,CAAC;
|
|
1
|
+
{"version":3,"file":"CommandFirewall.js","sourceRoot":"","sources":["../../../src/core/guardrails/CommandFirewall.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { NetworkTopology } from '../../shared/types';
|
|
2
|
+
export interface ValidationResult {
|
|
3
|
+
safe: boolean;
|
|
4
|
+
warnLevel: 'INFO' | 'WARNING' | 'CRITICAL';
|
|
5
|
+
reason?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare class PreExecutionValidator {
|
|
8
|
+
static validateCommand(command: string, deviceId: string, topology: NetworkTopology, currentInterfaceContext: string | null): ValidationResult;
|
|
9
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PreExecutionValidator = void 0;
|
|
4
|
+
class PreExecutionValidator {
|
|
5
|
+
static validateCommand(command, deviceId, topology, currentInterfaceContext) {
|
|
6
|
+
const normalized = command.toLowerCase().trim();
|
|
7
|
+
if (normalized.startsWith('no ip route 0.0.0.0') || normalized.startsWith('no ip route 0.0.0.0 0.0.0.0')) {
|
|
8
|
+
return {
|
|
9
|
+
safe: false,
|
|
10
|
+
warnLevel: 'CRITICAL',
|
|
11
|
+
reason: `Command attempts to remove the default gateway route. This will disconnect remote SSH/Telnet sessions.`
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
if (normalized.startsWith('router ospf') || normalized.startsWith('router bgp') || normalized.startsWith('router rip')) {
|
|
15
|
+
return {
|
|
16
|
+
safe: true,
|
|
17
|
+
warnLevel: 'WARNING',
|
|
18
|
+
reason: `Entering dynamic routing configuration mode. Incorrect network declarations can disrupt routing convergence across the backbone.`
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const interfaceMatch = /^interface\s+([A-Za-z0-9\/\.\-]+)/i.exec(command.trim());
|
|
22
|
+
let targetedInterface = interfaceMatch ? interfaceMatch[1].toLowerCase().trim() : null;
|
|
23
|
+
if (currentInterfaceContext && !targetedInterface) {
|
|
24
|
+
targetedInterface = currentInterfaceContext.toLowerCase().trim();
|
|
25
|
+
}
|
|
26
|
+
if (targetedInterface && normalized.includes('shutdown')) {
|
|
27
|
+
const connectedLink = topology.links.find(link => (link.localDeviceId.toLowerCase() === deviceId.toLowerCase() && link.localInterface.toLowerCase() === targetedInterface) ||
|
|
28
|
+
(link.remoteDeviceId.toLowerCase() === deviceId.toLowerCase() && link.remoteInterface.toLowerCase() === targetedInterface));
|
|
29
|
+
if (connectedLink) {
|
|
30
|
+
const neighborId = connectedLink.localDeviceId.toLowerCase() === deviceId.toLowerCase()
|
|
31
|
+
? connectedLink.remoteDeviceId
|
|
32
|
+
: connectedLink.localDeviceId;
|
|
33
|
+
return {
|
|
34
|
+
safe: false,
|
|
35
|
+
warnLevel: 'CRITICAL',
|
|
36
|
+
reason: `Interface "${targetedInterface}" is actively connected to neighbor device "${neighborId}" via ${connectedLink.protocol.toUpperCase()}. Shutting it down will break network topology adjacency.`
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
if (targetedInterface && (normalized.startsWith('no ip address') || normalized.startsWith('ip address'))) {
|
|
41
|
+
const connectedLink = topology.links.find(link => (link.localDeviceId.toLowerCase() === deviceId.toLowerCase() && link.localInterface.toLowerCase() === targetedInterface) ||
|
|
42
|
+
(link.remoteDeviceId.toLowerCase() === deviceId.toLowerCase() && link.remoteInterface.toLowerCase() === targetedInterface));
|
|
43
|
+
if (connectedLink && normalized.startsWith('no ip address')) {
|
|
44
|
+
return {
|
|
45
|
+
safe: false,
|
|
46
|
+
warnLevel: 'CRITICAL',
|
|
47
|
+
reason: `Removing IP address from "${targetedInterface}", which is an active network uplink to neighbor "${connectedLink.localDeviceId === deviceId ? connectedLink.remoteDeviceId : connectedLink.localDeviceId}".`
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
safe: true,
|
|
53
|
+
warnLevel: 'INFO'
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.PreExecutionValidator = PreExecutionValidator;
|
|
58
|
+
//# sourceMappingURL=PreExecutionValidator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PreExecutionValidator.js","sourceRoot":"","sources":["../../../src/core/guardrails/PreExecutionValidator.ts"],"names":[],"mappings":";;;AAQA,MAAa,qBAAqB;IAEvB,MAAM,CAAC,eAAe,CACzB,OAAe,EACf,QAAgB,EAChB,QAAyB,EACzB,uBAAsC;QAEtC,MAAM,UAAU,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;QAGhD,IAAI,UAAU,CAAC,UAAU,CAAC,qBAAqB,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,6BAA6B,CAAC,EAAE,CAAC;YACvG,OAAO;gBACH,IAAI,EAAE,KAAK;gBACX,SAAS,EAAE,UAAU;gBACrB,MAAM,EAAE,wGAAwG;aACnH,CAAC;QACN,CAAC;QAGD,IAAI,UAAU,CAAC,UAAU,CAAC,aAAa,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,YAAY,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;YACrH,OAAO;gBACH,IAAI,EAAE,IAAI;gBACV,SAAS,EAAE,SAAS;gBACpB,MAAM,EAAE,kIAAkI;aAC7I,CAAC;QACN,CAAC;QAED,MAAM,cAAc,GAAG,oCAAoC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QACjF,IAAI,iBAAiB,GAAG,cAAc,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QAEvF,IAAI,uBAAuB,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAChD,iBAAiB,GAAG,uBAAuB,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;QACrE,CAAC;QAED,IAAI,iBAAiB,IAAI,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;YAEvD,MAAM,aAAa,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC7C,CAAC,IAAI,CAAC,aAAa,CAAC,WAAW,EAAE,KAAK,QAAQ,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,cAAc,CAAC,WAAW,EAAE,KAAK,iBAAiB,CAAC;gBACxH,CAAC,IAAI,CAAC,cAAc,CAAC,WAAW,EAAE,KAAK,QAAQ,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,eAAe,CAAC,WAAW,EAAE,KAAK,iBAAiB,CAAC,CAC7H,CAAC;YAEF,IAAI,aAAa,EAAE,CAAC;gBAChB,MAAM,UAAU,GAAG,aAAa,CAAC,aAAa,CAAC,WAAW,EAAE,KAAK,QAAQ,CAAC,WAAW,EAAE;oBACnF,CAAC,CAAC,aAAa,CAAC,cAAc;oBAC9B,CAAC,CAAC,aAAa,CAAC,aAAa,CAAC;gBAElC,OAAO;oBACH,IAAI,EAAE,KAAK;oBACX,SAAS,EAAE,UAAU;oBACrB,MAAM,EAAE,cAAc,iBAAiB,+CAA+C,UAAU,SAAS,aAAa,CAAC,QAAQ,CAAC,WAAW,EAAE,2DAA2D;iBAC3M,CAAC;YACN,CAAC;QACL,CAAC;QAGD,IAAI,iBAAiB,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,eAAe,CAAC,IAAI,UAAU,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC;YACvG,MAAM,aAAa,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC7C,CAAC,IAAI,CAAC,aAAa,CAAC,WAAW,EAAE,KAAK,QAAQ,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,cAAc,CAAC,WAAW,EAAE,KAAK,iBAAiB,CAAC;gBACxH,CAAC,IAAI,CAAC,cAAc,CAAC,WAAW,EAAE,KAAK,QAAQ,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,eAAe,CAAC,WAAW,EAAE,KAAK,iBAAiB,CAAC,CAC7H,CAAC;YAEF,IAAI,aAAa,IAAI,UAAU,CAAC,UAAU,CAAC,eAAe,CAAC,EAAE,CAAC;gBAC1D,OAAO;oBACH,IAAI,EAAE,KAAK;oBACX,SAAS,EAAE,UAAU;oBACrB,MAAM,EAAE,6BAA6B,iBAAiB,qDAAqD,aAAa,CAAC,aAAa,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,cAAc,CAAC,CAAC,CAAC,aAAa,CAAC,aAAa,IAAI;iBACvN,CAAC;YACN,CAAC;QACL,CAAC;QAED,OAAO;YACH,IAAI,EAAE,IAAI;YACV,SAAS,EAAE,MAAM;SACpB,CAAC;IACN,CAAC;CACJ;AA5ED,sDA4EC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { SessionState } from '../../shared/types';
|
|
2
|
+
export interface InterfaceStateSnapshot {
|
|
3
|
+
name: string;
|
|
4
|
+
ip: string | null;
|
|
5
|
+
subnet: string | null;
|
|
6
|
+
adminShutdown: boolean;
|
|
7
|
+
lineProtocolUp: boolean;
|
|
8
|
+
description: string | null;
|
|
9
|
+
}
|
|
10
|
+
export interface RoutingStateSnapshot {
|
|
11
|
+
network: string;
|
|
12
|
+
mask: string;
|
|
13
|
+
nextHop: string | null;
|
|
14
|
+
}
|
|
15
|
+
export interface DeviceStateSnapshot {
|
|
16
|
+
deviceId: string;
|
|
17
|
+
timestamp: string;
|
|
18
|
+
sessionState: SessionState;
|
|
19
|
+
interfaces: InterfaceStateSnapshot[];
|
|
20
|
+
routes: RoutingStateSnapshot[];
|
|
21
|
+
vlans: number[];
|
|
22
|
+
}
|
|
23
|
+
export interface StateDiffResult {
|
|
24
|
+
modifiedInterfaces: Array<{
|
|
25
|
+
name: string;
|
|
26
|
+
changes: Array<{
|
|
27
|
+
field: string;
|
|
28
|
+
before: any;
|
|
29
|
+
after: any;
|
|
30
|
+
}>;
|
|
31
|
+
}>;
|
|
32
|
+
addedRoutes: RoutingStateSnapshot[];
|
|
33
|
+
removedRoutes: RoutingStateSnapshot[];
|
|
34
|
+
addedVlans: number[];
|
|
35
|
+
removedVlans: number[];
|
|
36
|
+
hostnameChanged: {
|
|
37
|
+
before: string;
|
|
38
|
+
after: string;
|
|
39
|
+
} | null;
|
|
40
|
+
}
|
|
41
|
+
export declare class StateDiff {
|
|
42
|
+
static diff(before: DeviceStateSnapshot, after: DeviceStateSnapshot): StateDiffResult;
|
|
43
|
+
/**
|
|
44
|
+
* Helper to render the diff output as a readable table/string.
|
|
45
|
+
*/
|
|
46
|
+
static renderDiff(diff: StateDiffResult): string;
|
|
47
|
+
}
|