dsh-group-status 0.2.0 → 0.2.1

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 (62) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.en.md +25 -12
  3. package/README.md +25 -12
  4. package/lib/client.js +709 -191
  5. package/lib/client.js.map +1 -1
  6. package/lib/tsconfig.tsbuildinfo +1 -1
  7. package/lib/types/client/BadgeSettingsCard.d.ts +24 -0
  8. package/lib/types/client/BadgeSettingsCard.d.ts.map +1 -0
  9. package/lib/types/client/BadgeSettingsCard.js +73 -0
  10. package/lib/types/client/BadgeSettingsCard.js.map +1 -0
  11. package/lib/types/client/WorkspacePicker.d.ts +2 -2
  12. package/lib/types/client/WorkspacePicker.d.ts.map +1 -1
  13. package/lib/types/client/badge-field.d.ts +44 -0
  14. package/lib/types/client/badge-field.d.ts.map +1 -0
  15. package/lib/types/client/badge-field.js +77 -0
  16. package/lib/types/client/badge-field.js.map +1 -0
  17. package/lib/types/client/badge-settings.d.ts +15 -3
  18. package/lib/types/client/badge-settings.d.ts.map +1 -1
  19. package/lib/types/client/badge-settings.js +38 -6
  20. package/lib/types/client/badge-settings.js.map +1 -1
  21. package/lib/types/client/group-status.d.ts +66 -1
  22. package/lib/types/client/group-status.d.ts.map +1 -1
  23. package/lib/types/client/group-status.js +109 -0
  24. package/lib/types/client/group-status.js.map +1 -1
  25. package/lib/types/client/index.d.ts.map +1 -1
  26. package/lib/types/client/index.js +31 -1
  27. package/lib/types/client/index.js.map +1 -1
  28. package/lib/types/client/locales.d.ts +44 -0
  29. package/lib/types/client/locales.d.ts.map +1 -1
  30. package/lib/types/client/locales.js +44 -0
  31. package/lib/types/client/locales.js.map +1 -1
  32. package/lib/types/client/rows/GroupBadge.d.ts +12 -7
  33. package/lib/types/client/rows/GroupBadge.d.ts.map +1 -1
  34. package/lib/types/client/rows/GroupBadge.js +56 -45
  35. package/lib/types/client/rows/GroupBadge.js.map +1 -1
  36. package/lib/types/client/rows/Rows.d.ts +6 -6
  37. package/lib/types/client/rows/Rows.d.ts.map +1 -1
  38. package/lib/types/client/rows/Rows.js +5 -5
  39. package/lib/types/client/rows/Rows.js.map +1 -1
  40. package/lib/types/client/rows/WorkspaceBrowser.d.ts +1 -1
  41. package/lib/types/client/rows/WorkspaceBrowser.d.ts.map +1 -1
  42. package/lib/types/client/rows/WorkspaceBrowser.js +47 -24
  43. package/lib/types/client/rows/WorkspaceBrowser.js.map +1 -1
  44. package/lib/types/client/session-actions/ArchiveSession.d.ts +3 -3
  45. package/lib/types/client/session-actions/ArchiveSession.d.ts.map +1 -1
  46. package/lib/types/client/session-actions/ForkSession.d.ts +1 -1
  47. package/lib/types/client/session-actions/ForkSession.d.ts.map +1 -1
  48. package/lib/types/client/session-actions/PinSession.d.ts +2 -2
  49. package/lib/types/client/session-actions/PinSession.d.ts.map +1 -1
  50. package/lib/types/client/session-actions/RenameSession.d.ts +2 -2
  51. package/lib/types/client/session-actions/RenameSession.d.ts.map +1 -1
  52. package/lib/types/client/session-actions/RowActionToast.d.ts +1 -1
  53. package/lib/types/client/session-actions/RowActionToast.d.ts.map +1 -1
  54. package/lib/types/client/tree.d.ts +5 -5
  55. package/lib/types/client/tree.d.ts.map +1 -1
  56. package/lib/types/client/tree.js +4 -14
  57. package/lib/types/client/tree.js.map +1 -1
  58. package/lib/types/index.d.ts +8 -33
  59. package/lib/types/index.d.ts.map +1 -1
  60. package/lib/types/index.js +13 -1
  61. package/lib/types/index.js.map +1 -1
  62. package/package.json +4 -4
