dsh-ensp 0.5.1 → 0.7.0
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.en.md +21 -1
- package/README.md +21 -1
- package/assets/icon.webp +0 -0
- package/docs/SCENARIOS.md +184 -0
- package/docs/plugin-detail.en.md +1 -2
- package/docs/plugin-detail.zh.md +1 -2
- package/locale/en.json +7 -0
- package/locale/zh.json +7 -0
- package/package.json +15 -5
- package/scripts/gen-curriculum.mjs +181 -0
- package/scripts/gen-knowledge.mjs +59 -20
- package/scripts/gen-scenarios-doc.mjs +11 -0
- package/src/cli/ensp.mjs +36 -2
- package/src/core/curriculum.json +1163 -0
- package/src/core/curriculum.mjs +70 -0
- package/src/core/index.mjs +8 -0
- package/src/core/knowledge.json +676 -128
- package/src/dsh/index.mjs +30 -6
- package/src/mcp/server.mjs +15 -4
package/src/dsh/index.mjs
CHANGED
|
@@ -49,6 +49,7 @@ import { SCENARIOS, SCENARIO_IDS, renderScenario, searchScenarios, byLevel } fro
|
|
|
49
49
|
import { doctor, modelsOf } from '../core/doctor.mjs'
|
|
50
50
|
import { runAcceptance, hasChecks } from '../core/acceptance.mjs'
|
|
51
51
|
import { knowledgeFor, searchKnowledge, knowledgeTopics, renderKnowledge } from '../core/knowledge.mjs'
|
|
52
|
+
import { curriculumFor, renderCurriculum, searchCurriculum } from '../core/curriculum.mjs'
|
|
52
53
|
import { VERSION } from '../core/version.mjs'
|
|
53
54
|
|
|
54
55
|
/** Declared hard dependency: the tool registry. */
|
|
@@ -582,6 +583,7 @@ export function apply(ctx) {
|
|
|
582
583
|
schema: obj({
|
|
583
584
|
id: req(str()),
|
|
584
585
|
brief: req(str()),
|
|
586
|
+
curriculum: req(arr()),
|
|
585
587
|
error: req(str()),
|
|
586
588
|
}),
|
|
587
589
|
render(args, value) {
|
|
@@ -600,7 +602,14 @@ export function apply(ctx) {
|
|
|
600
602
|
(hasChecks(id)
|
|
601
603
|
? `\n\n验收: ensp_verify { scenario: "${id}", topology: "${id}.topo" }`
|
|
602
604
|
: '\n\n验收: 无专门断言,ensp_verify 会逐条跑场景里的验证命令') +
|
|
605
|
+
renderCurriculum(id) +
|
|
603
606
|
renderKnowledge(id),
|
|
607
|
+
curriculum: curriculumFor(id).map((c) => ({
|
|
608
|
+
level: c.level,
|
|
609
|
+
title: c.title,
|
|
610
|
+
page: c.page,
|
|
611
|
+
verify: c.verify,
|
|
612
|
+
})),
|
|
604
613
|
}
|
|
605
614
|
},
|
|
606
615
|
})
|
|
@@ -610,13 +619,13 @@ export function apply(ctx) {
|
|
|
610
619
|
add(tools, {
|
|
611
620
|
name: 'ensp_knowledge',
|
|
612
621
|
description:
|
|
613
|
-
'Look up
|
|
614
|
-
|
|
615
|
-
'
|
|
616
|
-
'Pass scenario to list what one lab teaches, or query to search the index.',
|
|
622
|
+
'Look up two reference indexes. Pass scenario to list what one lab teaches, query to ' +
|
|
623
|
+
'search short term/answer notes, or syllabus to search the vendor manual chapter index ' +
|
|
624
|
+
'(chapter goals plus the display commands each chapter uses to prove its result).',
|
|
617
625
|
parameters: {
|
|
618
626
|
query: str('Keyword, e.g. "LSA" or "MED".'),
|
|
619
627
|
scenario: str('Scenario id, e.g. "ospf-lsa-types".'),
|
|
628
|
+
syllabus: str('Keyword to search the manual chapter index, e.g. "MPLS" or "BFD".'),
|
|
620
629
|
},
|
|
621
630
|
output: {
|
|
622
631
|
schema: obj({
|
|
@@ -629,7 +638,22 @@ export function apply(ctx) {
|
|
|
629
638
|
return text(value.points || '(no knowledge point matched)')
|
|
630
639
|
},
|
|
631
640
|
},
|
|
632
|
-
async execute({ query, scenario }) {
|
|
641
|
+
async execute({ query, scenario, syllabus }) {
|
|
642
|
+
if (syllabus) {
|
|
643
|
+
const chapters = searchCurriculum(syllabus)
|
|
644
|
+
return {
|
|
645
|
+
scope: `syllabus:${syllabus}`,
|
|
646
|
+
count: chapters.length,
|
|
647
|
+
points: chapters
|
|
648
|
+
.map(
|
|
649
|
+
(c) =>
|
|
650
|
+
`${c.level} · ${c.title} (p${c.page})\n` +
|
|
651
|
+
(c.scenarios.length ? ` 场景: ${c.scenarios.join(', ')}\n` : '') +
|
|
652
|
+
(c.verify.length ? ` 验证: ${c.verify.slice(0, 4).join(' / ')}` : ''),
|
|
653
|
+
)
|
|
654
|
+
.join('\n'),
|
|
655
|
+
}
|
|
656
|
+
}
|
|
633
657
|
if (scenario) {
|
|
634
658
|
if (!SCENARIOS[scenario]) throw new Error(`unknown scenario "${scenario}"`)
|
|
635
659
|
const points = knowledgeFor(scenario)
|
|
@@ -639,7 +663,7 @@ export function apply(ctx) {
|
|
|
639
663
|
points: points.map((p) => `#${p.n} [${p.topic}] ${p.q}\n 答: ${p.a}`).join('\n'),
|
|
640
664
|
}
|
|
641
665
|
}
|
|
642
|
-
if (!query) throw new Error('pass query or
|
|
666
|
+
if (!query) throw new Error('pass query, scenario or syllabus')
|
|
643
667
|
const points = searchKnowledge(query)
|
|
644
668
|
return {
|
|
645
669
|
scope: String(query),
|
package/src/mcp/server.mjs
CHANGED
|
@@ -41,6 +41,7 @@ import { calibrateAnchors, inspectAnchors, DEFAULT_ANCHORS } from '../core/calib
|
|
|
41
41
|
import { doctor, modelsOf } from '../core/doctor.mjs'
|
|
42
42
|
import { runAcceptance, hasChecks, EXPECTATIONS } from '../core/acceptance.mjs'
|
|
43
43
|
import { knowledgeFor, searchKnowledge, knowledgeTopics } from '../core/knowledge.mjs'
|
|
44
|
+
import { curriculumFor, renderCurriculum, searchCurriculum } from '../core/curriculum.mjs'
|
|
44
45
|
import { pushConfig, pushConfigMany, queryDevice } from '../core/provision.mjs'
|
|
45
46
|
import { SCENARIOS, SCENARIO_IDS, byLevel, renderScenario, searchScenarios } from '../core/presets.mjs'
|
|
46
47
|
import { PACKAGE_NAME, VERSION } from '../core/version.mjs'
|
|
@@ -327,12 +328,13 @@ const TOOLS = [
|
|
|
327
328
|
if (!SCENARIOS[id]) throw new Error(`unknown scenario "${id}"`)
|
|
328
329
|
return {
|
|
329
330
|
id,
|
|
330
|
-
brief: renderScenario(id),
|
|
331
|
+
brief: renderScenario(id) + renderCurriculum(id),
|
|
331
332
|
data: SCENARIOS[id],
|
|
332
333
|
hasTopology: hasLab(id),
|
|
333
334
|
hasCuratedChecks: hasChecks(id),
|
|
334
335
|
...(hasLab(id) ? { devices: labDevices(id), addressing: labAddressing(id) } : {}),
|
|
335
336
|
knowledge: knowledgeFor(id),
|
|
337
|
+
curriculum: curriculumFor(id),
|
|
336
338
|
}
|
|
337
339
|
},
|
|
338
340
|
},
|
|
@@ -386,13 +388,22 @@ const TOOLS = [
|
|
|
386
388
|
inputSchema: obj({
|
|
387
389
|
query: { type: 'string', description: 'keyword, e.g. "LSA" or "MED"' },
|
|
388
390
|
scenario: { type: 'string', description: 'scenario id, to list what that lab teaches' },
|
|
391
|
+
syllabus: { type: 'string', description: 'keyword to search the manual chapter index instead' },
|
|
389
392
|
}),
|
|
390
|
-
async run({ query, scenario }) {
|
|
393
|
+
async run({ query, scenario, syllabus }) {
|
|
394
|
+
if (syllabus) {
|
|
395
|
+
return { syllabus, chapters: searchCurriculum(syllabus) }
|
|
396
|
+
}
|
|
391
397
|
if (scenario) {
|
|
392
398
|
if (!SCENARIOS[scenario]) throw new Error(`unknown scenario "${scenario}"`)
|
|
393
|
-
return {
|
|
399
|
+
return {
|
|
400
|
+
scenario,
|
|
401
|
+
topics: knowledgeTopics(),
|
|
402
|
+
points: knowledgeFor(scenario),
|
|
403
|
+
curriculum: curriculumFor(scenario),
|
|
404
|
+
}
|
|
394
405
|
}
|
|
395
|
-
if (!query) throw new Error('pass query or
|
|
406
|
+
if (!query) throw new Error('pass query, scenario or syllabus')
|
|
396
407
|
return { query, points: searchKnowledge(query) }
|
|
397
408
|
},
|
|
398
409
|
},
|