@rezti/dsh-rez-suite 0.1.26 → 0.1.33

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.
Files changed (39) hide show
  1. package/README.md +1 -1
  2. package/lib/client.d.ts +7 -0
  3. package/lib/client.js +388 -187
  4. package/lib/index.d.ts +4 -0
  5. package/lib/index.js +85 -7
  6. package/lib/style.css +47 -0
  7. package/package.json +7 -7
  8. package/src/boss/mount.ts +2 -0
  9. package/src/client/assets/rez-mark.png +0 -0
  10. package/src/client/brand-mark.ts +4 -0
  11. package/src/client/brand.module.css +51 -0
  12. package/src/client/brand.ts +135 -0
  13. package/src/client/index.ts +11 -0
  14. package/src/client/locales.ts +14 -0
  15. package/src/client/panel/AuditTab.tsx +20 -19
  16. package/src/client/panel/ConfigTab.tsx +57 -39
  17. package/src/client/panel/StatusTab.tsx +11 -10
  18. package/src/client/panel/WeixinTab.tsx +9 -8
  19. package/src/client/panel/helpers.ts +20 -5
  20. package/src/client/settings-card.tsx +48 -42
  21. package/src/client/upgrade-button.tsx +24 -12
  22. package/src/index.ts +11 -0
  23. package/src/observe-mcp.ts +5 -2
  24. package/src/presets.ts +1 -0
  25. package/src/protocol.ts +2 -0
  26. package/src/store.ts +6 -0
  27. package/src/tianyancha.ts +79 -0
  28. package/templates/boss/money/AGENTS.md +2 -0
  29. package/templates/boss/ops/AGENTS.md +2 -0
  30. package/templates/boss/product/AGENTS.md +4 -0
  31. package/templates/staff/finance/.agents/skills/staff-finance/SKILL.md +1 -1
  32. package/templates/staff/finance/AGENTS.md +6 -0
  33. package/templates/staff/finance/MEMORY.md +1 -1
  34. package/templates/staff/hr/.agents/skills/staff-hr/SKILL.md +1 -1
  35. package/templates/staff/hr/AGENTS.md +6 -0
  36. package/templates/staff/hr/MEMORY.md +1 -1
  37. package/templates/staff/legal/.agents/skills/staff-legal/SKILL.md +1 -1
  38. package/templates/staff/legal/AGENTS.md +10 -0
  39. package/templates/staff/legal/MEMORY.md +1 -1
@@ -1,11 +1,13 @@
1
1
  /**
2
2
  * Sidebar footer action: upgrade @rezti/dsh-rez-suite without a terminal.
3
3
  * Host code still needs a process respawn; the button does that after pnpm add.
4
+ *
5
+ * `t` is the official locale seat (zh/en follows 设置 → 语言).
4
6
  */
5
7
 
6
8
  import { useEffect, useMemo, useState } from 'react'
9
+ import type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots'
7
10
  import { RezApi } from './api.ts'
8
- import { tt } from './panel/helpers.ts'
9
11
  import css from './panel/panel.module.css'
10
12
  import type { RezUpdateStatus } from '../protocol.ts'
11
13
 
@@ -24,7 +26,11 @@ function UpgradeIcon() {
24
26
  )
25
27
  }
26
28
 
27
- async function waitUntilHostBack(api: RezApi, timeoutMs = 60_000): Promise<void> {
29
+ async function waitUntilHostBack(
30
+ api: RezApi,
31
+ timeoutMessage: string,
32
+ timeoutMs = 60_000,
33
+ ): Promise<void> {
28
34
  const deadline = Date.now() + timeoutMs
29
35
  await new Promise((resolve) => setTimeout(resolve, 800))
30
36
  while (Date.now() < deadline) {
@@ -35,10 +41,16 @@ async function waitUntilHostBack(api: RezApi, timeoutMs = 60_000): Promise<void>
35
41
  await new Promise((resolve) => setTimeout(resolve, 700))
36
42
  }
37
43
  }
38
- throw new Error(tt('upgrade.reloadTimeout'))
44
+ throw new Error(timeoutMessage)
39
45
  }
40
46
 
