@stofone/dsh-agent-roster 0.8.2 → 0.9.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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,38 @@
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.9.0] - 2026-11-03
8
+
9
+ ### The roster list is a ledger
10
+
11
+ - **Rows, not cards.** Each roster is one row: a 3px state edge (lit only for `error` / `warn`),
12
+ a monospace id column, the title with its one-line description, right-aligned counts and a
13
+ quiet pair of actions. Duplicate / copy-create / delete moved into the expanded area — 21
14
+ rosters go from 105 always-visible buttons to 42.
15
+ - **The edge is the only loud thing.** Healthy rows carry no colour at all; the accent colour is
16
+ reserved for the selected tab underline and the selected tag's left edge. Every colour still
17
+ comes from `--dsw-alias-*` tokens, so light and dark themes stay consistent.
18
+ - **Teams are rows too**, collapsed by default, with the same state edge.
19
+ - **The header states what the library holds**: rosters, members, teams, and the owning
20
+ `organization.yaml` id when the directory has one.
21
+ - Narrow panels (below 860px) fold the tag pool into a wrapping top row instead of clipping it.
22
+
23
+ ## [0.8.3] - 2026-11-03
24
+
25
+ ### The panel no longer cuts long content
26
+
27
+ - **The page owns its own scroll.** A global panel is mounted inside the centre column, which is
28
+ `overflow: hidden`; a page that never asks for scroll silently clips everything below the fold —
29
+ that is why the sources tab looked half-rendered as soon as a collection was expanded. `.rstr-page`
30
+ now sets `height: 100%; min-height: 0; overflow-y: auto; overflow-x: hidden`.
31
+ - **Card grids no longer overflow narrow panels.** `repeat(auto-fill, minmax(380px, 1fr))` became
32
+ `repeat(auto-fill, minmax(min(380px, 100%), 1fr))`, so a narrow column stops clipping cards on the
33
+ right edge.
34
+ - **The expanded roster list scrolls inside its card** (`max-height: 340px`) instead of stretching
35
+ the card without bound, and long roster titles ellipsize instead of pushing the badges out.
36
+ - Three regression assertions pin the three layers (page / grid / expanded list) in
37
+ `test/client.test.js`, so a later style refactor cannot quietly bring the clipping back.
38
+
7
39
  ## [0.8.2] - 2026-11-03
8
40
 
9
41
  ### The whole family lives under one organization
@@ -324,7 +356,9 @@
324
356
  - 工具返回值含 `undefined` 键,运行时按 `value is not lossless JSON` 整次拒绝;缺失值统一写 `null`,
325
357
  且所有返回值先过 `lib/json.js#lossless`。
326
358
 
327
- [Unreleased]: https://github.com/dsh-agent-roster/dsh-agent-roster/compare/v0.8.2...main
359
+ [Unreleased]: https://github.com/dsh-agent-roster/dsh-agent-roster/compare/v0.9.0...main
360
+ [0.9.0]: https://github.com/dsh-agent-roster/dsh-agent-roster/releases/tag/v0.9.0
361
+ [0.8.3]: https://github.com/dsh-agent-roster/dsh-agent-roster/releases/tag/v0.8.3
328
362
  [0.8.2]: https://github.com/dsh-agent-roster/dsh-agent-roster/releases/tag/v0.8.2
329
363
  [0.8.1]: https://github.com/dsh-agent-roster/dsh-agent-roster/releases/tag/v0.8.1
330
364
  [0.8.0]: https://github.com/dsh-agent-roster/dsh-agent-roster/releases/tag/v0.8.0
package/README.md CHANGED
@@ -268,6 +268,8 @@ member and finally `roster_verify`. Creating the team stays with the runtime.
268
268
 
269
269
  ## Sidebar panel
270
270
 
271
+ The roster list is a **ledger, not a wall of cards**: one row per roster — a 3px state edge (lit only when something is wrong, quiet when it is fine), a monospace id column, the title with a one-line description, right-aligned counts (members / errors / warnings / deployment), and a quiet pair of actions (edit, expand). Duplicate, copy-create and delete moved into the expanded area, which turns 105 buttons across 21 rosters into 42. Below 860px the tag pool becomes a top row and the metadata wraps.
272
+
271
273
  The panel takes the full page width; nothing constrains it to a reading column. The archive list has
272
274
  a **tag pool** on the left: every tag present in the library, with how many archives carry it. Clicking
273
275
  tags narrows the list — multiple selections are ANDed — and one button clears the selection. The tag
@@ -387,7 +389,7 @@ test/ unit tests
387
389
 
388
390
  Verified on this machine:
389
391
 
390
- - `npm test` — 239/239 passing (format, parse, validate, registry, paths, bridge, verify buckets, digests and provenance, roster diff, capability requirements and the capability gate, library organization, registry schema, lossless JSON, write plan/apply, all routes, panel snapshot and hints, dictionary consistency, tool contracts, client loader contract, library snapshot, config view, package manifest, declared fields and captain block, schema/constant alignment, remote registry and one-click install).
392
+ - `npm test` — 240/240 passing (format, parse, validate, registry, paths, bridge, verify buckets, digests and provenance, roster diff, capability requirements and the capability gate, library organization, registry schema, lossless JSON, write plan/apply, all routes, panel snapshot and hints, dictionary consistency, tool contracts, client loader contract, library snapshot, config view, package manifest, declared fields and captain block, schema/constant alignment, remote registry and one-click install).
391
393
  - `npm run smoke` — `apply()` registers all six tools through a real `defineTool` from a DSH bundle; `roster_list` / `roster_show` / `roster_create` / `roster_verify` / `roster_diff` execute, every output survives `lossless` checks, `path` overrides are honored, effect disposal runs cleanly. The same command then loads `client.js` against a stubbed module table and asserts the three slot registrations, style injection and effect disposal.
392
394
  - CLI: `validate --dir examples` returns exit 0 over both example libraries.
393
395
  - Installed into a real profile with the plugin manager (`plugin_manager install_bundle` against this directory → `link:` dependency + bundle entry); the profile re-reads the linked files on restart.
package/README.zh.md CHANGED
@@ -260,7 +260,11 @@ node bin/cli.mjs validate --dir orgs/agent-roster-collective
260
260
 
261
261
  ## 左侧栏面板
262
262
 
263
- 面板铺满整个页面宽度,外层容器不设阅读列宽度。档案列表左侧是**标签池**:列出全库出现过的标签
263
+ 面板铺满整个页面宽度,外层容器不设阅读列宽度。
264
+
265
+ 档案列表是**账本,不是卡片墙**:一行一份档案——左沿 3 像素状态色(只有出错或有提醒时才亮,正常的档案不标记)、等宽字体的 id 列、标题与一句话描述、右侧计数(成员数 / 错误 / 提醒 / 部署态),最后是一对安静的操作(编辑、展开成员)。复制、复制建队、删除收在展开区里,21 份档案的 105 个按钮因此变成 42 个。窄于 860 像素时标签池从左侧栏变成顶上一行、元数据自动折行。
266
+
267
+ 档案列表左侧是**标签池**:列出全库出现过的标签
264
268
  以及各标签的档案数,点标签即筛选——多选是「且」,一个按钮清除选择。标签池只影响视图,不会把
265
269
  标签写回文件。
266
270
 
@@ -370,7 +374,7 @@ test/ 单测
370
374
 
371
375
  本机已验证:
372
376
 
373
- - `npm test` —— 239/239 通过(格式、解析、校验、扫描、路径、桥接、核对四桶、摘要与溯源、档案差异、能力要求与能力闸门、档案库组织、索引 schema、无损 JSON、写入计划与执行、六条路由、快照与提示、两本词典一致、工具契约、客户端加载器契约、包清单、配置视图、样式 token 约束、声明层字段与队长段、schema 与常量对齐)。
377
+ - `npm test` —— 240/240 通过(格式、解析、校验、扫描、路径、桥接、核对四桶、摘要与溯源、档案差异、能力要求与能力闸门、档案库组织、索引 schema、无损 JSON、写入计划与执行、六条路由、快照与提示、两本词典一致、工具契约、客户端加载器契约、包清单、配置视图、样式 token 约束、声明层字段与队长段、schema 与常量对齐)。
374
378
  - `npm run smoke` —— 用真实 DSH bundle 的 `defineTool` 注册六个工具,逐个调用:输出全部通过无损校验、`path` 覆盖生效、释放干净;同一条命令随后用桩模块表加载 `client.js`,断言三处槽位注册、样式只注入一次、effect 可回收。
375
379
  - CLI:`validate --dir examples` 对两座示例库退出码 0。
376
380
  - 用插件管理器真的装进了本机 profile(`plugin_manager install_bundle` 指向本仓库 → `link:` 依赖 + bundle 条目),重启后按链接读取本仓库文件。
package/client.js CHANGED
@@ -652,80 +652,100 @@ window.__ModuleLoader__.load({
652
652
  );
653
653
  }
654
654
 
