diff --git a/docs/MCP.md b/docs/MCP.md index 00f1d91..8e3d18c 100644 --- a/docs/MCP.md +++ b/docs/MCP.md @@ -121,7 +121,7 @@ pip install "git+https://github.com/hansjone/netx.git#subdirectory=packages/netx 可选:oclaw 专用字段展开版 [`mcp_install_payload.json`](../mcp_install_payload.json)(与 `mcp.json` 等价)。 -**Skills(真源)**:仓库根 [`skills/`](../skills/README.md) — `netx-nms` / `netx-common` / `netx-topology`。MCP 包不再带 skills 镜像;Cursor 直接指 `netx/skills/`。dsh-netxops 发版前可 `sync-skills-from-netx.ps1`。oclaw 旧 playbook 不再维护。 +**Skills(真源)**:仓库根 [`skills/`](../skills/README.md) — `netx-ops` / `netx-topology` (ops = NMS + managed CLI)。MCP 包不再带 skills 镜像;Cursor 直接指 `netx/skills/`。dsh-netxops 发版前可 `sync-skills-from-netx.ps1`。oclaw 旧 playbook 不再维护。 **拓扑画布 MCP**(独立安装/绑定)见 [`MCP_TOPOLOGY.md`](./MCP_TOPOLOGY.md)(`server_id=netx-topology`)。 diff --git a/packages/netx-mcp/README.md b/packages/netx-mcp/README.md index f4db519..6d700dd 100644 --- a/packages/netx-mcp/README.md +++ b/packages/netx-mcp/README.md @@ -38,16 +38,17 @@ python -m netx_mcp [`mcp.json`](./mcp.json) — `command: python`,`args: ["-m", "netx_mcp"]`,`env` 见文件。 -## 工具(14) +## 工具(14)— skill 组 **ops**(`netx-ops`) **NMS**(模型面通用名;当前适配器 zte-ume,REST 仍 `/v1/ume/*`): `queryNmsAlarms`, `aggregateNmsAlarms`, `runNmsDiagnostics`, `queryNmsNeInventory`, `getNmsNe`, `queryNmsAlarmsRaw`, `aggregateNmsAlarmsRaw`, `listNmsAlarmFields`, `sqlQueryNms` -**common**:`listManagedNe`, `getManagedNe`, `execManagedNe`, `listCliTargets`, `findTopologyPaths` +**Managed CLI + paths**(问「能否登录」必须走这里,不要只查 inventory): +`listManagedNe`, `getManagedNe`, `execManagedNe`, `listCliTargets`, `findTopologyPaths` 参数优先 `nms_ne_id` / `nms_ne_ids`(保留 `ume_*` 别名)。 -拓扑画布 / Fabric → 请单独安装 [`netx-topology-mcp`](../netx-topology-mcp)(见 [docs/MCP_TOPOLOGY.md](../../docs/MCP_TOPOLOGY.md))。 +拓扑画布 / Fabric → skill **topology** / [`netx-topology-mcp`](../netx-topology-mcp)(见 [docs/MCP_TOPOLOGY.md](../../docs/MCP_TOPOLOGY.md))。 ## Breaking (0.3.0) diff --git a/skills/README.md b/skills/README.md index 3dd447c..5382405 100644 --- a/skills/README.md +++ b/skills/README.md @@ -4,8 +4,7 @@ | Group | Skill bundle | 工具(MCP 裸名 / DSH = `netx__`+stem) | |-------|--------------|----------------------------------------| -| `nms` | `nms/netx-nms/` | `queryNmsAlarms` … `sqlQueryNms` | -| `common` | `common/netx-common/` | managed CLI + `findTopologyPaths` | +| `ops` | `ops/netx-ops/` | NMS 告警/库存/SQL + managed CLI + `findTopologyPaths` | | `topology` | `topology/netx-topology/` | 画布 / Fabric / dual_unit / 布图 | ## DSH 怎么用 @@ -13,6 +12,6 @@ 1. 运行时优先:`NETX_SKILLS_ROOT` → 旁路 `../netx/skills` → 包内 `presets/netxops/skills` 2. 发 npm 前:`powershell -File netxops/scripts/sync-skills-from-netx.ps1` 3. Settings → 能力组开关:开哪组就注册哪组的 **tools + 对应 skill** -4. 其它预设可强制挂:`dsh-netxops/tools-nms|common|topology` +4. 其它预设可强制挂:`dsh-netxops/tools-ops|topology`(旧别名 `tools-nms` / `tools-common` → ops) MCP / Cursor:skill 根直接指本目录。MCP 包内不镜像 skills。 diff --git a/skills/common/netx-common/SKILL.md b/skills/common/netx-common/SKILL.md deleted file mode 100644 index 18b5d16..0000000 --- a/skills/common/netx-common/SKILL.md +++ /dev/null @@ -1,91 +0,0 @@ ---- -name: netx-common -description: >- - netx common playbook (MCP + DSH): managed-NE CLI (SSH/Telnet batch-first) plus - native findTopologyPaths. Not NMS REST alarms/inventory. Trigger: execManagedNe, - show/display, optical, capacity A<>B, path between sites. ---- - -# netx-common (managed CLI + paths) - -## Naming (MCP + DSH) - -Canonical: **`netx/skills/common/netx-common/`**. Mirrored into MCP / dsh-netxops — edit once. - -| Host | How tools appear | -|------|------------------| -| **MCP** (`netx-mcp`) | Bare names: `execManagedNe`, `findTopologyPaths`, … | -| **DSH** (`dsh-netxops`) | Prefixed: `netx__execManagedNe`, … | - -NMS alarms/inventory → **netx-nms**. Canvas / dual_unit → **netx-topology**. - -## Tools - -| Purpose | Tool | -|---------|------| -| List managed NEs | `listManagedNe` | -| Managed detail | `getManagedNe` | -| Read-only CLI (batch-first) | `execManagedNe` | -| CLI target index | `listCliTargets` | -| Fabric paths | `findTopologyPaths` | - -Prefer `nms_ne_id` / `nms_ne_ids`; legacy `ume_*` accepted. `listCliTargets(source=nms)` preferred (`ume` alias). - -## CLI order - -1. `listManagedNe` (`connect_status=pass`) or `listCliTargets` (**once** per session, cache ids) -2. Multi-NE → **one** `execManagedNe` with `ne_ids` / `nms_ne_ids` / `targets` -3. Paths → `findTopologyPaths` (`nms_ne_id` **or** `managed_ne_id` per end) - -### Batch examples - -**Same commands, many NEs** - -```json -{ - "nms_ne_ids": ["uuid-a", "uuid-b", "uuid-c"], - "commands": ["show version"], - "read_timeout_sec": 60, - "concurrency": 4 -} -``` - -**Different commands per NE (still one call)** - -```json -{ - "targets": [ - {"nms_ne_id": "uuid-zte", "commands": ["show opticalinfo brief"]}, - {"nms_ne_id": "uuid-hw", "commands": ["display optical-module brief"]}, - {"nms_ne_id": "uuid-cisco", "commands": ["show interface transceiver"]} - ], - "read_timeout_sec": 90 -} -``` - -**Wrong:** N× single-NE `execManagedNe` in one turn (stdio serial). - -## Field recipes - -### Capacity / optical A<>B - -1. Resolve nicknames → `host_name` -2. `findTopologyPaths` and/or LLDP → both ports -3. Optics CLI on **both** ends; summarize RX/TX / thresholds -4. Do not answer with only NMS bandwidth/optical-power-threshold alarm tallies unless asked - -### ZTE optical CLI - -Try in order; one failure → switch spelling (do not blind-retry): - -| Prefer | Fallback | -|--------|----------| -| `show opticalinfo brief` | Field-confirmed on many ZXR10 | -| `show optical brief` | Some EN platforms | -| `show opticalinfo brief \| begin ` | After port known | - -## Guardrails - -- Never pass NMS alarm UUIDs as managed `ne_id` for `getManagedNe` -- Allowlist prefixes: `show ` / `display ` / `ping ` / `traceroute` … -- Prefer `host_name` for users; keep ids for tool params diff --git a/skills/nms/netx-nms/SKILL.md b/skills/nms/netx-nms/SKILL.md deleted file mode 100644 index 5839103..0000000 --- a/skills/nms/netx-nms/SKILL.md +++ /dev/null @@ -1,70 +0,0 @@ ---- -name: netx-nms -description: >- - netx NMS playbook (MCP + DSH): vendor NMS adapter (zte-ume) for alarm - query/aggregate/diagnostics, NE inventory, raw fields, and read-only SQL. - Trigger: NMS alarms, host_name, Critical Top, LOS, BN EMS, netx ops. ---- - -# netx-nms (vendor NMS adapter) - -## Naming (MCP + DSH) - -Canonical playbooks live in **`netx/skills/`** (this file is mirrored into MCP packages / dsh-netxops). -Edit the netx repo copy; run sync scripts — do not maintain divergent forks. - -| Host | How tools appear | -|------|------------------| -| **MCP** (`netx-mcp`) | Bare names: `queryNmsAlarms`, … | -| **DSH** (`dsh-netxops`) | Prefixed: `netx__queryNmsAlarms`, … (same camelCase stem) | - -REST still `/v1/ume/*` for provider `zte-ume`. -Prefer `nms_ne_id` / `nms_ne_ids`; legacy `ume_*` aliases still work. - -Path lookup → **common** skill `netx-common` (`findTopologyPaths`). -Canvas → **netx-topology**(含 dual_unit / 布图;DSH 可把部分布局工具放在实验 tool group)。 - -## Tool names - -| Purpose | Tool | -|---------|------| -| Alarm list | `queryNmsAlarms` | -| Alarm aggregate | `aggregateNmsAlarms` | -| Diagnostics | `runNmsDiagnostics` | -| NE inventory | `queryNmsNeInventory` | -| NE detail | `getNmsNe` | -| Field list | `listNmsAlarmFields` | -| Raw rows | `queryNmsAlarmsRaw` | -| Dynamic aggregate | `aggregateNmsAlarmsRaw` | -| SQL | `sqlQueryNms` | -| Managed CLI (other skill) | `listManagedNe` / `getManagedNe` / `execManagedNe` / `listCliTargets` | - -## Tool order - -1. **Freshness first**: `runNmsDiagnostics` or `aggregateNmsAlarms` → `meta.last_seen_min` / `last_seen_max`. -2. Overview: `aggregateNmsAlarms` + `runNmsDiagnostics`; samples via `queryNmsAlarms` (one page). -3. Evidence: `listNmsAlarmFields` → `queryNmsAlarmsRaw` (`field_preset=evidence`). -4. Custom aggregate: `aggregateNmsAlarmsRaw`. -5. SQL: `sqlQueryNms` (SELECT only; `statement_timeout_ms`). -6. Paths: `findTopologyPaths` via **netx-common**. -7. Device CLI: **netx-common** — multi-NE = **one** `execManagedNe` batch. - -## Short-intent recipes - -| User says | Recipe | -|-----------|--------| -| fiber cut / LOS / 断纤 | `queryNmsAlarmsRaw(keyword=LOS)` and/or `Fiber Break` → **host_name** list | -| offline / BN EMS | keyword=`BN EMS` | -| Critical Top | `aggregateNmsAlarms(severity=critical, top_ne=20)` | -| CRC in area | Raw `keyword=CRC` + `AREA-` hostname prefix | -| optical power **threshold** | keyword=`optical power` + area — **not** fiber-cut | -| one hostname | host-scoped `queryNmsAlarms` / Raw only | - -## Guardrails - -- Prefer non-SQL; filter severity → keyword/host → time → ne_id. -- Lists ≤2 pages; `page_size` default 50. -- Display **host_name** only; never bare UUID to users. -- `getManagedNe` needs managed id; NMS UUID → `getNmsNe` / `execManagedNe(nms_ne_id=...)`. - -See [reference.md](reference.md). diff --git a/skills/nms/netx-nms/reference.md b/skills/nms/netx-nms/reference.md deleted file mode 100644 index 7da47eb..0000000 --- a/skills/nms/netx-nms/reference.md +++ /dev/null @@ -1,20 +0,0 @@ -# netx-nms quick reference - -## Freshness - -- `runNmsDiagnostics` / `aggregateNmsAlarms` → `meta.last_seen_min` / `last_seen_max` -- Snapshot: windows inside min~max — do not default to `now()-30m` - -## Tools - -| Intent | Call | -|--------|------| -| Critical Top | `aggregateNmsAlarms(severity=critical, top_ne=20)` | -| Fiber / LOS | Raw `keyword=LOS` / `Fiber Break` | -| Offline / BN EMS | Raw keyword=`BN EMS` | -| Single host | `queryNmsAlarms(host_name=…)` | -| Inventory | `queryNmsNeInventory(keyword=…)` / `getNmsNe` | -| Paths | `findTopologyPaths(from_nms_ne_id, to_nms_ne_id)` — **common** skill | -| SQL | `sqlQueryNms` SELECT; `statement_timeout_ms=8000` | - -DSH: prefix every tool with `netx__`. diff --git a/skills/ops/netx-ops/SKILL.md b/skills/ops/netx-ops/SKILL.md new file mode 100644 index 0000000..22655e4 --- /dev/null +++ b/skills/ops/netx-ops/SKILL.md @@ -0,0 +1,94 @@ +--- +name: netx-ops +description: >- + Netx Ops playbook (MCP + DSH): NMS alarms/inventory/SQL plus managed-NE CLI + login (execManagedNe batch-first) and findTopologyPaths. Trigger: alarms, + host_name, Critical Top, LOS, 能否登录, show/display, optical, capacity A<>B, + path between sites, netx ops. +--- + +# netx-ops(告警 + 纳管登录) + +**一组一个 skill。** 问「能否登录 / CLI / show」必须走本 skill 的 managed 工具,不要只查 NMS inventory。 + +## Hosts + +| Host | Tools | +|------|--------| +| **MCP** `netx-mcp` | 裸名 `queryNmsAlarms` / `execManagedNe` / … | +| **DSH** `dsh-netxops` | `netx__` + 同 stem;能力组 **ops**(默认开) | + +REST NMS 仍 `/v1/ume/*`(`nmsProvider=zte-ume`)。优先 `nms_ne_id`;`ume_*` 别名可用。 +画布 / dual_unit → **netx-topology**(能力组 topology)。 + +## Tools + +### NMS + +| Purpose | Tool | +|---------|------| +| Alarm list / aggregate / diagnostics | `queryNmsAlarms` / `aggregateNmsAlarms` / `runNmsDiagnostics` | +| Inventory / detail | `queryNmsNeInventory` / `getNmsNe` | +| Raw / fields / SQL | `queryNmsAlarmsRaw` / `listNmsAlarmFields` / `aggregateNmsAlarmsRaw` / `sqlQueryNms` | + +### Managed CLI + paths + +| Purpose | Tool | +|---------|------| +| List CLI targets | `listManagedNe` / `listCliTargets` | +| Managed detail | `getManagedNe`(**仅**纳管 id) | +| Login / show | `execManagedNe`(batch-first) | +| Fabric paths | `findTopologyPaths` | + +## 「能否登录」决策树(强制) + +1. `listCliTargets(keyword=host_or_ip)` 或 `listManagedNe(keyword=…, connect_status=pass)` + - 命中 → `execManagedNe(ne_id|nms_ne_id, commands=["show version"])` **验证真正能登** + - 未命中 → `queryNmsNeInventory(keyword=…)` 说明 NMS 有无 / `connection_status`,并明确:**未纳管 netx CLI 则不能用本通道登录** +2. 禁止只查 inventory 就下「不能登录」或「能登录」结论而不尝试 `execManagedNe`(已纳管时)。 +3. NMS UUID 不要塞进 `getManagedNe`;用 `execManagedNe(nms_ne_id=…)` 或先 list 拿 managed `ne_id`。 + +## NMS 工具顺序 + +1. Freshness: `runNmsDiagnostics` / `aggregateNmsAlarms` → `meta.last_seen_*` +2. Overview + one-page `queryNmsAlarms` +3. Evidence: `queryNmsAlarmsRaw` (`field_preset=evidence`) +4. Paths / CLI as needed (same skill) + +## CLI order + +1. `listManagedNe` / `listCliTargets`(每会话最多一次,缓存 id) +2. 多台 → **一次** `execManagedNe`(`ne_ids` / `nms_ne_ids` / `targets`) +3. 路径 → `findTopologyPaths` + +### Batch 示例 + +```json +{ "nms_ne_ids": ["uuid-a", "uuid-b"], "commands": ["show version"], "concurrency": 4 } +``` + +```json +{ + "targets": [ + {"nms_ne_id": "uuid-zte", "commands": ["show opticalinfo brief"]}, + {"nms_ne_id": "uuid-hw", "commands": ["display optical-module brief"]} + ] +} +``` + +## Short recipes + +| User says | Recipe | +|-----------|--------| +| 能否登录 / login / SSH | 上表「能否登录」决策树 | +| fiber / LOS | Raw `keyword=LOS` / `Fiber Break` | +| Critical Top | `aggregateNmsAlarms(severity=critical, top_ne=20)` | +| capacity A<>B | paths / LLDP → 两端 optic CLI(一批) | + +## Guardrails + +- 展示 **host_name**;勿对用户甩裸 UUID +- CLI 白名单:`show` / `display` / `ping` / `traceroute` … +- 同轮禁止 N× 单台 `execManagedNe` + +See [reference.md](reference.md). diff --git a/skills/ops/netx-ops/reference.md b/skills/ops/netx-ops/reference.md new file mode 100644 index 0000000..e785467 --- /dev/null +++ b/skills/ops/netx-ops/reference.md @@ -0,0 +1,22 @@ +# netx-ops quick reference + +## Can it log in? + +1. `listCliTargets` / `listManagedNe` → if found, `execManagedNe(…, commands=["show version"])` +2. Else `queryNmsNeInventory` → report NMS presence; say CLI not managed if absent from managed list + +## NMS freshness + +- `runNmsDiagnostics` / `aggregateNmsAlarms` → `meta.last_seen_min` / `max` + +## Shortcuts + +| Intent | Call | +|--------|------| +| Critical Top | `aggregateNmsAlarms(severity=critical, top_ne=20)` | +| Fiber / LOS | Raw `keyword=LOS` / `Fiber Break` | +| Inventory | `queryNmsNeInventory(keyword=…)` / `getNmsNe` | +| CLI batch | `execManagedNe(nms_ne_ids=[…], commands=[…])` | +| Paths | `findTopologyPaths(from_nms_ne_id, to_nms_ne_id)` | + +DSH: prefix tools with `netx__`.