@whyshu/argent-erp 0.2.3 → 0.3.0

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 (3) hide show
  1. package/README.md +32 -21
  2. package/dist/client.js +54 -12
  3. package/package.json +2 -2
package/README.md CHANGED
@@ -1,9 +1,9 @@
1
- # @whyshu/argent-erp(v0.2.0)
1
+ # @whyshu/argent-erp(v0.3.0)
2
2
 
3
3
  **两件东西,一个货**:
4
4
 
5
- 1. **DSH 会话视图插件**:会话顶部 Chat / 轨迹 旁加一个「ERP」tab,把 Argent ERP 的
6
- 办公室现场 / 待办 / 时间线 / 货件 / 聊一聊入口渲染进 dsh,看 ERP 不用离开当前会话;
5
+ 1. **左侧栏 ERP 入口 + 主视图面板**:侧栏多一个「ERP」图标,点一下主视图(会话区)整页切到 ERP——
6
+ 办公室现场 / 待办 / 时间线 / 货件 / 聊一聊;点会话行或面板里的「← 会话」即可回到对话;
7
7
  2. **「六禾园办公室助理」preset**:让「和办公室聊一聊」变成一个**真正的 dsh 会话**
8
8
  (原生 Chat,含轨迹/统计/中断),但**边界写死在 preset 里**——只聊办公室、只读 ERP、无本机能力。
9
9
 
@@ -18,31 +18,40 @@ src/data.mjs 数据层:whoami / overview / timeline / flow / ship
18
18
  src/office-guard.js 办公室会话的**工具边界**(preset 内挂载:只放行 mcp__argent__erp_*)
19
19
  src/vendor/ account-token.mjs + redact.mjs 的**副本**(插件可发布,不能相对 import core/lib)
20
20
  presets/argent-office.patch.yml 「六禾园办公室助理」preset 声明行(dsh 0.2.x 行式 preset)
21
- dist/client.js 客户端 bundle(手写维护):注册 conversation.view(id=erp)+ 视图实现
21
+ dist/client.js 客户端 bundle(手写维护):注册 sidebar.panellist(id=erp,图标)+ main(key=erp,面板)
22
22
  test/ 客户端 bundle + preset 边界冒烟测试(纯夹具,不启 dsh、不联网)
23
23
  ```
24
24
 
25
25
  `package.json#dsh.bundle.patch` 是**数组**:`[cordis.patch.yml, presets/argent-office.patch.yml]`
26
26
  ⇒ 一次 `install_bundle` 同时落「ERP 视图」与「办公室助理 preset」。
27
27
 
28
- ## 2. 它是「会话视图」而不是「侧栏面板」
28
+ ## 2. 它是「左侧栏入口 + 主视图面板」,不是会话 tab、也不是右侧栏
29
29
 
30
- dsh 0.2.x 的 `conversation.view` 槽 = 对话顶部那排 **Chat / 轨迹 / 统计** 的注册位。
31
- 本插件向该槽注册一项:
30
+ dsh 0.2.x 的两项原生扩展点(`dsh-client-ui-sidebar` / `dsh-client-ui-layout`):
31
+
32
+ - `sidebar.panellist`:左侧栏那排**全局面板图标**(插件、定时任务…);列表条目的 `id` 就是"对应哪个主视图";
33
+ - `main`(keyed):主视图区,`activePanelId` 命中哪个 key 就渲染哪个;`null` = 显示对话。
34
+
35
+ 本插件注册两项,**id 与 key 必须相同**:
32
36
 
33
37
  ```js
34
- ctx.slots.inject("conversation.view", () => ctx.slots.register({
35
- name: "conversation.view",
36
- id: "erp",
37
- order: 5, // Chat=0,本视图=5,轨迹=10
38
- label: () => "ERP",
39
- inject: () => ({ sessions, workspaceNav, remote }), // 建会话 / 跳转 / 钉模型
38
+ // ① 左侧栏图标(owner props: { size, active })
39
+ ctx.slots.inject("sidebar.panellist", () => ctx.slots.register({
40
+ name: "sidebar.panellist", id: "erp", order: 15, label: () => "ERP",
41
+ }, ErpIcon))
42
+
43
+ // ② 主视图面板(root 作用域:没有 Session 绑定)
44
+ ctx.slots.inject("main", () => ctx.slots.register({
45
+ name: "main", key: "erp",
46
+ inject: () => ({ sessions, workspaceNav, remote, closePanel }), // 给「聊一聊」建会话 / 返回按钮用
40
47
  }, ErpView))
41
48
  ```