655
+ /**
656
+ * 一行 = 一份档案。
657
+ *
658
+ * 名册是列表不是画廊:id 立在第一列当"脊",状态长在左沿,操作平时只露两个入口。
659
+ * 复制/建队/删除这些低频且危险的动作收进展开区——否则 21 份档案就是 105 个按钮。
660
+ */
655
661
  function RosterCard({ roster, deployment, captainReport, sessions, onToast, onEdit, onDuplicate, onDelete, onCopy }) {
656
662
  const [open, setOpen] = useState(false);
657
- const errors = (roster.diagnostics ?? []).filter((item) => item?.severity === "error").length;
663
+ const diagnostics = roster.diagnostics ?? [];
664
+ const errors = diagnostics.filter((item) => item?.severity === "error").length;
665
+ const warnings = diagnostics.filter((item) => item?.severity === "warn").length;
658
666
  const deployed = deployment !== undefined && deployment.deployed > 0;
667
+ const drifted = deployment !== undefined ? deployment.drifted : 0;
668
+
669
+ const tone = errors > 0 ? " rstr-row-error" : warnings > 0 ? " rstr-row-warn" : "";
659
670
 
660
671
  return h(
661
672
  "article",
662
- { className: `rstr-card${errors > 0 ? " rstr-card-bad" : ""}` },
673
+ { className: `rstr-row${tone}${open ? " rstr-row-open" : ""}` },
663
674
  h(
664
- "header",
665
- { className: "rstr-card-head" },
675
+ "div",
676
+ { className: "rstr-row-body" },
677
+ h("code", { className: "rstr-row-id", title: roster.id }, roster.id),
666
678
  h(
667
679
  "div",
668
- null,
680
+ { className: "rstr-row-text" },
669
681
  h(
670
- "div",
671
- { className: "rstr-card-id" },
672
- h("code", { className: "rstr-code rstr-code-strong" }, roster.id),
682
+ "h3",
683
+ { className: "rstr-row-title" },
684
+ roster.title || roster.id,
673
685
  h(Chip, null, t("roster.version", { version: roster.version })),
674
686
  errors > 0 ? h(Badge, { tone: "error" }, t("roster.diagnostics", { count: errors })) : null,
675
687
  ),
676
- h("h3", { className: "rstr-card-title" }, roster.title || roster.id),
677
- roster.description ? h("p", { className: "rstr-muted" }, roster.description) : null,
688
+ roster.description ? h("p", { className: "rstr-row-desc" }, roster.description) : null,
678
689
  ),
679
- ),
680
- h(
681
- "div",
682
- { className: "rstr-card-meta" },
683
- h("span", null, t("roster.members", { count: roster.members.length })),
684
- h("span", { className: "rstr-muted" }, roster.file),
685
690
  h(
686
- "span",
687
- { className: deployed ? "rstr-ok" : "rstr-muted" },
688
- deployed
689
- ? t("roster.deployed", { teams: (deployment.teams ?? []).join(", ") })
690
- : t("roster.notDeployed"),
691
- ),
692
- deployment !== undefined && deployment.drifted > 0
693
- ? h(Badge, { tone: "warn" }, t("roster.drifted", { count: deployment.drifted }))
694
- : null,
695
- ),
696
- h(
697
- "div",
698
- { className: "rstr-card-actions" },
699
- h("button", { type: "button", className: "rstr-btn", onClick: () => onEdit(roster) }, t("roster.edit")),
700
- h("button", { type: "button", className: "rstr-btn", onClick: () => onDuplicate(roster) }, t("roster.duplicate")),
701
- h("button", { type: "button", className: "rstr-btn", onClick: () => onCopy(roster) }, t("roster.copyCreate")),
702
- h(
703
- "button",
704
- { type: "button", className: "rstr-btn rstr-btn-danger", onClick: () => onDelete(roster) },
705
- t("roster.delete"),
691
+ "div",
692
+ { className: "rstr-row-stats" },
693
+ h("span", null, t("roster.members", { count: roster.members.length })),
694
+ errors > 0
695
+ ? h("span", { className: "rstr-stat-error" }, t("roster.diagnostics", { count: errors }))
696
+ : warnings > 0
697
+ ? h("span", { className: "rstr-stat-warn" }, t("roster.warnings", { count: warnings }))
698
+ : null,
699
+ h(
700
+ "span",
701
+ { className: deployed ? "rstr-stat-ok" : undefined },
702
+ deployed
703
+ ? drifted > 0
704
+ ? t("roster.deployedDrifted", { teams: (deployment.teams ?? []).join(", "), count: drifted })
705
+ : t("roster.deployed", { teams: (deployment.teams ?? []).join(", ") })
706
+ : t("roster.notDeployed"),
707
+ ),
706
708
  ),
707
709
  h(
708
- "button",
709
- {
710
- type: "button",
711
- className: "rstr-btn rstr-btn-ghost",
712
- "aria-expanded": open,
713
- onClick: () => setOpen(!open),
714
- },
715
- open ? t("roster.hideMembers") : t("roster.showMembers"),
710
+ "div",
711
+ { className: "rstr-row-actions" },
712
+ h("button", { type: "button", className: "rstr-btn rstr-btn-sm rstr-btn-quiet", onClick: () => onEdit(roster) }, t("roster.edit")),
713
+ h(
714
+ "button",
715
+ {
716
+ type: "button",
717
+ className: "rstr-btn rstr-btn-sm rstr-btn-quiet",
718
+ "aria-expanded": open,
719
+ onClick: () => setOpen(!open),
720
+ },
721
+ open ? t("roster.hideMembers") : t("roster.showMembers"),
722
+ h("span", { className: "rstr-caret", "aria-hidden": "true" }, open ? "\u25b4" : "\u25be"),
723
+ ),
716
724
  ),
717
725
  ),
718
726
  open
719
727
  ? h(
720
728
  "div",
721
- { className: "rstr-members" },
729
+ { className: "rstr-row-detail" },
722
730
  roster.members.length === 0
723
731
  ? h("p", { className: "rstr-muted" }, t("roster.noMembers"))
724
- : roster.members.map((member) => h(MemberBlock, { key: member.name, member })),
732
+ : h(
733
+ "div",
734
+ { className: "rstr-members" },
735
+ roster.members.map((member) => h(MemberBlock, { key: member.name, member })),
736
+ ),
725
737
  roster.captain === null || roster.captain === undefined
726
738
  ? null
727
739
  : h(CaptainPanel, { roster, report: captainReport, sessions: sessions ?? [], onToast }),
728
- h(DiagnosticList, { items: roster.diagnostics }),
740
+ h(DiagnosticList, { items: diagnostics }),
741
+ h("p", { className: "rstr-hint" }, `roster.file: ${roster.file}`),
742
+ h(
743
+ "div",
744
+ { className: "rstr-row-detail-actions" },
745
+ h("button", { type: "button", className: "rstr-btn rstr-btn-sm", onClick: () => onDuplicate(roster) }, t("roster.duplicate")),
746
+ h("button", { type: "button", className: "rstr-btn rstr-btn-sm", onClick: () => onCopy(roster) }, t("roster.copyCreate")),
747
+ h("button", { type: "button", className: "rstr-btn rstr-btn-sm rstr-btn-danger", onClick: () => onDelete(roster) }, t("roster.delete")),
748
+ ),
729
749
  )
730
750
  : null,
731
751
  );
@@ -735,76 +755,104 @@ window.__ModuleLoader__.load({
735
755
  /* 团队视图 */
736
756
  /* ------------------------------------------------------------------ */
737
757
 
758
+ /**
759
+ * 一行 = 一个团队。默认收起:团队页是用来"看谁在跑、有没有偏"的,不是用来读成员清单的。
760
+ */
738
761
  function TeamCard({ team }) {
762
+ const [open, setOpen] = useState(false);
763
+ const phase = team.phase === "staged" ? t("team.phaseStaged") : t("team.phaseRunning");
764
+ const tone = team.escalated ? " rstr-row-error" : team.halted || team.phase === "staged" ? " rstr-row-warn" : "";
765
+
739
766
  return h(
740
767
  "article",
741
- { className: "rstr-card" },
768
+ { className: `rstr-row${tone}${open ? " rstr-row-open" : ""}` },
742
769
  h(
743
- "header",
744
- { className: "rstr-card-head" },
770
+ "div",
771
+ { className: "rstr-row-body" },
772
+ h("code", { className: "rstr-row-id", title: team.id }, team.id),
745
773
  h(
746
774
  "div",
747
- null,
775
+ { className: "rstr-row-text" },
748
776
  h(
749
- "div",
750
- { className: "rstr-card-id" },
751
- h("code", { className: "rstr-code rstr-code-strong" }, team.id),
752
- h(Badge, { tone: team.phase === "staged" ? "warn" : "ok" }, t(team.phase === "staged" ? "team.phaseStaged" : "team.phaseRunning")),
777
+ "h3",
778
+ { className: "rstr-row-title" },
779
+ team.name || team.id,
780
+ h(Badge, { tone: team.phase === "staged" ? "warn" : "ok" }, phase),
753
781
  team.halted ? h(Badge, { tone: "warn" }, t("team.halted")) : null,
754
782
  team.escalated ? h(Badge, { tone: "error" }, t("team.escalated")) : null,
755
783
  ),
756
- h("h3", { className: "rstr-card-title" }, team.name || team.id),
757
- team.description ? h("p", { className: "rstr-muted" }, team.description) : null,
784
+ team.description ? h("p", { className: "rstr-row-desc" }, team.description) : null,
758
785
  ),
759
- ),
760
- h(
761
- "div",
762
- { className: "rstr-card-meta" },
763
- h("span", null, t("team.tasks", team.tasks)),
764
- h("span", { className: "rstr-muted rstr-small" }, t("team.file") + ": " + team.file),
765
- ),
766
- h(
767
- "div",
768
- { className: "rstr-members" },
769
- h("div", { className: "rstr-label rstr-mt" }, t("team.members")),
770
- team.members.map((member) =>
786
+ h(
787
+ "div",
788
+ { className: "rstr-row-stats" },
789
+ h("span", null, t("team.taskCount", { count: team.tasks.total })),
790
+ h("span", null, t("roster.members", { count: team.members.length })),
791
+ ),
792
+ h(
793
+ "div",
794
+ { className: "rstr-row-actions" },
771
795
  h(
796
+ "button",
797
+ {
798
+ type: "button",
799
+ className: "rstr-btn rstr-btn-sm rstr-btn-quiet",
800
+ "aria-expanded": open,
801
+ onClick: () => setOpen(!open),
802
+ },
803
+ open ? t("team.hideMembers") : t("team.showMembers"),
804
+ h("span", { className: "rstr-caret", "aria-hidden": "true" }, open ? "\u25b4" : "\u25be"),
805
+ ),
806
+ ),
807
+ ),
808
+ open
809
+ ? h(
772
810
  "div",
773
- { key: member.name, className: "rstr-member" },
774
- h(
775
- "div",
776
- { className: "rstr-member-head" },
777
- h("strong", null, member.name),
778
- member.role ? h(Chip, null, member.role) : null,
779
- member.rosterId === null
780
- ? h(Badge, { tone: "muted" }, t("team.unmanaged"))
781
- : h(Badge, { tone: member.faithful ? "ok" : "warn" }, t(member.faithful ? "team.faithful" : "team.drift")),
782
- ),
811
+ { className: "rstr-row-detail" },
783
812
  h(
784
813
  "div",
785
- { className: "rstr-member-meta" },
786
- member.model ? h("span", null, `${t("member.model")}: ${member.model}`) : null,
787
- member.reasoningEffort ? h("span", null, `${t("member.effort")}: ${member.reasoningEffort}`) : null,
788
- member.toolPolicy ? h("span", null, `${t("member.policy")}: ${member.toolPolicy}`) : null,
789
- member.rosterId !== null ? h("span", { className: "rstr-muted" }, t("team.managed", { roster: member.rosterId })) : null,
790
- h("span", { className: "rstr-muted" }, t("team.promptChars", { count: member.promptChars })),
791
- ),
792
- member.drift.length > 0
793
- ? h(
794
- "ul",
795
- { className: "rstr-drift" },
796
- member.drift.map((item) =>
797
- h(
798
- "li",
799
- { key: item.field },
800
- t("team.driftDetail", { field: item.field, wanted: item.roster, actual: item.runtime }),
801
- ),
814
+ { className: "rstr-members" },
815
+ team.members.map((member) =>
816
+ h(
817
+ "div",
818
+ { key: member.name, className: "rstr-member" },
819
+ h(
820
+ "div",
821
+ { className: "rstr-member-head" },
822
+ h("strong", null, member.name),
823
+ member.role ? h(Chip, null, member.role) : null,
824
+ member.rosterId === null
825
+ ? h(Badge, { tone: "muted" }, t("team.unmanaged"))
826
+ : h(Badge, { tone: member.faithful ? "ok" : "warn" }, t(member.faithful ? "team.faithful" : "team.drift")),
802
827
  ),
803
- )
804
- : null,
805
- ),
806
- ),
807
- ),
828
+ h(
829
+ "div",
830
+ { className: "rstr-member-meta" },
831
+ member.model ? h("span", null, `${t("member.model")}: ${member.model}`) : null,
832
+ member.reasoningEffort ? h("span", null, `${t("member.effort")}: ${member.reasoningEffort}`) : null,
833
+ member.toolPolicy ? h("span", null, `${t("member.policy")}: ${member.toolPolicy}`) : null,
834
+ member.rosterId !== null ? h("span", { className: "rstr-muted" }, t("team.managed", { roster: member.rosterId })) : null,
835
+ h("span", { className: "rstr-muted" }, t("team.promptChars", { count: member.promptChars })),
836
+ ),
837
+ member.drift.length > 0
838
+ ? h(
839
+ "ul",
840
+ { className: "rstr-drift" },
841
+ member.drift.map((item) =>
842
+ h(
843
+ "li",
844
+ { key: item.field },
845
+ t("team.driftDetail", { field: item.field, wanted: item.roster, actual: item.runtime }),
846
+ ),
847
+ ),
848
+ )
849
+ : null,
850
+ ),
851
+ ),
852
+ ),
853
+ h("p", { className: "rstr-hint" }, `${t("team.file")}: ${team.file}`),
854
+ )
855
+ : null,
808
856
  );
809
857
  }
810
858
 
@@ -1320,21 +1368,23 @@ window.__ModuleLoader__.load({
1320
1368
  }
1321
1369
  }
1322
1370
 
1371
+ const organization = (snapshot?.workspaces ?? []).map((workspace) => workspace.organization).find((item) => item && item.id)?.id ?? "";
1372
+
1323
1373
  const header = h(
1324
1374
  "header",
1325
1375
  { className: "rstr-head" },
1326
1376
  h(
1327
1377
  "div",
1328
- null,
1378
+ { className: "rstr-head-main" },
1329
1379
  h("h1", { className: "rstr-h1" }, t("panel.title")),
1380
+ // 抬头只放"这库里有什么":几份档案、几个人、几支队在跑、属于哪个组织。
1330
1381
  h(
1331
- "p",
1332
- { className: "rstr-muted" },
1333
- t("panel.subtitle", {
1334
- rosters: snapshot?.summary?.rosters ?? 0,
1335
- members: snapshot?.summary?.members ?? 0,
1336
- teams: snapshot?.summary?.teams ?? 0,
1337
- }),
1382
+ "div",
1383
+ { className: "rstr-head-meta" },
1384
+ h("span", null, h("b", null, String(snapshot?.summary?.rosters ?? 0)), " ", t("panel.metaRosters")),
1385
+ h("span", null, h("b", null, String(snapshot?.summary?.members ?? 0)), " ", t("panel.metaMembers")),
1386
+ h("span", null, h("b", null, String(snapshot?.summary?.teams ?? 0)), " ", t("panel.metaTeams")),
1387
+ organization === "" ? null : h("span", null, t("panel.metaOrganization", { name: organization })),
1338
1388
  ),
1339
1389
  ),
1340
1390
  h(
@@ -2063,156 +2113,455 @@ window.__ModuleLoader__.load({
2063
2113
  * 需要"淡色底"的地方用 `color-mix(... , transparent)` 自己算,深浅主题都成立。
2064
2114
  * 文本色一律显式给出(不用 inherit),避免继承到与背景同色的文本。
2065
2115
  */
2066
- const CSS = `
2067
- .rstr-page { display: flex; flex-direction: column; gap: 16px; padding: 20px 24px 32px; width: 100%; box-sizing: border-box; color: var(--dsw-alias-label-primary); font-size: 14px; line-height: 1.55; }
2068
- .rstr-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
2069
- .rstr-h1 { margin: 0; font-size: 20px; font-weight: 600; letter-spacing: -0.01em; color: var(--dsw-alias-label-primary); }
2116
+ const CSS = `/* ============================================================
2117
+ dsh-agent-roster — panel styles
2118
+ Everything derives from host theme aliases (--dsw-alias-*).
2119
+ No literal colors: the host owns light/dark.
2120
+ ============================================================ */
2121
+
2122
+ .rstr-page {
2123
+ display: flex;
2124
+ flex-direction: column;
2125
+ gap: 0;
2126
+ padding: 0;
2127
+ width: 100%;
2128
+ height: 100%;
2129
+ min-height: 0;
2130
+ box-sizing: border-box;
2131
+ overflow-y: auto;
2132
+ overflow-x: hidden;
2133
+ color: var(--dsw-alias-label-primary);
2134
+ font-size: 13px;
2135
+ line-height: 1.6;
2136
+ }
2137
+
2138
+ /* ---- masthead --------------------------------------------------------- */
2139
+
2140
+ .rstr-head {
2141
+ display: flex;
2142
+ align-items: flex-end;
2143
+ justify-content: space-between;
2144
+ gap: 20px;
2145
+ flex-wrap: wrap;
2146
+ padding: 24px 28px 14px;
2147
+ border-bottom: 1px solid var(--dsw-alias-border-l1);
2148
+ }
2149
+ .rstr-head-main { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
2150
+ .rstr-h1 { margin: 0; font-size: 26px; font-weight: 650; letter-spacing: -0.02em; color: var(--dsw-alias-label-primary); }
2151
+ .rstr-head-meta { display: flex; flex-wrap: wrap; gap: 18px; font-size: 12px; color: var(--dsw-alias-label-secondary); font-variant-numeric: tabular-nums; }
2152
+ .rstr-head-meta > span > b { font-weight: 600; color: var(--dsw-alias-label-primary); }
2153
+ .rstr-head-actions { display: flex; gap: 6px; flex-wrap: wrap; }
2154
+
2155
+ /* ---- tabs ------------------------------------------------------------- */
2156
+
2157
+ .rstr-tabs {
2158
+ display: flex;
2159
+ gap: 22px;
2160
+ padding: 0 28px;
2161
+ border-bottom: 1px solid var(--dsw-alias-border-l1);
2162
+ position: sticky;
2163
+ top: 0;
2164
+ z-index: 2;
2165
+ background: var(--dsw-alias-bg-base);
2166
+ }
2167
+ .rstr-tab {
2168
+ border: none;
2169
+ background: transparent;
2170
+ padding: 11px 0 9px;
2171
+ font-size: 13px;
2172
+ font-family: inherit;
2173
+ color: var(--dsw-alias-label-secondary);
2174
+ cursor: pointer;
2175
+ border-bottom: 2px solid transparent;
2176
+ display: inline-flex;
2177
+ align-items: baseline;
2178
+ gap: 6px;
2179
+ margin-bottom: -1px;
2180
+ }
2181
+ .rstr-tab:hover { color: var(--dsw-alias-label-primary); }
2182
+ .rstr-tab:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary); outline-offset: 2px; }
2183
+ .rstr-tab-on { color: var(--dsw-alias-label-primary); border-bottom-color: var(--dsw-alias-state-business-primary); font-weight: 600; }
2184
+ .rstr-tab-count { font-size: 12px; color: var(--dsw-alias-label-secondary); font-variant-numeric: tabular-nums; }
2185
+
2186
+ /* ---- banner ----------------------------------------------------------- */
2187
+
2188
+ .rstr-banner {
2189
+ display: flex;
2190
+ align-items: center;
2191
+ justify-content: space-between;
2192
+ gap: 14px;
2193
+ margin: 14px 28px 0;
2194
+ padding: 9px 12px 9px 14px;
2195
+ border-left: 3px solid var(--dsw-alias-state-warn-primary);
2196
+ background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 8%, transparent);
2197
+ color: var(--dsw-alias-label-primary);
2198
+ font-size: 13px;
2199
+ }
2200
+
2201
+ /* ---- 档案页:标签脊 + 账本 ------------------------------------------- */
2202
+
2203
+ .rstr-rosters {
2204
+ display: grid;
2205
+ grid-template-columns: 176px minmax(0, 1fr);
2206
+ align-items: start;
2207
+ }
2208
+ .rstr-tagpool {
2209
+ display: flex;
2210
+ flex-direction: column;
2211
+ gap: 2px;
2212
+ padding: 16px 12px 20px 20px;
2213
+ border-right: 1px solid var(--dsw-alias-border-l1);
2214
+ position: sticky;
2215
+ top: 41px;
2216
+ align-self: start;
2217
+ min-width: 0;
2218
+ }
2219
+ .rstr-tagpool-title {
2220
+ display: flex;
2221
+ align-items: baseline;
2222
+ justify-content: space-between;
2223
+ font-size: 11px;
2224
+ font-weight: 600;
2225
+ color: var(--dsw-alias-label-secondary);
2226
+ padding: 0 6px 6px;
2227
+ }
2228
+ .rstr-tagpool-list { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
2229
+ .rstr-tag {
2230
+ display: flex;
2231
+ align-items: baseline;
2232
+ justify-content: space-between;
2233
+ gap: 8px;
2234
+ width: 100%;
2235
+ border: none;
2236
+ border-left: 2px solid transparent;
2237
+ background: transparent;
2238
+ color: var(--dsw-alias-label-secondary);
2239
+ padding: 4px 6px;
2240
+ font-size: 12px;
2241
+ font-family: inherit;
2242
+ cursor: pointer;
2243
+ text-align: left;
2244
+ border-radius: 0 4px 4px 0;
2245
+ }
2246
+ .rstr-tag:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }
2247
+ .rstr-tag:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary); outline-offset: -2px; }
2248
+ .rstr-tag-on {
2249
+ border-left-color: var(--dsw-alias-state-business-primary);
2250
+ background: color-mix(in srgb, var(--dsw-alias-state-business-primary) 8%, transparent);
2251
+ color: var(--dsw-alias-label-primary);
2252
+ font-weight: 600;
2253
+ }
2254
+ .rstr-tag-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2255
+ .rstr-tag-count { font-size: 11px; color: var(--dsw-alias-label-secondary); font-variant-numeric: tabular-nums; }
2256
+ .rstr-tag-clear { align-self: flex-start; margin-top: 8px; }
2257
+
2258
+ .rstr-rosters-main { display: flex; flex-direction: column; min-width: 0; padding: 16px 28px 28px; gap: 12px; }
2259
+
2260
+ /* ---- 工具条 ----------------------------------------------------------- */
2261
+
2262
+ .rstr-toolbar { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
2263
+ .rstr-toolbar-actions { display: flex; gap: 6px; margin-left: auto; }
2264
+ .rstr-search {
2265
+ max-width: 320px;
2266
+ border-color: transparent;
2267
+ background: var(--dsw-alias-bg-layer-2);
2268
+ }
2269
+ .rstr-search:focus-visible { background: var(--dsw-alias-bg-layer-1); border-color: var(--dsw-alias-border-l3); }
2270
+
2271
+ /* ---- 账本(行) ------------------------------------------------------- */
2272
+
2273
+ .rstr-cards { display: flex; flex-direction: column; min-width: 0; border-top: 1px solid var(--dsw-alias-border-l2); }
2274
+
2275
+ .rstr-row {
2276
+ position: relative;
2277
+ display: flex;
2278
+ flex-direction: column;
2279
+ min-width: 0;
2280
+ border-bottom: 1px solid var(--dsw-alias-border-l1);
2281
+ padding-left: 15px;
2282
+ content-visibility: auto;
2283
+ contain-intrinsic-size: auto 68px;
2284
+ }
2285
+ .rstr-row::before {
2286
+ content: "";
2287
+ position: absolute;
2288
+ left: 0;
2289
+ top: 0;
2290
+ bottom: 0;
2291
+ width: 3px;
2292
+ background: transparent;
2293
+ transition: width .12s ease;
2294
+ }
2295
+ .rstr-row-error::before { background: var(--dsw-alias-state-error-primary); }
2296
+ .rstr-row-warn::before { background: var(--dsw-alias-state-warn-primary); }
2297
+ .rstr-row:hover { background: var(--dsw-alias-interactive-bg-hover); }
2298
+ .rstr-row:hover::before { width: 5px; }
2299
+ .rstr-row-open { background: var(--dsw-alias-interactive-bg-hover); }
2300
+ .rstr-row-open::before { width: 5px; }
2301
+
2302
+ .rstr-row-body {
2303
+ display: grid;
2304
+ grid-template-columns: minmax(88px, 140px) minmax(0, 1fr) auto auto;
2305
+ align-items: baseline;
2306
+ gap: 8px 16px;
2307
+ padding: 13px 8px 13px 0;
2308
+ min-width: 0;
2309
+ }
2310
+ .rstr-row-id {
2311
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
2312
+ font-size: 13px;
2313
+ font-weight: 600;
2314
+ color: var(--dsw-alias-label-primary);
2315
+ overflow: hidden;
2316
+ text-overflow: ellipsis;
2317
+ white-space: nowrap;
2318
+ }
2319
+ .rstr-row-text { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
2320
+ .rstr-row-title { margin: 0; font-size: 14px; font-weight: 500; color: var(--dsw-alias-label-primary); display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; }
2321
+ .rstr-row-desc {
2322
+ margin: 0;
2323
+ font-size: 12px;
2324
+ color: var(--dsw-alias-label-secondary);
2325
+ overflow: hidden;
2326
+ text-overflow: ellipsis;
2327
+ white-space: nowrap;
2328
+ }
2329
+ .rstr-row-stats { display: flex; align-items: baseline; gap: 12px; font-size: 12px; color: var(--dsw-alias-label-secondary); font-variant-numeric: tabular-nums; white-space: nowrap; }
2330
+ .rstr-row-stats b { font-weight: 600; color: var(--dsw-alias-label-primary); }
2331
+ .rstr-stat-error { color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 78%, var(--dsw-alias-label-primary)); font-weight: 600; }
2332
+ .rstr-stat-warn { color: color-mix(in srgb, var(--dsw-alias-state-warn-label) 82%, var(--dsw-alias-label-primary)); font-weight: 600; }
2333
+ .rstr-stat-ok { color: color-mix(in srgb, var(--dsw-alias-state-success-primary) 65%, var(--dsw-alias-label-primary)); }
2334
+ .rstr-row-actions { display: flex; align-items: center; gap: 4px; justify-self: end; }
2335
+
2336
+ .rstr-row-detail {
2337
+ display: flex;
2338
+ flex-direction: column;
2339
+ gap: 12px;
2340
+ padding: 10px 14px 18px 14px;
2341
+ margin: 0 0 12px -1px;
2342
+ min-width: 0;
2343
+ background: var(--dsw-alias-bg-layer-2);
2344
+ }
2345
+ .rstr-row-detail-actions { display: flex; gap: 6px; flex-wrap: wrap; padding-top: 4px; }
2346
+
2347
+ /* ---- 成员块 ----------------------------------------------------------- */
2348
+
2349
+ .rstr-members { display: flex; flex-direction: column; gap: 0; border-top: 1px dashed var(--dsw-alias-border-l1); }
2350
+ .rstr-member {
2351
+ display: grid;
2352
+ grid-template-columns: minmax(120px, 170px) minmax(0, 1fr) auto;
2353
+ gap: 6px 16px;
2354
+ align-items: baseline;
2355
+ padding: 9px 4px;
2356
+ border-bottom: 1px solid var(--dsw-alias-border-l1);
2357
+ min-width: 0;
2358
+ }
2359
+ .rstr-member:last-child { border-bottom: none; }
2360
+ .rstr-member-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; min-width: 0; }
2361
+ .rstr-member-name { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary); }
2362
+ .rstr-member-desc { margin: 0; font-size: 12px; color: var(--dsw-alias-label-secondary); min-width: 0; }
2363
+ .rstr-member-meta { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; font-size: 11px; color: var(--dsw-alias-label-secondary); justify-self: end; font-variant-numeric: tabular-nums; }
2364
+
2365
+ /* ---- 队长块 ----------------------------------------------------------- */
2366
+
2367
+ .rstr-captain { display: flex; flex-direction: column; gap: 10px; border-top: 1px dashed var(--dsw-alias-border-l1); padding-top: 12px; }
2368
+ .rstr-meta-grid { display: grid; grid-template-columns: auto repeat(3, auto); justify-content: start; gap: 6px 20px; align-items: baseline; font-size: 12px; font-variant-numeric: tabular-nums; }
2369
+ .rstr-checks { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, max-content)); gap: 0 24px; }
2370
+ .rstr-check { display: flex; justify-content: space-between; gap: 18px; font-size: 12px; border-bottom: 1px solid var(--dsw-alias-border-l1); padding: 4px 0; }
2371
+ .rstr-apply { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
2372
+ .rstr-segmented { display: inline-flex; border: 1px solid var(--dsw-alias-border-l3); }
2373
+ .rstr-seg { border: none; background: transparent; padding: 5px 12px; font-size: 12px; font-family: inherit; cursor: pointer; color: var(--dsw-alias-label-secondary); }
2374
+ .rstr-seg:hover { background: var(--dsw-alias-interactive-bg-hover); }
2375
+ .rstr-seg-on { background: color-mix(in srgb, var(--dsw-alias-state-business-primary) 10%, transparent); color: var(--dsw-alias-label-primary); font-weight: 600; }
2376
+
2377
+ /* ---- 诊断 ------------------------------------------------------------- */
2378
+
2379
+ .rstr-diagnostics { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
2380
+ .rstr-diag {
2381
+ display: flex;
2382
+ gap: 10px;
2383
+ align-items: baseline;
2384
+ flex-wrap: wrap;
2385
+ font-size: 12px;
2386
+ padding: 7px 0 7px 10px;
2387
+ border-left: 2px solid var(--dsw-alias-border-l3);
2388
+ color: var(--dsw-alias-label-primary);
2389
+ }
2390
+ .rstr-diag-error { border-left-color: var(--dsw-alias-state-error-primary); }
2391
+ .rstr-diag-warn { border-left-color: var(--dsw-alias-state-warn-primary); }
2392
+ .rstr-diag-reason { color: var(--dsw-alias-label-primary); }
2393
+ .rstr-diag code.rstr-code { font-size: 11px; }
2394
+
2395
+ /* ---- 档案源 ----------------------------------------------------------- */
2396
+
2397
+ .rstr-sources { display: flex; flex-direction: column; gap: 0; border-top: 1px solid var(--dsw-alias-border-l2); }
2398
+ .rstr-sources-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 12px; }
2399
+ .rstr-source-detail {
2400
+ display: flex;
2401
+ flex-direction: column;
2402
+ gap: 2px;
2403
+ min-width: 0;
2404
+ max-height: 320px;
2405
+ overflow-y: auto;
2406
+ overflow-x: hidden;
2407
+ padding: 6px 0 10px 15px;
2408
+ border-bottom: 1px solid var(--dsw-alias-border-l1);
2409
+ }
2410
+ .rstr-source-roster { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; min-width: 0; font-size: 12px; padding: 3px 0; }
2411
+ .rstr-source-roster > .rstr-muted { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2412
+
2413
+ /* ---- 通用件 ----------------------------------------------------------- */
2414
+
2070
2415
  .rstr-muted { color: var(--dsw-alias-label-secondary); margin: 0; }
2071
2416
  .rstr-small { font-size: 12px; }
2072
2417
  .rstr-mono, .rstr-code, code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
2073
2418
  .rstr-code { font-size: 12px; color: var(--dsw-alias-label-secondary); }
2074
2419
  .rstr-code-strong { font-size: 13px; color: var(--dsw-alias-label-primary); font-weight: 600; }
2075
2420
  .rstr-truncate { display: inline-block; max-width: 420px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; vertical-align: bottom; }
2076
- .rstr-head-actions { display: flex; gap: 8px; flex-wrap: wrap; }
2077
- .rstr-settings-btn { display: inline-flex; align-items: center; gap: 6px; }
2078
- .rstr-settings-glyph { font-size: 14px; line-height: 1; }
2079
- .rstr-toolbar { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 12px; }
2080
- .rstr-toolbar-actions { display: flex; gap: 8px; margin-left: auto; }
2081
- .rstr-sources-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; margin-bottom: 12px; }
2082
- .rstr-settings { display: flex; flex-direction: column; gap: 10px; }
2083
- .rstr-settings-title { margin: 0; font-size: 14px; font-weight: 600; }
2084
-
2085
- .rstr-btn { border: 1px solid var(--dsw-alias-border-l3); background: var(--dsw-alias-bg-layer-1); color: var(--dsw-alias-label-primary); border-radius: 8px; padding: 6px 12px; font-size: 13px; font-family: inherit; cursor: pointer; transition: background .12s ease, border-color .12s ease; }
2421
+ .rstr-ok { color: color-mix(in srgb, var(--dsw-alias-state-success-primary) 62%, var(--dsw-alias-label-primary)); }
2422
+ .rstr-bad { color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 80%, var(--dsw-alias-label-primary)); }
2423
+ .rstr-label { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-secondary); }
2424
+ .rstr-hint { font-size: 12px; color: var(--dsw-alias-label-secondary); margin: 0; }
2425
+ .rstr-hint-warn { color: color-mix(in srgb, var(--dsw-alias-state-warn-label) 75%, var(--dsw-alias-label-primary)); }
2426
+ .rstr-section-title { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-secondary); }
2427
+ .rstr-mt { margin-top: 6px; }
2428
+ .rstr-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 10px; }
2429
+
2430
+ .rstr-btn {
2431
+ border: 1px solid var(--dsw-alias-border-l3);
2432
+ background: transparent;
2433
+ color: var(--dsw-alias-label-primary);
2434
+ border-radius: 6px;
2435
+ padding: 5px 11px;
2436
+ font-size: 12px;
2437
+ font-family: inherit;
2438
+ cursor: pointer;
2439
+ transition: background .12s ease, border-color .12s ease;
2440
+ }
2086
2441
  .rstr-btn:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }
