@rezti/dsh-rez-suite 0.1.18 → 0.1.19
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/lib/index.d.ts +3 -2
- package/lib/index.js +69 -18
- package/package.json +4 -4
- package/src/boss/mount.ts +46 -13
- package/src/boss/register.ts +38 -2
- package/src/index.ts +14 -6
package/README.md
CHANGED
|
@@ -12,4 +12,4 @@ dsh plugin --profile web update @rezti/dsh-rez-suite
|
|
|
12
12
|
|
|
13
13
|
包名是 `@rezti/dsh-rez-suite`,不是 `dsh-rezti-suite`。不要对同一 profile 再单独 add 子包,会重复注册。
|
|
14
14
|
|
|
15
|
-
拆分包(`dsh-rez-odoo` 等)给开发改代码用。Web
|
|
15
|
+
拆分包(`dsh-rez-odoo` 等)给开发改代码用。Web 面板(含微信扫码)暂时仍在本包。设置里角色选「老板」后,才会在侧栏登记搞钱 / 产品 / 运营;切走老板会拿掉这三间(文件夹保留)。**不要**再装 `@rezti/dsh-rez-boss-desk`。
|
package/lib/index.d.ts
CHANGED
|
@@ -1741,7 +1741,8 @@ declare const name = "rez-suite";
|
|
|
1741
1741
|
declare const inject: string[];
|
|
1742
1742
|
declare const REZ_SETTINGS_NAMESPACE: SettingsNamespace;
|
|
1743
1743
|
declare const Config: Schema<RezConfig>;
|
|
1744
|
-
declare const
|
|
1744
|
+
declare const REZ_GUIDANCE_CORE: string;
|
|
1745
|
+
declare function rezGuidanceFor(role: RezConfig['role']): string;
|
|
1745
1746
|
declare function apply(ctx: Context, config?: RezConfig): void;
|
|
1746
1747
|
//#endregion
|
|
1747
|
-
export { Config,
|
|
1748
|
+
export { Config, REZ_GUIDANCE_CORE, REZ_SETTINGS_NAMESPACE, apply, inject, name, rezGuidanceFor };
|
package/lib/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { createRequire } from "node:module";
|
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { dirname, join, relative } from "node:path";
|
|
4
4
|
import { REZ_CREDENTIAL_REFS, REZ_DEFAULT_CONNECTIONS, REZ_SYSTEMS, lastMcpStartError, mergeConnections, secretConfigured, writeManagedCredential } from "@rezti/dsh-rez-sso";
|
|
5
|
-
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, statSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { DatabaseSync } from "node:sqlite";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
//#region ../../node_modules/.pnpm/@deepseek-ai+cosmokit@1.8.2/node_modules/@deepseek-ai/cosmokit/lib/index.js
|
|
@@ -7667,9 +7667,32 @@ function rezConfigTool(config) {
|
|
|
7667
7667
|
}
|
|
7668
7668
|
//#endregion
|
|
7669
7669
|
//#region src/boss/register.ts
|
|
7670
|
+
/**
|
|
7671
|
+
* Register or drop the three boss rooms in the official workspace sidebar.
|
|
7672
|
+
* `workspaceRegistry.create` is idempotent: same canonical path returns the
|
|
7673
|
+
* existing record. New records are prepended, so we register in reverse to
|
|
7674
|
+
* keep 搞钱 → 产品 → 运营 at the top of the sidebar.
|
|
7675
|
+
* `delete` only drops the registry row — directories and session logs stay.
|
|
7676
|
+
*/
|
|
7677
|
+
function canon(path) {
|
|
7678
|
+
try {
|
|
7679
|
+
return realpathSync(path);
|
|
7680
|
+
} catch {
|
|
7681
|
+
return path;
|
|
7682
|
+
}
|
|
7683
|
+
}
|
|
7684
|
+
function isRegisteredBossRoom(workspace, rooms) {
|
|
7685
|
+
return new Set(rooms.map((room) => canon(room.path))).has(canon(workspace.path));
|
|
7686
|
+
}
|
|
7670
7687
|
async function registerBossWorkspaces(registry, rooms) {
|
|
7671
7688
|
for (const room of [...rooms].reverse()) await registry.create(room.path, room.folder);
|
|
7672
7689
|
}
|
|
7690
|
+
async function unregisterBossWorkspaces(registry, rooms) {
|
|
7691
|
+
for (const workspace of registry.list()) {
|
|
7692
|
+
if (!isRegisteredBossRoom(workspace, rooms)) continue;
|
|
7693
|
+
await registry.delete(workspace.id);
|
|
7694
|
+
}
|
|
7695
|
+
}
|
|
7673
7696
|
//#endregion
|
|
7674
7697
|
//#region src/boss/seed.ts
|
|
7675
7698
|
const BOSS_ROOMS = [
|
|
@@ -7766,26 +7789,47 @@ function listFiles(root) {
|
|
|
7766
7789
|
}
|
|
7767
7790
|
//#endregion
|
|
7768
7791
|
//#region src/boss/mount.ts
|
|
7792
|
+
const BOSS_ROLE_HINT = "设置 → 插件 → ReZ-TI → 角色选「老板」后,左侧会出现搞钱 / 产品 / 运营三室。不必手动「添加工作区」。";
|
|
7769
7793
|
const BOSS_GUIDANCE = [
|
|
7770
|
-
"
|
|
7771
|
-
"
|
|
7794
|
+
"当前角色是老板。侧栏已登记三室:~/.dsh/workspaces/搞钱、产品、运营。不必手动「添加工作区」。",
|
|
7795
|
+
"每个文件夹是独立作战室,官方 dsh 会注入该目录 AGENTS.md。",
|
|
7772
7796
|
"若该室仍有 BOOTSTRAP.md:本会话先做短问三拍,沉淀到 PRIORITIES.md / MEMORY.md,然后删除 BOOTSTRAP.md。",
|
|
7773
7797
|
"已初始化后:读 PRIORITIES.md + MEMORY.md + 今日/昨日 memory/;回答固定四行:结论 → 数字(哪家公司、哪段时间)→ 拍板 1~3 件事 → 未执行任何过账/付款/对外发送。",
|
|
7774
7798
|
"微信文件夹仍是收件箱,不要在那边查账或砍 SKU。"
|
|
7775
7799
|
].join("");
|
|
7800
|
+
function bossGuidanceFor(role) {
|
|
7801
|
+
return role === "boss" ? BOSS_GUIDANCE : BOSS_ROLE_HINT;
|
|
7802
|
+
}
|
|
7776
7803
|
function destRoot(env = process.env) {
|
|
7777
7804
|
if (env.REZ_BOSS_WORKSPACES !== void 0 && env.REZ_BOSS_WORKSPACES !== "") return env.REZ_BOSS_WORKSPACES;
|
|
7778
7805
|
return join(env.DSH_HOME !== void 0 && env.DSH_HOME !== "" ? env.DSH_HOME : join(homedir(), ".dsh"), "workspaces");
|
|
7779
7806
|
}
|
|
7780
|
-
|
|
7781
|
-
|
|
7782
|
-
|
|
7783
|
-
|
|
7784
|
-
|
|
7785
|
-
|
|
7786
|
-
|
|
7807
|
+
function expectedBossRooms(env = process.env) {
|
|
7808
|
+
const root = destRoot(env);
|
|
7809
|
+
return BOSS_ROOMS.map((room) => ({
|
|
7810
|
+
path: join(root, room.folder),
|
|
7811
|
+
folder: room.folder
|
|
7812
|
+
}));
|
|
7813
|
+
}
|
|
7814
|
+
async function syncBossWorkspaces(registry, role, env = process.env) {
|
|
7815
|
+
if (role === "boss") {
|
|
7816
|
+
await registerBossWorkspaces(registry, seedBossWorkspaces({ destRoot: destRoot(env) }).rooms);
|
|
7817
|
+
return;
|
|
7818
|
+
}
|
|
7819
|
+
await unregisterBossWorkspaces(registry, expectedBossRooms(env));
|
|
7820
|
+
}
|
|
7821
|
+
/** Seed/register 三室 only for role=boss; drop sidebar rows otherwise. Returns a re-sync function. */
|
|
7822
|
+
function mountBossDesk(ctx, getRole) {
|
|
7823
|
+
const run = () => {
|
|
7824
|
+
ctx.inject(["workspaceRegistry"], (inner) => {
|
|
7825
|
+
syncBossWorkspaces(inner.get("workspaceRegistry"), getRole()).catch((error) => {
|
|
7826
|
+
const why = error instanceof Error ? error.message : String(error);
|
|
7827
|
+
console.error("[dsh-rez-suite] boss workspace sync failed:", why);
|
|
7828
|
+
});
|
|
7787
7829
|
});
|
|
7788
|
-
}
|
|
7830
|
+
};
|
|
7831
|
+
run();
|
|
7832
|
+
return run;
|
|
7789
7833
|
}
|
|
7790
7834
|
//#endregion
|
|
7791
7835
|
//#region src/index.ts
|
|
@@ -7845,15 +7889,17 @@ const Config = Schema.object({
|
|
|
7845
7889
|
})
|
|
7846
7890
|
});
|
|
7847
7891
|
const SECTION_ORDER = 150;
|
|
7848
|
-
const
|
|
7892
|
+
const REZ_GUIDANCE_CORE = [
|
|
7849
7893
|
"本机已安装 ReZ-TI 拆分包:工作身份由 dsh-rez-sso 提供,MCP 由官方 dsh-mcp-client 接入 Odoo / Nextcloud / 企业微信 / Home Assistant。",
|
|
7850
7894
|
"工具名 mcp__odoo__*、mcp__nextcloud__*、mcp__wechat__*、mcp__homeassistant__*。",
|
|
7851
7895
|
"密钥:REZ_ODOO_TOKEN、REZ_NEXTCLOUD_PASSWORD、REZ_WECHAT_WEBHOOK、REZ_HA_TOKEN。",
|
|
7852
7896
|
"个人微信(QClaw/ClawBot):打开 设置 → 插件 → ReZ-TI → 微信 扫码,然后直接在微信里说话。消息进入网页左侧「微信」文件夹并延续同一会话,模型跟网页默认。网页归档了再从微信说话会自动恢复到侧栏。发「重启对话」会新开一条可见会话并把旧会话归档。网页端必须开着。不必再跑命令、也不要调用微信 MCP 工具。",
|
|
7853
7897
|
"意图用 rez_set_intent(erp/files/chat/home/auto)。审计用 rez_audit。",
|
|
7854
|
-
"涉及资金、对外发送、设备控制、生产写入时先征得用户批准。"
|
|
7855
|
-
BOSS_GUIDANCE
|
|
7898
|
+
"涉及资金、对外发送、设备控制、生产写入时先征得用户批准。"
|
|
7856
7899
|
].join("");
|
|
7900
|
+
function rezGuidanceFor(role) {
|
|
7901
|
+
return REZ_GUIDANCE_CORE + bossGuidanceFor(role);
|
|
7902
|
+
}
|
|
7857
7903
|
function normalize(input) {
|
|
7858
7904
|
return mergeConfig(defaultConfig(), input ?? {});
|
|
7859
7905
|
}
|
|
@@ -7873,8 +7919,8 @@ function delegatedHost(ctx, getConfig) {
|
|
|
7873
7919
|
};
|
|
7874
7920
|
}
|
|
7875
7921
|
function apply(ctx, config) {
|
|
7876
|
-
mountBossDesk(ctx);
|
|
7877
7922
|
let current = () => normalize(config);
|
|
7923
|
+
const syncBossDesk = mountBossDesk(ctx, () => current().role);
|
|
7878
7924
|
const tokens = new TokenManager(joinTokenDb());
|
|
7879
7925
|
const host = delegatedHost(ctx, () => current());
|
|
7880
7926
|
ctx.effect(() => () => {
|
|
@@ -7887,6 +7933,7 @@ function apply(ctx, config) {
|
|
|
7887
7933
|
const value = normalize(next);
|
|
7888
7934
|
saveConfig(value);
|
|
7889
7935
|
current = () => value;
|
|
7936
|
+
syncBossDesk();
|
|
7890
7937
|
try {
|
|
7891
7938
|
const settings = ctx.get("settings");
|
|
7892
7939
|
if (settings?.update !== void 0) await settings.update(REZ_SETTINGS_NAMESPACE, value);
|
|
@@ -7923,7 +7970,7 @@ function apply(ctx, config) {
|
|
|
7923
7970
|
if (value.announceToAgent) disposeSection = ctx.systemPrompt.section({
|
|
7924
7971
|
name: "plugin:dsh-rez-suite",
|
|
7925
7972
|
order: SECTION_ORDER,
|
|
7926
|
-
text:
|
|
7973
|
+
text: rezGuidanceFor(value.role)
|
|
7927
7974
|
});
|
|
7928
7975
|
disposeRoutes = ctx.effect(() => {
|
|
7929
7976
|
const disposers = routes.map((route) => ctx.webServer.register(route));
|
|
@@ -7942,8 +7989,12 @@ function apply(ctx, config) {
|
|
|
7942
7989
|
setSource: (source) => {
|
|
7943
7990
|
current = source;
|
|
7944
7991
|
sync();
|
|
7992
|
+
syncBossDesk();
|
|
7945
7993
|
},
|
|
7946
|
-
onChange:
|
|
7994
|
+
onChange: () => {
|
|
7995
|
+
sync();
|
|
7996
|
+
syncBossDesk();
|
|
7997
|
+
}
|
|
7947
7998
|
});
|
|
7948
7999
|
sync();
|
|
7949
8000
|
}
|
|
@@ -7951,4 +8002,4 @@ function joinTokenDb() {
|
|
|
7951
8002
|
return join(homedir(), ".dsh", "dsh-rez-token-manager.sqlite");
|
|
7952
8003
|
}
|
|
7953
8004
|
//#endregion
|
|
7954
|
-
export { Config,
|
|
8005
|
+
export { Config, REZ_GUIDANCE_CORE, REZ_SETTINGS_NAMESPACE, apply, inject, name, rezGuidanceFor };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rezti/dsh-rez-suite",
|
|
3
3
|
"description": "ReZ-TI one-package install for DeepSeek Harness. Update with: dsh plugin --profile web update @rezti/dsh-rez-suite",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.19",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
7
7
|
"node": "^22.19.0 || >=24.0.0"
|
|
@@ -39,12 +39,12 @@
|
|
|
39
39
|
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
40
40
|
"zod": "^4.4.3",
|
|
41
41
|
"@rezti/dsh-rez-ha-bridge": "0.1.7",
|
|
42
|
+
"@rezti/dsh-rez-odoo": "0.1.7",
|
|
42
43
|
"@rezti/dsh-rez-intent": "0.1.4",
|
|
43
44
|
"@rezti/dsh-rez-nextcloud": "0.1.7",
|
|
44
|
-
"@rezti/dsh-rez-
|
|
45
|
+
"@rezti/dsh-rez-sso": "0.1.7",
|
|
45
46
|
"@rezti/dsh-rez-wechat": "0.1.11",
|
|
46
|
-
"@rezti/dsh-rez-
|
|
47
|
-
"@rezti/dsh-rez-sso": "0.1.7"
|
|
47
|
+
"@rezti/dsh-rez-token-manager": "0.1.4"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"react": "^18.2.0",
|
package/src/boss/mount.ts
CHANGED
|
@@ -1,31 +1,64 @@
|
|
|
1
1
|
import { homedir } from 'node:os'
|
|
2
2
|
import { join } from 'node:path'
|
|
3
3
|
import type { Context } from '@deepseek-ai/cordis'
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import type { RezRoleId } from '../protocol.ts'
|
|
5
|
+
import {
|
|
6
|
+
registerBossWorkspaces,
|
|
7
|
+
unregisterBossWorkspaces,
|
|
8
|
+
type BossRoomRef,
|
|
9
|
+
type WorkspaceRegistrar,
|
|
10
|
+
} from './register.ts'
|
|
11
|
+
import { BOSS_ROOMS, seedBossWorkspaces } from './seed.ts'
|
|
12
|
+
|
|
13
|
+
export const BOSS_ROLE_HINT = '设置 → 插件 → ReZ-TI → 角色选「老板」后,左侧会出现搞钱 / 产品 / 运营三室。不必手动「添加工作区」。'
|
|
6
14
|
|
|
7
15
|
export const BOSS_GUIDANCE = [
|
|
8
|
-
'
|
|
9
|
-
'
|
|
16
|
+
'当前角色是老板。侧栏已登记三室:~/.dsh/workspaces/搞钱、产品、运营。不必手动「添加工作区」。',
|
|
17
|
+
'每个文件夹是独立作战室,官方 dsh 会注入该目录 AGENTS.md。',
|
|
10
18
|
'若该室仍有 BOOTSTRAP.md:本会话先做短问三拍,沉淀到 PRIORITIES.md / MEMORY.md,然后删除 BOOTSTRAP.md。',
|
|
11
19
|
'已初始化后:读 PRIORITIES.md + MEMORY.md + 今日/昨日 memory/;回答固定四行:结论 → 数字(哪家公司、哪段时间)→ 拍板 1~3 件事 → 未执行任何过账/付款/对外发送。',
|
|
12
20
|
'微信文件夹仍是收件箱,不要在那边查账或砍 SKU。',
|
|
13
21
|
].join('')
|
|
14
22
|
|
|
23
|
+
export function bossGuidanceFor(role: RezRoleId): string {
|
|
24
|
+
return role === 'boss' ? BOSS_GUIDANCE : BOSS_ROLE_HINT
|
|
25
|
+
}
|
|
26
|
+
|
|
15
27
|
function destRoot(env: NodeJS.ProcessEnv = process.env): string {
|
|
16
28
|
if (env.REZ_BOSS_WORKSPACES !== undefined && env.REZ_BOSS_WORKSPACES !== '') return env.REZ_BOSS_WORKSPACES
|
|
17
29
|
const home = env.DSH_HOME !== undefined && env.DSH_HOME !== '' ? env.DSH_HOME : join(homedir(), '.dsh')
|
|
18
30
|
return join(home, 'workspaces')
|
|
19
31
|
}
|
|
20
32
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
33
|
+
export function expectedBossRooms(env: NodeJS.ProcessEnv = process.env): BossRoomRef[] {
|
|
34
|
+
const root = destRoot(env)
|
|
35
|
+
return BOSS_ROOMS.map((room) => ({ path: join(root, room.folder), folder: room.folder }))
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export async function syncBossWorkspaces(
|
|
39
|
+
registry: WorkspaceRegistrar,
|
|
40
|
+
role: RezRoleId,
|
|
41
|
+
env: NodeJS.ProcessEnv = process.env,
|
|
42
|
+
): Promise<void> {
|
|
43
|
+
if (role === 'boss') {
|
|
44
|
+
const seeded = seedBossWorkspaces({ destRoot: destRoot(env) })
|
|
45
|
+
await registerBossWorkspaces(registry, seeded.rooms)
|
|
46
|
+
return
|
|
47
|
+
}
|
|
48
|
+
await unregisterBossWorkspaces(registry, expectedBossRooms(env))
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Seed/register 三室 only for role=boss; drop sidebar rows otherwise. Returns a re-sync function. */
|
|
52
|
+
export function mountBossDesk(ctx: Context, getRole: () => RezRoleId): () => void {
|
|
53
|
+
const run = (): void => {
|
|
54
|
+
ctx.inject(['workspaceRegistry'], (inner) => {
|
|
55
|
+
const registry = inner.get('workspaceRegistry') as WorkspaceRegistrar
|
|
56
|
+
void syncBossWorkspaces(registry, getRole()).catch((error: unknown) => {
|
|
57
|
+
const why = error instanceof Error ? error.message : String(error)
|
|
58
|
+
console.error('[dsh-rez-suite] boss workspace sync failed:', why)
|
|
59
|
+
})
|
|
29
60
|
})
|
|
30
|
-
}
|
|
61
|
+
}
|
|
62
|
+
run()
|
|
63
|
+
return run
|
|
31
64
|
}
|
package/src/boss/register.ts
CHANGED
|
@@ -1,18 +1,54 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Register
|
|
2
|
+
* Register or drop the three boss rooms in the official workspace sidebar.
|
|
3
3
|
* `workspaceRegistry.create` is idempotent: same canonical path returns the
|
|
4
4
|
* existing record. New records are prepended, so we register in reverse to
|
|
5
5
|
* keep 搞钱 → 产品 → 运营 at the top of the sidebar.
|
|
6
|
+
* `delete` only drops the registry row — directories and session logs stay.
|
|
6
7
|
*/
|
|
8
|
+
import { realpathSync } from 'node:fs'
|
|
9
|
+
|
|
10
|
+
export interface WorkspaceRecord {
|
|
11
|
+
id: string
|
|
12
|
+
path: string
|
|
13
|
+
title: string
|
|
14
|
+
}
|
|
15
|
+
|
|
7
16
|
export interface WorkspaceRegistrar {
|
|
8
17
|
create(path: string, title?: string): Promise<unknown>
|
|
18
|
+
list(): WorkspaceRecord[]
|
|
19
|
+
delete(id: string): Promise<boolean>
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type BossRoomRef = { path: string; folder: string }
|
|
23
|
+
|
|
24
|
+
function canon(path: string): string {
|
|
25
|
+
try {
|
|
26
|
+
return realpathSync(path)
|
|
27
|
+
} catch {
|
|
28
|
+
return path
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function isRegisteredBossRoom(workspace: WorkspaceRecord, rooms: ReadonlyArray<BossRoomRef>): boolean {
|
|
33
|
+
const wanted = new Set(rooms.map((room) => canon(room.path)))
|
|
34
|
+
return wanted.has(canon(workspace.path))
|
|
9
35
|
}
|
|
10
36
|
|
|
11
37
|
export async function registerBossWorkspaces(
|
|
12
38
|
registry: WorkspaceRegistrar,
|
|
13
|
-
rooms: ReadonlyArray<
|
|
39
|
+
rooms: ReadonlyArray<BossRoomRef>,
|
|
14
40
|
): Promise<void> {
|
|
15
41
|
for (const room of [...rooms].reverse()) {
|
|
16
42
|
await registry.create(room.path, room.folder)
|
|
17
43
|
}
|
|
18
44
|
}
|
|
45
|
+
|
|
46
|
+
export async function unregisterBossWorkspaces(
|
|
47
|
+
registry: WorkspaceRegistrar,
|
|
48
|
+
rooms: ReadonlyArray<BossRoomRef>,
|
|
49
|
+
): Promise<void> {
|
|
50
|
+
for (const workspace of registry.list()) {
|
|
51
|
+
if (!isRegisteredBossRoom(workspace, rooms)) continue
|
|
52
|
+
await registry.delete(workspace.id)
|
|
53
|
+
}
|
|
54
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -27,7 +27,7 @@ import { defaultConfig, mergeConfig, saveConfig } from './store.ts'
|
|
|
27
27
|
import { TokenManager } from './token-manager.ts'
|
|
28
28
|
import { rezConfigTool, rezStatusTool } from './tools.ts'
|
|
29
29
|
import type { RezConfig } from './protocol.ts'
|
|
30
|
-
import {
|
|
30
|
+
import { bossGuidanceFor, mountBossDesk } from './boss/mount.ts'
|
|
31
31
|
|
|
32
32
|
export const name = 'rez-suite'
|
|
33
33
|
|
|
@@ -79,16 +79,19 @@ export const Config: z<RezConfig> = z.object({
|
|
|
79
79
|
|
|
80
80
|
const SECTION_ORDER = 150
|
|
81
81
|
|
|
82
|
-
export const
|
|
82
|
+
export const REZ_GUIDANCE_CORE = [
|
|
83
83
|
'本机已安装 ReZ-TI 拆分包:工作身份由 dsh-rez-sso 提供,MCP 由官方 dsh-mcp-client 接入 Odoo / Nextcloud / 企业微信 / Home Assistant。',
|
|
84
84
|
'工具名 mcp__odoo__*、mcp__nextcloud__*、mcp__wechat__*、mcp__homeassistant__*。',
|
|
85
85
|
'密钥:REZ_ODOO_TOKEN、REZ_NEXTCLOUD_PASSWORD、REZ_WECHAT_WEBHOOK、REZ_HA_TOKEN。',
|
|
86
86
|
'个人微信(QClaw/ClawBot):打开 设置 → 插件 → ReZ-TI → 微信 扫码,然后直接在微信里说话。消息进入网页左侧「微信」文件夹并延续同一会话,模型跟网页默认。网页归档了再从微信说话会自动恢复到侧栏。发「重启对话」会新开一条可见会话并把旧会话归档。网页端必须开着。不必再跑命令、也不要调用微信 MCP 工具。',
|
|
87
87
|
'意图用 rez_set_intent(erp/files/chat/home/auto)。审计用 rez_audit。',
|
|
88
88
|
'涉及资金、对外发送、设备控制、生产写入时先征得用户批准。',
|
|
89
|
-
BOSS_GUIDANCE,
|
|
90
89
|
].join('')
|
|
91
90
|
|
|
91
|
+
export function rezGuidanceFor(role: RezConfig['role']): string {
|
|
92
|
+
return REZ_GUIDANCE_CORE + bossGuidanceFor(role)
|
|
93
|
+
}
|
|
94
|
+
|
|
92
95
|
function normalize(input: Partial<RezConfig> | undefined): RezConfig {
|
|
93
96
|
return mergeConfig(defaultConfig(), input ?? {})
|
|
94
97
|
}
|
|
@@ -110,8 +113,8 @@ function delegatedHost(ctx: Context, getConfig: () => RezConfig): McpHost {
|
|
|
110
113
|
}
|
|
111
114
|
|
|
112
115
|
export function apply(ctx: Context, config?: RezConfig): void {
|
|
113
|
-
mountBossDesk(ctx)
|
|
114
116
|
let current: () => RezConfig = () => normalize(config)
|
|
117
|
+
const syncBossDesk = mountBossDesk(ctx, () => current().role)
|
|
115
118
|
|
|
116
119
|
const tokens = new TokenManager(joinTokenDb())
|
|
117
120
|
const host = delegatedHost(ctx, () => current())
|
|
@@ -128,6 +131,7 @@ export function apply(ctx: Context, config?: RezConfig): void {
|
|
|
128
131
|
const value = normalize(next as Partial<RezConfig>)
|
|
129
132
|
saveConfig(value)
|
|
130
133
|
current = () => value
|
|
134
|
+
syncBossDesk()
|
|
131
135
|
try {
|
|
132
136
|
const settings = ctx.get('settings') as { update?: (namespace: unknown, value: unknown) => Promise<void> } | undefined
|
|
133
137
|
if (settings?.update !== undefined) await settings.update(REZ_SETTINGS_NAMESPACE, value)
|
|
@@ -160,7 +164,7 @@ export function apply(ctx: Context, config?: RezConfig): void {
|
|
|
160
164
|
disposeSection = ctx.systemPrompt.section({
|
|
161
165
|
name: 'plugin:dsh-rez-suite',
|
|
162
166
|
order: SECTION_ORDER,
|
|
163
|
-
text:
|
|
167
|
+
text: rezGuidanceFor(value.role),
|
|
164
168
|
})
|
|
165
169
|
}
|
|
166
170
|
|
|
@@ -179,8 +183,12 @@ export function apply(ctx: Context, config?: RezConfig): void {
|
|
|
179
183
|
setSource: (source) => {
|
|
180
184
|
current = source
|
|
181
185
|
sync()
|
|
186
|
+
syncBossDesk()
|
|
187
|
+
},
|
|
188
|
+
onChange: () => {
|
|
189
|
+
sync()
|
|
190
|
+
syncBossDesk()
|
|
182
191
|
},
|
|
183
|
-
onChange: sync,
|
|
184
192
|
})
|
|
185
193
|
|
|
186
194
|
sync()
|