42
49
 
43
- - 纯 UI 视图**不需要**注册 `ctx.uiConversation.views.register({ target })`
44
- —— 那个 registry 是"消费 Session 事件"的 target 才需要的;ERP 视图读的是自己的宿主端点。
45
- - 视图随会话存在:切会话 → 视图重挂;切 tab 不丢别的 tab 状态。
50
+ - 点击侧栏图标由 sidebar 调 `ctx.layout.selectPanel("erp")`;点任意会话行由 workspace 调
51
+ `selectPanel(null)` 回到对话;面板内再给一个「← 会话」按钮(同样走 `selectPanel(null)`)。
52
+ - 主视图面板是 **root 作用域**(没有 `sessionId`):"在哪个 workspace 建办公室会话"取
53
+ `useWorkspaces` 的第 1 个 workspace(有当前会话时优先当前会话所属 workspace)。
54
+ - 面板只在被选中时挂载 ⇒ 轮询/请求随关闭自动停。
46
55
 
47
56
  ## 3. 视图内容
48
57
 
@@ -117,7 +126,7 @@ ERP 网页里那个「办公室聊一聊」**保持原样**(服务端 SSE +
117
126
 
118
127
  | 路径 | 作用 |
119
128
  |---|---|
120
- | `/api/argent-erp/health` | 存活 + 版本 + `erpTools`(ERP 工具数;0=缺 @whyshu/argent)+ `officePreset` + `clientPingAt`(bundle 加载)/ `viewPingAt`(视图渲染)|
129
+ | `/api/argent-erp/health` | 存活 + 版本 + `erpTools`(ERP 工具数;0=缺 @whyshu/argent)+ `officePreset` + `clientPingAt`(bundle 加载)/ `viewPingAt`(面板打开/渲染)|
121
130
  | `/api/argent-erp/whoami` | 账号 + 租户列表 + 默认租户 |
122
131
  | `/api/argent-erp/overview?tenant=` | 办公室现场(KPI/在岗/执行机/待办 20/动态 10,脱敏) |
123
132
  | `/api/argent-erp/timeline?tenant=&days=` | 时间线(`/sku-flows`,按天分组) |
@@ -142,7 +151,7 @@ dsh 设置 → 插件(Plugins)→ 安装 bundle → @whyshu/argent-erp
142
151
  ```
143
152
 
144
153
  - 装完**重启 dsh**(bundle patch 的宿主行与 preset 行在启动时装配);
145
- - 之后新建会话的 **preset 选择器**里会出现「六禾园办公室助理」,对话顶部出现「ERP」tab;
154
+ - 之后**左侧栏出现「ERP」图标**(点击切主视图),新建会话的 **preset 选择器**里出现「六禾园办公室助理」;
146
155
  - ⚠️ **同机需要 `@whyshu/argent`**(≥0.2.0):它提供 `mcp__argent__erp_*` 工具与 `whyshu` provider。
147
156
  缺它时插件仍能装、视图仍能看(端点会报 no_token),但办公室角色会被 `office-guard` **安全降级为无工具**;
148
157
  宿主 `/api/argent-erp/health` 的 `erpTools` 会返回 `0`(= 没有 ERP 工具),`-1` = 读不到 tools 服务。
@@ -159,9 +168,11 @@ curl -s http://127.0.0.1:3080/api/argent-erp/health # {"ok":true,"version":
159
168
  # 3) preset 行是否落了(应含 include:preset-argent-office)
160
169
  # cordis_inspect_query host/Config/listConfigs name='@deepseek-ai/dsh-agent-preset'
161
170
 
162
- # 4) 客户端 tab 是否注册
163
- # cordis_inspect_query client/Slots/listSubTree root='conversation.view'
164
- # ⇒ occupants 含 { registrant: "argent-erp-client", id: "erp", order: 5, active: true }
171
+ # 4) 客户端两处注册
172
+ # cordis_inspect_query client/Slots/listSubTree root='sidebar.panellist'
173
+ # ⇒ occupants 含 { registrant: "argent-erp-client", id: "erp", order: 15, active: true }
174
+ # cordis_inspect_query client/Slots/listSubTree root='main'
175
+ # ⇒ occupants 含 { registrant: "argent-erp-client", key: "erp", active: true }
165
176
 
166
177
  # 5) 单测(15 项,含 preset 边界断言)
167
178
  node plugins/argent-erp/test/client-bundle.test.mjs
package/dist/client.js CHANGED
@@ -1,10 +1,12 @@
1
1
  /**
2
2
  * argent-erp · 客户端(dsh browser bundle 格式,**手写维护**)
3
3
  *
4
- * 形态:一个 `conversation.view` tab(对话顶部的 Chat / 轨迹 / **ERP** 切换项),
4
+ * 形态:**左侧栏一个「ERP」图标**(`sidebar.panellist`,id=erp)+ **主视图面板**(`main`,key=erp)——
5
+ * 点侧栏图标,主视图(会话区)切到 ERP;点会话行或面板里的「← 会话」回到对话。
5
6
  * 渲染 ERP 的只读视图:办公室现场 / 待办 / 时间线 / 货件 / 聊一聊。
6
7
  *
7
- * 为什么不是侧栏面板:会话视图与"正在做的那一单"同屏——看 ERP 不用离开会话。
8
+ * 为什么不是右侧栏:ERP 是"一整页工作台"(KPI/待办/时间线/货件/聊天入口),塞进窄侧栏只能看数字;
9
+ * 主视图面板能给它完整宽度,同时左侧栏一点就回来,不打断会话。
8
10
  *
9
11
  * 数据全部来自宿主端点 `/api/argent-erp/*`(token 在宿主侧,浏览器拿不到)。
10
12
  * ⛔ 不做写操作;重编辑一律跳 ERP web。
@@ -521,7 +523,7 @@ window.__ModuleLoader__.load({
521
523
  const [tenant, setTenant] = React.useState("")
522
524
  const [detail, setDetail] = React.useState(null) // { kind:'flow'|'shipment', id }
523
525
  const [nonce, setNonce] = React.useState(0) // 刷新时让各自取数的面板重挂
524
- // 渲染信标:只有切到 ERP tab 才会打 ⇒ /health 的 viewPingAt 能证明"真的渲染了"
526
+ // 渲染信标:只有打开 ERP 面板才会打 ⇒ /health 的 viewPingAt 能证明"真的渲染了"
525
527
  React.useEffect(() => { try { fetch(API + "/ping?from=view") } catch { /* noop */ } }, [])