2087
2442
  .rstr-btn:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary); outline-offset: 1px; }
2088
2443
  .rstr-btn:disabled { opacity: .5; cursor: not-allowed; }
2089
2444
  .rstr-btn-primary { background: var(--dsw-alias-button-primary-fill); border-color: var(--dsw-alias-button-primary-fill); color: var(--dsw-alias-label-primary-inverted); }
2090
2445
  .rstr-btn-primary:hover:not(:disabled) { background: var(--dsw-alias-button-primary-hover); border-color: var(--dsw-alias-button-primary-hover); }
2091
- .rstr-btn-danger { color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 72%, var(--dsw-alias-label-primary)); border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 45%, transparent); }
2092
- .rstr-btn-danger:hover:not(:disabled) { background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 14%, transparent); }
2093
- .rstr-btn-ghost { border-style: dashed; }
2094
- .rstr-btn-sm { padding: 3px 9px; font-size: 12px; }
2446
+ .rstr-btn-danger { color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 72%, var(--dsw-alias-label-primary)); }
2447
+ .rstr-btn-danger:hover:not(:disabled) { background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent); border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 45%, transparent); }
2448
+ .rstr-btn-quiet { border-color: transparent; color: var(--dsw-alias-label-secondary); }
2449
+ .rstr-btn-quiet:hover:not(:disabled) { color: var(--dsw-alias-label-primary); }
2450
+ .rstr-btn-sm { padding: 3px 9px; font-size: 11px; }
2095
2451
  .rstr-btn-dashed { width: 100%; border-style: dashed; margin-top: 8px; }
2096
- .rstr-icon-btn { border: none; background: transparent; font-size: 20px; line-height: 1; cursor: pointer; color: var(--dsw-alias-label-secondary); padding: 4px 8px; border-radius: 6px; }
2452
+ .rstr-caret { display: inline-block; margin-left: 6px; font-size: 9px; opacity: .7; }
2453
+ .rstr-icon-btn { border: none; background: transparent; font-size: 18px; line-height: 1; cursor: pointer; color: var(--dsw-alias-label-secondary); padding: 4px 8px; border-radius: 4px; }
2097
2454
  .rstr-icon-btn:hover { background: var(--dsw-alias-interactive-bg-hover); }
2098
-
2099
- .rstr-input { width: 100%; box-sizing: border-box; border: 1px solid var(--dsw-alias-border-l3); background: var(--dsw-alias-bg-layer-1); color: var(--dsw-alias-label-primary); border-radius: 8px; padding: 7px 10px; font-size: 13px; font-family: inherit; }
2455
+ .rstr-settings-btn { display: inline-flex; align-items: center; gap: 6px; }
2456
+ .rstr-settings-glyph { font-size: 13px; line-height: 1; }
2457
+
2458
+ .rstr-input {
2459
+ width: 100%;
2460
+ box-sizing: border-box;
2461
+ border: 1px solid var(--dsw-alias-border-l3);
2462
+ background: var(--dsw-alias-bg-layer-1);
2463
+ color: var(--dsw-alias-label-primary);
2464
+ border-radius: 6px;
2465
+ padding: 6px 10px;
2466
+ font-size: 12px;
2467
+ font-family: inherit;
2468
+ }
2100
2469
  .rstr-input::placeholder { color: var(--dsw-alias-label-secondary); }
2101
2470
  .rstr-input:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary); outline-offset: 1px; }
2102
2471
  .rstr-textarea { resize: vertical; line-height: 1.5; }
2103
2472
  .rstr-textarea.rstr-mono { font-size: 12px; }
2104
- .rstr-search { max-width: 320px; }
2105
-
2106
- .rstr-banner { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 14px; border-radius: 10px; background: var(--dsw-alias-state-warn-tertiary); border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 45%, transparent); color: var(--dsw-alias-label-primary); }
2107
-
2108
- .rstr-tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--dsw-alias-border-l1); }
2109
- .rstr-tab { border: none; background: transparent; padding: 8px 12px; font-size: 13px; color: var(--dsw-alias-label-secondary); cursor: pointer; border-bottom: 2px solid transparent; display: inline-flex; align-items: center; gap: 6px; }
2110
- .rstr-tab:hover { color: var(--dsw-alias-label-primary); }
2111
- .rstr-tab-on { color: var(--dsw-alias-label-primary); border-bottom-color: var(--dsw-alias-state-business-primary); font-weight: 600; }
2112
- .rstr-tab-count { font-size: 11px; padding: 0 6px; border-radius: 999px; background: var(--dsw-alias-button-ghost-active-fill); color: var(--dsw-alias-label-secondary); }
2113
-
2114
- .rstr-rosters { display: grid; grid-template-columns: 200px minmax(0, 1fr); gap: 16px; align-items: start; }
2115
- @media (max-width: 860px) { .rstr-rosters { grid-template-columns: minmax(0, 1fr); } }
2116
- .rstr-tagpool { display: flex; flex-direction: column; gap: 8px; padding: 12px; border: 1px solid var(--dsw-alias-border-l2); border-radius: 12px; background: var(--dsw-alias-bg-layer-2); position: sticky; top: 12px; }
2117
- .rstr-tagpool-title { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-secondary); text-transform: uppercase; letter-spacing: 0.04em; }
2118
- .rstr-tagpool-list { display: flex; flex-direction: column; gap: 4px; }
2119
- .rstr-tag { display: flex; align-items: center; justify-content: space-between; gap: 8px; width: 100%; border: 1px solid transparent; background: transparent; color: var(--dsw-alias-label-secondary); border-radius: 6px; padding: 4px 8px; font-size: 12px; font-family: inherit; cursor: pointer; text-align: left; }
2120
- .rstr-tag:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }
2121
- .rstr-tag:focus-visible { outline: 2px solid var(--dsw-alias-state-business-primary); outline-offset: 1px; }
2122
- .rstr-tag-on { background: var(--dsw-alias-button-ghost-active-fill); border-color: var(--dsw-alias-border-l3); color: var(--dsw-alias-label-primary); font-weight: 600; }
2123
- .rstr-tag-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
2124
- .rstr-tag-count { font-size: 11px; color: var(--dsw-alias-label-secondary); font-variant-numeric: tabular-nums; }
2125
- .rstr-tag-clear { align-self: flex-start; }
2126
- .rstr-cards { display: grid; gap: 12px; grid-template-columns: repeat(auto-fill, minmax(380px, 1fr)); align-items: start; }
2127
- .rstr-card { border: 1px solid var(--dsw-alias-border-l2); border-radius: 12px; padding: 14px 16px; background: var(--dsw-alias-bg-layer-1); color: var(--dsw-alias-label-primary); display: flex; flex-direction: column; gap: 10px; }
2128
- .rstr-card-bad { border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 50%, transparent); }
2129
- .rstr-card-id { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
2130
- .rstr-card-title { margin: 4px 0 2px; font-size: 15px; font-weight: 600; color: var(--dsw-alias-label-primary); }
2131
- .rstr-card-meta { display: flex; gap: 12px; flex-wrap: wrap; font-size: 12px; color: var(--dsw-alias-label-secondary); }
2132
- .rstr-card-actions { display: flex; gap: 6px; flex-wrap: wrap; }
2133
- .rstr-sources { display: flex; flex-direction: column; gap: 10px; }
2134
- .rstr-source-detail { display: flex; flex-direction: column; gap: 6px; border-top: 1px dashed var(--dsw-alias-border-l1); padding-top: 8px; }
2135
- .rstr-source-roster { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 12px; }
2136
- .rstr-source-roster > .rstr-muted { flex: 1 1 auto; }
2137
- .rstr-ok { color: var(--dsw-alias-label-secondary); font-weight: 600; }
2138
-
2139
- .rstr-chip { font-size: 11px; padding: 1px 7px; border-radius: 999px; background: var(--dsw-alias-button-ghost-active-fill); color: var(--dsw-alias-label-secondary); }
2140
- .rstr-chip-policy { background: var(--dsw-alias-state-business-tertiary); color: var(--dsw-alias-label-primary); border: 1px solid color-mix(in srgb, var(--dsw-alias-state-business-primary) 40%, transparent); }
2141
- .rstr-badge { font-size: 11px; padding: 1px 7px; border-radius: 6px; border: 1px solid transparent; color: var(--dsw-alias-label-primary); }
2142
- .rstr-badge-error { background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 16%, transparent); border-color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 45%, transparent); }
2143
- .rstr-badge-warn { background: var(--dsw-alias-state-warn-tertiary); border-color: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 45%, transparent); }
2144
- .rstr-badge-ok { background: var(--dsw-alias-state-success-tertiary); border-color: color-mix(in srgb, var(--dsw-alias-state-success-primary) 45%, transparent); }
2145
- .rstr-badge-info, .rstr-badge-muted { background: var(--dsw-alias-button-ghost-active-fill); color: var(--dsw-alias-label-secondary); }
2146
-
2147
- .rstr-members { display: flex; flex-direction: column; gap: 8px; border-top: 1px dashed var(--dsw-alias-border-l1); padding-top: 10px; }
2148
- .rstr-member { padding: 8px 10px; border-radius: 8px; background: var(--dsw-alias-markdown-code-block); color: var(--dsw-alias-label-primary); }
2149
- .rstr-member-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
2150
- .rstr-member-meta { display: flex; gap: 10px; flex-wrap: wrap; font-size: 12px; color: var(--dsw-alias-label-secondary); margin-top: 4px; }
2151
- .rstr-drift { margin: 4px 0 0; padding-left: 18px; font-size: 12px; color: color-mix(in srgb, var(--dsw-alias-state-warn-label) 72%, var(--dsw-alias-label-primary)); }
2152
-
2153
- .rstr-empty { border: 1px dashed var(--dsw-alias-border-l3); border-radius: 12px; padding: 32px 24px; text-align: center; display: flex; flex-direction: column; gap: 8px; align-items: center; color: var(--dsw-alias-label-primary); }
2154
- .rstr-empty-title { margin: 0; font-size: 15px; font-weight: 600; color: var(--dsw-alias-label-primary); }
2155
-
2156
- .rstr-health { display: flex; flex-direction: column; gap: 14px; }
2157
- .rstr-config { display: flex; flex-direction: column; gap: 6px; padding: 12px 14px; border-radius: 10px; background: var(--dsw-alias-markdown-code-block); color: var(--dsw-alias-label-primary); }
2473
+ .rstr-select { background: var(--dsw-alias-bg-layer-2); color: var(--dsw-alias-label-primary); border: 1px solid var(--dsw-alias-border-l3); border-radius: 6px; padding: 5px 8px; font-size: 12px; max-width: 320px; }
2474
+
2475
+ .rstr-chip { font-size: 11px; padding: 0 6px; border-radius: 4px; background: var(--dsw-alias-markdown-tag); color: var(--dsw-alias-label-secondary); font-variant-numeric: tabular-nums; }
2476
+ .rstr-chip-policy { color: var(--dsw-alias-label-secondary); background: color-mix(in srgb, var(--dsw-alias-state-business-primary) 9%, transparent); }
2477
+ .rstr-badge { font-size: 11px; padding: 0 6px; border-radius: 4px; font-weight: 600; }
2478
+ .rstr-badge-error { background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 14%, transparent); color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 80%, var(--dsw-alias-label-primary)); }
2479
+ .rstr-badge-warn { background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 16%, transparent); color: color-mix(in srgb, var(--dsw-alias-state-warn-label) 85%, var(--dsw-alias-label-primary)); }
2480
+ .rstr-badge-ok { background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 14%, transparent); color: color-mix(in srgb, var(--dsw-alias-state-success-primary) 62%, var(--dsw-alias-label-primary)); }
2481
+ .rstr-badge-info, .rstr-badge-muted { background: var(--dsw-alias-markdown-tag); color: var(--dsw-alias-label-secondary); }
2482
+ .rstr-drift { margin: 4px 0 0; padding-left: 16px; font-size: 12px; color: color-mix(in srgb, var(--dsw-alias-state-warn-label) 72%, var(--dsw-alias-label-primary)); }
2483
+
2484
+ /* ---- 空态 / 健康 / 页脚 ------------------------------------------------ */
2485
+
2486
+ .rstr-empty { display: flex; flex-direction: column; gap: 6px; align-items: flex-start; padding: 40px 2px; color: var(--dsw-alias-label-primary); }
2487
+ .rstr-empty-title { margin: 0; font-size: 15px; font-weight: 600; }
2488
+ .rstr-health { display: flex; flex-direction: column; gap: 14px; padding: 16px 28px 28px; }
2489
+ .rstr-config { display: flex; flex-direction: column; gap: 4px; padding: 12px 14px; background: var(--dsw-alias-bg-layer-2); }
2158
2490
  .rstr-config-row { display: flex; gap: 12px; align-items: baseline; }
2159
- .rstr-config-row .rstr-label { min-width: 160px; }
2160
- .rstr-hint-cards { display: grid; gap: 10px; }
2161
- .rstr-hint-card { border: 1px solid var(--dsw-alias-border-l2); border-radius: 10px; padding: 10px 12px; color: var(--dsw-alias-label-primary); }
2162
- .rstr-hint-card-head { display: flex; gap: 8px; align-items: center; margin-bottom: 4px; }
2491
+ .rstr-config-row .rstr-label { min-width: 150px; }
2492
+ .rstr-hint-cards { display: grid; gap: 0; border-top: 1px solid var(--dsw-alias-border-l2); }
2493
+ .rstr-hint-card { padding: 10px 2px; border-bottom: 1px solid var(--dsw-alias-border-l1); }
2494
+ .rstr-hint-card-head { display: flex; gap: 8px; align-items: center; margin-bottom: 2px; }
2495
+ .rstr-settings { display: flex; flex-direction: column; gap: 10px; }
2496
+ .rstr-settings-title { margin: 0; font-size: 13px; font-weight: 600; }
2497
+ .rstr-settings-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
2498
+ .rstr-settings-row .rstr-label { min-width: 110px; }
2499
+ .rstr-settings-field { display: flex; flex-direction: column; gap: 6px; }
2500
+ .rstr-settings-inline { display: flex; align-items: center; gap: 8px; }
2501
+ .rstr-settings-inline .rstr-input { flex: 1 1 auto; min-width: 0; }
2163
2502
 