@@ -0,0 +1,24 @@
1
+ import type { JSX } from 'react';
2
+ import { type SettingsFormScope } from '@deepseek-ai/dsh-client-ui-primitives';
3
+ import type { WorkspaceKey } from './locales.ts';
4
+ /**
5
+ * 卡片 props:宿主设置表单 + 本命名空间文案取值器。
6
+ *
7
+ * `scope` 直接用官方 `SettingsFormScope`(= `configForms.get(条目 id)` 的运行时形状:
8
+ * `getSnapshot` / `subscribe` / `mutate`),因此不需要本地复刻契约,也就不会与宿主漂移。
9
+ * `locale: NS` 由框架按声明注入 `t`。
10
+ */
11
+ export interface BadgeSettingsCardProps {
12
+ readonly scope: SettingsFormScope<Record<string, unknown>>;
13
+ readonly t: (key: WorkspaceKey) => string;
14
+ }
15
+ /**
16
+ * 渲染折叠徽标的设置表单。
17
+ *
18
+ * 模型与投影都按 `scope` 记忆:宿主换一份表单(条目重新服务)时整体重建,旧模型
19
+ * 在 effect 清理里 `dispose()`,不会留下悬挂订阅。
20
+ * @param props - 宿主设置表单与文案取值器。
21
+ * @returns 官方表单框架包着本插件的开关字段。
22
+ */
23
+ export declare function BadgeSettingsCard({ scope, t }: BadgeSettingsCardProps): JSX.Element;
24
+ //# sourceMappingURL=BadgeSettingsCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BadgeSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/BadgeSettingsCard.tsx"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,OAAO,CAAA;AAChC,OAAO,EAKL,KAAK,iBAAiB,EACvB,MAAM,uCAAuC,CAAA;AAE9C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAGhD;;;;;;GAMG;AACH,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,KAAK,EAAE,iBAAiB,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IAC1D,QAAQ,CAAC,CAAC,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,MAAM,CAAA;CAC1C;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,sBAAsB,GAAG,GAAG,CAAC,OAAO,CA2DnF"}
@@ -0,0 +1,73 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * 折叠徽标的设置卡片:插件 → dsh-group-status(bundle 详情页的配置表单)。
4
+ *
5
+ * 为什么需要这张卡片:0.2.0 起宿主把插件 `Config`(`src/index.ts`,根节点
6
+ * `.volatile()`)投影到客户端 `configForms` 服务上,但**不会**自动把表单画进
7
+ * 「插件」页——插件页只在客户端往 `plugins.bundle.config` 注册了卡片时才渲染
8
+ * (见 dsh-later / dsh-gitea-dispatch 的同款做法)。没有它,README「设置项」一节
9
+ * 描述的配置表单在 GUI 里根本不存在。
10
+ *
11
+ * 视觉与交互**不自造**,全部交给官方组件(`@deepseek-ai/dsh-client-ui-primitives`):
12
+ * - `SettingsForm`:表单框架——只读提示、不可用提示、保存按钮、失败行、间距;
13
+ * - `SettingsFormModel`:分步草稿与保存(revision 围栏、宿主拒绝时不丢草稿);
14
+ * - `Switch`:开关本体。
15
+ * 官方设置页(设置 → 内置插件 → 子智能体 / 网页搜索)用的就是这三件,本卡片的
16
+ * 类名与取值也逐条对齐它们的 CSS(见 `BadgeSettingsCard.module.css` 头部)。
17
+ *
18
+ * 字段定义在 `badge-field.ts`(纯逻辑,可单测);这里只管把它们接到模型与槽位上。
19
+ */
20
+ import { useEffect, useId, useMemo, useSyncExternalStore } from 'react';
21
+ import { SettingsForm, SettingsFormModel, Switch, } from '@deepseek-ai/dsh-client-ui-primitives';
22
+ import { ALL_BADGE_FIELDS, BADGE_FIELDS, isDraftEnabled } from "./badge-field.js";
23
+ import css from './BadgeSettingsCard.module.css';
24
+ /**
25
+ * 渲染折叠徽标的设置表单。
26
+ *
27
+ * 模型与投影都按 `scope` 记忆:宿主换一份表单(条目重新服务)时整体重建,旧模型
28
+ * 在 effect 清理里 `dispose()`,不会留下悬挂订阅。
29
+ * @param props - 宿主设置表单与文案取值器。
30
+ * @returns 官方表单框架包着本插件的开关字段。
31
+ */
32
+ export function BadgeSettingsCard({ scope, t }) {
33
+ const model = useMemo(() => new SettingsFormModel(scope, ALL_BADGE_FIELDS), [scope]);
34
+ useEffect(() => () => { model.dispose(); }, [model]);
35
+ // 投影:框架状态 + 所有字段的草稿。模型的 publish 会在宿主折叠或草稿变化时重算。
36
+ const store = useMemo(() => model.bind(() => ({
37
+ ...model.shell(),
38
+ fields: ALL_BADGE_FIELDS.map(spec => ({ field: spec.field, text: model.field(spec.field).text })),
39
+ })), [model]);
40
+ const state = useSyncExternalStore(store.subscribe, store.getSnapshot);
41
+ const actions = useMemo(() => model.actions(), [model]);
42
+ const badgeSectionId = useId();
43
+ const hoverSectionId = useId();
44
+ const countSectionId = useId();
45
+ const labels = {
46
+ unavailable: t('settings.unavailable'),
47
+ readOnly: t('settings.readOnly'),
48
+ saveFailed: t('settings.saveFailed'),
49
+ save: t('settings.save'),
50
+ saving: t('settings.saving'),
51
+ };
52
+ // 按字段名查草稿文本。
53
+ const fieldText = (field) => {
54
+ const found = state.fields.find(f => f.field === field);
55
+ return found?.text ?? 'true';
56
+ };
57
+ return (_jsxs(SettingsForm, { labels: labels, state: state, onSave: () => { actions.save(); }, onDiscard: () => { actions.discard(); }, children: [_jsxs("section", { className: css.section, "aria-labelledby": badgeSectionId, children: [_jsx("h3", { className: css.heading, id: badgeSectionId, children: t('settings.badge.section') }), _jsx(ToggleRow, { field: BADGE_FIELDS.showRunningInBadge, text: fieldText(BADGE_FIELDS.showRunningInBadge), label: t('settings.badge.showRunning'), hint: t('settings.badge.showRunningHint'), state: state, actions: actions }), _jsx(ToggleRow, { field: BADGE_FIELDS.showPendingInBadge, text: fieldText(BADGE_FIELDS.showPendingInBadge), label: t('settings.badge.showPending'), hint: t('settings.badge.showPendingHint'), state: state, actions: actions }), _jsx(ToggleRow, { field: BADGE_FIELDS.showCompletedInBadge, text: fieldText(BADGE_FIELDS.showCompletedInBadge), label: t('settings.badge.showCompleted'), hint: t('settings.badge.showCompletedHint'), state: state, actions: actions }), _jsx(ToggleRow, { field: BADGE_FIELDS.showScheduledInBadge, text: fieldText(BADGE_FIELDS.showScheduledInBadge), label: t('settings.badge.showScheduled'), hint: t('settings.badge.showScheduledHint'), state: state, actions: actions }), _jsx(ToggleRow, { field: BADGE_FIELDS.showWaitingReviewInBadge, text: fieldText(BADGE_FIELDS.showWaitingReviewInBadge), label: t('settings.badge.showWaitingReview'), hint: t('settings.badge.showWaitingReviewHint'), state: state, actions: actions })] }), _jsxs("section", { className: css.section, "aria-labelledby": hoverSectionId, children: [_jsx("h3", { className: css.heading, id: hoverSectionId, children: t('settings.hover.section') }), _jsx(ToggleRow, { field: BADGE_FIELDS.showHoverDetails, text: fieldText(BADGE_FIELDS.showHoverDetails), label: t('settings.hover.showDetails'), hint: t('settings.hover.showDetailsHint'), state: state, actions: actions })] }), _jsxs("section", { className: css.section, "aria-labelledby": countSectionId, children: [_jsx("h3", { className: css.heading, id: countSectionId, children: t('settings.count.section') }), _jsx(NumberRow, { field: BADGE_FIELDS.countThreshold, text: fieldText(BADGE_FIELDS.countThreshold), label: t('settings.count.threshold'), hint: t('settings.count.thresholdHint'), state: state, actions: actions })] })] }));
58
+ }
59
+ /** 单行开关:label + Switch + hint。 */
60
+ function ToggleRow({ field, text, label, hint, state, actions }) {
61
+ return (_jsxs("div", { className: css.badgeField, children: [_jsxs("div", { className: css.badgeToggleRow, children: [_jsx("span", { className: css.badgeToggleLabel, children: label }), _jsx(Switch, { checked: isDraftEnabled(text), label: label, disabled: !state.writable || state.saving, onChange: next => { actions.edit(field, next ? 'true' : 'false'); } })] }), _jsx("p", { className: css.hint, children: hint })] }));
62
+ }
63
+ /** 单行数字输入:label + 带加减按钮的数字输入 + hint。 */
64
+ function NumberRow({ field, text, label, hint, state, actions }) {
65
+ const disabled = !state.writable || state.saving;
66
+ const currentValue = Number(text) || 0;
67
+ const decrement = () => { if (!disabled && currentValue > 0)
68
+ actions.edit(field, String(currentValue - 1)); };
69
+ const increment = () => { if (!disabled)
70
+ actions.edit(field, String(currentValue + 1)); };
71
+ return (_jsxs("div", { className: css.badgeField, children: [_jsxs("div", { className: css.badgeToggleRow, children: [_jsx("span", { className: css.badgeToggleLabel, children: label }), _jsxs("div", { className: css.badgeNumberControl, children: [_jsx("button", { type: "button", className: css.badgeNumberButton, disabled: disabled || currentValue <= 0, onClick: decrement, "aria-label": "\u51CF\u5C11", children: "\u2212" }), _jsx("span", { className: css.badgeNumberValue, children: text }), _jsx("button", { type: "button", className: css.badgeNumberButton, disabled: disabled, onClick: increment, "aria-label": "\u589E\u52A0", children: "+" })] })] }), _jsx("p", { className: css.hint, children: hint })] }));
72
+ }
73
+ //# sourceMappingURL=BadgeSettingsCard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BadgeSettingsCard.js","sourceRoot":"","sources":["../../../src/client/BadgeSettingsCard.tsx"],"names":[],"mappings":"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"}
@@ -48,12 +48,12 @@ export interface WorkspacePickFlowProps {
48
48
  * @param props - owner-controlled flow props.
49
49
  * @returns menu + dialog elements.
50
50
  */
51
- export declare function WorkspacePickFlow({ t, open, anchorRef, useWorkspaces, createWorkspace, useDirectoryFlow, renderDirectoryFlow, onPick, onClose, addOnly, onBusyChange, side, selectedId, }: WorkspacePickFlowProps): import("react").JSX.Element;
51
+ export declare function WorkspacePickFlow({ t, open, anchorRef, useWorkspaces, createWorkspace, useDirectoryFlow, renderDirectoryFlow, onPick, onClose, addOnly, onBusyChange, side, selectedId, }: WorkspacePickFlowProps): any;
52
52
  /**
53
53
  * The conversation empty-state registration: adapts the owner share to the
54
54
  * core flow (all state and semantics live in the flow / the owner).
55
55
  * @param props - empty-state slot props (owner share + injected creation callback).
56
56
  * @returns the flow element.
57
57
  */
58
- export declare function WorkspacePicker({ open, anchorRef, useWorkspaces, selectedId, onPick, onClose, createWorkspace, useDirectoryFlow, renderSlot, t, }: WorkspacePickerProps): import("react").JSX.Element;
58
+ export declare function WorkspacePicker({ open, anchorRef, useWorkspaces, selectedId, onPick, onClose, createWorkspace, useDirectoryFlow, renderSlot, t, }: WorkspacePickerProps): any;
59
59
  //# sourceMappingURL=WorkspacePicker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"WorkspacePicker.d.ts","sourceRoot":"","sources":["../../../src/client/WorkspacePicker.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAKjD,OAAO,KAAK,EACV,WAAW,EAAE,iBAAiB,EAAE,aAAa,EAC9C,MAAM,kDAAkD,CAAA;AAEzD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAA;AAC5E,OAAO,KAAK,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAKxF,8EAA8E;AAC9E,MAAM,WAAW,sBAAsB;IACrC,kFAAkF;IAClF,CAAC,EAAE,oBAAoB,CAAC,GAAG,CAAC,CAAA;IAC5B,oEAAoE;IACpE,IAAI,EAAE,OAAO,CAAA;IACb,kEAAkE;IAClE,SAAS,CAAC,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,SAAS,CAAA;IACrD,uEAAuE;IACvE,aAAa,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,CAAC,KAAK,CAAC,CAAA;IAClE,yDAAyD;IACzD,eAAe,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,aAAa,CAAC,CAAA;IACpE,0HAA0H;IAC1H,gBAAgB,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAA;IAC/C,+GAA+G;IAC/G,mBAAmB,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,SAAS,CAAA;IAClE,8CAA8C;IAC9C,MAAM,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,IAAI,CAAA;IAC1C,8DAA8D;IAC9D,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,6DAA6D;IAC7D,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC,2DAA2D;IAC3D,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,qDAAqD;IACrD,IAAI,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,OAAO,CAAA;IACjC,sEAAsE;IACtE,UAAU,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;CACrC;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,CAAC,EACD,IAAI,EACJ,SAAS,EACT,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,MAAM,EACN,OAAO,EACP,OAAe,EACf,YAAY,EACZ,IAAe,EACf,UAAU,GACX,EAAE,sBAAsB,+BAmJxB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,SAAS,EACT,aAAa,EACb,UAAU,EACV,MAAM,EACN,OAAO,EACP,eAAe,EACf,gBAAgB,EAChB,UAAU,EACV,CAAC,GACF,EAAE,oBAAoB,+BAetB"}
1
+ {"version":3,"file":"WorkspacePicker.d.ts","sourceRoot":"","sources":["../../../src/client/WorkspacePicker.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAKjD,OAAO,KAAK,EACV,WAAW,EAAE,iBAAiB,EAAE,aAAa,EAC9C,MAAM,kDAAkD,CAAA;AAEzD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,kCAAkC,CAAA;AAC5E,OAAO,KAAK,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAA;AAKxF,8EAA8E;AAC9E,MAAM,WAAW,sBAAsB;IACrC,kFAAkF;IAClF,CAAC,EAAE,oBAAoB,CAAC,GAAG,CAAC,CAAA;IAC5B,oEAAoE;IACpE,IAAI,EAAE,OAAO,CAAA;IACb,kEAAkE;IAClE,SAAS,CAAC,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,SAAS,CAAA;IACrD,uEAAuE;IACvE,aAAa,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,CAAC,KAAK,CAAC,CAAA;IAClE,yDAAyD;IACzD,eAAe,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,aAAa,CAAC,CAAA;IACpE,0HAA0H;IAC1H,gBAAgB,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAA;IAC/C,+GAA+G;IAC/G,mBAAmB,EAAE,CAAC,KAAK,EAAE,uBAAuB,KAAK,SAAS,CAAA;IAClE,8CAA8C;IAC9C,MAAM,EAAE,CAAC,WAAW,EAAE,WAAW,KAAK,IAAI,CAAA;IAC1C,8DAA8D;IAC9D,OAAO,EAAE,MAAM,IAAI,CAAA;IACnB,6DAA6D;IAC7D,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAA;IACtC,2DAA2D;IAC3D,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,qDAAqD;IACrD,IAAI,CAAC,EAAE,QAAQ,GAAG,KAAK,GAAG,OAAO,CAAA;IACjC,sEAAsE;IACtE,UAAU,CAAC,EAAE,WAAW,GAAG,SAAS,CAAA;CACrC;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,CAAC,EACD,IAAI,EACJ,SAAS,EACT,aAAa,EACb,eAAe,EACf,gBAAgB,EAChB,mBAAmB,EACnB,MAAM,EACN,OAAO,EACP,OAAe,EACf,YAAY,EACZ,IAAe,EACf,UAAU,GACX,EAAE,sBAAsB,OAmJxB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,SAAS,EACT,aAAa,EACb,UAAU,EACV,MAAM,EACN,OAAO,EACP,eAAe,EACf,gBAAgB,EAChB,UAAU,EACV,CAAC,GACF,EAAE,oBAAoB,OAetB"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * 折叠徽标设置项的字段定义(纯逻辑,不碰 React / 宿主组件)。
3
+ *
4
+ * 官方设置卡片的模型(`SettingsFormModel`)把每个字段都当**草稿文本**处理:控件读
5
+ * `format(存储值)` 得到文本,用户编辑后 `parse(文本)` 决定这次保存写什么。布尔字段
6
+ * 没有现成的官方 spec(官方只提供 `settingsTextField` / `settingsNumberField`),所以
7
+ * 这里按同一契约写一份:文本就是 schema 的布尔字面量。
8
+ *
9
+ * 单独成文件是为了可测:`parse` 必须对非法草稿返回 `undefined`(模型据此把该字段标为
10
+ * invalid 并挡住保存,而不是把畸形值写下去),`format` 必须把缺失值读成默认 `true`
11
+ * ——与 `Config` 各字段的 schema 默认、`badge-settings.ts` 的解析同源。
12
+ *
13
+ * 类型从 primitives **type-only** 引入:编译期接住官方契约,运行时不留依赖,
14
+ * 测试里也就不必把那个包(及其整棵依赖闭包)拉进来。
15
+ */
16
+ import type { SettingsFieldSpec } from '@deepseek-ai/dsh-client-ui-primitives';
17
+ /** 卡片字段名(与 `src/index.ts` 的 `Config` 同名同义)。 */
18
+ export declare const BADGE_FIELDS: {
19
+ readonly showCompletedInBadge: "showCompletedInBadge";
20
+ readonly showRunningInBadge: "showRunningInBadge";
21
+ readonly showPendingInBadge: "showPendingInBadge";
22
+ readonly showScheduledInBadge: "showScheduledInBadge";
23
+ readonly showWaitingReviewInBadge: "showWaitingReviewInBadge";
24
+ readonly showHoverDetails: "showHoverDetails";
25
+ readonly countThreshold: "countThreshold";
26
+ };
27
+ /** 存储值解析成开关状态:只有显式 false 才是「关闭」。 */
28
+ export declare function isFieldEnabled(value: unknown): boolean;
29
+ /**
30
+ * 草稿文本解析成开关状态:与 {@link isFieldEnabled} 不同,这里比较的是模型给的
31
+ * **文本**,别把字符串喂给上面那个函数(`'false' !== false` 恒真)。
32
+ */
33
+ export declare function isDraftEnabled(text: string): boolean;
34
+ /** 各字段的字段转换规格。 */
35
+ export declare const showCompletedField: SettingsFieldSpec;
36
+ export declare const showRunningField: SettingsFieldSpec;
37
+ export declare const showPendingField: SettingsFieldSpec;
38
+ export declare const showScheduledField: SettingsFieldSpec;
39
+ export declare const showWaitingReviewField: SettingsFieldSpec;
40
+ export declare const showHoverDetailsField: SettingsFieldSpec;
41
+ export declare const countThresholdField: SettingsFieldSpec;
42
+ /** 所有字段规格(按卡片渲染顺序)。 */
43
+ export declare const ALL_BADGE_FIELDS: SettingsFieldSpec[];
44
+ //# sourceMappingURL=badge-field.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"badge-field.d.ts","sourceRoot":"","sources":["../../../src/client/badge-field.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uCAAuC,CAAA;AAE9E,+CAA+C;AAC/C,eAAO,MAAM,YAAY;;;;;;;;CAQf,CAAA;AAEV,oCAAoC;AACpC,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAEtD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AA2BD,kBAAkB;AAClB,eAAO,MAAM,kBAAkB,EAAE,iBAA6E,CAAA;AAC9G,eAAO,MAAM,gBAAgB,EAAE,iBAA2E,CAAA;AAC1G,eAAO,MAAM,gBAAgB,EAAE,iBAA2E,CAAA;AAC1G,eAAO,MAAM,kBAAkB,EAAE,iBAA6E,CAAA;AAC9G,eAAO,MAAM,sBAAsB,EAAE,iBAAiF,CAAA;AACtH,eAAO,MAAM,qBAAqB,EAAE,iBAAyE,CAAA;AAC7G,eAAO,MAAM,mBAAmB,EAAE,iBAajC,CAAA;AAED,uBAAuB;AACvB,eAAO,MAAM,gBAAgB,EAAE,iBAAiB,EAQ/C,CAAA"}
@@ -0,0 +1,77 @@
1
+ /** 卡片字段名(与 `src/index.ts` 的 `Config` 同名同义)。 */
2
+ export const BADGE_FIELDS = {
3
+ showCompletedInBadge: 'showCompletedInBadge',
4
+ showRunningInBadge: 'showRunningInBadge',
5
+ showPendingInBadge: 'showPendingInBadge',
6
+ showScheduledInBadge: 'showScheduledInBadge',
7
+ showWaitingReviewInBadge: 'showWaitingReviewInBadge',
8
+ showHoverDetails: 'showHoverDetails',
9
+ countThreshold: 'countThreshold',
10
+ };
11
+ /** 存储值解析成开关状态:只有显式 false 才是「关闭」。 */
12
+ export function isFieldEnabled(value) {
13
+ return value !== false;
14
+ }
15
+ /**
16
+ * 草稿文本解析成开关状态:与 {@link isFieldEnabled} 不同,这里比较的是模型给的
17
+ * **文本**,别把字符串喂给上面那个函数(`'false' !== false` 恒真)。
18
+ */
19
+ export function isDraftEnabled(text) {
20
+ return text !== 'false';
21
+ }
22
+ /**
23
+ * 构造一个布尔字段的字段转换规格。
24
+ *
25
+ * `parse` 只接受 `'true'` / `'false'`:空串、任意其它文本都返回 `undefined`,
26
+ * 让模型把字段判为 invalid 并拒绝保存(官方模型的既定行为)。
27
+ *
28
+ * @param field - 字段名(与 Config 同名)。
29
+ * @param defaultValue - 缺失值时的默认(true = 默认显示,false = 默认隐藏)。
30
+ */
31
+ function makeBooleanField(field, defaultValue) {
32
+ return {
33
+ field,
34
+ format: value => {
35
+ const enabled = value === undefined || value === null || typeof value !== 'boolean'
36
+ ? defaultValue
37
+ : value;
38
+ return enabled ? 'true' : 'false';
39
+ },
40
+ parse: text => text === 'true' ? { kind: 'set', value: true }
41
+ : text === 'false' ? { kind: 'set', value: false }
42
+ : undefined,
43
+ };
44
+ }
45
+ /** 各字段的字段转换规格。 */
46
+ export const showCompletedField = makeBooleanField(BADGE_FIELDS.showCompletedInBadge, true);
47
+ export const showRunningField = makeBooleanField(BADGE_FIELDS.showRunningInBadge, true);
48
+ export const showPendingField = makeBooleanField(BADGE_FIELDS.showPendingInBadge, true);
49
+ export const showScheduledField = makeBooleanField(BADGE_FIELDS.showScheduledInBadge, true);
50
+ export const showWaitingReviewField = makeBooleanField(BADGE_FIELDS.showWaitingReviewInBadge, true);
51
+ export const showHoverDetailsField = makeBooleanField(BADGE_FIELDS.showHoverDetails, true);
52
+ export const countThresholdField = {
53
+ field: BADGE_FIELDS.countThreshold,
54
+ format: value => {
55
+ const n = value === undefined || value === null || typeof value !== 'number' || !Number.isFinite(value)
56
+ ? 2
57
+ : Math.floor(value);
58
+ return String(n < 0 ? 0 : n);
59
+ },
60
+ parse: text => {
61
+ const n = Number(text);
62
+ if (!Number.isFinite(n) || n < 0 || n !== Math.floor(n))
63
+ return undefined;
64
+ return { kind: 'set', value: n };
65
+ },
66
+ };
67
+ /** 所有字段规格(按卡片渲染顺序)。 */
68
+ export const ALL_BADGE_FIELDS = [
69
+ showCompletedField,
70
+ showRunningField,
71
+ showPendingField,
72
+ showScheduledField,
73
+ showWaitingReviewField,
74
+ showHoverDetailsField,
75
+ countThresholdField,
76
+ ];
77
+ //# sourceMappingURL=badge-field.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"badge-field.js","sourceRoot":"","sources":["../../../src/client/badge-field.ts"],"names":[],"mappings":"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"}
@@ -16,8 +16,8 @@
16
16
  * 引用——每次都构造新对象会让选择器的 `Object.is` 比较永不成立,触发
17
17
  * 「Maximum update depth exceeded」死循环(React #185),折叠行徽标会整块崩掉。
18
18
  *
19
- * 设置面缺席或未就绪时,回落到**默认显示已完成**,与 `Config.showCompletedInBadge` 的
20
- * schema 默认值同源:读不到配置不是「关掉」。
19
+ * 设置面缺席或未就绪时,回落到**默认全部显示**,与 `Config` 各字段的 schema 默认值同源:
20
+ * 读不到配置不是「关掉」。
21
21
  */
22
22
  /** Loader 条目 id —— 设置页的寻址键,也是宿主 `describe()` 的 ns。 */
23
23
  export declare const ENTRY_ID = "dsh-group-status";
@@ -35,6 +35,18 @@ export interface SettingsScopeLike {
35
35
  export interface ResolvedBadgeSettings {
36
36
  /** 折叠徽标是否显示「已完成」绿点;缺失/非法一律回落 true。 */
37
37
  showCompletedInBadge: boolean;
38
+ /** 折叠徽标是否显示「进行中」转圈(含子智能体);缺失/非法一律回落 true。 */
39
+ showRunningInBadge: boolean;
40
+ /** 折叠徽标是否显示「待审批」黄点(approval / plan-review / question);缺失/非法一律回落 true。 */
41
+ showPendingInBadge: boolean;
42
+ /** 折叠徽标是否显示「定时任务」时钟图标(数据来自 dsh-later);缺失/非法一律回落 true。 */
43
+ showScheduledInBadge: boolean;
44
+ /** 折叠徽标是否显示「等待评审」列表笔图标(数据来自 dsh-gitea-dispatch);缺失/非法一律回落 true。 */
45
+ showWaitingReviewInBadge: boolean;
46
+ /** 悬停卡里是否显示聚合明细行;缺失/非法一律回落 true。 */
47
+ showHoverDetails: boolean;
48
+ /** 徽标数字显示阈值:数量 >= 此值时才显示数字;缺失/非法一律回落 2(默认 count=1 时省略)。 */
49
+ countThreshold: number;
38
50
  }
39
51
  /** 标准 props 源的结构面(与 `HostObservable<ResolvedBadgeSettings>` 兼容)。 */
40
52
  export interface BadgeSettingsSource {
@@ -52,7 +64,7 @@ export interface MutableBadgeSettingsSource extends BadgeSettingsSource {
52
64
  */
53
65
  publish(snapshot: SettingsSnapshotLike | undefined): void;
54
66
  }
55
- /** 默认值:与 `Config.showCompletedInBadge` 的 schema 默认同源(true)。 */
67
+ /** 默认值:与 `Config` 各字段的 schema 默认同源(全部显示,数字阈值 2 即 count=1 时省略)。 */
56
68
  export declare const DEFAULT_BADGE_SETTINGS: ResolvedBadgeSettings;
57
69
  /**
58
70
  * 建一个恒在、取值稳定的徽标设置源。
@@ -1 +1 @@
1
- {"version":3,"file":"badge-settings.d.ts","sourceRoot":"","sources":["../../../src/client/badge-settings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,sDAAsD;AACtD,eAAO,MAAM,QAAQ,qBAAqB,CAAA;AAE1C,gDAAgD;AAChD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CACzB;AAED,sCAAsC;AACtC,MAAM,WAAW,iBAAiB;IAChC,WAAW,IAAI,oBAAoB,CAAA;IACnC,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAA;CAC5C;AAED,sBAAsB;AACtB,MAAM,WAAW,qBAAqB;IACpC,sCAAsC;IACtC,oBAAoB,EAAE,OAAO,CAAA;CAC9B;AAED,oEAAoE;AACpE,MAAM,WAAW,mBAAmB;IAClC,WAAW,IAAI,qBAAqB,CAAA;IACpC,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAA;CAC5C;AAED,qDAAqD;AACrD,MAAM,WAAW,0BAA2B,SAAQ,mBAAmB;IACrE;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,EAAE,oBAAoB,GAAG,SAAS,GAAG,IAAI,CAAA;CAC1D;AAED,+DAA+D;AAC/D,eAAO,MAAM,sBAAsB,EAAE,qBAEnC,CAAA;AAUF;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,IAAI,0BAA0B,CAuBtE;AAED,qCAAqC;AACrC,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,oBAAoB,GAAG,SAAS,GAAG,qBAAqB,CAEtG"}
1
+ {"version":3,"file":"badge-settings.d.ts","sourceRoot":"","sources":["../../../src/client/badge-settings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,sDAAsD;AACtD,eAAO,MAAM,QAAQ,qBAAqB,CAAA;AAE1C,gDAAgD;AAChD,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CACzB;AAED,sCAAsC;AACtC,MAAM,WAAW,iBAAiB;IAChC,WAAW,IAAI,oBAAoB,CAAA;IACnC,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAA;CAC5C;AAED,sBAAsB;AACtB,MAAM,WAAW,qBAAqB;IACpC,sCAAsC;IACtC,oBAAoB,EAAE,OAAO,CAAA;IAC7B,6CAA6C;IAC7C,kBAAkB,EAAE,OAAO,CAAA;IAC3B,yEAAyE;IACzE,kBAAkB,EAAE,OAAO,CAAA;IAC3B,yDAAyD;IACzD,oBAAoB,EAAE,OAAO,CAAA;IAC7B,mEAAmE;IACnE,wBAAwB,EAAE,OAAO,CAAA;IACjC,oCAAoC;IACpC,gBAAgB,EAAE,OAAO,CAAA;IACzB,2DAA2D;IAC3D,cAAc,EAAE,MAAM,CAAA;CACvB;AAED,oEAAoE;AACpE,MAAM,WAAW,mBAAmB;IAClC,WAAW,IAAI,qBAAqB,CAAA;IACpC,SAAS,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAA;CAC5C;AAED,qDAAqD;AACrD,MAAM,WAAW,0BAA2B,SAAQ,mBAAmB;IACrE;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,EAAE,oBAAoB,GAAG,SAAS,GAAG,IAAI,CAAA;CAC1D;AAED,kEAAkE;AAClE,eAAO,MAAM,sBAAsB,EAAE,qBAQnC,CAAA;AAuCF;;;;;;;GAOG;AACH,wBAAgB,yBAAyB,IAAI,0BAA0B,CAuBtE;AAED,qCAAqC;AACrC,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,oBAAoB,GAAG,SAAS,GAAG,qBAAqB,CAEtG"}
@@ -16,23 +16,55 @@
16
16
  * 引用——每次都构造新对象会让选择器的 `Object.is` 比较永不成立,触发
17
17
  * 「Maximum update depth exceeded」死循环(React #185),折叠行徽标会整块崩掉。
18
18
  *
19
- * 设置面缺席或未就绪时,回落到**默认显示已完成**,与 `Config.showCompletedInBadge` 的
20
- * schema 默认值同源:读不到配置不是「关掉」。
19
+ * 设置面缺席或未就绪时,回落到**默认全部显示**,与 `Config` 各字段的 schema 默认值同源:
20
+ * 读不到配置不是「关掉」。
21
21
  */
22
22
  /** Loader 条目 id —— 设置页的寻址键,也是宿主 `describe()` 的 ns。 */
23
23
  export const ENTRY_ID = 'dsh-group-status';
24
- /** 默认值:与 `Config.showCompletedInBadge` 的 schema 默认同源(true)。 */
24
+ /** 默认值:与 `Config` 各字段的 schema 默认同源(全部显示,数字阈值 2 即 count=1 时省略)。 */
25
25
  export const DEFAULT_BADGE_SETTINGS = Object.freeze({
26
26
  showCompletedInBadge: true,
27
+ showRunningInBadge: true,
28
+ showPendingInBadge: true,
29
+ showScheduledInBadge: true,
30
+ showWaitingReviewInBadge: true,
31
+ showHoverDetails: true,
32
+ countThreshold: 2,
27
33
  });
28
- /** 从原始快照派生:只有**显式 false** 才隐藏,缺失/非法一律显示。 */
34
+ /** 两个设置对象是否逐字段相等(用于发布前比较,避免无谓通知)。 */
35
+ function settingsEqual(a, b) {
36
+ return (a.showCompletedInBadge === b.showCompletedInBadge &&
37
+ a.showRunningInBadge === b.showRunningInBadge &&
38
+ a.showPendingInBadge === b.showPendingInBadge &&
39
+ a.showScheduledInBadge === b.showScheduledInBadge &&
40
+ a.showWaitingReviewInBadge === b.showWaitingReviewInBadge &&
41
+ a.showHoverDetails === b.showHoverDetails &&
42
+ a.countThreshold === b.countThreshold);
43
+ }
44
+ /** 从原始快照派生:只有**显式 false** 才隐藏,缺失/非法一律显示(countThreshold 默认 2)。 */
29
45
  function resolveFromSnapshot(snap) {
30
46
  if (snap === undefined || snap.status !== 'ready')
31
47
  return DEFAULT_BADGE_SETTINGS;
32
48
  const value = snap.value;
33
49
  if (value === undefined || value === null || typeof value !== 'object')
34
50
  return DEFAULT_BADGE_SETTINGS;
35
- return { showCompletedInBadge: value['showCompletedInBadge'] !== false };
51
+ const getBool = (field, def) => {
52
+ const v = value[field];
53
+ return typeof v === 'boolean' ? v : def;
54
+ };
55
+ const getNumber = (field, def) => {
56
+ const v = value[field];
57
+ return typeof v === 'number' && Number.isFinite(v) && v >= 0 ? Math.floor(v) : def;
58
+ };
59
+ return {
60
+ showCompletedInBadge: getBool('showCompletedInBadge', true),
61
+ showRunningInBadge: getBool('showRunningInBadge', true),
62
+ showPendingInBadge: getBool('showPendingInBadge', true),
63
+ showScheduledInBadge: getBool('showScheduledInBadge', true),
64
+ showWaitingReviewInBadge: getBool('showWaitingReviewInBadge', true),
65
+ showHoverDetails: getBool('showHoverDetails', true),
66
+ countThreshold: getNumber('countThreshold', 2),
67
+ };
36
68
  }
37
69
  /**
38
70
  * 建一个恒在、取值稳定的徽标设置源。
@@ -61,7 +93,7 @@ export function createBadgeSettingsSource() {
61
93
  seenSet = true;
62
94
  const next = resolveFromSnapshot(snapshot);
63
95
  // 取值没变就不替换引用、不通知:宿主为无关字段替换快照时不该惊动折叠行。
64
- if (next.showCompletedInBadge === resolved.showCompletedInBadge)
96
+ if (settingsEqual(next, resolved))
65
97
  return;
66
98
  resolved = next;
67
99
  for (const listener of [...listeners])
@@ -1 +1 @@
1
- {"version":3,"file":"badge-settings.js","sourceRoot":"","sources":["../../../src/client/badge-settings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,sDAAsD;AACtD,MAAM,CAAC,MAAM,QAAQ,GAAG,kBAAkB,CAAA;AAsC1C,+DAA+D;AAC/D,MAAM,CAAC,MAAM,sBAAsB,GAA0B,MAAM,CAAC,MAAM,CAAC;IACzE,oBAAoB,EAAE,IAAI;CAC3B,CAAC,CAAA;AAEF,4CAA4C;AAC5C,SAAS,mBAAmB,CAAC,IAAsC;IACjE,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,KAAK,OAAO;QAAE,OAAO,sBAAsB,CAAA;IAChF,MAAM,KAAK,GAAG,IAAI,CAAC,KAA4C,CAAA;IAC/D,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,sBAAsB,CAAA;IACrG,OAAO,EAAE,oBAAoB,EAAE,KAAK,CAAC,sBAAsB,CAAC,KAAK,KAAK,EAAE,CAAA;AAC1E,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,yBAAyB;IACvC,MAAM,SAAS,GAAG,IAAI,GAAG,EAAc,CAAA;IACvC,IAAI,QAAQ,GAA0B,sBAAsB,CAAA;IAC5D,IAAI,IAAsC,CAAA;IAC1C,IAAI,OAAO,GAAG,KAAK,CAAA;IACnB,OAAO;QACL,WAAW,EAAE,GAAG,EAAE,CAAC,QAAQ;QAC3B,SAAS,EAAE,CAAC,QAAQ,EAAE,EAAE;YACtB,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;YACvB,OAAO,GAAG,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA,CAAC,CAAC,CAAA;QAC7C,CAAC;QACD,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE;YACpB,2CAA2C;YAC3C,IAAI,OAAO,IAAI,QAAQ,KAAK,IAAI;gBAAE,OAAM;YACxC,IAAI,GAAG,QAAQ,CAAA;YACf,OAAO,GAAG,IAAI,CAAA;YACd,MAAM,IAAI,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAA;YAC1C,sCAAsC;YACtC,IAAI,IAAI,CAAC,oBAAoB,KAAK,QAAQ,CAAC,oBAAoB;gBAAE,OAAM;YACvE,QAAQ,GAAG,IAAI,CAAA;YACf,KAAK,MAAM,QAAQ,IAAI,CAAC,GAAG,SAAS,CAAC;gBAAE,QAAQ,EAAE,CAAA;QACnD,CAAC;KACF,CAAA;AACH,CAAC;AAED,qCAAqC;AACrC,MAAM,UAAU,oBAAoB,CAAC,QAA0C;IAC7E,OAAO,mBAAmB,CAAC,QAAQ,CAAC,CAAA;AACtC,CAAC"}
1
+ {"version":3,"file":"badge-settings.js","sourceRoot":"","sources":["../../../src/client/badge-settings.ts"],"names":[],"mappings":"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"}
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * @module
9
9
  */
10
- import type { SessionNode } from './tree.ts';
10
+ import type { GroupNode, SessionNode } from './tree.ts';
11
11
  /**
12
12
  * One session's waiting-review fact, as published by dsh-gitea-dispatch's
13
13
  * `useWaitingSummary()` (issue: dsh-gitea-dispatch#16).
@@ -66,6 +66,15 @@ export interface GroupLiveStatus {
66
66
  * React selectors never trigger spurious re-renders on it.
67
67
  */
68
68
  export declare const EMPTY_LIVE_STATUS: GroupLiveStatus;
69
+ /**
70
+ * Merge two {@link GroupLiveStatus} objects by summing counters and taking the
71
+ * highest-priority state (overdue > urgent > scheduled for schedule; overdue > waiting
72
+ * for waiting-review).
73
+ *
74
+ * Used for multi-level aggregation: when a parent group is collapsed, its badge
75
+ * must reflect all descendant sessions, not just direct members.
76
+ */
77
+ export declare function mergeLiveStatus(a: GroupLiveStatus, b: GroupLiveStatus): GroupLiveStatus;
69
78
  /**
70
79
  * Fold every member row of a group into counts so a collapsed folder can hint at
71
80
  * hidden live sessions. Mirrors the session-row status priority (pending
@@ -77,4 +86,60 @@ export declare const EMPTY_LIVE_STATUS: GroupLiveStatus;
77
86
  * @param scheduleSummary - dsh-later schedule map, when that plugin is loaded.
78
87
  */
79
88
  export declare function summarizeGroupStatus(nodes: readonly SessionNode[], sessionIds: readonly string[], waitingReviewSummary?: WaitingReviewSummaryMap, scheduleSummary?: ScheduleSummaryMap): GroupLiveStatus;
89
+ /**
90
+ * Measure each group's own members, as the input to {@link aggregateGroupStatuses}.
91
+ *
92
+ * Every group is measured, expanded ones included. A folder row shows no badge while
93
+ * it is expanded, but its sessions still need attention and a collapsed ancestor must
94
+ * keep counting them — so expansion is a rendering fact, never an input to the
95
+ * aggregation. Short-circuiting expanded groups to `EMPTY_LIVE_STATUS` (the shape this
96
+ * had before the tree-wide aggregator existed, harmless while nothing aggregated) makes
97
+ * every collapsed parent undercount by the size of its expanded descendants.
98
+ *
99
+ * @param groups - derived groups, each with its member rows already populated.
100
+ * @param waitingReviewSummary - dsh-gitea-dispatch waiting map, when that plugin is loaded.
101
+ * @param scheduleSummary - dsh-later schedule map, when that plugin is loaded.
102
+ */
103
+ export declare function directStatusesForGroups(groups: readonly {
104
+ key: string;
105
+ sessions: readonly SessionNode[];
106
+ }[], waitingReviewSummary?: WaitingReviewSummaryMap, scheduleSummary?: ScheduleSummaryMap): Map<string, GroupLiveStatus>;
107
+ /**
108
+ * Fold every group's DIRECT status up the workspace tree, so a collapsed folder
109
+ * counts every descendant session. A group's own row shows no badge while it is
110
+ * expanded, but its sessions still need attention and its collapsed ancestor must
111
+ * keep counting them — so the walk never depends on a group's expanded state.
112
+ *
113
+ * @param direct - each group's own-member status, keyed by group key.
114
+ * @param childrenByParent - the rendered tree: parent key (`undefined` = roots) → children.
115
+ * @returns aggregated status per group key: own members plus the whole subtree.
116
+ */
117
+ export declare function aggregateGroupStatuses(direct: ReadonlyMap<string, GroupLiveStatus>, childrenByParent: ReadonlyMap<string | undefined, readonly {
118
+ key: string;
119
+ }[]>): Map<string, GroupLiveStatus>;
120
+ /**
121
+ * A group row whose badge input is resolved: its own members plus its whole subtree.
122
+ *
123
+ * `GroupNode.liveStatus` is optional only because upstream never fills it — this
124
+ * package's aggregator is the sole producer. Typing a rendered row as
125
+ * `StatusedGroupNode` is what turns "a row that skipped the aggregator" into a compile
126
+ * error instead of a folder that silently lost its badge, which is how the PR #10
127
+ * regression reached main.
128
+ */
129
+ export interface StatusedGroupNode extends GroupNode {
130
+ liveStatus: GroupLiveStatus;
131
+ }
132
+ /**
133
+ * Attach each group's subtree-wide status, in derivation order. This is the producer
134
+ * the sidebar renders from.
135
+ *
136
+ * Expanded groups carry their status too: their own row draws no badge (a decision
137
+ * inside `groupLiveBadge`), but a collapsed ancestor still has to count them, so
138
+ * expansion never suppresses the measurement.
139
+ *
140
+ * @param groups - derived rows, in the order they render.
141
+ * @param direct - each group's own-member status, from {@link directStatusesForGroups}.
142
+ * @param childrenByParent - the rendered tree: parent key (`undefined` = roots) → children.
143
+ */
144
+ export declare function withAggregatedStatus(groups: readonly GroupNode[], direct: ReadonlyMap<string, GroupLiveStatus>, childrenByParent: ReadonlyMap<string | undefined, readonly GroupNode[]>): StatusedGroupNode[];
80
145
  //# sourceMappingURL=group-status.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"group-status.d.ts","sourceRoot":"","sources":["../../../src/client/group-status.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAI5C;;;GAGG;AACH,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,CAAA;CACtC;AAED,gFAAgF;AAChF,MAAM,MAAM,uBAAuB,GAAG,WAAW,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAA;AAEpF;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAA;CACnD;AAED,iFAAiF;AACjF,MAAM,MAAM,kBAAkB,GAAG,WAAW,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAA;AAI1E;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAA;IACf,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAA;IAChB,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAA;IAClB,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAA;IAChB,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAA;IACZ,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAA;IACjB,qDAAqD;IACrD,iBAAiB,EAAE,MAAM,CAAA;IACzB,+DAA+D;IAC/D,cAAc,EAAE,MAAM,CAAA;IACtB,qEAAqE;IACrE,aAAa,EAAE,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAA;IAC7D,2EAA2E;IAC3E,kBAAkB,EAAE,MAAM,CAAA;IAC1B,wEAAwE;IACxE,kBAAkB,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAAA;CACtD;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,EAAE,eAIX,CAAA;AAkBrB;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,oBAAoB,CAAC,EAAE,uBAAuB,EAC9C,eAAe,CAAC,EAAE,kBAAkB,GACnC,eAAe,CAgEjB"}
1
+ {"version":3,"file":"group-status.d.ts","sourceRoot":"","sources":["../../../src/client/group-status.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AAIvD;;;GAGG;AACH,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,CAAA;CACtC;AAED,gFAAgF;AAChF,MAAM,MAAM,uBAAuB,GAAG,WAAW,CAAC,MAAM,EAAE,yBAAyB,CAAC,CAAA;AAEpF;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,QAAQ,GAAG,SAAS,CAAA;CACnD;AAED,iFAAiF;AACjF,MAAM,MAAM,kBAAkB,GAAG,WAAW,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAA;AAI1E;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,iCAAiC;IACjC,OAAO,EAAE,MAAM,CAAA;IACf,sCAAsC;IACtC,QAAQ,EAAE,MAAM,CAAA;IAChB,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAA;IAClB,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAA;IAChB,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAA;IACZ,8CAA8C;IAC9C,SAAS,EAAE,MAAM,CAAA;IACjB,qDAAqD;IACrD,iBAAiB,EAAE,MAAM,CAAA;IACzB,+DAA+D;IAC/D,cAAc,EAAE,MAAM,CAAA;IACtB,qEAAqE;IACrE,aAAa,EAAE,WAAW,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAA;IAC7D,2EAA2E;IAC3E,kBAAkB,EAAE,MAAM,CAAA;IAC1B,wEAAwE;IACxE,kBAAkB,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAAA;CACtD;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,EAAE,eAIX,CAAA;AAErB;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,eAAe,GAAG,eAAe,CA0BvF;AAkBD;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,UAAU,EAAE,SAAS,MAAM,EAAE,EAC7B,oBAAoB,CAAC,EAAE,uBAAuB,EAC9C,eAAe,CAAC,EAAE,kBAAkB,GACnC,eAAe,CAgEjB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,SAAS;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAA;CAAE,EAAE,EACpE,oBAAoB,CAAC,EAAE,uBAAuB,EAC9C,eAAe,CAAC,EAAE,kBAAkB,GACnC,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAQ9B;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,EAC5C,gBAAgB,EAAE,WAAW,CAAC,MAAM,GAAG,SAAS,EAAE,SAAS;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,EAAE,CAAC,GAC5E,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAwB9B;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAkB,SAAQ,SAAS;IAClD,UAAU,EAAE,eAAe,CAAA;CAC5B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,SAAS,EAAE,EAC5B,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,eAAe,CAAC,EAC5C,gBAAgB,EAAE,WAAW,CAAC,MAAM,GAAG,SAAS,EAAE,SAAS,SAAS,EAAE,CAAC,GACtE,iBAAiB,EAAE,CAKrB"}
@@ -11,6 +11,38 @@ export const EMPTY_LIVE_STATUS = Object.freeze({
11
11
  scheduledSessions: 0, scheduledCount: 0, scheduleState: undefined,
12
12
  waitingReviewCount: 0, waitingReviewState: undefined,
13
13
  });
14
+ /**
15
+ * Merge two {@link GroupLiveStatus} objects by summing counters and taking the
16
+ * highest-priority state (overdue > urgent > scheduled for schedule; overdue > waiting
17
+ * for waiting-review).
18
+ *
19
+ * Used for multi-level aggregation: when a parent group is collapsed, its badge
20
+ * must reflect all descendant sessions, not just direct members.
21
+ */
22
+ export function mergeLiveStatus(a, b) {
23
+ // Schedule state: overdue (3) > urgent (2) > scheduled (1) > undefined (0)
24
+ const priorityOf = (s) => s === 'overdue' ? 3 : s === 'urgent' ? 2 : s === 'scheduled' ? 1 : 0;
25
+ const schedulePriorityA = priorityOf(a.scheduleState);
26
+ const schedulePriorityB = priorityOf(b.scheduleState);
27
+ const scheduleState = schedulePriorityA >= schedulePriorityB ? a.scheduleState : b.scheduleState;
28
+ // Waiting-review state: overdue > waiting > undefined
29
+ const waitingPriorityA = a.waitingReviewState === 'overdue' ? 2 : a.waitingReviewState === 'waiting' ? 1 : 0;
30
+ const waitingPriorityB = b.waitingReviewState === 'overdue' ? 2 : b.waitingReviewState === 'waiting' ? 1 : 0;
31
+ const waitingReviewState = waitingPriorityA >= waitingPriorityB ? a.waitingReviewState : b.waitingReviewState;
32
+ return {
33
+ running: a.running + b.running,
34
+ approval: a.approval + b.approval,
35
+ planReview: a.planReview + b.planReview,
36
+ question: a.question + b.question,
37
+ done: a.done + b.done,
38
+ subagents: a.subagents + b.subagents,
39
+ scheduledSessions: a.scheduledSessions + b.scheduledSessions,
40
+ scheduledCount: a.scheduledCount + b.scheduledCount,
41
+ scheduleState,
42
+ waitingReviewCount: a.waitingReviewCount + b.waitingReviewCount,
43
+ waitingReviewState,
44
+ };
45
+ }
14
46
  // ── Helpers ──
15
47
  /**
16
48
  * Strip the `session-` / `webhook-` prefix from a Session id.
@@ -109,4 +141,81 @@ export function summarizeGroupStatus(nodes, sessionIds, waitingReviewSummary, sc
109
141
  waitingReviewCount, waitingReviewState,
110
142
  };
111
143
  }
144
+ /**
145
+ * Measure each group's own members, as the input to {@link aggregateGroupStatuses}.
146
+ *
147
+ * Every group is measured, expanded ones included. A folder row shows no badge while
148
+ * it is expanded, but its sessions still need attention and a collapsed ancestor must
149
+ * keep counting them — so expansion is a rendering fact, never an input to the
150
+ * aggregation. Short-circuiting expanded groups to `EMPTY_LIVE_STATUS` (the shape this
151
+ * had before the tree-wide aggregator existed, harmless while nothing aggregated) makes
152
+ * every collapsed parent undercount by the size of its expanded descendants.
153
+ *
154
+ * @param groups - derived groups, each with its member rows already populated.
155
+ * @param waitingReviewSummary - dsh-gitea-dispatch waiting map, when that plugin is loaded.
156
+ * @param scheduleSummary - dsh-later schedule map, when that plugin is loaded.
157
+ */
158
+ export function directStatusesForGroups(groups, waitingReviewSummary, scheduleSummary) {
159
+ const map = new Map();
160
+ for (const group of groups) {
161
+ map.set(group.key, summarizeGroupStatus(group.sessions, group.sessions.map(s => s.id), waitingReviewSummary, scheduleSummary));
162
+ }
163
+ return map;
164
+ }
165
+ /**
166
+ * Fold every group's DIRECT status up the workspace tree, so a collapsed folder
167
+ * counts every descendant session. A group's own row shows no badge while it is
168
+ * expanded, but its sessions still need attention and its collapsed ancestor must
169
+ * keep counting them — so the walk never depends on a group's expanded state.
170
+ *
171
+ * @param direct - each group's own-member status, keyed by group key.
172
+ * @param childrenByParent - the rendered tree: parent key (`undefined` = roots) → children.
173
+ * @returns aggregated status per group key: own members plus the whole subtree.
174
+ */
175
+ export function aggregateGroupStatuses(direct, childrenByParent) {
176
+ const aggregated = new Map();
177
+ // Parentage comes from path-prefix matching, so a self- or mutual-parent edge is
178
+ // representable; without this guard the fold would recurse forever and hang the sidebar.
179
+ const visiting = new Set();
180
+ const fold = (key) => {
181
+ const cached = aggregated.get(key);
182
+ if (cached !== undefined)
183
+ return cached;
184
+ if (visiting.has(key))
185
+ return direct.get(key) ?? EMPTY_LIVE_STATUS;
186
+ visiting.add(key);
187
+ let total = direct.get(key) ?? EMPTY_LIVE_STATUS;
188
+ for (const child of childrenByParent.get(key) ?? []) {
189
+ total = mergeLiveStatus(total, fold(child.key));
190
+ }
191
+ visiting.delete(key);
192
+ aggregated.set(key, total);
193
+ return total;
194
+ };
195
+ // Every listed child is folded, not just the roots: an unreachable group would
196
+ // otherwise be missing from the map and lose its badge.
197
+ for (const children of childrenByParent.values()) {
198
+ for (const child of children)
199
+ fold(child.key);
200
+ }
201
+ return aggregated;
202
+ }
203
+ /**
204
+ * Attach each group's subtree-wide status, in derivation order. This is the producer
205
+ * the sidebar renders from.
206
+ *
207
+ * Expanded groups carry their status too: their own row draws no badge (a decision
208
+ * inside `groupLiveBadge`), but a collapsed ancestor still has to count them, so
209
+ * expansion never suppresses the measurement.
210
+ *
211
+ * @param groups - derived rows, in the order they render.
212
+ * @param direct - each group's own-member status, from {@link directStatusesForGroups}.
213
+ * @param childrenByParent - the rendered tree: parent key (`undefined` = roots) → children.
214
+ */
215
+ export function withAggregatedStatus(groups, direct, childrenByParent) {
216
+ const aggregated = aggregateGroupStatuses(direct, childrenByParent);
217
+ // A group missing from the fold has neither measured members nor listed children,
218
+ // so it is idle rather than unknown.
219
+ return groups.map(group => ({ ...group, liveStatus: aggregated.get(group.key) ?? EMPTY_LIVE_STATUS }));
220
+ }
112
221
  //# sourceMappingURL=group-status.js.map