41
- export function UpgradeButton({ wide }: { wide: boolean }) {
47
+ export function UpgradeButton({
48
+ wide,
49
+ t,
50
+ }: {
51
+ wide: boolean
52
+ t: TranslateNS<'dsh-rez-suite'>
53
+ }) {
42
54
  const api = useMemo(() => new RezApi(), [])
43
55
  const [info, setInfo] = useState<RezUpdateStatus>()
44
56
  const [busy, setBusy] = useState(false)
@@ -55,10 +67,10 @@ export function UpgradeButton({ wide }: { wide: boolean }) {
55
67
  }, [api])
56
68
 
57
69
  const label = busy
58
- ? tt('upgrade.running')
70
+ ? t('upgrade.running')
59
71
  : info?.outdated === true
60
- ? tt('upgrade.label')
61
- : tt('upgrade.current')
72
+ ? t('upgrade.label')
73
+ : t('upgrade.current')
62
74
 
63
75
  const meta = note !== ''
64
76
  ? note
@@ -76,18 +88,18 @@ export function UpgradeButton({ wide }: { wide: boolean }) {
76
88
  const snapshot = info ?? await api.updateStatus()
77
89
  setInfo(snapshot)
78
90
  if (!snapshot.outdated) {
79
- setNote(tt('upgrade.already', { version: snapshot.installed }))
91
+ setNote(t('upgrade.already', { version: snapshot.installed }))
80
92
  return
81
93
  }
82
94
  const result = await api.applyUpdate()
83
95
  setInfo(result)
84
96
  if (result.restarting) {
85
- setNote(tt('upgrade.reloading'))
86
- await waitUntilHostBack(api)
97
+ setNote(t('upgrade.reloading'))
98
+ await waitUntilHostBack(api, t('upgrade.reloadTimeout'))
87
99
  window.location.reload()
88
100
  return
89
101
  }
90
- setNote(tt('upgrade.already', { version: result.installed }))
102
+ setNote(t('upgrade.already', { version: result.installed }))
91
103
  } catch (error) {
92
104
  setNote(error instanceof Error ? error.message : String(error))
93
105
  } finally {
@@ -101,7 +113,7 @@ export function UpgradeButton({ wide }: { wide: boolean }) {
101
113
  type="button"
102
114
  className={css.upgradeButton}
103
115
  data-outdated={info?.outdated === true ? '' : undefined}
104
- aria-label={tt('upgrade.aria')}
116
+ aria-label={t('upgrade.aria')}
105
117
  disabled={busy}
106
118
  onClick={() => { void onClick() }}
107
119
  >
package/src/index.ts CHANGED
@@ -29,6 +29,7 @@ import { rezConfigTool, rezStatusTool } from './tools.ts'
29
29
  import type { RezConfig } from './protocol.ts'
30
30
  import { workspaceGuidanceFor, mountRezWorkspaces } from './boss/mount.ts'
31
31
  import { liveSelfUpdate } from './self-update.ts'
32
+ import { mountTianyanchaMcp } from './tianyancha.ts'
32
33
 
33
34
  export const name = 'rez-suite'
34
35
 
@@ -79,6 +80,10 @@ export const Config: z<RezConfig> = z.object({
79
80
  enabled: z.boolean().default(true),
80
81
  siteUrl: z.string().default(REZ_DEFAULT_CONNECTIONS.gsc.siteUrl),
81
82
  }).default(REZ_DEFAULT_CONNECTIONS.gsc),
83
+ tianyancha: z.object({
84
+ enabled: z.boolean().default(true),
85
+ url: z.string().default(REZ_DEFAULT_CONNECTIONS.tianyancha.url),
86
+ }).default(REZ_DEFAULT_CONNECTIONS.tianyancha),
82
87
  }).default(REZ_DEFAULT_CONNECTIONS),
83
88
  billing: z.object({
84
89
  inputCostPer1k: z.number().default(0.001),
@@ -96,6 +101,8 @@ export const REZ_GUIDANCE_CORE = [
96
101
  '个人微信(QClaw/ClawBot):打开 设置 → 插件 → ReZ-TI → 微信 扫码,然后直接在微信里说话。消息进入网页左侧「微信」文件夹并延续同一会话,模型跟网页默认。网页归档了再从微信说话会自动恢复到侧栏。发「重启对话」会新开一条可见会话并把旧会话归档。网页端必须开着。不必再跑命令、也不要调用微信 MCP 工具。',
97
102
  '意图用 rez_set_intent(erp/files/chat/home/auto)。审计用 rez_audit。',
98
103
  '涉及资金、对外发送、设备控制、生产写入时先征得用户批准。',
104
+ 'Match the user language: Chinese or English. Do not force 中文 when they write English.',
105
+ '制度、手册、出差/报销标准、素材路径:打开 Nextcloud Documents/Standards/INDEX.yaml,按 code 取当前 effective_from 最新且未被 replace 的条目,再按相对 uri 打开。引用带路径+生效日。找不到就说「标准文件未归档」,不要用 MEMORY 旧数字。素材文件夹用首次创建标题,不用会变的 Odoo/销售名。',
99
106
  ].join('')
100
107
 
101
108
  export function rezGuidanceFor(role: RezConfig['role']): string {
@@ -128,6 +135,7 @@ function delegatedHost(ctx: Context, getConfig: () => RezConfig): McpHost {
128
135
  export function apply(ctx: Context, config?: RezConfig): void {
129
136
  let current: () => RezConfig = () => normalize(config)
130
137
  const syncWorkspaces = mountRezWorkspaces(ctx, () => current().role)
138
+ const syncTianyancha = mountTianyanchaMcp(ctx, () => current().role)
131
139
 
132
140
  const tokens = new TokenManager(joinTokenDb())
133
141
  const host = delegatedHost(ctx, () => current())
@@ -145,6 +153,7 @@ export function apply(ctx: Context, config?: RezConfig): void {
145
153
  saveConfig(value)
146
154
  current = () => value
147
155
  syncWorkspaces()
156
+ syncTianyancha()
148
157
  try {
149
158
  const settings = ctx.get('settings') as { update?: (namespace: unknown, value: unknown) => Promise<void> } | undefined
150
159
  if (settings?.update !== undefined) await settings.update(REZ_SETTINGS_NAMESPACE, value)
@@ -198,10 +207,12 @@ export function apply(ctx: Context, config?: RezConfig): void {
198
207
  current = source
199
208
  sync()
200
209
  syncWorkspaces()
210
+ syncTianyancha()
201
211
  },
202
212
  onChange: () => {
203
213
  sync()
204
214
  syncWorkspaces()
215
+ syncTianyancha()
205
216
  },
206
217
  })
207
218
 
@@ -9,7 +9,7 @@
9
9
  import { lastMcpStartError, REZ_CREDENTIAL_REFS, secretConfigured, type RezSystem } from '@rezti/dsh-rez-sso'
10
10
  import type { RezConfig, RezServerStatus, RezTestResult } from './protocol.ts'
11
11
 
12
- export const COMPOSED_SERVERS = ['odoo', 'nextcloud', 'wechat', 'homeassistant', 'tapd', 'gsc'] as const
12
+ export const COMPOSED_SERVERS = ['odoo', 'nextcloud', 'wechat', 'homeassistant', 'tapd', 'gsc', 'tianyancha'] as const
13
13
 
14
14
  export type ComposedServer = (typeof COMPOSED_SERVERS)[number]
15
15
 
@@ -102,7 +102,10 @@ export function observeServer(
102
102
  }
103
103
 
104
104
  export function observeComposedServers(input: ObserveInput): RezServerStatus[] {
105
- return COMPOSED_SERVERS.map(server => observeServer(server, input))
105
+ const servers = input.config.role === 'boss'
106
+ ? COMPOSED_SERVERS
107
+ : COMPOSED_SERVERS.filter((server) => server !== 'tianyancha')
108
+ return servers.map(server => observeServer(server, input))
106
109
  }
107
110
 
108
111
  export function testComposedServers(input: ObserveInput): RezTestResult[] {
package/src/presets.ts CHANGED
@@ -127,6 +127,7 @@ const COMPILED: Record<Exclude<RezRoleId, 'all' | 'boss'>, { server: RezServerId
127
127
 
128
128
  /** Whether one MCP tool may be registered for the selected role. */
129
129
  export function isToolAllowed(role: RezRoleId, server: string, rawName: string): boolean {
130
+ if (server === 'tianyancha') return role === 'boss'
130
131
  if (role === 'all' || role === 'boss') return true
131
132
  const rules = COMPILED[role]
132
133
  return rules.some(rule => rule.server === server && rule.test.test(rawName))
package/src/protocol.ts CHANGED
@@ -48,6 +48,7 @@ export interface RezConnections {
48
48
  homeassistant: { enabled: boolean; url: string }
49
49
  tapd: { enabled: boolean; workspaceId: string; nickName: string }
50
50
  gsc: { enabled: boolean; siteUrl: string }
51
+ tianyancha: { enabled: boolean; url: string }
51
52
  }
52
53
 
53
54
  export interface RezPublicConnection {
@@ -90,6 +91,7 @@ export interface RezPublicConfig {
90
91
  homeassistant: RezPublicConnection
91
92
  tapd: RezPublicConnection
92
93
  gsc: RezPublicConnection
94
+ tianyancha: RezPublicConnection
93
95
  }
94
96
  billing: { inputCostPer1k: number; outputCostPer1k: number; monthlyBudget: number }
95
97
  }
package/src/store.ts CHANGED
@@ -125,6 +125,12 @@ export function publicConfig(config: RezConfig): RezPublicConfig {
125
125
  secretConfigured: secretConfigured('gsc'),
126
126
  secretRef: REZ_CREDENTIAL_REFS.gsc,
127
127
  },
128
+ tianyancha: {
129
+ enabled: connections.tianyancha.enabled,
130
+ url: connections.tianyancha.url,
131
+ secretConfigured: secretConfigured('tianyancha'),
132
+ secretRef: REZ_CREDENTIAL_REFS.tianyancha,
133
+ },
128
134
  },
129
135
  billing: { ...config.billing },
130
136
  }
@@ -0,0 +1,79 @@
1
+ /**
2
+ * TianyanCha official MCP for the 法务助理 workspace.
3
+ * Reuse https://mcp.tianyancha.com/mcp via dsh-mcp-client. Do not spawn a
4
+ * local 162-tool catalog — tools/list only exposes a few agent entrypoints.
5
+ * Start the client only when suite role is boss so other identities never
6
+ * see mcp__tianyancha__* in the prompt.
7
+ */
8
+ import type { Context } from '@deepseek-ai/cordis'
9
+ import { loadRezConnections, startMcpWhenSecret } from '@rezti/dsh-rez-sso'
10
+ import type { RezRoleId } from './protocol.ts'
11
+
12
+ export const TIANYANCHA_MCP_URL = 'https://mcp.tianyancha.com/mcp'
13
+
14
+ export function shouldStartTianyancha(role: RezRoleId): boolean {
15
+ return role === 'boss'
16
+ }
17
+
18
+ export function bearerAuthorization(secret: string): string {
19
+ const trimmed = secret.trim()
20
+ if (/^bearer\s+/i.test(trimmed)) return 'Bearer ' + trimmed.replace(/^bearer\s+/i, '')
21
+ return 'Bearer ' + trimmed
22
+ }
23
+
24
+ export function tianyanchaMcpConfig(secret: string): Record<string, unknown> {
25
+ const { url } = loadRezConnections().tianyancha
26
+ return {
27
+ serverName: 'tianyancha',
28
+ transport: 'streamable-http',
29
+ url: url.length > 0 ? url : TIANYANCHA_MCP_URL,
30
+ headers: { Authorization: bearerAuthorization(secret) },
31
+ failOnStartupError: false,
32
+ }
33
+ }
34
+
35
+ /** Start when role is boss; dispose the mcp-client fiber when the identity leaves. */
36
+ export function mountTianyanchaMcp(
37
+ ctx: Context,
38
+ getRole: () => RezRoleId,
39
+ start: typeof startMcpWhenSecret = startMcpWhenSecret,
40
+ ): () => void {
41
+ let session: (() => void) | undefined
42
+ let pending = false
43
+
44
+ const ensure = (): void => {
45
+ void (async () => {
46
+ const want = shouldStartTianyancha(getRole())
47
+ if (!want) {
48
+ session?.()
49
+ session = undefined
50
+ return
51
+ }
52
+ if (session !== undefined || pending) return
53
+ pending = true
54
+ let raced = false
55
+ try {
56
+ const dispose = await start(ctx, {
57
+ system: 'tianyancha',
58
+ label: '天眼查',
59
+ config: tianyanchaMcpConfig,
60
+ })
61
+ if (!shouldStartTianyancha(getRole())) {
62
+ raced = true
63
+ dispose()
64
+ return
65
+ }
66
+ session = dispose
67
+ } catch (error: unknown) {
68
+ const why = error instanceof Error ? error.message : String(error)
69
+ console.error('[dsh-rez-suite] tianyancha MCP start failed:', why)
70
+ } finally {
71
+ pending = false
72
+ if (raced && shouldStartTianyancha(getRole()) && session === undefined) ensure()
73
+ }
74
+ })()
75
+ }
76
+
77
+ ensure()
78
+ return ensure
79
+ }
@@ -2,6 +2,8 @@
2
2
 
3
3
  你是雷泽智能老板的**搞钱简报官**,不是会计、不是销售、不是程序员。
4
4
 
5
+ 语言:用户用中文就中文,用英文就英文;结构不变。不要因为本文件是中文就强制中文。
6
+
5
7
  ## 每次回答(无 BOOTSTRAP.md 之后)
6
8
 
7
9
  严格四段,不要写成待办清单:
@@ -2,6 +2,8 @@
2
2
 
3
3
  你是雷泽智能老板的**运营简报官**。稳定 = 只报例外,不是把所有群消息喂进来。
4
4
 
5
+ 语言:用户用中文就中文,用英文就英文;结构不变。不要因为本文件是中文就强制中文。
6
+
5
7
  ## 每次回答(无 BOOTSTRAP.md 之后)
6
8
 
7
9
  严格四段:
@@ -2,6 +2,8 @@
2
2
 
3
3
  你是雷泽智能老板的**产品简报官**,不是固件工程师,不是项目经理堆 Story 的人。
4
4
 
5
+ 语言:用户用中文就中文,用英文就英文;结构不变。不要因为本文件是中文就强制中文。
6
+
5
7
  ## 每次回答(无 BOOTSTRAP.md 之后)
6
8
 
7
9
  严格四段:
@@ -37,4 +39,6 @@
37
39
 
38
40
  - 货好不好、该不该做:主销 SKU、退货/客诉、认证与交期、明确停做的事。
39
41
  - TAPD 只读阻塞和等老板拍板的;Odoo 只读退货/质量相关。
42
+ - 新产品或改产品 Wiki:Wiki **必须**同时写死 Nextcloud RAW 路径,以及 Git 3D 源路径 `products/{slug}/models` 与 `products/{slug}/motion`。缺任一项就说「Wiki 未归档」,不要猜路径。
43
+ - 问某产品素材在哪:打开 Nextcloud `Documents/Standards/INDEX.yaml`,再按相对 uri 读路径规则;加上该产品 Wiki **首次创建标题**,不要用会变的 Odoo `name` / 销售标题。
40
44
  - 禁止在这里写固件、开辅线、做 HA Add-on、做微信通道。那些走仓库和员工机。
@@ -3,4 +3,4 @@ name: staff-finance
3
3
  description: 财务助理。全员报销;审批/报表/过账仅当当前 Odoo 帐号能看见对应单据。不自审不自过账。
4
4
  ---
5
5
 
6
- 完整规矩在工作区 `AGENTS.md`。先 `mcp__odoo__get_current_context`。报销走 `hr.expense` / `hr.expense.sheet`。搞钱室不要在这里做。
6
+ 完整规矩在工作区 `AGENTS.md`。先 `mcp__odoo__get_current_context`。报销走 `hr.expense` / `hr.expense.sheet`。搞钱室不要在这里做。问制度/报销标准先打开 Nextcloud `Documents/Standards/INDEX.yaml`,再按相对 uri 读,不要把手册写入 MEMORY。用户用中文就中文、用英文就英文。
@@ -2,6 +2,8 @@
2
2
 
3
3
  你是雷泽智能的**财务助理**(报销是给所有人的入口)。同一套工作区全员能进。能看见哪张单、能不能提交/批准/过账,一律以**当前 Odoo 登录帐号**为准。Harness **只做选择**:起草、列待办、让人点选项;**不自审、不自过账、不编分录**。
4
4
 
5
+ 语言:用户用中文就中文,用英文就英文;结构不变。不要因为本文件是中文就强制中文。
6
+
5
7
  战略回款简报请去 **搞钱** 室。本室做单据流。
6
8
 
7
9
  ## 每次开场
@@ -52,6 +54,10 @@
52
54
 
53
55
  沉淀:默认公司、常用费用产品、是否要发票。禁止写密钥、完整卡号、未获批的付款指令。
54
56
 
57
+ ## 公司标准(Nextcloud INDEX)
58
+
59
+ 问制度、手册、报销/出差标准、素材路径:打开 Nextcloud `Documents/Standards/INDEX.yaml`,再按相对 uri 读。按 `code` 找当前 `effective_from` 最新且未被 replace 的条目。引用时带路径 + 生效日。找不到就说「标准文件未归档」,不要用 MEMORY 里的旧数字。禁止把手册全文写入 MEMORY。
60
+
55
61
  ## 范围与红线
56
62
 
57
63
  - 只用 `mcp__odoo__*`。费用模型已开放读写;工资单模型若列表里没有就不要编。
@@ -1,6 +1,6 @@
1
1
  # MEMORY.md · 财务助理(长期)
2
2
 
3
- 控制约 80 行。只留:默认公司、常用费用类型、金额确认习惯、红线。
3
+ 控制约 80 行。只留:默认公司、常用费用类型、金额确认习惯、红线。制度数字以 Nextcloud `Documents/Standards/INDEX.yaml` 为准,禁止把手册抄进本文件。
4
4
 
5
5
  ## 已归档优先级
6
6
 
@@ -3,4 +3,4 @@ name: staff-hr
3
3
  description: 人事助理。全员请假/查自己;主管批假;权限完全跟当前 Odoo 帐号。
4
4
  ---
5
5
 
6
- 完整规矩在工作区 `AGENTS.md`。先 `mcp__odoo__get_current_context`。有 `BOOTSTRAP.md` 时正事优先再三拍。
6
+ 完整规矩在工作区 `AGENTS.md`。先 `mcp__odoo__get_current_context`。有 `BOOTSTRAP.md` 时正事优先再三拍。问制度/出差标准先打开 Nextcloud `Documents/Standards/INDEX.yaml`,再按相对 uri 读,不要把手册写入 MEMORY。用户用中文就中文、用英文就英文。
@@ -2,6 +2,8 @@
2
2
 
3
3
  你是雷泽智能的**人事助理**。同一套工作区给所有人用。能看见、能提交、能审批,一律以**当前 Odoo 登录帐号**的权限组 / 记录规则 / 公司为准。Harness 只帮人选动作、填草稿、解释状态,**不代替 Odoo 审核**。
4
4
 
5
+ 语言:用户用中文就中文,用英文就英文;结构不变。不要因为本文件是中文就强制中文。
6
+
5
7
  ## 每次开场
6
8
 
7
9
  1. 调 `mcp__odoo__get_current_context`,记住用户、时区、当前公司、可切换公司。
@@ -36,6 +38,10 @@
36
38
 
37
39
  新的偏好、默认公司、常请假类型:追加 `memory/YYYY-MM-DD.md`,更新 `PRIORITIES.md`(最多 5 条)。禁止写密钥、完整身份证号、银行帐号。
38
40
 
41
+ ## 公司标准(Nextcloud INDEX)
42
+
43
+ 问制度、手册、出差标准、素材路径:打开 Nextcloud `Documents/Standards/INDEX.yaml`,再按相对 uri 读。按 `code` 找当前 `effective_from` 最新且未被 replace 的条目。引用时带路径 + 生效日。找不到就说「标准文件未归档」,不要用 MEMORY 里的旧数字。禁止把手册全文写入 MEMORY。
44
+
39
45
  ## 范围与红线
40
46
 
41
47
  - 走现成 `mcp__odoo__*`(`hr.leave`、`hr.leave.allocation`、`hr.employee` 等)。不自写人事系统。
@@ -1,6 +1,6 @@
1
1
  # MEMORY.md · 人事助理(长期)
2
2
 
3
- 控制约 80 行。只留:默认公司、常用假期类型、批假习惯、红线。
3
+ 控制约 80 行。只留:默认公司、常用假期类型、批假习惯、红线。制度数字以 Nextcloud `Documents/Standards/INDEX.yaml` 为准,禁止把手册抄进本文件。
4
4
 
5
5
  ## 已归档优先级
6
6
 
@@ -3,4 +3,4 @@ name: staff-legal
3
3
  description: 法务助理。全员可问制度、整理风险;能看哪些合同跟当前 Odoo/Nextcloud 帐号。不下具约束力的法律结论。
4
4
  ---
5
5
 
6
- 完整规矩在工作区 `AGENTS.md`。先 `mcp__odoo__get_current_context`。不是律师。
6
+ 完整规矩在工作区 `AGENTS.md`。先 `mcp__odoo__get_current_context`。不是律师。问制度先打开 Nextcloud `Documents/Standards/INDEX.yaml`,再按相对 uri 读,不要把手册写入 MEMORY。有 `mcp__tianyancha__*` 才查工商(仅老板身份会挂上)。用户用中文就中文、用英文就英文。
@@ -2,6 +2,8 @@
2
2
 
3
3
  你是雷泽智能的**法务助理**。同一套工作区全员能进。能看哪些合同、客户、附件,以**当前 Odoo / Nextcloud 帐号**为准。Harness 只整理风险点、列选项、帮你找到原文;**不是律师,不下具有约束力的法律结论**。
4
4
 
5
+ 语言:用户用中文就中文,用英文就英文;结构不变。不要因为本文件是中文就强制中文。
6
+
5
7
  ## 每次开场
6
8
 
7
9
  1. `mcp__odoo__get_current_context`
@@ -19,6 +21,10 @@
19
21
 
20
22
  没有独立的法务 App 时,不要假装有「案件模块」。用订单、伙伴、Nextcloud 文档凑齐材料即可。
21
23
 
24
+ ## 天眼查(仅老板身份)
25
+
26
+ 出现 `mcp__tianyancha__*` 时,才用来查对方公司工商/司法。官方 `tools/list` 只有搜索、公司画像、`call_tool` 等入口,不要枚举 162 个工具。没有这些工具就当没开通,不要提天眼查。
27
+
22
28
  ## 每次回答
23
29
 
24
30
  1. **结论**(风险高/中/低或「缺材料」)
@@ -28,6 +34,10 @@
28
34
 
29
35
  禁止:编造法条、承诺「这样一定合法」、自动对外发函、自动盖章。
30
36
 
37
+ ## 公司标准(Nextcloud INDEX)
38
+
39
+ 问制度、手册、合同模板、素材路径:打开 Nextcloud `Documents/Standards/INDEX.yaml`,再按相对 uri 读。按 `code` 找当前 `effective_from` 最新且未被 replace 的条目。引用时带路径 + 生效日。找不到就说「标准文件未归档」,不要用 MEMORY 里的旧数字。禁止把手册全文写入 MEMORY。合同卷宗仍以当前帐号能读的 Odoo / Nextcloud 原文为准。
40
+
31
41
  ## 初始化
32
42
 
33
43
  有 `BOOTSTRAP.md`:正事优先。三拍后删除该文件,不得重建。
@@ -1,6 +1,6 @@
1
1
  # MEMORY.md · 法务助理(长期)
2
2
 
3
- 控制约 80 行。只留:默认公司、必须真人看的条款类型、金额阈值。不贴合同全文。
3
+ 控制约 80 行。只留:默认公司、必须真人看的条款类型、金额阈值。不贴合同全文。制度数字以 Nextcloud `Documents/Standards/INDEX.yaml` 为准,禁止把手册抄进本文件。
4
4
 
5
5
  ## 已归档优先级
6
6