Add bizMonitor host tools for cutover analysis via netx REST (0.1.40).

Expose getBizMonitor* / getBizCollect* on the Ops preset with skill netx-biz-monitor; keep tooling in netxops instead of netx-mcp.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-09-19 22:48:42 +08:00
parent f7801db296
commit 0934e10409
23 changed files with 1022 additions and 62 deletions

View file

@ -1,7 +1,8 @@
// src/netx/capability-groups.ts
var DEFAULT_CAPABILITY_GROUPS = Object.freeze({
ops: Object.freeze({ inPreset: true, public: false }),
topology: Object.freeze({ inPreset: false, public: false })
topology: Object.freeze({ inPreset: false, public: false }),
bizMonitor: Object.freeze({ inPreset: true, public: false })
});
var TOOLS_BY_GROUP = Object.freeze({
ops: Object.freeze([
@ -37,15 +38,25 @@ var TOOLS_BY_GROUP = Object.freeze({
"netx__suggestSinkHubs",
"netx__analyzeTopologyViewLayout",
"netx__sinkTopologyDualUnits"
]),
bizMonitor: Object.freeze([
"netx__getBizMonitorContext",
"netx__getBizMonitorBoard",
"netx__listBizMonitorReds",
"netx__getBizMonitorDiffs",
"netx__getBizCollectBatch",
"netx__getBizCollectCommandRaw"
])
});
var SKILL_DIR_BY_GROUP = Object.freeze({
ops: "ops",
topology: "topology"
topology: "topology",
bizMonitor: "biz-monitor"
});
var CAPABILITY_GROUP_IDS = Object.freeze([
"ops",
"topology"
"topology",
"bizMonitor"
]);
function groupsForPlane(groups, plane, only) {
const policy = groups ?? DEFAULT_CAPABILITY_GROUPS;
@ -60,12 +71,12 @@ function groupsForced(only) {
return CAPABILITY_GROUP_IDS.filter((id) => normalized.includes(id));
}
function toolNamesForGroups(groupIds) {
const names = new Set;
const out = new Set;
for (const id of groupIds) {
for (const tool of TOOLS_BY_GROUP[id])
names.add(tool);
for (const name of TOOLS_BY_GROUP[id] ?? [])
out.add(name);
}
return names;
return out;
}
// src/netx/group-skills.ts
@ -1458,6 +1469,68 @@ async function findTopologyPaths(client, args, signal) {
body.to_managed_ne_id = toMid;
return client.post("/v1/topology/fabric/paths", body, signal, 30000);
}
async function getBizMonitorContext(client, args, signal) {
const projectId = str2(args, "project_id").trim();
const taskId = str2(args, "task_id").trim();
if (!projectId && !taskId) {
return { ok: false, error: "project_id_or_task_id_required" };
}
const params = {};
if (projectId)
params.project_id = projectId;
if (taskId)
params.task_id = taskId;
return client.get("/v1/biz-migration/monitor-context", params, signal);
}
async function getBizMonitorBoard(client, args, signal) {
const batchId = str2(args, "batch_id").trim();
if (!batchId)
return { ok: false, error: "batch_id_required" };
const params = {};
const runId = str2(args, "run_id").trim();
if (runId)
params.run_id = runId;
return client.get(`/v1/biz-migration/batches/${encodeURIComponent(batchId)}/board`, params, signal);
}
async function listBizMonitorReds(client, args, signal) {
const projectId = str2(args, "project_id").trim();
if (!projectId)
return { ok: false, error: "project_id_required" };
const params = {};
putStr(params, args, ["status"]);
const limit = num2(args, "limit");
if (limit !== undefined)
params.limit = clampInt(limit, 200, 1, 500);
return client.get(`/v1/biz-migration/projects/${encodeURIComponent(projectId)}/red-tickets`, params, signal);
}
async function getBizMonitorDiffs(client, args, signal) {
const runId = str2(args, "run_id").trim();
if (!runId)
return { ok: false, error: "run_id_required" };
const params = {};
putStr(params, args, ["metric_id", "sheet_id", "verdict", "color", "q"]);
const limit = num2(args, "limit");
if (limit !== undefined)
params.limit = clampInt(limit, 200, 1, 500);
const offset = num2(args, "offset");
if (offset !== undefined)
params.offset = clampInt(offset, 0, 0, Number.MAX_SAFE_INTEGER);
return client.get(`/v1/biz-migration/runs/${encodeURIComponent(runId)}/diffs`, params, signal);
}
async function getBizCollectBatch(client, args, signal) {
const batchId = str2(args, "batch_id").trim();
if (!batchId)
return { ok: false, error: "batch_id_required" };
return client.get(`/v1/biz-state/batches/${encodeURIComponent(batchId)}`, {}, signal);
}
async function getBizCollectCommandRaw(client, args, signal) {
const batchId = str2(args, "batch_id").trim();
const commandId = str2(args, "command_id").trim();
if (!batchId || !commandId) {
return { ok: false, error: "batch_id_and_command_id_required" };
}
return client.get(`/v1/biz-state/batches/${encodeURIComponent(batchId)}/commands/${encodeURIComponent(commandId)}`, {}, signal);
}
// src/netx/topology-handlers.ts
function asRecord2(value) {
@ -2282,6 +2355,36 @@ function registerNetxTools(ctx, connection, options) {
layer: str4(),
detail: str4("summary | full")
}, findTopologyPaths, getClient, t),
tool2("netx__getBizMonitorContext", "Biz-monitor definition bundle: cutover project + monitor/compare templates + iface normalize + port mapping + related tasks/commands. Prefer project_id. Display keys are device-raw A/B.", {
project_id: str4("Cutover / biz-migration project id"),
task_id: str4("biz_state task id (optional if project_id set)")
}, getBizMonitorContext, getClient, t),
tool2("netx__getBizMonitorBoard", "Cutover batch board: project/batch status, evaluate run summary, sheet cards, verdict counts, metric_batches.", {
batch_id: { type: "string", required: true },
run_id: str4("Optional evaluate run id")
}, getBizMonitorBoard, getClient, t),
tool2("netx__listBizMonitorReds", "Open/carried red tickets. Each item has old_key/new_key (raw A/B) and evidence (device, collect time, show command, iface raw→norm→map).", {
project_id: { type: "string", required: true },
status: str4("open|carried|resolved or empty=all"),
limit: num4()
}, listBizMonitorReds, getClient, t),
tool2("netx__getBizMonitorDiffs", "Paged evaluate diffs. Rows expose old_key/new_key (raw A/B), match_* keys, status, evidence with show commands.", {
run_id: { type: "string", required: true },
metric_id: str4(),
sheet_id: str4(),
verdict: str4(),
color: str4("e.g. red"),
q: str4(),
limit: num4(),
offset: num4()
}, getBizMonitorDiffs, getClient, t),
tool2("netx__getBizCollectBatch", "One biz_state collect batch: commands (raw_command, parse_status, preview), parsed metrics.", {
batch_id: { type: "string", required: true }
}, getBizCollectBatch, getClient, t),
tool2("netx__getBizCollectCommandRaw", "Full CLI raw_text for one collect command inside a batch (deep dive).", {
batch_id: { type: "string", required: true },
command_id: { type: "string", required: true }
}, getBizCollectCommandRaw, getClient, t),
tool2("netx__getTopologyTree", "Get topology folder tree (nav roots + Root map canvases). Start here before createTopologyFolder.", { compact: bool4(), max_depth: num4() }, getTopologyTree, getClient, t),
tool2("netx__getTopologyView", "Get a topology view by view_id. Default detail=summary with sample_nodes + links[].", {
view_id: { type: "string", required: true },

View file

@ -1,7 +1,8 @@
// src/netx/capability-groups.ts
var DEFAULT_CAPABILITY_GROUPS = Object.freeze({
ops: Object.freeze({ inPreset: true, public: false }),
topology: Object.freeze({ inPreset: false, public: false })
topology: Object.freeze({ inPreset: false, public: false }),
bizMonitor: Object.freeze({ inPreset: true, public: false })
});
var TOOLS_BY_GROUP = Object.freeze({
ops: Object.freeze([
@ -37,15 +38,25 @@ var TOOLS_BY_GROUP = Object.freeze({
"netx__suggestSinkHubs",
"netx__analyzeTopologyViewLayout",
"netx__sinkTopologyDualUnits"
]),
bizMonitor: Object.freeze([
"netx__getBizMonitorContext",
"netx__getBizMonitorBoard",
"netx__listBizMonitorReds",
"netx__getBizMonitorDiffs",
"netx__getBizCollectBatch",
"netx__getBizCollectCommandRaw"
])
});
var SKILL_DIR_BY_GROUP = Object.freeze({
ops: "ops",
topology: "topology"
topology: "topology",
bizMonitor: "biz-monitor"
});
var CAPABILITY_GROUP_IDS = Object.freeze([
"ops",
"topology"
"topology",
"bizMonitor"
]);
function groupsForPlane(groups, plane, only) {
const policy = groups ?? DEFAULT_CAPABILITY_GROUPS;
@ -60,12 +71,12 @@ function groupsForced(only) {
return CAPABILITY_GROUP_IDS.filter((id) => normalized.includes(id));
}
function toolNamesForGroups(groupIds) {
const names = new Set;
const out = new Set;
for (const id of groupIds) {
for (const tool of TOOLS_BY_GROUP[id])
names.add(tool);
for (const name of TOOLS_BY_GROUP[id] ?? [])
out.add(name);
}
return names;
return out;
}
// src/netx/group-skills.ts
@ -1458,6 +1469,68 @@ async function findTopologyPaths(client, args, signal) {
body.to_managed_ne_id = toMid;
return client.post("/v1/topology/fabric/paths", body, signal, 30000);
}
async function getBizMonitorContext(client, args, signal) {
const projectId = str2(args, "project_id").trim();
const taskId = str2(args, "task_id").trim();
if (!projectId && !taskId) {
return { ok: false, error: "project_id_or_task_id_required" };
}
const params = {};
if (projectId)
params.project_id = projectId;
if (taskId)
params.task_id = taskId;
return client.get("/v1/biz-migration/monitor-context", params, signal);
}
async function getBizMonitorBoard(client, args, signal) {
const batchId = str2(args, "batch_id").trim();
if (!batchId)
return { ok: false, error: "batch_id_required" };
const params = {};
const runId = str2(args, "run_id").trim();
if (runId)
params.run_id = runId;
return client.get(`/v1/biz-migration/batches/${encodeURIComponent(batchId)}/board`, params, signal);
}
async function listBizMonitorReds(client, args, signal) {
const projectId = str2(args, "project_id").trim();
if (!projectId)
return { ok: false, error: "project_id_required" };
const params = {};
putStr(params, args, ["status"]);
const limit = num2(args, "limit");
if (limit !== undefined)
params.limit = clampInt(limit, 200, 1, 500);
return client.get(`/v1/biz-migration/projects/${encodeURIComponent(projectId)}/red-tickets`, params, signal);
}
async function getBizMonitorDiffs(client, args, signal) {
const runId = str2(args, "run_id").trim();
if (!runId)
return { ok: false, error: "run_id_required" };
const params = {};
putStr(params, args, ["metric_id", "sheet_id", "verdict", "color", "q"]);
const limit = num2(args, "limit");
if (limit !== undefined)
params.limit = clampInt(limit, 200, 1, 500);
const offset = num2(args, "offset");
if (offset !== undefined)
params.offset = clampInt(offset, 0, 0, Number.MAX_SAFE_INTEGER);
return client.get(`/v1/biz-migration/runs/${encodeURIComponent(runId)}/diffs`, params, signal);
}
async function getBizCollectBatch(client, args, signal) {
const batchId = str2(args, "batch_id").trim();
if (!batchId)
return { ok: false, error: "batch_id_required" };
return client.get(`/v1/biz-state/batches/${encodeURIComponent(batchId)}`, {}, signal);
}
async function getBizCollectCommandRaw(client, args, signal) {
const batchId = str2(args, "batch_id").trim();
const commandId = str2(args, "command_id").trim();
if (!batchId || !commandId) {
return { ok: false, error: "batch_id_and_command_id_required" };
}
return client.get(`/v1/biz-state/batches/${encodeURIComponent(batchId)}/commands/${encodeURIComponent(commandId)}`, {}, signal);
}
// src/netx/topology-handlers.ts
function asRecord2(value) {
@ -2282,6 +2355,36 @@ function registerNetxTools(ctx, connection, options) {
layer: str4(),
detail: str4("summary | full")
}, findTopologyPaths, getClient, t),
tool2("netx__getBizMonitorContext", "Biz-monitor definition bundle: cutover project + monitor/compare templates + iface normalize + port mapping + related tasks/commands. Prefer project_id. Display keys are device-raw A/B.", {
project_id: str4("Cutover / biz-migration project id"),
task_id: str4("biz_state task id (optional if project_id set)")
}, getBizMonitorContext, getClient, t),
tool2("netx__getBizMonitorBoard", "Cutover batch board: project/batch status, evaluate run summary, sheet cards, verdict counts, metric_batches.", {
batch_id: { type: "string", required: true },
run_id: str4("Optional evaluate run id")
}, getBizMonitorBoard, getClient, t),
tool2("netx__listBizMonitorReds", "Open/carried red tickets. Each item has old_key/new_key (raw A/B) and evidence (device, collect time, show command, iface raw→norm→map).", {
project_id: { type: "string", required: true },
status: str4("open|carried|resolved or empty=all"),
limit: num4()
}, listBizMonitorReds, getClient, t),
tool2("netx__getBizMonitorDiffs", "Paged evaluate diffs. Rows expose old_key/new_key (raw A/B), match_* keys, status, evidence with show commands.", {
run_id: { type: "string", required: true },
metric_id: str4(),
sheet_id: str4(),
verdict: str4(),
color: str4("e.g. red"),
q: str4(),
limit: num4(),
offset: num4()
}, getBizMonitorDiffs, getClient, t),
tool2("netx__getBizCollectBatch", "One biz_state collect batch: commands (raw_command, parse_status, preview), parsed metrics.", {
batch_id: { type: "string", required: true }
}, getBizCollectBatch, getClient, t),
tool2("netx__getBizCollectCommandRaw", "Full CLI raw_text for one collect command inside a batch (deep dive).", {
batch_id: { type: "string", required: true },
command_id: { type: "string", required: true }
}, getBizCollectCommandRaw, getClient, t),
tool2("netx__getTopologyTree", "Get topology folder tree (nav roots + Root map canvases). Start here before createTopologyFolder.", { compact: bool4(), max_depth: num4() }, getTopologyTree, getClient, t),
tool2("netx__getTopologyView", "Get a topology view by view_id. Default detail=summary with sample_nodes + links[].", {
view_id: { type: "string", required: true },

View file

@ -1,7 +1,8 @@
// src/netx/capability-groups.ts
var DEFAULT_CAPABILITY_GROUPS = Object.freeze({
ops: Object.freeze({ inPreset: true, public: false }),
topology: Object.freeze({ inPreset: false, public: false })
topology: Object.freeze({ inPreset: false, public: false }),
bizMonitor: Object.freeze({ inPreset: true, public: false })
});
var TOOLS_BY_GROUP = Object.freeze({
ops: Object.freeze([
@ -37,15 +38,25 @@ var TOOLS_BY_GROUP = Object.freeze({
"netx__suggestSinkHubs",
"netx__analyzeTopologyViewLayout",
"netx__sinkTopologyDualUnits"
]),
bizMonitor: Object.freeze([
"netx__getBizMonitorContext",
"netx__getBizMonitorBoard",
"netx__listBizMonitorReds",
"netx__getBizMonitorDiffs",
"netx__getBizCollectBatch",
"netx__getBizCollectCommandRaw"
])
});
var SKILL_DIR_BY_GROUP = Object.freeze({
ops: "ops",
topology: "topology"
topology: "topology",
bizMonitor: "biz-monitor"
});
var CAPABILITY_GROUP_IDS = Object.freeze([
"ops",
"topology"
"topology",
"bizMonitor"
]);
function groupsForPlane(groups, plane, only) {
const policy = groups ?? DEFAULT_CAPABILITY_GROUPS;
@ -60,12 +71,12 @@ function groupsForced(only) {
return CAPABILITY_GROUP_IDS.filter((id) => normalized.includes(id));
}
function toolNamesForGroups(groupIds) {
const names = new Set;
const out = new Set;
for (const id of groupIds) {
for (const tool of TOOLS_BY_GROUP[id])
names.add(tool);
for (const name of TOOLS_BY_GROUP[id] ?? [])
out.add(name);
}
return names;
return out;
}
// src/netx/group-skills.ts
@ -1458,6 +1469,68 @@ async function findTopologyPaths(client, args, signal) {
body.to_managed_ne_id = toMid;
return client.post("/v1/topology/fabric/paths", body, signal, 30000);
}
async function getBizMonitorContext(client, args, signal) {
const projectId = str2(args, "project_id").trim();
const taskId = str2(args, "task_id").trim();
if (!projectId && !taskId) {
return { ok: false, error: "project_id_or_task_id_required" };
}
const params = {};
if (projectId)
params.project_id = projectId;
if (taskId)
params.task_id = taskId;
return client.get("/v1/biz-migration/monitor-context", params, signal);
}
async function getBizMonitorBoard(client, args, signal) {
const batchId = str2(args, "batch_id").trim();
if (!batchId)
return { ok: false, error: "batch_id_required" };
const params = {};
const runId = str2(args, "run_id").trim();
if (runId)
params.run_id = runId;
return client.get(`/v1/biz-migration/batches/${encodeURIComponent(batchId)}/board`, params, signal);
}
async function listBizMonitorReds(client, args, signal) {
const projectId = str2(args, "project_id").trim();
if (!projectId)
return { ok: false, error: "project_id_required" };
const params = {};
putStr(params, args, ["status"]);
const limit = num2(args, "limit");
if (limit !== undefined)
params.limit = clampInt(limit, 200, 1, 500);
return client.get(`/v1/biz-migration/projects/${encodeURIComponent(projectId)}/red-tickets`, params, signal);
}
async function getBizMonitorDiffs(client, args, signal) {
const runId = str2(args, "run_id").trim();
if (!runId)
return { ok: false, error: "run_id_required" };
const params = {};
putStr(params, args, ["metric_id", "sheet_id", "verdict", "color", "q"]);
const limit = num2(args, "limit");
if (limit !== undefined)
params.limit = clampInt(limit, 200, 1, 500);
const offset = num2(args, "offset");
if (offset !== undefined)
params.offset = clampInt(offset, 0, 0, Number.MAX_SAFE_INTEGER);
return client.get(`/v1/biz-migration/runs/${encodeURIComponent(runId)}/diffs`, params, signal);
}
async function getBizCollectBatch(client, args, signal) {
const batchId = str2(args, "batch_id").trim();
if (!batchId)
return { ok: false, error: "batch_id_required" };
return client.get(`/v1/biz-state/batches/${encodeURIComponent(batchId)}`, {}, signal);
}
async function getBizCollectCommandRaw(client, args, signal) {
const batchId = str2(args, "batch_id").trim();
const commandId = str2(args, "command_id").trim();
if (!batchId || !commandId) {
return { ok: false, error: "batch_id_and_command_id_required" };
}
return client.get(`/v1/biz-state/batches/${encodeURIComponent(batchId)}/commands/${encodeURIComponent(commandId)}`, {}, signal);
}
// src/netx/topology-handlers.ts
function asRecord2(value) {
@ -2282,6 +2355,36 @@ function registerNetxTools(ctx, connection, options) {
layer: str4(),
detail: str4("summary | full")
}, findTopologyPaths, getClient, t),
tool2("netx__getBizMonitorContext", "Biz-monitor definition bundle: cutover project + monitor/compare templates + iface normalize + port mapping + related tasks/commands. Prefer project_id. Display keys are device-raw A/B.", {
project_id: str4("Cutover / biz-migration project id"),
task_id: str4("biz_state task id (optional if project_id set)")
}, getBizMonitorContext, getClient, t),
tool2("netx__getBizMonitorBoard", "Cutover batch board: project/batch status, evaluate run summary, sheet cards, verdict counts, metric_batches.", {
batch_id: { type: "string", required: true },
run_id: str4("Optional evaluate run id")
}, getBizMonitorBoard, getClient, t),
tool2("netx__listBizMonitorReds", "Open/carried red tickets. Each item has old_key/new_key (raw A/B) and evidence (device, collect time, show command, iface raw→norm→map).", {
project_id: { type: "string", required: true },
status: str4("open|carried|resolved or empty=all"),
limit: num4()
}, listBizMonitorReds, getClient, t),
tool2("netx__getBizMonitorDiffs", "Paged evaluate diffs. Rows expose old_key/new_key (raw A/B), match_* keys, status, evidence with show commands.", {
run_id: { type: "string", required: true },
metric_id: str4(),
sheet_id: str4(),
verdict: str4(),
color: str4("e.g. red"),
q: str4(),
limit: num4(),
offset: num4()
}, getBizMonitorDiffs, getClient, t),
tool2("netx__getBizCollectBatch", "One biz_state collect batch: commands (raw_command, parse_status, preview), parsed metrics.", {
batch_id: { type: "string", required: true }
}, getBizCollectBatch, getClient, t),
tool2("netx__getBizCollectCommandRaw", "Full CLI raw_text for one collect command inside a batch (deep dive).", {
batch_id: { type: "string", required: true },
command_id: { type: "string", required: true }
}, getBizCollectCommandRaw, getClient, t),
tool2("netx__getTopologyTree", "Get topology folder tree (nav roots + Root map canvases). Start here before createTopologyFolder.", { compact: bool4(), max_depth: num4() }, getTopologyTree, getClient, t),
tool2("netx__getTopologyView", "Get a topology view by view_id. Default detail=summary with sample_nodes + links[].", {
view_id: { type: "string", required: true },

View file

@ -1,7 +1,8 @@
// src/netx/capability-groups.ts
var DEFAULT_CAPABILITY_GROUPS = Object.freeze({
ops: Object.freeze({ inPreset: true, public: false }),
topology: Object.freeze({ inPreset: false, public: false })
topology: Object.freeze({ inPreset: false, public: false }),
bizMonitor: Object.freeze({ inPreset: true, public: false })
});
var TOOLS_BY_GROUP = Object.freeze({
ops: Object.freeze([
@ -37,15 +38,25 @@ var TOOLS_BY_GROUP = Object.freeze({
"netx__suggestSinkHubs",
"netx__analyzeTopologyViewLayout",
"netx__sinkTopologyDualUnits"
]),
bizMonitor: Object.freeze([
"netx__getBizMonitorContext",
"netx__getBizMonitorBoard",
"netx__listBizMonitorReds",
"netx__getBizMonitorDiffs",
"netx__getBizCollectBatch",
"netx__getBizCollectCommandRaw"
])
});
var SKILL_DIR_BY_GROUP = Object.freeze({
ops: "ops",
topology: "topology"
topology: "topology",
bizMonitor: "biz-monitor"
});
var CAPABILITY_GROUP_IDS = Object.freeze([
"ops",
"topology"
"topology",
"bizMonitor"
]);
function groupsForPlane(groups, plane, only) {
const policy = groups ?? DEFAULT_CAPABILITY_GROUPS;
@ -60,12 +71,12 @@ function groupsForced(only) {
return CAPABILITY_GROUP_IDS.filter((id) => normalized.includes(id));
}
function toolNamesForGroups(groupIds) {
const names = new Set;
const out = new Set;
for (const id of groupIds) {
for (const tool of TOOLS_BY_GROUP[id])
names.add(tool);
for (const name of TOOLS_BY_GROUP[id] ?? [])
out.add(name);
}
return names;
return out;
}
// src/netx/group-skills.ts
@ -1458,6 +1469,68 @@ async function findTopologyPaths(client, args, signal) {
body.to_managed_ne_id = toMid;
return client.post("/v1/topology/fabric/paths", body, signal, 30000);
}
async function getBizMonitorContext(client, args, signal) {
const projectId = str2(args, "project_id").trim();
const taskId = str2(args, "task_id").trim();
if (!projectId && !taskId) {
return { ok: false, error: "project_id_or_task_id_required" };
}
const params = {};
if (projectId)
params.project_id = projectId;
if (taskId)
params.task_id = taskId;
return client.get("/v1/biz-migration/monitor-context", params, signal);
}
async function getBizMonitorBoard(client, args, signal) {
const batchId = str2(args, "batch_id").trim();
if (!batchId)
return { ok: false, error: "batch_id_required" };
const params = {};
const runId = str2(args, "run_id").trim();
if (runId)
params.run_id = runId;
return client.get(`/v1/biz-migration/batches/${encodeURIComponent(batchId)}/board`, params, signal);
}
async function listBizMonitorReds(client, args, signal) {
const projectId = str2(args, "project_id").trim();
if (!projectId)
return { ok: false, error: "project_id_required" };
const params = {};
putStr(params, args, ["status"]);
const limit = num2(args, "limit");
if (limit !== undefined)
params.limit = clampInt(limit, 200, 1, 500);
return client.get(`/v1/biz-migration/projects/${encodeURIComponent(projectId)}/red-tickets`, params, signal);
}
async function getBizMonitorDiffs(client, args, signal) {
const runId = str2(args, "run_id").trim();
if (!runId)
return { ok: false, error: "run_id_required" };
const params = {};
putStr(params, args, ["metric_id", "sheet_id", "verdict", "color", "q"]);
const limit = num2(args, "limit");
if (limit !== undefined)
params.limit = clampInt(limit, 200, 1, 500);
const offset = num2(args, "offset");
if (offset !== undefined)
params.offset = clampInt(offset, 0, 0, Number.MAX_SAFE_INTEGER);
return client.get(`/v1/biz-migration/runs/${encodeURIComponent(runId)}/diffs`, params, signal);
}
async function getBizCollectBatch(client, args, signal) {
const batchId = str2(args, "batch_id").trim();
if (!batchId)
return { ok: false, error: "batch_id_required" };
return client.get(`/v1/biz-state/batches/${encodeURIComponent(batchId)}`, {}, signal);
}
async function getBizCollectCommandRaw(client, args, signal) {
const batchId = str2(args, "batch_id").trim();
const commandId = str2(args, "command_id").trim();
if (!batchId || !commandId) {
return { ok: false, error: "batch_id_and_command_id_required" };
}
return client.get(`/v1/biz-state/batches/${encodeURIComponent(batchId)}/commands/${encodeURIComponent(commandId)}`, {}, signal);
}
// src/netx/topology-handlers.ts
function asRecord2(value) {
@ -2282,6 +2355,36 @@ function registerNetxTools(ctx, connection, options) {
layer: str4(),
detail: str4("summary | full")
}, findTopologyPaths, getClient, t),
tool2("netx__getBizMonitorContext", "Biz-monitor definition bundle: cutover project + monitor/compare templates + iface normalize + port mapping + related tasks/commands. Prefer project_id. Display keys are device-raw A/B.", {
project_id: str4("Cutover / biz-migration project id"),
task_id: str4("biz_state task id (optional if project_id set)")
}, getBizMonitorContext, getClient, t),
tool2("netx__getBizMonitorBoard", "Cutover batch board: project/batch status, evaluate run summary, sheet cards, verdict counts, metric_batches.", {
batch_id: { type: "string", required: true },
run_id: str4("Optional evaluate run id")
}, getBizMonitorBoard, getClient, t),
tool2("netx__listBizMonitorReds", "Open/carried red tickets. Each item has old_key/new_key (raw A/B) and evidence (device, collect time, show command, iface raw→norm→map).", {
project_id: { type: "string", required: true },
status: str4("open|carried|resolved or empty=all"),
limit: num4()
}, listBizMonitorReds, getClient, t),
tool2("netx__getBizMonitorDiffs", "Paged evaluate diffs. Rows expose old_key/new_key (raw A/B), match_* keys, status, evidence with show commands.", {
run_id: { type: "string", required: true },
metric_id: str4(),
sheet_id: str4(),
verdict: str4(),
color: str4("e.g. red"),
q: str4(),
limit: num4(),
offset: num4()
}, getBizMonitorDiffs, getClient, t),
tool2("netx__getBizCollectBatch", "One biz_state collect batch: commands (raw_command, parse_status, preview), parsed metrics.", {
batch_id: { type: "string", required: true }
}, getBizCollectBatch, getClient, t),
tool2("netx__getBizCollectCommandRaw", "Full CLI raw_text for one collect command inside a batch (deep dive).", {
batch_id: { type: "string", required: true },
command_id: { type: "string", required: true }
}, getBizCollectCommandRaw, getClient, t),
tool2("netx__getTopologyTree", "Get topology folder tree (nav roots + Root map canvases). Start here before createTopologyFolder.", { compact: bool4(), max_depth: num4() }, getTopologyTree, getClient, t),
tool2("netx__getTopologyView", "Get a topology view by view_id. Default detail=summary with sample_nodes + links[].", {
view_id: { type: "string", required: true },

View file

@ -1,7 +1,8 @@
// src/netx/capability-groups.ts
var DEFAULT_CAPABILITY_GROUPS = Object.freeze({
ops: Object.freeze({ inPreset: true, public: false }),
topology: Object.freeze({ inPreset: false, public: false })
topology: Object.freeze({ inPreset: false, public: false }),
bizMonitor: Object.freeze({ inPreset: true, public: false })
});
var TOOLS_BY_GROUP = Object.freeze({
ops: Object.freeze([
@ -37,15 +38,25 @@ var TOOLS_BY_GROUP = Object.freeze({
"netx__suggestSinkHubs",
"netx__analyzeTopologyViewLayout",
"netx__sinkTopologyDualUnits"
]),
bizMonitor: Object.freeze([
"netx__getBizMonitorContext",
"netx__getBizMonitorBoard",
"netx__listBizMonitorReds",
"netx__getBizMonitorDiffs",
"netx__getBizCollectBatch",
"netx__getBizCollectCommandRaw"
])
});
var SKILL_DIR_BY_GROUP = Object.freeze({
ops: "ops",
topology: "topology"
topology: "topology",
bizMonitor: "biz-monitor"
});
var CAPABILITY_GROUP_IDS = Object.freeze([
"ops",
"topology"
"topology",
"bizMonitor"
]);
function groupsForPlane(groups, plane, only) {
const policy = groups ?? DEFAULT_CAPABILITY_GROUPS;
@ -60,12 +71,12 @@ function groupsForced(only) {
return CAPABILITY_GROUP_IDS.filter((id) => normalized.includes(id));
}
function toolNamesForGroups(groupIds) {
const names = new Set;
const out = new Set;
for (const id of groupIds) {
for (const tool of TOOLS_BY_GROUP[id])
names.add(tool);
for (const name of TOOLS_BY_GROUP[id] ?? [])
out.add(name);
}
return names;
return out;
}
// src/netx/group-skills.ts
@ -1458,6 +1469,68 @@ async function findTopologyPaths(client, args, signal) {
body.to_managed_ne_id = toMid;
return client.post("/v1/topology/fabric/paths", body, signal, 30000);
}
async function getBizMonitorContext(client, args, signal) {
const projectId = str2(args, "project_id").trim();
const taskId = str2(args, "task_id").trim();
if (!projectId && !taskId) {
return { ok: false, error: "project_id_or_task_id_required" };
}
const params = {};
if (projectId)
params.project_id = projectId;
if (taskId)
params.task_id = taskId;
return client.get("/v1/biz-migration/monitor-context", params, signal);
}
async function getBizMonitorBoard(client, args, signal) {
const batchId = str2(args, "batch_id").trim();
if (!batchId)
return { ok: false, error: "batch_id_required" };
const params = {};
const runId = str2(args, "run_id").trim();
if (runId)
params.run_id = runId;
return client.get(`/v1/biz-migration/batches/${encodeURIComponent(batchId)}/board`, params, signal);
}
async function listBizMonitorReds(client, args, signal) {
const projectId = str2(args, "project_id").trim();
if (!projectId)
return { ok: false, error: "project_id_required" };
const params = {};
putStr(params, args, ["status"]);
const limit = num2(args, "limit");
if (limit !== undefined)
params.limit = clampInt(limit, 200, 1, 500);
return client.get(`/v1/biz-migration/projects/${encodeURIComponent(projectId)}/red-tickets`, params, signal);
}
async function getBizMonitorDiffs(client, args, signal) {
const runId = str2(args, "run_id").trim();
if (!runId)
return { ok: false, error: "run_id_required" };
const params = {};
putStr(params, args, ["metric_id", "sheet_id", "verdict", "color", "q"]);
const limit = num2(args, "limit");
if (limit !== undefined)
params.limit = clampInt(limit, 200, 1, 500);
const offset = num2(args, "offset");
if (offset !== undefined)
params.offset = clampInt(offset, 0, 0, Number.MAX_SAFE_INTEGER);
return client.get(`/v1/biz-migration/runs/${encodeURIComponent(runId)}/diffs`, params, signal);
}
async function getBizCollectBatch(client, args, signal) {
const batchId = str2(args, "batch_id").trim();
if (!batchId)
return { ok: false, error: "batch_id_required" };
return client.get(`/v1/biz-state/batches/${encodeURIComponent(batchId)}`, {}, signal);
}
async function getBizCollectCommandRaw(client, args, signal) {
const batchId = str2(args, "batch_id").trim();
const commandId = str2(args, "command_id").trim();
if (!batchId || !commandId) {
return { ok: false, error: "batch_id_and_command_id_required" };
}
return client.get(`/v1/biz-state/batches/${encodeURIComponent(batchId)}/commands/${encodeURIComponent(commandId)}`, {}, signal);
}
// src/netx/topology-handlers.ts
function asRecord2(value) {
@ -2282,6 +2355,36 @@ function registerNetxTools(ctx, connection, options) {
layer: str4(),
detail: str4("summary | full")
}, findTopologyPaths, getClient, t),
tool2("netx__getBizMonitorContext", "Biz-monitor definition bundle: cutover project + monitor/compare templates + iface normalize + port mapping + related tasks/commands. Prefer project_id. Display keys are device-raw A/B.", {
project_id: str4("Cutover / biz-migration project id"),
task_id: str4("biz_state task id (optional if project_id set)")
}, getBizMonitorContext, getClient, t),
tool2("netx__getBizMonitorBoard", "Cutover batch board: project/batch status, evaluate run summary, sheet cards, verdict counts, metric_batches.", {
batch_id: { type: "string", required: true },
run_id: str4("Optional evaluate run id")
}, getBizMonitorBoard, getClient, t),
tool2("netx__listBizMonitorReds", "Open/carried red tickets. Each item has old_key/new_key (raw A/B) and evidence (device, collect time, show command, iface raw→norm→map).", {
project_id: { type: "string", required: true },
status: str4("open|carried|resolved or empty=all"),
limit: num4()
}, listBizMonitorReds, getClient, t),
tool2("netx__getBizMonitorDiffs", "Paged evaluate diffs. Rows expose old_key/new_key (raw A/B), match_* keys, status, evidence with show commands.", {
run_id: { type: "string", required: true },
metric_id: str4(),
sheet_id: str4(),
verdict: str4(),
color: str4("e.g. red"),
q: str4(),
limit: num4(),
offset: num4()
}, getBizMonitorDiffs, getClient, t),
tool2("netx__getBizCollectBatch", "One biz_state collect batch: commands (raw_command, parse_status, preview), parsed metrics.", {
batch_id: { type: "string", required: true }
}, getBizCollectBatch, getClient, t),
tool2("netx__getBizCollectCommandRaw", "Full CLI raw_text for one collect command inside a batch (deep dive).", {
batch_id: { type: "string", required: true },
command_id: { type: "string", required: true }
}, getBizCollectCommandRaw, getClient, t),
tool2("netx__getTopologyTree", "Get topology folder tree (nav roots + Root map canvases). Start here before createTopologyFolder.", { compact: bool4(), max_depth: num4() }, getTopologyTree, getClient, t),
tool2("netx__getTopologyView", "Get a topology view by view_id. Default detail=summary with sample_nodes + links[].", {
view_id: { type: "string", required: true },

View file

@ -1451,6 +1451,20 @@ function NetxopsCard(props) {
onEditPublic: (checked) => {
props.edit("groupTopologyPublic", checked ? "true" : "false");
}
}),
/* @__PURE__ */ jsx_runtime.jsx(CapabilityGroupBlock, {
title: t("groupBizMonitor"),
inPresetLabel: t("groupInPreset"),
publicLabel: t("groupPublic"),
inPreset: state.groupBizMonitorInPreset,
published: state.groupBizMonitorPublic,
disabled,
onEditInPreset: (checked) => {
props.edit("groupBizMonitorInPreset", checked ? "true" : "false");
},
onEditPublic: (checked) => {
props.edit("groupBizMonitorPublic", checked ? "true" : "false");
}
})
]
}),
@ -1995,6 +2009,8 @@ class NetxopsCardController {
booleanField("groupOpsPublic"),
booleanField("groupTopologyInPreset"),
booleanField("groupTopologyPublic"),
booleanFieldPersistFalse("groupBizMonitorInPreset"),
booleanField("groupBizMonitorPublic"),
booleanFieldPersistFalse("groupKbInPreset"),
booleanField("groupKbPublic"),
booleanField("alarmPushEnabled"),
@ -2312,6 +2328,8 @@ class NetxopsCardController {
groupOpsPublic: this.form.field("groupOpsPublic"),
groupTopologyInPreset: this.form.field("groupTopologyInPreset"),
groupTopologyPublic: this.form.field("groupTopologyPublic"),
groupBizMonitorInPreset: this.form.field("groupBizMonitorInPreset"),
groupBizMonitorPublic: this.form.field("groupBizMonitorPublic"),
groupKbInPreset: this.form.field("groupKbInPreset"),
groupKbPublic: this.form.field("groupKbPublic"),
alarmPushEnabled: this.form.field("alarmPushEnabled"),
@ -2471,6 +2489,7 @@ var en = {
nmsProviderHint: "zte-ume",
groupOps: "ops",
groupTopology: "topology",
groupBizMonitor: "bizMonitor",
groupKb: "Knowledge skills",
groupInPreset: "In Netx Ops preset",
groupPublic: "Publish to other presets",
@ -2548,6 +2567,7 @@ var zh = {
nmsProviderHint: "zte-ume",
groupOps: "ops",
groupTopology: "topology",
groupBizMonitor: "bizMonitor",
groupKb: "知识库技能",
groupInPreset: "在 Netx Ops 预设中启用",
groupPublic: "对其他预设公开",

View file

@ -572,7 +572,8 @@ async function dispatchAlarmToSinks(ctx, payload, options, sinks = {}) {
// src/netx/capability-groups.ts
var DEFAULT_CAPABILITY_GROUPS = Object.freeze({
ops: Object.freeze({ inPreset: true, public: false }),
topology: Object.freeze({ inPreset: false, public: false })
topology: Object.freeze({ inPreset: false, public: false }),
bizMonitor: Object.freeze({ inPreset: true, public: false })
});
var TOOLS_BY_GROUP = Object.freeze({
ops: Object.freeze([
@ -608,15 +609,25 @@ var TOOLS_BY_GROUP = Object.freeze({
"netx__suggestSinkHubs",
"netx__analyzeTopologyViewLayout",
"netx__sinkTopologyDualUnits"
]),
bizMonitor: Object.freeze([
"netx__getBizMonitorContext",
"netx__getBizMonitorBoard",
"netx__listBizMonitorReds",
"netx__getBizMonitorDiffs",
"netx__getBizCollectBatch",
"netx__getBizCollectCommandRaw"
])
});
var SKILL_DIR_BY_GROUP = Object.freeze({
ops: "ops",
topology: "topology"
topology: "topology",
bizMonitor: "biz-monitor"
});
var CAPABILITY_GROUP_IDS = Object.freeze([
"ops",
"topology"
"topology",
"bizMonitor"
]);
function capabilityGroupsFromSettings(fields) {
const src = fields ?? {};
@ -633,6 +644,10 @@ function capabilityGroupsFromSettings(fields) {
opsInPreset = legacy.some((v) => v === true);
}
}
let bizMonitorInPreset = true;
if (src.groupBizMonitorInPreset !== undefined) {
bizMonitorInPreset = src.groupBizMonitorInPreset !== false;
}
return {
ops: {
inPreset: opsInPreset,
@ -641,6 +656,10 @@ function capabilityGroupsFromSettings(fields) {
topology: {
inPreset: src.groupTopologyInPreset === true || src.groupTopologyLayoutInPreset === true,
public: src.groupTopologyPublic === true || src.groupTopologyLayoutPublic === true
},
bizMonitor: {
inPreset: bizMonitorInPreset,
public: src.groupBizMonitorPublic === true
}
};
}
@ -653,12 +672,12 @@ function groupsForPlane(groups, plane, only) {
return enabled.filter((id) => allow.has(id));
}
function toolNamesForGroups(groupIds) {
const names = new Set;
const out = new Set;
for (const id of groupIds) {
for (const tool of TOOLS_BY_GROUP[id])
names.add(tool);
for (const name of TOOLS_BY_GROUP[id] ?? [])
out.add(name);
}
return names;
return out;
}
// src/netx/group-skills.ts
@ -3709,6 +3728,68 @@ async function findTopologyPaths(client, args, signal) {
body.to_managed_ne_id = toMid;
return client.post("/v1/topology/fabric/paths", body, signal, 30000);
}
async function getBizMonitorContext(client, args, signal) {
const projectId = str2(args, "project_id").trim();
const taskId = str2(args, "task_id").trim();
if (!projectId && !taskId) {
return { ok: false, error: "project_id_or_task_id_required" };
}
const params = {};
if (projectId)
params.project_id = projectId;
if (taskId)
params.task_id = taskId;
return client.get("/v1/biz-migration/monitor-context", params, signal);
}
async function getBizMonitorBoard(client, args, signal) {
const batchId = str2(args, "batch_id").trim();
if (!batchId)
return { ok: false, error: "batch_id_required" };
const params = {};
const runId = str2(args, "run_id").trim();
if (runId)
params.run_id = runId;
return client.get(`/v1/biz-migration/batches/${encodeURIComponent(batchId)}/board`, params, signal);
}
async function listBizMonitorReds(client, args, signal) {
const projectId = str2(args, "project_id").trim();
if (!projectId)
return { ok: false, error: "project_id_required" };
const params = {};
putStr(params, args, ["status"]);
const limit = num2(args, "limit");
if (limit !== undefined)
params.limit = clampInt(limit, 200, 1, 500);
return client.get(`/v1/biz-migration/projects/${encodeURIComponent(projectId)}/red-tickets`, params, signal);
}
async function getBizMonitorDiffs(client, args, signal) {
const runId = str2(args, "run_id").trim();
if (!runId)
return { ok: false, error: "run_id_required" };
const params = {};
putStr(params, args, ["metric_id", "sheet_id", "verdict", "color", "q"]);
const limit = num2(args, "limit");
if (limit !== undefined)
params.limit = clampInt(limit, 200, 1, 500);
const offset = num2(args, "offset");
if (offset !== undefined)
params.offset = clampInt(offset, 0, 0, Number.MAX_SAFE_INTEGER);
return client.get(`/v1/biz-migration/runs/${encodeURIComponent(runId)}/diffs`, params, signal);
}
async function getBizCollectBatch(client, args, signal) {
const batchId = str2(args, "batch_id").trim();
if (!batchId)
return { ok: false, error: "batch_id_required" };
return client.get(`/v1/biz-state/batches/${encodeURIComponent(batchId)}`, {}, signal);
}
async function getBizCollectCommandRaw(client, args, signal) {
const batchId = str2(args, "batch_id").trim();
const commandId = str2(args, "command_id").trim();
if (!batchId || !commandId) {
return { ok: false, error: "batch_id_and_command_id_required" };
}
return client.get(`/v1/biz-state/batches/${encodeURIComponent(batchId)}/commands/${encodeURIComponent(commandId)}`, {}, signal);
}
// src/netx/topology-handlers.ts
function asRecord2(value) {
@ -4533,6 +4614,36 @@ function registerNetxTools(ctx, connection, options) {
layer: str4(),
detail: str4("summary | full")
}, findTopologyPaths, getClient, t),
tool2("netx__getBizMonitorContext", "Biz-monitor definition bundle: cutover project + monitor/compare templates + iface normalize + port mapping + related tasks/commands. Prefer project_id. Display keys are device-raw A/B.", {
project_id: str4("Cutover / biz-migration project id"),
task_id: str4("biz_state task id (optional if project_id set)")
}, getBizMonitorContext, getClient, t),
tool2("netx__getBizMonitorBoard", "Cutover batch board: project/batch status, evaluate run summary, sheet cards, verdict counts, metric_batches.", {
batch_id: { type: "string", required: true },
run_id: str4("Optional evaluate run id")
}, getBizMonitorBoard, getClient, t),
tool2("netx__listBizMonitorReds", "Open/carried red tickets. Each item has old_key/new_key (raw A/B) and evidence (device, collect time, show command, iface raw→norm→map).", {
project_id: { type: "string", required: true },
status: str4("open|carried|resolved or empty=all"),
limit: num4()
}, listBizMonitorReds, getClient, t),
tool2("netx__getBizMonitorDiffs", "Paged evaluate diffs. Rows expose old_key/new_key (raw A/B), match_* keys, status, evidence with show commands.", {
run_id: { type: "string", required: true },
metric_id: str4(),
sheet_id: str4(),
verdict: str4(),
color: str4("e.g. red"),
q: str4(),
limit: num4(),
offset: num4()
}, getBizMonitorDiffs, getClient, t),
tool2("netx__getBizCollectBatch", "One biz_state collect batch: commands (raw_command, parse_status, preview), parsed metrics.", {
batch_id: { type: "string", required: true }
}, getBizCollectBatch, getClient, t),
tool2("netx__getBizCollectCommandRaw", "Full CLI raw_text for one collect command inside a batch (deep dive).", {
batch_id: { type: "string", required: true },
command_id: { type: "string", required: true }
}, getBizCollectCommandRaw, getClient, t),
tool2("netx__getTopologyTree", "Get topology folder tree (nav roots + Root map canvases). Start here before createTopologyFolder.", { compact: bool4(), max_depth: num4() }, getTopologyTree, getClient, t),
tool2("netx__getTopologyView", "Get a topology view by view_id. Default detail=summary with sample_nodes + links[].", {
view_id: { type: "string", required: true },
@ -4734,6 +4845,8 @@ var Config = z.object({
groupOpsPublic: z.boolean().default(false),
groupTopologyInPreset: z.boolean().default(false),
groupTopologyPublic: z.boolean().default(false),
groupBizMonitorInPreset: z.boolean().default(true),
groupBizMonitorPublic: z.boolean().default(false),
kbRoot: z.string().default(""),
groupKbInPreset: z.boolean().default(true),
groupKbPublic: z.boolean().default(false)