526
528
  const who = useApi("/whoami")
527
529
  const health = useApi("/health")
@@ -556,6 +558,12 @@ window.__ModuleLoader__.load({
556
558
 
557
559
  return h("div", { className: "aerp-root" },
558
560
  h("div", { className: "aerp-head" },
561
+ props && typeof props.closePanel === "function"
562
+ ? h("button", {
563
+ type: "button", className: "aerp-btn", title: "回到会话",
564
+ onClick: () => { try { props.closePanel() } catch { /* noop */ } },
565
+ }, "← 会话")
566
+ : null,
559
567
  h("span", { className: "aerp-title" }, "Argent ERP"),
560
568
  tenants.length > 1
561
569
  ? h("select", {
@@ -581,26 +589,60 @@ window.__ModuleLoader__.load({
581
589
  const name = "argent-erp-client"
582
590
  const inject = ["slots"]
583
591
 
592
+ /** 侧栏入口 id 与主视图面板 key 必须一致(sidebar 用 id 去 main 槽取面板) */
593
+ const PANEL_ID = "erp"
594
+
595
+ /** 左侧栏「ERP」图标(owner props: { size, active };用 currentColor,跟随主题) */
596
+ function ErpIcon(props) {
597
+ const size = (props && props.size) || 16
598
+ const active = Boolean(props && props.active)
599
+ const color = active ? "var(--dsw-alias-brand-primary)" : "currentColor"
600
+ return h("svg", {
601
+ width: size, height: size, viewBox: "0 0 24 24", fill: "none",
602
+ stroke: color, strokeWidth: 1.6, strokeLinecap: "round", strokeLinejoin: "round",
603
+ style: { display: "block" }, "aria-hidden": "true", focusable: "false",
604
+ },
605
+ h("path", { d: "M3.6 9.6 5.3 4.3h13.4l1.7 5.3" }),
606
+ h("path", { d: "M4.3 9.6h15.4v9.1a1.3 1.3 0 0 1-1.3 1.3H5.6a1.3 1.3 0 0 1-1.3-1.3V9.6Z" }),
607
+ h("path", { d: "M9.4 20v-4.7h5.2V20" }))
608
+ }
609
+
610
+ /** 取服务;没有/未注入时返回 undefined(动态插件 ctx 的白名单可能不含某个服务) */
611
+ const getService = (ctx, name) => { try { return ctx.get(name) } catch { return undefined } }
612
+
584
613
  function apply(ctx) {
585
614
  injectCss()
586
615
  // 自检信标:宿主 /health 会回报 clientPingAt ⇒ 能区分"bundle 没加载"与"加载了但没显示"
587
616
  try { fetch(API + "/ping?from=client").catch(() => {}) } catch { /* noop */ }
588
617
 
589
- // ⛔ 永不抛出:注册失败只影响这个 tab,不能让 web boot 报 "entry did not activate"
618
+ // ⛔ 永不抛出:注册失败只影响 ERP 入口,不能让 web boot 报 "entry did not activate"
619
+
620
+ // ① 左侧栏入口(图标按钮):点击后 sidebar 调 ctx.layout.selectPanel('erp') 切主视图
590
621
  try {
591
- ctx.slots.inject("conversation.view", () => ctx.slots.register({
592
- name: "conversation.view",
593
- id: "erp",
594
- order: 5,
622
+ ctx.slots.inject("sidebar.panellist", () => ctx.slots.register({
623
+ name: "sidebar.panellist",
624
+ id: PANEL_ID,
625
+ order: 15,
595
626
  label: () => "ERP",
627
+ }, ErpIcon))
628
+ } catch (e) {
629
+ console.warn("[argent-erp] 侧栏入口注册失败(不影响 dsh):", (e && e.message) || e)
630
+ }
631
+
632
+ // ② 主视图面板:key 与侧栏 id 相同;root 作用域(没有 Session 绑定)
633
+ try {
634
+ ctx.slots.inject("main", () => ctx.slots.register({
635
+ name: "main",
636
+ key: PANEL_ID,
596
637
  inject: () => ({
597
- sessions: (() => { try { return ctx.get("sessions") } catch { return undefined } })(),
598
- workspaceNav: (() => { try { return ctx.get("uiWorkspace") } catch { return undefined } })(),
599
- remote: (() => { try { return ctx.get("remote") } catch { return undefined } })(),
638
+ sessions: getService(ctx, "sessions"),
639
+ workspaceNav: getService(ctx, "uiWorkspace"),
640
+ remote: getService(ctx, "remote"),
641
+ closePanel: () => { try { getService(ctx, "layout")?.selectPanel?.(null) } catch { /* noop */ } },
600
642
  }),
601
643
  }, ErpView))
602
644
  } catch (e) {
603
- console.warn("[argent-erp] conversation.view 注册失败(不影响 dsh):", (e && e.message) || e)
645
+ console.warn("[argent-erp] 主视图面板注册失败(不影响 dsh):", (e && e.message) || e)
604
646
  }
605
647
  }
606
648
 
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@whyshu/argent-erp",
3
- "version": "0.2.3",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
- "description": "Argent ERP 会话视图(dsh conversation.view)+ 六禾园办公室助理 preset(只聊办公室、只读 ERP)+ 办公室聊一聊入口",
5
+ "description": "Argent ERP 左侧栏入口 + 主视图面板(dsh sidebar.panellist/main)+ 六禾园办公室助理 preset + 办公室聊一聊",
6
6
  "keywords": [
7
7
  "dsh",
8
8
  "deepseek-harness",