@rezti/dsh-rez-suite 0.1.5 → 0.1.7
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.md +1 -1
- package/README.zh.md +1 -1
- package/lib/client.d.ts +11 -3
- package/lib/client.js +215 -161
- package/lib/index.d.ts +20 -0
- package/lib/index.js +182 -29
- package/package.json +6 -6
- package/src/client/locales.ts +23 -7
- package/src/client/panel/ConfigTab.tsx +141 -86
- package/src/client/panel/StatusTab.tsx +1 -0
- package/src/index.ts +40 -20
- package/src/observe-mcp.ts +121 -0
- package/src/protocol.ts +23 -0
- package/src/routes.ts +32 -4
- package/src/store.ts +37 -1
package/README.md
CHANGED
|
@@ -8,4 +8,4 @@ dsh plugin --profile web add @rezti/dsh-rez-suite
|
|
|
8
8
|
|
|
9
9
|
组成见仓库根 README。子包不要单独 `dsh plugin add`。
|
|
10
10
|
|
|
11
|
-
配置在 **设置 → 插件 → 插件配置** 展开 **ReZ-TI**(同页还有独立的 ReZ-TI
|
|
11
|
+
配置在 **设置 → 插件 → 插件配置** 展开 **ReZ-TI**(同页还有独立的 ReZ-TI 标签)。Odoo / Nextcloud / WeCom / HA 的地址和密钥都在「配置」页。个人微信在卡片的「微信」页扫码,然后直接在微信里说话。状态页看的是本机已注册的 `mcp__odoo__*` 等工具,不是直接 ping 远端 MCP。
|
package/README.zh.md
CHANGED
|
@@ -8,6 +8,6 @@ dsh plugin --profile web add @rezti/dsh-rez-suite
|
|
|
8
8
|
|
|
9
9
|
密钥用环境变量或 dsh-credentials:`REZ_ODOO_TOKEN`、`REZ_NEXTCLOUD_PASSWORD`、`REZ_WECHAT_WEBHOOK`、`REZ_HA_TOKEN`。未配置时不拉起对应 MCP。
|
|
10
10
|
|
|
11
|
-
配置在 **设置 → 插件 → 插件配置** 展开 **ReZ-TI**(同页还有独立的 ReZ-TI
|
|
11
|
+
配置在 **设置 → 插件 → 插件配置** 展开 **ReZ-TI**(同页还有独立的 ReZ-TI 标签)。Odoo / Nextcloud / 企微 / HA 的地址和密钥都在「配置」页。个人微信在卡片的「微信」页扫码,然后直接在微信里说话。状态页看的是本机已注册的 `mcp__odoo__*` 等工具,不是直接 ping 远端 MCP。
|
|
12
12
|
|
|
13
13
|
子包不要再单独 `dsh plugin add`,否则会重复注册 MCP。
|
package/lib/client.d.ts
CHANGED
|
@@ -7275,16 +7275,23 @@ declare const zh: {
|
|
|
7275
7275
|
readonly 'config.env': "环境变量 (JSON)";
|
|
7276
7276
|
readonly 'config.headers': "Headers (JSON)";
|
|
7277
7277
|
readonly 'config.jsonInvalid': "JSON 格式错误:{error}";
|
|
7278
|
+
readonly 'config.mcpHint': "四个公司 MCP 在这里配。密钥写入 ~/.dsh/.credentials.yaml(REZ_*)。新填的密钥会立刻拉起连接;改 URL 后如果已经连上,需要重启 dsh web。";
|
|
7279
|
+
readonly 'config.secretConfigured': "已配置(留空则保持)";
|
|
7280
|
+
readonly 'config.secretMissing': "未配置";
|
|
7278
7281
|
readonly 'config.odoo': "Odoo";
|
|
7279
|
-
readonly 'config.odoo.url': "Odoo URL";
|
|
7280
|
-
readonly 'config.odoo.apiKey': "API
|
|
7282
|
+
readonly 'config.odoo.url': "Odoo MCP URL";
|
|
7283
|
+
readonly 'config.odoo.apiKey': "API Token";
|
|
7281
7284
|
readonly 'config.nextcloud': "Nextcloud";
|
|
7282
|
-
readonly 'config.nextcloud.url': "Nextcloud
|
|
7285
|
+
readonly 'config.nextcloud.url': "Nextcloud 主机";
|
|
7283
7286
|
readonly 'config.nextcloud.username': "用户名";
|
|
7284
7287
|
readonly 'config.nextcloud.appPassword': "App Password";
|
|
7285
7288
|
readonly 'config.wecom': "企业微信";
|
|
7286
7289
|
readonly 'config.wecom.botId': "Bot ID";
|
|
7287
7290
|
readonly 'config.wecom.secret': "Secret";
|
|
7291
|
+
readonly 'config.wecom.webhook': "群机器人 Webhook";
|
|
7292
|
+
readonly 'config.ha': "Home Assistant";
|
|
7293
|
+
readonly 'config.ha.url': "HA MCP URL";
|
|
7294
|
+
readonly 'config.ha.token': "长期访问令牌";
|
|
7288
7295
|
readonly 'config.fs': "本地文件 (fs-mcp-server)";
|
|
7289
7296
|
readonly 'config.fs.root': "根目录";
|
|
7290
7297
|
readonly 'config.sqlite': "SQLite (sqlite-mcp-server)";
|
|
@@ -7300,6 +7307,7 @@ declare const zh: {
|
|
|
7300
7307
|
readonly 'config.testResult': "{server}: {status}";
|
|
7301
7308
|
readonly 'config.testOk': "成功({tools} 个工具, {latency}ms)";
|
|
7302
7309
|
readonly 'config.testFail': "失败:{error}";
|
|
7310
|
+
readonly 'status.hint': "绿标表示本机已注册 mcp__<系统>__* 工具。远端 MCP 通了但这里仍红,说明 dsh-mcp-client 还没挂上。";
|
|
7303
7311
|
readonly 'status.total': "当前角色 {role},共注册 {count} 个 MCP 工具";
|
|
7304
7312
|
readonly 'status.col.server': "Server";
|
|
7305
7313
|
readonly 'status.col.state': "状态";
|
package/lib/client.js
CHANGED
|
@@ -36,16 +36,23 @@ const zh = {
|
|
|
36
36
|
"config.env": "环境变量 (JSON)",
|
|
37
37
|
"config.headers": "Headers (JSON)",
|
|
38
38
|
"config.jsonInvalid": "JSON 格式错误:{error}",
|
|
39
|
+
"config.mcpHint": "四个公司 MCP 在这里配。密钥写入 ~/.dsh/.credentials.yaml(REZ_*)。新填的密钥会立刻拉起连接;改 URL 后如果已经连上,需要重启 dsh web。",
|
|
40
|
+
"config.secretConfigured": "已配置(留空则保持)",
|
|
41
|
+
"config.secretMissing": "未配置",
|
|
39
42
|
"config.odoo": "Odoo",
|
|
40
|
-
"config.odoo.url": "Odoo URL",
|
|
41
|
-
"config.odoo.apiKey": "API
|
|
43
|
+
"config.odoo.url": "Odoo MCP URL",
|
|
44
|
+
"config.odoo.apiKey": "API Token",
|
|
42
45
|
"config.nextcloud": "Nextcloud",
|
|
43
|
-
"config.nextcloud.url": "Nextcloud
|
|
46
|
+
"config.nextcloud.url": "Nextcloud 主机",
|
|
44
47
|
"config.nextcloud.username": "用户名",
|
|
45
48
|
"config.nextcloud.appPassword": "App Password",
|
|
46
49
|
"config.wecom": "企业微信",
|
|
47
50
|
"config.wecom.botId": "Bot ID",
|
|
48
51
|
"config.wecom.secret": "Secret",
|
|
52
|
+
"config.wecom.webhook": "群机器人 Webhook",
|
|
53
|
+
"config.ha": "Home Assistant",
|
|
54
|
+
"config.ha.url": "HA MCP URL",
|
|
55
|
+
"config.ha.token": "长期访问令牌",
|
|
49
56
|
"config.fs": "本地文件 (fs-mcp-server)",
|
|
50
57
|
"config.fs.root": "根目录",
|
|
51
58
|
"config.sqlite": "SQLite (sqlite-mcp-server)",
|
|
@@ -61,6 +68,7 @@ const zh = {
|
|
|
61
68
|
"config.testResult": "{server}: {status}",
|
|
62
69
|
"config.testOk": "成功({tools} 个工具, {latency}ms)",
|
|
63
70
|
"config.testFail": "失败:{error}",
|
|
71
|
+
"status.hint": "绿标表示本机已注册 mcp__<系统>__* 工具。远端 MCP 通了但这里仍红,说明 dsh-mcp-client 还没挂上。",
|
|
64
72
|
"status.total": "当前角色 {role},共注册 {count} 个 MCP 工具",
|
|
65
73
|
"status.col.server": "Server",
|
|
66
74
|
"status.col.state": "状态",
|
|
@@ -125,16 +133,23 @@ const en = {
|
|
|
125
133
|
"config.env": "Env vars (JSON)",
|
|
126
134
|
"config.headers": "Headers (JSON)",
|
|
127
135
|
"config.jsonInvalid": "Invalid JSON: {error}",
|
|
136
|
+
"config.mcpHint": "Company MCP lives here. Secrets go to ~/.dsh/.credentials.yaml (REZ_*). A newly saved secret starts the connection immediately; URL changes after a live connection need a dsh web restart.",
|
|
137
|
+
"config.secretConfigured": "Configured (leave blank to keep)",
|
|
138
|
+
"config.secretMissing": "Not configured",
|
|
128
139
|
"config.odoo": "Odoo",
|
|
129
|
-
"config.odoo.url": "Odoo URL",
|
|
130
|
-
"config.odoo.apiKey": "API
|
|
140
|
+
"config.odoo.url": "Odoo MCP URL",
|
|
141
|
+
"config.odoo.apiKey": "API token",
|
|
131
142
|
"config.nextcloud": "Nextcloud",
|
|
132
|
-
"config.nextcloud.url": "Nextcloud
|
|
143
|
+
"config.nextcloud.url": "Nextcloud host",
|
|
133
144
|
"config.nextcloud.username": "Username",
|
|
134
|
-
"config.nextcloud.appPassword": "App
|
|
145
|
+
"config.nextcloud.appPassword": "App password",
|
|
135
146
|
"config.wecom": "WeCom",
|
|
136
147
|
"config.wecom.botId": "Bot ID",
|
|
137
148
|
"config.wecom.secret": "Secret",
|
|
149
|
+
"config.wecom.webhook": "Group bot webhook",
|
|
150
|
+
"config.ha": "Home Assistant",
|
|
151
|
+
"config.ha.url": "HA MCP URL",
|
|
152
|
+
"config.ha.token": "Long-lived access token",
|
|
138
153
|
"config.fs": "Local files (fs-mcp-server)",
|
|
139
154
|
"config.fs.root": "Root directory",
|
|
140
155
|
"config.sqlite": "SQLite (sqlite-mcp-server)",
|
|
@@ -150,6 +165,7 @@ const en = {
|
|
|
150
165
|
"config.testResult": "{server}: {status}",
|
|
151
166
|
"config.testOk": "OK ({tools} tools, {latency}ms)",
|
|
152
167
|
"config.testFail": "Failed: {error}",
|
|
168
|
+
"status.hint": "Green means this host registered mcp__<system>__* tools. A live remote MCP with a red row means dsh-mcp-client has not attached yet.",
|
|
153
169
|
"status.total": "Role {role}, {count} MCP tools registered",
|
|
154
170
|
"status.col.server": "Server",
|
|
155
171
|
"status.col.state": "State",
|
|
@@ -489,8 +505,8 @@ function AuditTab({ api }) {
|
|
|
489
505
|
//#endregion
|
|
490
506
|
//#region src/client/panel/ConfigTab.tsx
|
|
491
507
|
/**
|
|
492
|
-
* Config tab:
|
|
493
|
-
*
|
|
508
|
+
* Config tab: company MCP connections (Odoo / Nextcloud / WeCom / HA),
|
|
509
|
+
* role, and billing. Secrets are write-only and land in credentials.yaml.
|
|
494
510
|
*/
|
|
495
511
|
const ROLES = [
|
|
496
512
|
{
|
|
@@ -510,6 +526,12 @@ const ROLES = [
|
|
|
510
526
|
label: "role.operations"
|
|
511
527
|
}
|
|
512
528
|
];
|
|
529
|
+
const EMPTY_SECRETS = {
|
|
530
|
+
odoo: "",
|
|
531
|
+
nextcloud: "",
|
|
532
|
+
wechat: "",
|
|
533
|
+
homeassistant: ""
|
|
534
|
+
};
|
|
513
535
|
function Field({ label, children }) {
|
|
514
536
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
515
537
|
className: panel_module_default.field,
|
|
@@ -528,42 +550,81 @@ function Section({ title, children }) {
|
|
|
528
550
|
}), children]
|
|
529
551
|
});
|
|
530
552
|
}
|
|
531
|
-
function
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
553
|
+
function SecretField({ label, configured, value, onChange }) {
|
|
554
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
555
|
+
label,
|
|
556
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
557
|
+
className: panel_module_default.input,
|
|
558
|
+
type: "password",
|
|
559
|
+
autoComplete: "off",
|
|
560
|
+
value,
|
|
561
|
+
placeholder: configured ? tt("config.secretConfigured") : tt("config.secretMissing"),
|
|
562
|
+
onChange: (event) => {
|
|
563
|
+
onChange(event.target.value);
|
|
564
|
+
}
|
|
565
|
+
})
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
function McpSection({ title, row, secret, onEnabled, onUrl, onUsername, onSecret, urlLabel, secretLabel, usernameLabel }) {
|
|
569
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Section, {
|
|
570
|
+
title,
|
|
571
|
+
children: [
|
|
572
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
573
|
+
label: tt("config.enabled"),
|
|
574
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
575
|
+
className: panel_module_default.checkbox,
|
|
576
|
+
type: "checkbox",
|
|
577
|
+
checked: row.enabled,
|
|
578
|
+
onChange: (event) => {
|
|
579
|
+
onEnabled(event.target.checked);
|
|
580
|
+
}
|
|
581
|
+
})
|
|
582
|
+
}),
|
|
583
|
+
onUrl !== void 0 && urlLabel !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
584
|
+
label: urlLabel,
|
|
585
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
586
|
+
className: panel_module_default.input,
|
|
587
|
+
value: row.url ?? "",
|
|
588
|
+
onChange: (event) => {
|
|
589
|
+
onUrl(event.target.value);
|
|
590
|
+
}
|
|
591
|
+
})
|
|
592
|
+
}),
|
|
593
|
+
onUsername !== void 0 && usernameLabel !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
594
|
+
label: usernameLabel,
|
|
595
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
596
|
+
className: panel_module_default.input,
|
|
597
|
+
value: row.username ?? "",
|
|
598
|
+
onChange: (event) => {
|
|
599
|
+
onUsername(event.target.value);
|
|
600
|
+
}
|
|
601
|
+
})
|
|
602
|
+
}),
|
|
603
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SecretField, {
|
|
604
|
+
label: secretLabel,
|
|
605
|
+
configured: row.secretConfigured,
|
|
606
|
+
value: secret,
|
|
607
|
+
onChange: onSecret
|
|
608
|
+
}),
|
|
609
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
610
|
+
className: panel_module_default.message,
|
|
611
|
+
children: row.secretRef
|
|
612
|
+
})
|
|
613
|
+
]
|
|
614
|
+
});
|
|
537
615
|
}
|
|
538
616
|
function ConfigTab({ api }) {
|
|
539
617
|
const [config, setConfig] = (0, react.useState)(null);
|
|
618
|
+
const [secrets, setSecrets] = (0, react.useState)(EMPTY_SECRETS);
|
|
540
619
|
const [loading, setLoading] = (0, react.useState)(true);
|
|
541
620
|
const [saving, setSaving] = (0, react.useState)(false);
|
|
542
621
|
const [testing, setTesting] = (0, react.useState)(false);
|
|
543
622
|
const [message, setMessage] = (0, react.useState)("");
|
|
544
623
|
const [error, setError] = (0, react.useState)("");
|
|
545
624
|
const [results, setResults] = (0, react.useState)([]);
|
|
546
|
-
const [argsText, setArgsText] = (0, react.useState)({});
|
|
547
|
-
const [envText, setEnvText] = (0, react.useState)({});
|
|
548
|
-
const [headerText, setHeaderText] = (0, react.useState)({});
|
|
549
|
-
const initTexts = (next) => {
|
|
550
|
-
const args = {};
|
|
551
|
-
const envs = {};
|
|
552
|
-
const headers = {};
|
|
553
|
-
for (const [id, server] of Object.entries(next.servers)) {
|
|
554
|
-
args[id] = (server.args ?? []).join("\n");
|
|
555
|
-
envs[id] = JSON.stringify(server.env ?? {}, null, 2);
|
|
556
|
-
headers[id] = JSON.stringify(server.headers ?? {}, null, 2);
|
|
557
|
-
}
|
|
558
|
-
setArgsText(args);
|
|
559
|
-
setEnvText(envs);
|
|
560
|
-
setHeaderText(headers);
|
|
561
|
-
};
|
|
562
625
|
const load = async () => {
|
|
563
626
|
try {
|
|
564
|
-
|
|
565
|
-
setConfig(next);
|
|
566
|
-
initTexts(next);
|
|
627
|
+
setConfig(await api.getConfig());
|
|
567
628
|
} catch (err) {
|
|
568
629
|
setError(errorMessage(err));
|
|
569
630
|
} finally {
|
|
@@ -587,13 +648,13 @@ function ConfigTab({ api }) {
|
|
|
587
648
|
[key]: value
|
|
588
649
|
});
|
|
589
650
|
};
|
|
590
|
-
const
|
|
651
|
+
const patchConnection = (id, patch) => {
|
|
591
652
|
setConfig((prev) => prev === null ? prev : {
|
|
592
653
|
...prev,
|
|
593
|
-
|
|
594
|
-
...prev.
|
|
654
|
+
connections: {
|
|
655
|
+
...prev.connections,
|
|
595
656
|
[id]: {
|
|
596
|
-
...prev.
|
|
657
|
+
...prev.connections[id],
|
|
597
658
|
...patch
|
|
598
659
|
}
|
|
599
660
|
}
|
|
@@ -604,9 +665,32 @@ function ConfigTab({ api }) {
|
|
|
604
665
|
setMessage("");
|
|
605
666
|
setError("");
|
|
606
667
|
try {
|
|
607
|
-
const
|
|
668
|
+
const payload = {
|
|
669
|
+
enabled: config.enabled,
|
|
670
|
+
role: config.role,
|
|
671
|
+
billing: config.billing,
|
|
672
|
+
connections: {
|
|
673
|
+
odoo: {
|
|
674
|
+
...config.connections.odoo,
|
|
675
|
+
secret: secrets.odoo || void 0
|
|
676
|
+
},
|
|
677
|
+
nextcloud: {
|
|
678
|
+
...config.connections.nextcloud,
|
|
679
|
+
secret: secrets.nextcloud || void 0
|
|
680
|
+
},
|
|
681
|
+
wechat: {
|
|
682
|
+
...config.connections.wechat,
|
|
683
|
+
secret: secrets.wechat || void 0
|
|
684
|
+
},
|
|
685
|
+
homeassistant: {
|
|
686
|
+
...config.connections.homeassistant,
|
|
687
|
+
secret: secrets.homeassistant || void 0
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
};
|
|
691
|
+
const saved = await api.saveConfig(payload);
|
|
608
692
|
setConfig(saved);
|
|
609
|
-
|
|
693
|
+
setSecrets(EMPTY_SECRETS);
|
|
610
694
|
setMessage(tt("config.saved"));
|
|
611
695
|
} catch (err) {
|
|
612
696
|
setError(errorMessage(err));
|
|
@@ -628,28 +712,22 @@ function ConfigTab({ api }) {
|
|
|
628
712
|
}
|
|
629
713
|
};
|
|
630
714
|
const renderResult = (result) => {
|
|
631
|
-
if (result.ok)
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
const commitArgs = (id) => {
|
|
638
|
-
updateServer(id, { args: argsText[id] === "" ? [] : argsText[id].split("\n").map((line) => line.trim()).filter(Boolean) });
|
|
639
|
-
};
|
|
640
|
-
const commitRecord = (id, kind) => {
|
|
641
|
-
const text = kind === "env" ? envText[id] : headerText[id];
|
|
642
|
-
try {
|
|
643
|
-
const record = parseRecord(text ?? "{}");
|
|
644
|
-
updateServer(id, kind === "env" ? { env: record } : { headers: record });
|
|
645
|
-
setError("");
|
|
646
|
-
} catch (err) {
|
|
647
|
-
setError(tt("config.jsonInvalid", { error: errorMessage(err) }));
|
|
715
|
+
if (result.ok) {
|
|
716
|
+
if (result.serverInfo !== void 0) return result.serverInfo;
|
|
717
|
+
return tt("config.testOk", {
|
|
718
|
+
tools: result.toolCount ?? 0,
|
|
719
|
+
latency: result.latencyMs ?? 0
|
|
720
|
+
});
|
|
648
721
|
}
|
|
722
|
+
return tt("config.testFail", { error: result.error ?? "" });
|
|
649
723
|
};
|
|
650
724
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
651
725
|
className: panel_module_default.tabBody,
|
|
652
726
|
children: [
|
|
727
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
728
|
+
className: panel_module_default.message,
|
|
729
|
+
children: tt("config.mcpHint")
|
|
730
|
+
}),
|
|
653
731
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Section, {
|
|
654
732
|
title: tt("config.role"),
|
|
655
733
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
@@ -677,110 +755,82 @@ function ConfigTab({ api }) {
|
|
|
677
755
|
})
|
|
678
756
|
})]
|
|
679
757
|
}),
|
|
680
|
-
|
|
681
|
-
title:
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
})
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
757
|
-
label: tt("config.url"),
|
|
758
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
759
|
-
className: panel_module_default.input,
|
|
760
|
-
value: server.url ?? "",
|
|
761
|
-
onChange: (event) => {
|
|
762
|
-
updateServer(id, { url: event.target.value });
|
|
763
|
-
}
|
|
764
|
-
})
|
|
765
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Field, {
|
|
766
|
-
label: tt("config.headers"),
|
|
767
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
|
|
768
|
-
className: panel_module_default.input,
|
|
769
|
-
rows: 4,
|
|
770
|
-
value: headerText[id] ?? "{}",
|
|
771
|
-
onChange: (event) => {
|
|
772
|
-
setHeaderText((prev) => ({
|
|
773
|
-
...prev,
|
|
774
|
-
[id]: event.target.value
|
|
775
|
-
}));
|
|
776
|
-
},
|
|
777
|
-
onBlur: () => {
|
|
778
|
-
commitRecord(id, "headers");
|
|
779
|
-
}
|
|
780
|
-
})
|
|
781
|
-
})] })
|
|
782
|
-
]
|
|
783
|
-
}, id)),
|
|
758
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(McpSection, {
|
|
759
|
+
title: tt("config.odoo"),
|
|
760
|
+
row: config.connections.odoo,
|
|
761
|
+
secret: secrets.odoo,
|
|
762
|
+
onEnabled: (enabled) => {
|
|
763
|
+
patchConnection("odoo", { enabled });
|
|
764
|
+
},
|
|
765
|
+
onUrl: (url) => {
|
|
766
|
+
patchConnection("odoo", { url });
|
|
767
|
+
},
|
|
768
|
+
onSecret: (value) => {
|
|
769
|
+
setSecrets((prev) => ({
|
|
770
|
+
...prev,
|
|
771
|
+
odoo: value
|
|
772
|
+
}));
|
|
773
|
+
},
|
|
774
|
+
urlLabel: tt("config.odoo.url"),
|
|
775
|
+
secretLabel: tt("config.odoo.apiKey")
|
|
776
|
+
}),
|
|
777
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(McpSection, {
|
|
778
|
+
title: tt("config.nextcloud"),
|
|
779
|
+
row: config.connections.nextcloud,
|
|
780
|
+
secret: secrets.nextcloud,
|
|
781
|
+
onEnabled: (enabled) => {
|
|
782
|
+
patchConnection("nextcloud", { enabled });
|
|
783
|
+
},
|
|
784
|
+
onUrl: (url) => {
|
|
785
|
+
patchConnection("nextcloud", { url });
|
|
786
|
+
},
|
|
787
|
+
onUsername: (username) => {
|
|
788
|
+
patchConnection("nextcloud", { username });
|
|
789
|
+
},
|
|
790
|
+
onSecret: (value) => {
|
|
791
|
+
setSecrets((prev) => ({
|
|
792
|
+
...prev,
|
|
793
|
+
nextcloud: value
|
|
794
|
+
}));
|
|
795
|
+
},
|
|
796
|
+
urlLabel: tt("config.nextcloud.url"),
|
|
797
|
+
usernameLabel: tt("config.nextcloud.username"),
|
|
798
|
+
secretLabel: tt("config.nextcloud.appPassword")
|
|
799
|
+
}),
|
|
800
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(McpSection, {
|
|
801
|
+
title: tt("config.wecom"),
|
|
802
|
+
row: config.connections.wechat,
|
|
803
|
+
secret: secrets.wechat,
|
|
804
|
+
onEnabled: (enabled) => {
|
|
805
|
+
patchConnection("wechat", { enabled });
|
|
806
|
+
},
|
|
807
|
+
onSecret: (value) => {
|
|
808
|
+
setSecrets((prev) => ({
|
|
809
|
+
...prev,
|
|
810
|
+
wechat: value
|
|
811
|
+
}));
|
|
812
|
+
},
|
|
813
|
+
secretLabel: tt("config.wecom.webhook")
|
|
814
|
+
}),
|
|
815
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(McpSection, {
|
|
816
|
+
title: tt("config.ha"),
|
|
817
|
+
row: config.connections.homeassistant,
|
|
818
|
+
secret: secrets.homeassistant,
|
|
819
|
+
onEnabled: (enabled) => {
|
|
820
|
+
patchConnection("homeassistant", { enabled });
|
|
821
|
+
},
|
|
822
|
+
onUrl: (url) => {
|
|
823
|
+
patchConnection("homeassistant", { url });
|
|
824
|
+
},
|
|
825
|
+
onSecret: (value) => {
|
|
826
|
+
setSecrets((prev) => ({
|
|
827
|
+
...prev,
|
|
828
|
+
homeassistant: value
|
|
829
|
+
}));
|
|
830
|
+
},
|
|
831
|
+
urlLabel: tt("config.ha.url"),
|
|
832
|
+
secretLabel: tt("config.ha.token")
|
|
833
|
+
}),
|
|
784
834
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(Section, {
|
|
785
835
|
title: tt("config.billing"),
|
|
786
836
|
children: [
|
|
@@ -929,6 +979,10 @@ function StatusTab({ api }) {
|
|
|
929
979
|
children: tt("common.refresh")
|
|
930
980
|
})]
|
|
931
981
|
}),
|
|
982
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
983
|
+
className: panel_module_default.message,
|
|
984
|
+
children: tt("status.hint")
|
|
985
|
+
}),
|
|
932
986
|
error !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
933
987
|
className: panel_module_default.error,
|
|
934
988
|
children: error
|
package/lib/index.d.ts
CHANGED
|
@@ -1702,12 +1702,32 @@ interface RezMcpServerSpec {
|
|
|
1702
1702
|
/** Per-tool-call timeout in milliseconds. */
|
|
1703
1703
|
toolCallTimeoutMs?: number;
|
|
1704
1704
|
}
|
|
1705
|
+
/** Company MCP endpoints persisted under ~/.dsh/dsh-rez-suite.json. Secrets are not stored here. */
|
|
1706
|
+
interface RezConnections {
|
|
1707
|
+
odoo: {
|
|
1708
|
+
enabled: boolean;
|
|
1709
|
+
url: string;
|
|
1710
|
+
};
|
|
1711
|
+
nextcloud: {
|
|
1712
|
+
enabled: boolean;
|
|
1713
|
+
url: string;
|
|
1714
|
+
username: string;
|
|
1715
|
+
};
|
|
1716
|
+
wechat: {
|
|
1717
|
+
enabled: boolean;
|
|
1718
|
+
};
|
|
1719
|
+
homeassistant: {
|
|
1720
|
+
enabled: boolean;
|
|
1721
|
+
url: string;
|
|
1722
|
+
};
|
|
1723
|
+
}
|
|
1705
1724
|
/** Full plugin configuration persisted under ~/.dsh/dsh-rez-suite.json. */
|
|
1706
1725
|
interface RezConfig {
|
|
1707
1726
|
enabled: boolean;
|
|
1708
1727
|
announceToAgent: boolean;
|
|
1709
1728
|
role: RezRoleId;
|
|
1710
1729
|
servers: Record<string, RezMcpServerSpec>;
|
|
1730
|
+
connections: RezConnections;
|
|
1711
1731
|
billing: {
|
|
1712
1732
|
inputCostPer1k: number;
|
|
1713
1733
|
outputCostPer1k: number;
|