mirror of
https://github.com/hansjone/netxops.git
synced 2026-10-09 05:10:45 +08:00
Add operator-subset knowledge base wiring for Netx Ops P1.
Locate and validate MANIFEST under kbRoot, show anti-mixup status in settings, and inject KB_* env plus kb-context so sessions degrade to pure netx when unset. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
e6f9d062ed
commit
de7c6a0c4b
23 changed files with 2694 additions and 68 deletions
|
|
@ -215,22 +215,120 @@ async function registerGroupSkills(ctx, groupIds, providerLabel) {
|
|||
};
|
||||
}
|
||||
|
||||
// src/netx/runtime.ts
|
||||
var STORE_KEY = Symbol.for("dsh-netxops.connection-store");
|
||||
// src/netx/kb-context-skill.ts
|
||||
var SKILL_NAME = "kb-context";
|
||||
function skillBody(snapshot) {
|
||||
if (snapshot.status === "configured") {
|
||||
const flags = Object.entries(snapshot.content).filter(([, on]) => on).map(([key]) => key).join(", ") || "(none)";
|
||||
return {
|
||||
description: "Operator knowledge-base context for this Host (paths + identity from MANIFEST).",
|
||||
content: [
|
||||
"## Knowledge base (configured)",
|
||||
"",
|
||||
"When troubleshooting with operator playbooks or docs, **compose paths from this root**.",
|
||||
"Do not invent another operator or country.",
|
||||
"",
|
||||
`| Field | Value |`,
|
||||
`| --- | --- |`,
|
||||
`| kbStatus | configured |`,
|
||||
`| kbRoot | \`${snapshot.realRoot}\` |`,
|
||||
`| kbOperator | ${snapshot.operatorName} |`,
|
||||
`| kbCountry | ${snapshot.country} |`,
|
||||
`| kbVersion | ${snapshot.version} |`,
|
||||
`| kbContent (on) | ${flags} |`,
|
||||
"",
|
||||
"Environment mirrors: `KB_ROOT`, `KB_OPERATOR`, `KB_COUNTRY`, `KB_VERSION`, `KB_CONTENT`, `KB_STATUS`."
|
||||
].join(`
|
||||
`)
|
||||
};
|
||||
}
|
||||
const reason = snapshot.status === "error" ? snapshot.errorMessage || "invalid knowledge base" : "kbRoot is empty";
|
||||
return {
|
||||
description: "Knowledge-base context is unavailable — stay on pure netx evidence.",
|
||||
content: [
|
||||
"## Knowledge base (unavailable)",
|
||||
"",
|
||||
`kbStatus=\`${snapshot.status}\`. ${reason}`,
|
||||
"",
|
||||
"**Do not invent an operator, country, or KB paths.**",
|
||||
"Use only netx tools / live evidence (alarms, inventory, CLI, topology).",
|
||||
"Operator-specific playbooks are out of scope until a valid MANIFEST is configured."
|
||||
].join(`
|
||||
`)
|
||||
};
|
||||
}
|
||||
function registerKbContextSkill(ctx, snapshot) {
|
||||
const skillsApi = ctx.skills;
|
||||
if (!skillsApi || typeof skillsApi.register !== "function") {
|
||||
return () => {};
|
||||
}
|
||||
const body = skillBody(snapshot);
|
||||
return skillsApi.register({
|
||||
name: SKILL_NAME,
|
||||
description: body.description,
|
||||
content: body.content,
|
||||
provider: "netxops-kb",
|
||||
source: "custom"
|
||||
});
|
||||
}
|
||||
|
||||
// src/netx/kb-manifest.ts
|
||||
var EMPTY_CONTENT = {
|
||||
regions: false,
|
||||
theory: false,
|
||||
packet: false,
|
||||
skills: false
|
||||
};
|
||||
function unconfiguredKbSnapshot() {
|
||||
return {
|
||||
status: "unconfigured",
|
||||
realRoot: "",
|
||||
operatorName: "",
|
||||
country: "",
|
||||
version: "",
|
||||
content: { ...EMPTY_CONTENT },
|
||||
errorMessage: ""
|
||||
};
|
||||
}
|
||||
|
||||
// src/netx/kb-runtime.ts
|
||||
var STORE_KEY = Symbol.for("dsh-netxops.kb-store");
|
||||
function store() {
|
||||
const root = globalThis;
|
||||
let current = root[STORE_KEY];
|
||||
if (current === undefined) {
|
||||
current = { connection: undefined, listeners: new Set };
|
||||
current = { snapshot: unconfiguredKbSnapshot(), listeners: new Set };
|
||||
root[STORE_KEY] = current;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
function getKbContext() {
|
||||
return { ...store().snapshot, content: { ...store().snapshot.content } };
|
||||
}
|
||||
function watchKbContext(listener) {
|
||||
const state = store();
|
||||
state.listeners.add(listener);
|
||||
return () => {
|
||||
state.listeners.delete(listener);
|
||||
};
|
||||
}
|
||||
|
||||
// src/netx/runtime.ts
|
||||
var STORE_KEY2 = Symbol.for("dsh-netxops.connection-store");
|
||||
function store2() {
|
||||
const root = globalThis;
|
||||
let current = root[STORE_KEY2];
|
||||
if (current === undefined) {
|
||||
current = { connection: undefined, listeners: new Set };
|
||||
root[STORE_KEY2] = current;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
function getNetxConnection() {
|
||||
return store().connection;
|
||||
return store2().connection;
|
||||
}
|
||||
function watchNetxConnection(listener) {
|
||||
const state = store();
|
||||
const state = store2();
|
||||
state.listeners.add(listener);
|
||||
return () => {
|
||||
state.listeners.delete(listener);
|
||||
|
|
@ -1749,6 +1847,7 @@ function applyGroupToolsPlugin(ctx, options) {
|
|||
remountTools();
|
||||
});
|
||||
ctx.inject(["skills"], (skillsCtx) => {
|
||||
let unregisterKbSkill;
|
||||
const remountSkills = () => {
|
||||
const gen = ++skillGeneration;
|
||||
unregisterSkills?.();
|
||||
|
|
@ -1766,15 +1865,27 @@ function applyGroupToolsPlugin(ctx, options) {
|
|||
skillsCtx.logger.warn("%s: skill register failed: %s", options.name, error);
|
||||
});
|
||||
};
|
||||
const remountKbSkill = () => {
|
||||
unregisterKbSkill?.();
|
||||
unregisterKbSkill = undefined;
|
||||
unregisterKbSkill = registerKbContextSkill(skillsCtx, getKbContext());
|
||||
};
|
||||
remountSkills();
|
||||
remountKbSkill();
|
||||
const stopSkillWatch = watchNetxConnection(() => {
|
||||
remountSkills();
|
||||
});
|
||||
const stopKbWatch = watchKbContext(() => {
|
||||
remountKbSkill();
|
||||
});
|
||||
skillsCtx.effect(() => () => {
|
||||
skillGeneration += 1;
|
||||
stopSkillWatch();
|
||||
stopKbWatch();
|
||||
unregisterSkills?.();
|
||||
unregisterSkills = undefined;
|
||||
unregisterKbSkill?.();
|
||||
unregisterKbSkill = undefined;
|
||||
}, `${options.name}: dispose skills`);
|
||||
});
|
||||
ctx.effect(() => () => {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue