mirror of
https://github.com/hansjone/netxops.git
synced 2026-10-17 15:00:46 +08:00
Hot-reload capability public toggles via settings/document-updated (0.1.52).
Subscribe to live settings events so opening/closing publish-to-other-presets remounts host tools and skills immediately without restarting Desktop. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
6c9f323368
commit
e2e65b0324
7 changed files with 49 additions and 21 deletions
|
|
@ -67,7 +67,7 @@ One command, three **direct** profile bundles. Do **not** nest IM/cron under net
|
||||||
Token fallback: `scripts/set-netx-token.ps1` / `.sh`.
|
Token fallback: `scripts/set-netx-token.ps1` / `.sh`.
|
||||||
Optional: enable **关键告警推送** so this DSH dials `ws(s)://<apiUrl>/v1/integrations/dsh-alarm/ws`. Choose **投递到 DSH 会话** and/or **投递到 WhatsApp / IM**. For IM, install `dsh-im-ops`, create a delivery target, then paste `imBotId` / `imTargetId`. The card header shows live WSS status.
|
Optional: enable **关键告警推送** so this DSH dials `ws(s)://<apiUrl>/v1/integrations/dsh-alarm/ws`. Choose **投递到 DSH 会话** and/or **投递到 WhatsApp / IM**. For IM, install `dsh-im-ops`, create a delivery target, then paste `imBotId` / `imTargetId`. The card header shows live WSS status.
|
||||||
Optional: **导出全部会话** downloads `dsh-sessions-<host>-<utc>.zip` via `GET /api/netxops.sessions.export` (browser download; works for cloud Hosts).
|
Optional: **导出全部会话** downloads `dsh-sessions-<host>-<utc>.zip` via `GET /api/netxops.sessions.export` (browser download; works for cloud Hosts).
|
||||||
Capability groups: **ops** defaults on (in Netx Ops + published to other presets). Enable **topology** if needed; uncheck **对其他预设公开** to keep tools Netx-Ops-only. Capability toggles auto-save (new sessions after restart if Host just healed a sparse Desktop override).
|
Capability groups: **ops** defaults on (in Netx Ops + published to other presets). Enable **topology** if needed; uncheck **对其他预设公开** to keep tools Netx-Ops-only. Capability toggles **auto-save and hot-reload** (Host remounts `netx__*` / skills immediately — no Desktop restart).
|
||||||
Optional: **知识库** — set package root (MANIFEST v1.0); default mounts `_skills/kb-*` into Netx Ops; optional public. See [KNOWLEDGE_BASE.md](KNOWLEDGE_BASE.md).
|
Optional: **知识库** — set package root (MANIFEST v1.0); default mounts `_skills/kb-*` into Netx Ops; optional public. See [KNOWLEDGE_BASE.md](KNOWLEDGE_BASE.md).
|
||||||
2. Restart after install/upgrade so the bundle patch layers apply. Open Settings → **Agent presets** → **Netx Ops** should appear.
|
2. Restart after install/upgrade so the bundle patch layers apply. Open Settings → **Agent presets** → **Netx Ops** should appear.
|
||||||
The Netx Ops preset is **standard + netxops tools/persona** (shell, search, plan, todo, web, workflows, … plus `netx__*`). Re-activate (or restart the Host) so `$DSH_HOME/.agent-presets/netxops` is recomposed from the current Harness `standard` preset.
|
The Netx Ops preset is **standard + netxops tools/persona** (shell, search, plan, todo, web, workflows, … plus `netx__*`). Re-activate (or restart the Host) so `$DSH_HOME/.agent-presets/netxops` is recomposed from the current Harness `standard` preset.
|
||||||
|
|
|
||||||
|
|
@ -2506,7 +2506,7 @@ var en = {
|
||||||
groupBizMonitor: "bizMonitor",
|
groupBizMonitor: "bizMonitor",
|
||||||
groupKb: "Knowledge skills",
|
groupKb: "Knowledge skills",
|
||||||
groupInPreset: "In Netx Ops preset",
|
groupInPreset: "In Netx Ops preset",
|
||||||
groupPublic: "Publish to other presets (auto-saves; new sessions)",
|
groupPublic: "Publish to other presets (auto-saves; hot-reloads)",
|
||||||
kbRoot: "Package root",
|
kbRoot: "Package root",
|
||||||
kbRootHint: "Folder with MANIFEST.json (operator-subset v1.0). Browse auto-saves. Pack skills load from paths.skills/_skills and paths.localSkills when hasSkills.",
|
kbRootHint: "Folder with MANIFEST.json (operator-subset v1.0). Browse auto-saves. Pack skills load from paths.skills/_skills and paths.localSkills when hasSkills.",
|
||||||
kbBrowse: "Browse…",
|
kbBrowse: "Browse…",
|
||||||
|
|
@ -2584,7 +2584,7 @@ var zh = {
|
||||||
groupBizMonitor: "bizMonitor",
|
groupBizMonitor: "bizMonitor",
|
||||||
groupKb: "知识库技能",
|
groupKb: "知识库技能",
|
||||||
groupInPreset: "在 Netx Ops 预设中启用",
|
groupInPreset: "在 Netx Ops 预设中启用",
|
||||||
groupPublic: "对其他预设公开(勾选后自动保存;新会话生效)",
|
groupPublic: "对其他预设公开(自动保存,即时挂载/卸载)",
|
||||||
kbRoot: "知识包根目录",
|
kbRoot: "知识包根目录",
|
||||||
kbRootHint: "含 MANIFEST.json 的运营商子集包(v1.0)。浏览选目录后会自动保存;hasSkills 时加载 paths.skills/_skills 与 paths.localSkills。",
|
kbRootHint: "含 MANIFEST.json 的运营商子集包(v1.0)。浏览选目录后会自动保存;hasSkills 时加载 paths.skills/_skills 与 paths.localSkills。",
|
||||||
kbBrowse: "浏览…",
|
kbBrowse: "浏览…",
|
||||||
|
|
|
||||||
28
lib/index.js
28
lib/index.js
|
|
@ -203,7 +203,7 @@ function healNetxopsProfileEntries(logger) {
|
||||||
continue;
|
continue;
|
||||||
writeFileSync(patchPath, normalized, "utf8");
|
writeFileSync(patchPath, normalized, "utf8");
|
||||||
rewritten += 1;
|
rewritten += 1;
|
||||||
logger.info("netxops: healed sparse host entry in profiles/%s/cordis.patch.yml (restart %s to load capability defaults)", profileName, profileName === "desktop" ? "Desktop" : "dsh web");
|
logger.info("netxops: healed sparse host entry in profiles/%s/cordis.patch.yml " + "(public toggles hot-reload via settings; restart %s only if tools still missing after heal)", profileName, profileName === "desktop" ? "Desktop" : "dsh web");
|
||||||
}
|
}
|
||||||
return rewritten;
|
return rewritten;
|
||||||
}
|
}
|
||||||
|
|
@ -6042,18 +6042,32 @@ function installNetxopsSettings(ctx, entry, hooks) {
|
||||||
hooks.setSource(readLive);
|
hooks.setSource(readLive);
|
||||||
hooks.onChange();
|
hooks.onChange();
|
||||||
let lastFingerprint = JSON.stringify(readLive());
|
let lastFingerprint = JSON.stringify(readLive());
|
||||||
const timer = setInterval(() => {
|
const bumpIfChanged = (reason) => {
|
||||||
const next = readLive();
|
const next = readLive();
|
||||||
const fingerprint = JSON.stringify(next);
|
const fingerprint = JSON.stringify(next);
|
||||||
if (fingerprint === lastFingerprint)
|
if (fingerprint === lastFingerprint)
|
||||||
return;
|
return;
|
||||||
lastFingerprint = fingerprint;
|
lastFingerprint = fingerprint;
|
||||||
|
settingsCtx.logger.info("netxops: live settings changed (%s) → republish connection", reason);
|
||||||
hooks.onChange();
|
hooks.onChange();
|
||||||
}, 2000);
|
};
|
||||||
settingsCtx.effect(() => () => {
|
settingsCtx.effect(() => {
|
||||||
clearInterval(timer);
|
const onDocumentUpdated = (ns) => {
|
||||||
}, "netxops: settings describe poll");
|
if (ns !== NETXOPS_SETTINGS_NAMESPACE && ns !== "dsh-netxops")
|
||||||
settingsCtx.logger.info("netxops: following settings via describe() (no installSection — DSH ≥0.1.7 path)");
|
return;
|
||||||
|
bumpIfChanged("document-updated");
|
||||||
|
};
|
||||||
|
const off = settingsCtx.on("settings/document-updated", onDocumentUpdated);
|
||||||
|
const timer = setInterval(() => {
|
||||||
|
bumpIfChanged("poll");
|
||||||
|
}, 2000);
|
||||||
|
return () => {
|
||||||
|
clearInterval(timer);
|
||||||
|
if (typeof off === "function")
|
||||||
|
off();
|
||||||
|
};
|
||||||
|
}, "netxops: settings live follow");
|
||||||
|
settingsCtx.logger.info("netxops: hot-following settings (document-updated + describe poll)");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function apply(ctx, config = Config({})) {
|
function apply(ctx, config = Config({})) {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "dsh-netxops",
|
"name": "dsh-netxops",
|
||||||
"version": "0.1.51",
|
"version": "0.1.52",
|
||||||
"description": "DeepSeek Harness Netx Ops: ops/topology + IM delivery + session export + knowledge-base MANIFEST/_skills + localSkills",
|
"description": "DeepSeek Harness Netx Ops: ops/topology + IM delivery + session export + knowledge-base MANIFEST/_skills + localSkills",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ export const en: Record<NetxopsLocaleKey, string> = {
|
||||||
groupBizMonitor: 'bizMonitor',
|
groupBizMonitor: 'bizMonitor',
|
||||||
groupKb: 'Knowledge skills',
|
groupKb: 'Knowledge skills',
|
||||||
groupInPreset: 'In Netx Ops preset',
|
groupInPreset: 'In Netx Ops preset',
|
||||||
groupPublic: 'Publish to other presets (auto-saves; new sessions)',
|
groupPublic: 'Publish to other presets (auto-saves; hot-reloads)',
|
||||||
kbRoot: 'Package root',
|
kbRoot: 'Package root',
|
||||||
kbRootHint: 'Folder with MANIFEST.json (operator-subset v1.0). Browse auto-saves. Pack skills load from paths.skills/_skills and paths.localSkills when hasSkills.',
|
kbRootHint: 'Folder with MANIFEST.json (operator-subset v1.0). Browse auto-saves. Pack skills load from paths.skills/_skills and paths.localSkills when hasSkills.',
|
||||||
kbBrowse: 'Browse…',
|
kbBrowse: 'Browse…',
|
||||||
|
|
@ -181,7 +181,7 @@ export const zh: Record<NetxopsLocaleKey, string> = {
|
||||||
groupBizMonitor: 'bizMonitor',
|
groupBizMonitor: 'bizMonitor',
|
||||||
groupKb: '知识库技能',
|
groupKb: '知识库技能',
|
||||||
groupInPreset: '在 Netx Ops 预设中启用',
|
groupInPreset: '在 Netx Ops 预设中启用',
|
||||||
groupPublic: '对其他预设公开(勾选后自动保存;新会话生效)',
|
groupPublic: '对其他预设公开(自动保存,即时挂载/卸载)',
|
||||||
kbRoot: '知识包根目录',
|
kbRoot: '知识包根目录',
|
||||||
kbRootHint: '含 MANIFEST.json 的运营商子集包(v1.0)。浏览选目录后会自动保存;hasSkills 时加载 paths.skills/_skills 与 paths.localSkills。',
|
kbRootHint: '含 MANIFEST.json 的运营商子集包(v1.0)。浏览选目录后会自动保存;hasSkills 时加载 paths.skills/_skills 与 paths.localSkills。',
|
||||||
kbBrowse: '浏览…',
|
kbBrowse: '浏览…',
|
||||||
|
|
|
||||||
27
src/index.ts
27
src/index.ts
|
|
@ -273,7 +273,9 @@ function installNetxopsSettings(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// DSH ≥0.1.7: profile Config projection — follow describe() for live values.
|
// DSH ≥0.1.7: profile Config projection — follow live fiber config.
|
||||||
|
// `settings/document-updated` fires right after configForms save → remount
|
||||||
|
// public tools/skills without restart (poll is a slow backup only).
|
||||||
const readLive = (): Config => {
|
const readLive = (): Config => {
|
||||||
const row = describeRows(settings.describe).find(item => item.ns === NETXOPS_SETTINGS_NAMESPACE)
|
const row = describeRows(settings.describe).find(item => item.ns === NETXOPS_SETTINGS_NAMESPACE)
|
||||||
if (row?.value !== null && typeof row?.value === 'object' && !Array.isArray(row.value)) {
|
if (row?.value !== null && typeof row?.value === 'object' && !Array.isArray(row.value)) {
|
||||||
|
|
@ -285,18 +287,29 @@ function installNetxopsSettings(
|
||||||
hooks.onChange()
|
hooks.onChange()
|
||||||
|
|
||||||
let lastFingerprint = JSON.stringify(readLive())
|
let lastFingerprint = JSON.stringify(readLive())
|
||||||
const timer = setInterval(() => {
|
const bumpIfChanged = (reason: string): void => {
|
||||||
const next = readLive()
|
const next = readLive()
|
||||||
const fingerprint = JSON.stringify(next)
|
const fingerprint = JSON.stringify(next)
|
||||||
if (fingerprint === lastFingerprint) return
|
if (fingerprint === lastFingerprint) return
|
||||||
lastFingerprint = fingerprint
|
lastFingerprint = fingerprint
|
||||||
|
settingsCtx.logger.info('netxops: live settings changed (%s) → republish connection', reason)
|
||||||
hooks.onChange()
|
hooks.onChange()
|
||||||
}, 2_000)
|
}
|
||||||
settingsCtx.effect(() => () => {
|
|
||||||
clearInterval(timer)
|
settingsCtx.effect(() => {
|
||||||
}, 'netxops: settings describe poll')
|
const onDocumentUpdated = (ns: string): void => {
|
||||||
|
if (ns !== NETXOPS_SETTINGS_NAMESPACE && ns !== 'dsh-netxops') return
|
||||||
|
bumpIfChanged('document-updated')
|
||||||
|
}
|
||||||
|
const off = settingsCtx.on('settings/document-updated', onDocumentUpdated)
|
||||||
|
const timer = setInterval(() => { bumpIfChanged('poll') }, 2_000)
|
||||||
|
return () => {
|
||||||
|
clearInterval(timer)
|
||||||
|
if (typeof off === 'function') off()
|
||||||
|
}
|
||||||
|
}, 'netxops: settings live follow')
|
||||||
settingsCtx.logger.info(
|
settingsCtx.logger.info(
|
||||||
'netxops: following settings via describe() (no installSection — DSH ≥0.1.7 path)',
|
'netxops: hot-following settings (document-updated + describe poll)',
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -194,7 +194,8 @@ export function healNetxopsProfileEntries(logger: Context['logger']): number {
|
||||||
writeFileSync(patchPath, normalized, 'utf8')
|
writeFileSync(patchPath, normalized, 'utf8')
|
||||||
rewritten += 1
|
rewritten += 1
|
||||||
logger.info(
|
logger.info(
|
||||||
'netxops: healed sparse host entry in profiles/%s/cordis.patch.yml (restart %s to load capability defaults)',
|
'netxops: healed sparse host entry in profiles/%s/cordis.patch.yml '
|
||||||
|
+ '(public toggles hot-reload via settings; restart %s only if tools still missing after heal)',
|
||||||
profileName,
|
profileName,
|
||||||
profileName === 'desktop' ? 'Desktop' : 'dsh web',
|
profileName === 'desktop' ? 'Desktop' : 'dsh web',
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue