@modesto_ma/dsh-channels 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/README.md +302 -2
  2. package/cordis.patch.yml +3 -0
  3. package/docs/access-control-design.md +550 -0
  4. package/docs/assets/web-settings-panel.png +0 -0
  5. package/docs/assets/web-settings-restart-pending.png +0 -0
  6. package/docs/feasibility-and-design.md +213 -0
  7. package/docs/feishu-onboarding.md +268 -0
  8. package/docs/persistence.md +199 -0
  9. package/docs/refactor-plan.md +56 -0
  10. package/docs/review-dsh-0.2.0.md +389 -0
  11. package/docs/slash-commands-implementation-plan.md +410 -0
  12. package/docs/web-display-only-surface-roadmap.md +363 -0
  13. package/lib/client.js +2226 -0
  14. package/lib/client.js.map +1 -0
  15. package/lib/index.js +10217 -0
  16. package/lib/index.js.map +1 -0
  17. package/package.json +98 -4
  18. package/src/access/cards.ts +188 -0
  19. package/src/access/controller.ts +201 -0
  20. package/src/access/index.ts +13 -0
  21. package/src/access/policy.ts +103 -0
  22. package/src/access/requests.ts +512 -0
  23. package/src/access/store.ts +220 -0
  24. package/src/approvals.ts +8 -0
  25. package/src/cards/approval.ts +114 -0
  26. package/src/cards/index.ts +11 -0
  27. package/src/cards/primitives.ts +82 -0
  28. package/src/cards/question.ts +141 -0
  29. package/src/cards/streaming.ts +563 -0
  30. package/src/cards.ts +8 -0
  31. package/src/cleanup.ts +398 -0
  32. package/src/client/api.ts +262 -0
  33. package/src/client/catalog.ts +92 -0
  34. package/src/client/index.ts +61 -0
  35. package/src/client/panel.tsx +1475 -0
  36. package/src/client/styles.ts +98 -0
  37. package/src/commands/registry.ts +155 -0
  38. package/src/commands.ts +335 -0
  39. package/src/config.ts +206 -0
  40. package/src/domain.ts +428 -0
  41. package/src/dsh-types.ts +11 -0
  42. package/src/feishu/agent-context.ts +62 -0
  43. package/src/feishu/delivery.ts +188 -0
  44. package/src/feishu/inbound-attachments.ts +436 -0
  45. package/src/feishu-channel.ts +339 -0
  46. package/src/health.ts +233 -0
  47. package/src/host/agent.ts +181 -0
  48. package/src/host/commands.ts +63 -0
  49. package/src/host/core.ts +345 -0
  50. package/src/host/index.ts +12 -0
  51. package/src/host/interaction.ts +101 -0
  52. package/src/host/services.ts +320 -0
  53. package/src/index.ts +122 -0
  54. package/src/interactions/approvals.ts +154 -0
  55. package/src/interactions/pending.ts +162 -0
  56. package/src/interactions/questions.ts +274 -0
  57. package/src/questions.ts +8 -0
  58. package/src/routing/inbound.ts +524 -0
  59. package/src/service.ts +2138 -0
  60. package/src/session/manager.ts +352 -0
  61. package/src/session/repair.ts +157 -0
  62. package/src/session/request-policy.ts +192 -0
  63. package/src/session/routes.ts +165 -0
  64. package/src/session-commands.ts +310 -0
  65. package/src/session-export.ts +112 -0
  66. package/src/settings/catalog.ts +309 -0
  67. package/src/settings/contract.ts +508 -0
  68. package/src/settings/overlay.ts +164 -0
  69. package/src/settings/routes.ts +409 -0
  70. package/src/settings/surface.ts +773 -0
  71. package/src/stats.ts +485 -0
  72. package/src/streamer.ts +1108 -0
  73. package/src/workspaces.ts +199 -0
@@ -0,0 +1,92 @@
1
+ /**
2
+ * 浏览器半区的设置面板选择器目录折叠:把 Host 下发的字段描述与实时目录
3
+ * (`/dsh-channels/catalog`)合成通用表单需要的 select 描述。
4
+ *
5
+ * 拆成独立模块(不含 JSX/React)以便单测;`panel.tsx` 只负责串起状态与渲染。
6
+ *
7
+ * @module dsh-channels/client/catalog
8
+ */
9
+
10
+ import { PANEL_COPY } from '../settings/contract.ts'
11
+ import type {
12
+ CatalogWire,
13
+ EditableFieldWire,
14
+ EditableKey,
15
+ FieldOptionWire,
16
+ SelectCatalogWire,
17
+ } from '../settings/contract.ts'
18
+
19
+ /** Keys whose options come from the Host selector catalog. */
20
+ export const CATALOG_KEYS = ['provider', 'model', 'reasoningEffort', 'agentPreset'] as const
21
+ export type CatalogKey = (typeof CATALOG_KEYS)[number]
22
+
23
+ export function isCatalogKey(key: EditableKey): key is CatalogKey {
24
+ return (CATALOG_KEYS as readonly string[]).includes(key)
25
+ }
26
+
27
+ /** Read one selector group back out of the Host-resolved panel fields. */
28
+ export function selectorOf(field: EditableFieldWire | undefined): SelectCatalogWire {
29
+ if (field?.kind !== 'select') return { selectable: false, options: [] }
30
+ return {
31
+ selectable: true,
32
+ options: field.options === undefined ? [] : [...field.options],
33
+ ...(field.disabled === true ? { disabled: true } : {}),
34
+ ...(field.help === undefined ? {} : { help: field.help }),
35
+ }
36
+ }
37
+
38
+ /** Seed the client catalog from the options the Host already resolved for the panel. */
39
+ export function catalogFromFields(fields: readonly EditableFieldWire[]): CatalogWire | null {
40
+ const byKey = new Map(fields.map(field => [field.key, field]))
41
+ const catalog: CatalogWire = {
42
+ provider: selectorOf(byKey.get('provider')),
43
+ model: selectorOf(byKey.get('model')),
44
+ reasoningEffort: selectorOf(byKey.get('reasoningEffort')),
45
+ agentPreset: selectorOf(byKey.get('agentPreset')),
46
+ }
47
+ return CATALOG_KEYS.every(key => !catalog[key].selectable) ? null : catalog
48
+ }
49
+
50
+ /** Current-value option kept when a saved value is missing from the live list. */
51
+ function withCurrentOption(options: readonly FieldOptionWire[], value: string): FieldOptionWire[] {
52
+ const [inherit, ...rest] = options
53
+ const extra: FieldOptionWire = { value, label: `${value}(当前配置,不在宿主机列表中)` }
54
+ return inherit === undefined ? [extra] : [inherit, extra, ...rest]
55
+ }
56
+
57
+ /**
58
+ * Layer the live catalog over the Host panel fields. A group the Host cannot
59
+ * enumerate falls back to the free-text control; the rest render as selects.
60
+ *
61
+ * `disabled` must be cleared explicitly: the Host's initial panel descriptor
62
+ * carries `disabled: true` for dependent selectors (model without a provider,
63
+ * effort without a model), and a fetched catalog that resolved the dependency
64
+ * has to re-enable them. Forgetting this is exactly what made the model and
65
+ * reasoning selects permanently unusable after choosing a provider/model.
66
+ */
67
+ export function applyCatalogFields(
68
+ fields: readonly EditableFieldWire[],
69
+ catalog: CatalogWire | null,
70
+ current: Partial<Record<CatalogKey, string | undefined>> = {},
71
+ ): EditableFieldWire[] {
72
+ if (catalog === null) return [...fields]
73
+ return fields.map((field) => {
74
+ if (!isCatalogKey(field.key)) return field
75
+ const selector = catalog[field.key]
76
+ if (!selector.selectable) {
77
+ return field.kind === 'select'
78
+ ? { ...field, kind: 'text', options: undefined, help: PANEL_COPY.catalogUnavailable, disabled: undefined }
79
+ : field
80
+ }
81
+ const value = current[field.key] ?? ''
82
+ const options = value !== '' && !selector.options.some(option => option.value === value)
83
+ ? withCurrentOption(selector.options, value)
84
+ : [...selector.options]
85
+ const next: EditableFieldWire = { ...field, kind: 'select', options }
86
+ if (selector.disabled === true) next.disabled = true
87
+ else delete next.disabled
88
+ if (selector.help === undefined) delete next.help
89
+ else next.help = selector.help
90
+ return next
91
+ })
92
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * dsh-channels client half: 设置 →「飞书渠道」分区。
3
+ *
4
+ * 只依赖平台核心的 `slots` 服务与 react(bundle 里 react 走平台模块表,
5
+ * 其余全部内联)。页面数据来自 Host 半侧的 `/dsh-channels/*` 路由,因此
6
+ * 不需要 typert 契约,也不 import 任何 DSH 客户端包。
7
+ *
8
+ * @module dsh-channels/client
9
+ */
10
+
11
+ import { PANEL_COPY } from '../settings/contract.ts'
12
+ import { FeishuChannelsSection } from './panel.tsx'
13
+ import { installStyles } from './styles.ts'
14
+
15
+ // 平台 client runtime 的最小结构声明:只声明本 bundle 用到的两个能力。
16
+ // 与安装的 DSH Web 版本(0.2.x)的 slots 运行时 API 一致。
17
+ export interface ClientSlots {
18
+ inject(slot: string, contribution: () => unknown): void
19
+ register(
20
+ declaration: {
21
+ name: string
22
+ id: string
23
+ order?: number
24
+ label: () => string
25
+ },
26
+ component: (props: { close?: () => void }) => unknown,
27
+ ): () => void
28
+ }
29
+
30
+ export interface ClientContext {
31
+ slots: ClientSlots
32
+ effect?(callback: () => void | (() => void), label?: string): void
33
+ }
34
+
35
+ /** Cordis client plugin name. */
36
+ export const name = 'dsh-channels'
37
+
38
+ /** Required client services: the Slots registry is part of the web shell core. */
39
+ export const inject = ['slots']
40
+
41
+ /** Section id and nav order (built-ins: account -10, general 0, models 10, plugins 15, agent-presets 20). */
42
+ export const SETTINGS_SECTION_ID = 'feishu-channels'
43
+ export const SETTINGS_SECTION_ORDER = 40
44
+
45
+ /**
46
+ * Mount the settings section and its stylesheet.
47
+ * @param ctx - client plugin context carrying the slots registry.
48
+ */
49
+ export function apply(ctx: ClientContext): void {
50
+ if (typeof ctx.effect === 'function') {
51
+ ctx.effect(() => installStyles(), 'dsh-channels: settings styles')
52
+ } else {
53
+ installStyles()
54
+ }
55
+ ctx.slots.inject('settings.section', () => ctx.slots.register({
56
+ name: 'settings.section',
57
+ id: SETTINGS_SECTION_ID,
58
+ order: SETTINGS_SECTION_ORDER,
59
+ label: () => PANEL_COPY.title,
60
+ }, FeishuChannelsSection))
61
+ }