2164
- .rstr-diagnostics { list-style: none; margin: 6px 0 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
2165
- .rstr-diag { display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; font-size: 12px; padding: 6px 8px; border-radius: 8px; background: var(--dsw-alias-markdown-code-block); color: var(--dsw-alias-label-primary); }
2166
- .rstr-diag-reason { color: var(--dsw-alias-label-primary); }
2503
+ .rstr-foot {
2504
+ display: flex;
2505
+ justify-content: space-between;
2506
+ gap: 12px;
2507
+ padding: 12px 28px 16px;
2508
+ margin-top: auto;
2509
+ border-top: 1px solid var(--dsw-alias-border-l1);
2510
+ color: var(--dsw-alias-label-secondary);
2511
+ font-size: 11px;
2512
+ font-variant-numeric: tabular-nums;
2513
+ }
2514
+
2515
+ /* ---- 弹窗 / 编辑器 ---------------------------------------------------- */
2167
2516
 
2168
2517
  .rstr-overlay { position: fixed; inset: 0; background: var(--dsw-alias-bg-mask-3); display: flex; align-items: flex-start; justify-content: center; padding: 5vh 16px; z-index: 1000; overflow: auto; }
2169
- .rstr-modal { background: var(--dsw-alias-bg-layer-1); color: var(--dsw-alias-label-primary); border: 1px solid var(--dsw-alias-border-l2); border-radius: 14px; width: 640px; max-width: 100%; box-shadow: 0 24px 64px rgba(0,0,0,.32); display: flex; flex-direction: column; max-height: 90vh; }
2518
+ .rstr-modal { background: var(--dsw-alias-bg-layer-1); color: var(--dsw-alias-label-primary); border: 1px solid var(--dsw-alias-border-l2); border-radius: 8px; width: 640px; max-width: 100%; box-shadow: 0 24px 64px var(--dsw-alias-bg-mask-1); display: flex; flex-direction: column; max-height: 90vh; }
2170
2519
  .rstr-modal-head { display: flex; align-items: center; justify-content: space-between; padding: 14px 18px; border-bottom: 1px solid var(--dsw-alias-border-l1); }
2171
- .rstr-modal-title { margin: 0; font-size: 15px; font-weight: 600; color: var(--dsw-alias-label-primary); }
2520
+ .rstr-modal-title { margin: 0; font-size: 14px; font-weight: 600; }
2172
2521
  .rstr-modal-body { padding: 16px 18px; overflow: auto; display: flex; flex-direction: column; gap: 12px; }
2173
2522
  .rstr-modal-foot { padding: 12px 18px; border-top: 1px solid var(--dsw-alias-border-l1); display: flex; justify-content: flex-end; gap: 8px; }
2174
2523
  .rstr-modal-foot-actions { display: flex; gap: 8px; }
2175
-
2176
2524
  .rstr-field { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
2177
- .rstr-label { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-secondary); }
2178
- .rstr-hint { font-size: 12px; color: var(--dsw-alias-label-secondary); margin: 0; }
2179
- .rstr-hint-warn { color: color-mix(in srgb, var(--dsw-alias-state-warn-label) 70%, var(--dsw-alias-label-primary)); }
2180
- .rstr-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 10px; }
2181
- .rstr-section-title { font-size: 13px; font-weight: 600; color: var(--dsw-alias-label-primary); }
2182
- .rstr-mt { margin-top: 6px; }
2183
-
2184
2525
  .rstr-editor-toolbar { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
2185
2526
  .rstr-editor-toolbar .rstr-input { width: 110px; }
2186
- .rstr-captain { display: flex; flex-direction: column; gap: 8px; border-top: 1px dashed var(--dsw-alias-border-l3); margin-top: 12px; padding-top: 10px; }
2187
- .rstr-meta-grid { display: grid; grid-template-columns: auto repeat(4, minmax(0, auto)); gap: 6px 12px; align-items: baseline; font-size: 12px; }
2188
- .rstr-checks { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
2189
- .rstr-check { display: flex; justify-content: space-between; gap: 12px; font-size: 12px; border-bottom: 1px solid var(--dsw-alias-border-l1); padding-bottom: 3px; }
2190
- .rstr-apply { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
2191
- .rstr-select { background: var(--dsw-alias-bg-l2); color: var(--dsw-alias-label-primary); border: 1px solid var(--dsw-alias-border-l3); border-radius: 8px; padding: 5px 8px; font-size: 12px; max-width: 320px; }
2192
- .rstr-bad { color: var(--dsw-alias-state-error-primary); }
2193
- .rstr-segmented { display: inline-flex; border: 1px solid var(--dsw-alias-border-l3); border-radius: 8px; overflow: hidden; }
2194
- .rstr-seg { border: none; background: transparent; padding: 5px 12px; font-size: 12px; cursor: pointer; color: var(--dsw-alias-label-secondary); }
2195
- .rstr-seg:hover { background: var(--dsw-alias-interactive-bg-hover); }
2196
- .rstr-seg-on { background: var(--dsw-alias-state-business-tertiary); color: var(--dsw-alias-label-primary); font-weight: 600; box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--dsw-alias-state-business-primary) 45%, transparent); }
2197
-
2198
- .rstr-member-editor { border: 1px solid var(--dsw-alias-border-l2); border-radius: 10px; padding: 10px 12px; display: flex; flex-direction: column; gap: 8px; color: var(--dsw-alias-label-primary); }
2527
+ .rstr-member-editor { border: 1px solid var(--dsw-alias-border-l2); border-radius: 6px; padding: 10px 12px; display: flex; flex-direction: column; gap: 8px; }
2199
2528
  .rstr-member-editor-head { display: flex; align-items: center; gap: 8px; }
2200
2529
  .rstr-member-editor-head .rstr-input { width: 180px; }
2201
- .rstr-step { width: 20px; height: 20px; border-radius: 50%; background: var(--dsw-alias-button-ghost-active-fill); font-size: 11px; display: inline-flex; align-items: center; justify-content: center; color: var(--dsw-alias-label-secondary); }
2202
-
2203
- .rstr-error { border: 1px solid color-mix(in srgb, var(--dsw-alias-state-error-primary) 45%, transparent); background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 12%, transparent); border-radius: 10px; padding: 10px 12px; display: flex; flex-direction: column; gap: 6px; color: var(--dsw-alias-label-primary); }
2204
- .rstr-error-title { margin: 0; font-weight: 600; color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 72%, var(--dsw-alias-label-primary)); }
2205
- .rstr-confirm { border: 1px solid color-mix(in srgb, var(--dsw-alias-state-warn-primary) 45%, transparent); background: var(--dsw-alias-state-warn-tertiary); border-radius: 10px; padding: 10px 12px; display: flex; flex-direction: column; gap: 8px; align-items: flex-start; color: var(--dsw-alias-label-primary); }
2206
-
2207
- .rstr-toast { position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%); background: var(--dsw-alias-toast-bg); color: var(--dsw-alias-toast-label); padding: 8px 16px; border-radius: 999px; font-size: 13px; z-index: 1100; box-shadow: 0 8px 24px rgba(0,0,0,.24); }
2208
-
2209
- .rstr-foot { display: flex; justify-content: space-between; gap: 12px; border-top: 1px solid var(--dsw-alias-border-l1); padding-top: 10px; margin-top: 4px; color: var(--dsw-alias-label-secondary); }
2210
-
2211
- .rstr-settings-row { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
2212
- .rstr-settings-row .rstr-label { min-width: 120px; }
2213
- .rstr-settings-field { display: flex; flex-direction: column; gap: 6px; }
2214
- .rstr-settings-inline { display: flex; align-items: center; gap: 8px; }
2215
- .rstr-settings-inline .rstr-input { flex: 1 1 auto; min-width: 0; }
2530
+ .rstr-step { width: 18px; height: 18px; border: 1px solid var(--dsw-alias-border-l3); font-size: 10px; display: inline-flex; align-items: center; justify-content: center; color: var(--dsw-alias-label-secondary); font-variant-numeric: tabular-nums; }
2531
+ .rstr-error { border-left: 3px solid var(--dsw-alias-state-error-primary); background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 8%, transparent); padding: 10px 12px; display: flex; flex-direction: column; gap: 6px; }
2532
+ .rstr-error-title { margin: 0; font-weight: 600; color: color-mix(in srgb, var(--dsw-alias-state-error-primary) 78%, var(--dsw-alias-label-primary)); }
2533
+ .rstr-confirm { border-left: 3px solid var(--dsw-alias-state-warn-primary); background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 8%, transparent); padding: 10px 12px; display: flex; flex-direction: column; gap: 8px; align-items: flex-start; }
2534
+ .rstr-toast { position: fixed; bottom: 24px; left: 50%; transform: translateX(-50%); background: var(--dsw-alias-toast-bg); color: var(--dsw-alias-toast-label); padding: 8px 16px; border-radius: 4px; font-size: 12px; z-index: 1100; }
2535
+
2536
+ /* ---- 窄面板 ----------------------------------------------------------- */
2537
+
2538
+ @media (max-width: 860px) {
2539
+ .rstr-head, .rstr-tabs, .rstr-rosters-main, .rstr-health, .rstr-foot { padding-left: 18px; padding-right: 18px; }
2540
+ .rstr-banner { margin-left: 18px; margin-right: 18px; }
2541
+ .rstr-rosters { grid-template-columns: minmax(0, 1fr); }
2542
+ .rstr-tagpool {
2543
+ position: static;
2544
+ flex-direction: row;
2545
+ flex-wrap: wrap;
2546
+ align-items: center;
2547
+ gap: 6px;
2548
+ padding: 10px 18px;
2549
+ border-right: none;
2550
+ border-bottom: 1px solid var(--dsw-alias-border-l1);
2551
+ }
2552
+ .rstr-tagpool-title { display: none; }
2553
+ .rstr-tagpool-list { flex-direction: row; flex-wrap: wrap; gap: 4px; min-width: 0; }
2554
+ .rstr-tag { border-left: none; border-bottom: 2px solid transparent; border-radius: 0; white-space: nowrap; }
2555
+ .rstr-tag-on { border-left: none; border-bottom-color: var(--dsw-alias-state-business-primary); background: transparent; }
2556
+ .rstr-tag-clear { margin-top: 0; flex: 0 0 auto; }
2557
+ .rstr-row-body { grid-template-columns: minmax(0, 1fr) auto; }
2558
+ .rstr-row-id { grid-column: 1; }
2559
+ .rstr-row-text { grid-column: 1; }
2560
+ .rstr-row-stats { grid-column: 1; }
2561
+ .rstr-row-actions { grid-column: 2; grid-row: 1; align-self: start; }
2562
+ .rstr-member { grid-template-columns: minmax(0, 1fr); gap: 2px; }
2563
+ .rstr-member-meta { justify-self: start; }
2564
+ }
2216
2565
  `;
2217
2566
 
2218
2567
  function ensureStyle() {
package/lib/library.js CHANGED
@@ -58,6 +58,11 @@ export function collectLibrary(ctx, config, meta) {
58
58
  missing: scan.missing === true,
59
59
  stats: scan.stats,
60
60
  rosters: scan.rosters.map((roster) => serializeRoster(roster, scan.diagnostics)),
61
+ // 面板抬头要显示"这份库属于哪个组织",只给 id 与标题,不带成员细节。
62
+ organization:
63
+ scan.organization === null || scan.organization === undefined
64
+ ? null
65
+ : { id: scan.organization.organization, title: scan.organization.title ?? "" },
61
66
  diagnostics: scan.diagnostics,
62
67
  });
63
68
  }
package/locale/en.json CHANGED
@@ -60,7 +60,11 @@
60
60
  "tagPool": "Tags",
61
61
  "tagPoolEmpty": "No tags yet — add `tags:` to an archive.",
62
62
  "tagClear": "Clear tags",
63
- "settings": "Settings"
63
+ "settings": "Settings",
64
+ "metaRosters": "rosters",
65
+ "metaMembers": "members",
66
+ "metaTeams": "teams",
67
+ "metaOrganization": "Organization {name}"
64
68
  },
65
69
  "roster": {
66
70
  "members": "{count} members",
@@ -79,7 +83,9 @@
79
83
  "noMembers": "This roster has no members.",
80
84
  "diagnostics": "{count} findings",
81
85
  "showMembers": "Show members",
82
- "hideMembers": "Hide members"
86
+ "hideMembers": "Hide members",
87
+ "warnings": "{count} warnings",
88
+ "deployedDrifted": "In {teams} ({count} drifted)"
83
89
  },
84
90
  "member": {
85
91
  "prompt": "Prompt",
@@ -109,7 +115,10 @@
109
115
  "faithful": "Matches the roster",
110
116
  "drift": "Differs from the roster",
111
117
  "promptChars": "{count} prompt characters",
112
- "driftDetail": "{field}: roster {wanted}, runtime {actual}"
118
+ "driftDetail": "{field}: roster {wanted}, runtime {actual}",
119
+ "showMembers": "Show members",
120
+ "hideMembers": "Hide members",
121
+ "taskCount": "{count} tasks"
113
122
  },
114
123
  "editor": {
115
124
  "createTitle": "New roster",
package/locale/zh.json CHANGED
@@ -60,7 +60,11 @@
60
60
  "tagPool": "标签",
61
61
  "tagPoolEmpty": "还没有标签——给档案加 `tags:`。",
62
62
  "tagClear": "清除标签",
63
- "settings": "设置"
63
+ "settings": "设置",
64
+ "metaRosters": "份档案",
65
+ "metaMembers": "名成员",
66
+ "metaTeams": "支团队",
67
+ "metaOrganization": "组织 {name}"
64
68
  },
65
69
  "roster": {
66
70
  "members": "{count} 名成员",
@@ -79,7 +83,9 @@
79
83
  "noMembers": "这份档案没有成员。",
80
84
  "diagnostics": "{count} 条发现",
81
85
  "showMembers": "展开成员",
82
- "hideMembers": "收起成员"
86
+ "hideMembers": "收起成员",
87
+ "warnings": "{count} 条提醒",
88
+ "deployedDrifted": "在 {teams}({count} 处不一致)"
83
89
  },
84
90
  "member": {
85
91
  "prompt": "人设",
@@ -109,7 +115,10 @@
109
115
  "faithful": "与档案一致",
110
116
  "drift": "与档案不一致",
111
117
  "promptChars": "{count} 字人设",
112
- "driftDetail": "{field}:档案 {wanted},运行时 {actual}"
118
+ "driftDetail": "{field}:档案 {wanted},运行时 {actual}",
119
+ "showMembers": "展开成员",
120
+ "hideMembers": "收起成员",
121
+ "taskCount": "{count} 个任务"
113
122
  },
114
123
  "editor": {
115
124
  "createTitle": "新建档案",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stofone/dsh-agent-roster",
3
- "version": "0.8.2",
3
+ "version": "0.9.0",
4
4
  "description": "多 Agent 团队的静态成员档案定义与校验层:档案库在面板里看得见、改得动,团队成员的人设、模型与工具边界固化成可校验、可版本化的文件,并在 dsh-agent-teams 创建成员时把档案桥接给运行时。",
5
5
  "type": "module",
6
6
  "main": "index.js",