Ship capability groups (nms/common/topology) with shared netx skills.

One group maps to one skill and tools-*; rename NMS tools to *Nms*; sync playbooks from netx/skills.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-09-06 01:46:07 +08:00
parent 83c3796fbb
commit 3c9a383071
47 changed files with 11790 additions and 680 deletions

View file

@ -31,6 +31,7 @@ test('formatAlarmPrompt keeps human fields without raw sockets', () => {
ne: { host_name: 'PE1', ip_address: '10.0.0.1' },
}, 'zh')
assert.match(text, /告警产生/)
assert.match(text, /\[NMS /)
assert.match(text, /PE1 \(10\.0\.0\.1\)/)
assert.match(text, /请分析这条关键告警/)
})

View file

@ -0,0 +1,70 @@
/**
* Capability-group defaults and plane filters.
*/
import assert from 'node:assert/strict'
import test from 'node:test'
import {
capabilityGroupsFromSettings,
DEFAULT_CAPABILITY_GROUPS,
groupsForPlane,
groupsForced,
SKILL_DIR_BY_GROUP,
toolNamesForGroups,
TOOLS_BY_GROUP,
} from '../src/netx/capability-groups.ts'
test('defaults: nms + common in preset; topology and public off', () => {
assert.deepEqual(DEFAULT_CAPABILITY_GROUPS, {
nms: { inPreset: true, public: false },
common: { inPreset: true, public: false },
topology: { inPreset: false, public: false },
})
assert.deepEqual(groupsForPlane(undefined, 'preset'), ['nms', 'common'])
assert.deepEqual(groupsForPlane(undefined, 'public'), [])
})
test('one group one skill dir; topology owns canvas + layout tools', () => {
assert.deepEqual(SKILL_DIR_BY_GROUP, {
nms: 'nms',
common: 'common',
topology: 'topology',
})
assert.ok(TOOLS_BY_GROUP.common.includes('netx__findTopologyPaths'))
assert.ok(TOOLS_BY_GROUP.topology.includes('netx__getTopologyTree'))
assert.ok(TOOLS_BY_GROUP.topology.includes('netx__layoutTopologyView'))
assert.ok(TOOLS_BY_GROUP.topology.includes('netx__suggestSinkHubs'))
assert.ok(TOOLS_BY_GROUP.topology.includes('netx__sinkTopologyDualUnits'))
assert.ok(TOOLS_BY_GROUP.nms.includes('netx__queryNmsAlarms'))
})
test('capabilityGroupsFromSettings honors explicit false for inPreset defaults', () => {
const groups = capabilityGroupsFromSettings({
groupNmsInPreset: false,
groupCommonInPreset: false,
groupTopologyInPreset: true,
groupTopologyPublic: true,
})
assert.deepEqual(groupsForPlane(groups, 'preset'), ['topology'])
assert.deepEqual(groupsForPlane(groups, 'public'), ['topology'])
assert.ok(toolNamesForGroups(['topology']).has('netx__layoutTopologyView'))
assert.ok(toolNamesForGroups(['topology']).has('netx__sinkTopologyDualUnits'))
assert.equal(toolNamesForGroups(['topology']).has('netx__queryNmsAlarms'), false)
})
test('legacy groupManagedNe* maps to common; legacy layout flags OR into topology', () => {
const groups = capabilityGroupsFromSettings({
groupManagedNeInPreset: false,
groupManagedNePublic: true,
groupTopologyLayoutInPreset: true,
})
assert.equal(groups.common.inPreset, false)
assert.equal(groups.common.public, true)
assert.equal(groups.topology.inPreset, true)
})
test('groupsForced ignores settings for per-export mounts', () => {
assert.deepEqual(groupsForced(['common']), ['common'])
assert.deepEqual(groupsForced(['nms', 'topology']), ['nms', 'topology'])
})

View file

@ -0,0 +1,32 @@
/**
* Group skill loader: one capability group ↔ one skill dir.
*/
import assert from 'node:assert/strict'
import test from 'node:test'
import { readdirSync, readFileSync, existsSync } from 'node:fs'
import { join } from 'node:path'
import { opsSkillsRoot } from '../src/netx/group-skills.ts'
import { SKILL_DIR_BY_GROUP } from '../src/netx/capability-groups.ts'
test('opsSkillsRoot points at nms / common / topology playbook dirs', () => {
const root = opsSkillsRoot()
assert.ok(existsSync(root), root)
for (const dir of Object.values(SKILL_DIR_BY_GROUP)) {
assert.ok(existsSync(join(root, dir)), join(root, dir))
}
})
test('each group dir has a playbook with name + description', () => {
const root = opsSkillsRoot()
for (const group of Object.keys(SKILL_DIR_BY_GROUP)) {
const groupDir = join(root, SKILL_DIR_BY_GROUP[group])
const bundles = readdirSync(groupDir).filter((name) => existsSync(join(groupDir, name, 'SKILL.md')))
assert.ok(bundles.length >= 1, group)
const raw = readFileSync(join(groupDir, bundles[0], 'SKILL.md'), 'utf8')
assert.match(raw, /^---\r?\n/)
assert.match(raw, /\nname:\s+\S+/)
assert.match(raw, /\ndescription:\s/)
}
})