@y9931666/dsh-plugin-roundtable 1.0.0-rc.2
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/LICENSE +21 -0
- package/README.md +328 -0
- package/cordis.patch.yml +22 -0
- package/lib/client.js +4276 -0
- package/lib/edge-helper-iqXOG5o_.js +12 -0
- package/lib/index.js +4535 -0
- package/lib/state-BzBQig2q.js +479 -0
- package/lib/state-pJShWoUr.js +3 -0
- package/lib/types/aggregator.d.ts +15 -0
- package/lib/types/budget.d.ts +46 -0
- package/lib/types/charter.d.ts +13 -0
- package/lib/types/client/RoundTableSettings.d.ts +14 -0
- package/lib/types/client/RoundTableView.d.ts +27 -0
- package/lib/types/client/brand-logos.generated.d.ts +5 -0
- package/lib/types/client/index.d.ts +23 -0
- package/lib/types/client/locales.d.ts +14 -0
- package/lib/types/client/slot-boundary.d.ts +49 -0
- package/lib/types/client/tool-views-model.d.ts +65 -0
- package/lib/types/client/tool-views.d.ts +31 -0
- package/lib/types/client/wire.d.ts +238 -0
- package/lib/types/edge-helper.d.ts +7 -0
- package/lib/types/harness-compat.d.ts +204 -0
- package/lib/types/index.d.ts +53 -0
- package/lib/types/kb-digest.d.ts +47 -0
- package/lib/types/members.d.ts +83 -0
- package/lib/types/node-events.d.ts +90 -0
- package/lib/types/plan.d.ts +86 -0
- package/lib/types/preferences.d.ts +143 -0
- package/lib/types/prompt.d.ts +52 -0
- package/lib/types/proxy-thinking.d.ts +12 -0
- package/lib/types/review-split.d.ts +61 -0
- package/lib/types/rpc.d.ts +89 -0
- package/lib/types/skills.d.ts +61 -0
- package/lib/types/snapshot.d.ts +96 -0
- package/lib/types/state.d.ts +142 -0
- package/lib/types/token-usage.d.ts +71 -0
- package/lib/types/tools.d.ts +59 -0
- package/lib/types/types.d.ts +330 -0
- package/lib/types/version.d.ts +21 -0
- package/lib/types/web-guard.d.ts +37 -0
- package/lib/types/workspace-candidates.d.ts +17 -0
- package/lib/workspace-candidates-B7isleLt.js +3 -0
- package/lib/workspace-candidates-DNmGPpSc.js +20 -0
- package/package.json +161 -0
- package/release-notes/v0.2.0.md +39 -0
- package/release-notes/v0.2.1.md +39 -0
- package/release-notes/v0.2.2.md +54 -0
- package/release-notes/v0.2.21.md +42 -0
- package/release-notes/v0.2.31.md +70 -0
- package/release-notes/v0.2.32.md +52 -0
- package/release-notes/v0.2.35.md +116 -0
- package/release-notes/v0.2.36.md +84 -0
- package/release-notes/v1.0.0-rc.1.md +165 -0
- package/release-notes/v1.0.0-rc.2.md +180 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render-failure boundary for the two RoundTable slot entries.
|
|
3
|
+
*
|
|
4
|
+
* WHY THIS EXISTS (v0.2.36): DSH retires a slot entry that throws during render
|
|
5
|
+
* (`onEntryError` + abdication) — correct isolation, but for the user the 圆桌
|
|
6
|
+
* 会议 tab simply is not there, with no message anywhere. That silent
|
|
7
|
+
* disappearance is exactly the shape the "界面调不出来" reports arrived in, and
|
|
8
|
+
* it is undiagnosable from the outside.
|
|
9
|
+
*
|
|
10
|
+
* Wrapping each entry in a boundary turns a crash into a readable panel naming
|
|
11
|
+
* the error, and mirrors it to the browser console with the component stack.
|
|
12
|
+
* The boundary deliberately renders NO data of its own, so it cannot become a
|
|
13
|
+
* second failure source; the panel is swapped out as soon as React re-renders
|
|
14
|
+
* a healthy tree after a reload.
|
|
15
|
+
*
|
|
16
|
+
* @module dsh-plugin-roundtable/client/slot-boundary
|
|
17
|
+
*/
|
|
18
|
+
import { Component, type ComponentType, type ErrorInfo, type ReactNode } from 'react';
|
|
19
|
+
/** The inject face every RoundTable slot entry receives (see client/index.ts). */
|
|
20
|
+
export interface SlotEntryFace {
|
|
21
|
+
/** Locale-bound translator for the `roundtable` namespace. */
|
|
22
|
+
t?: (key: string) => string;
|
|
23
|
+
}
|
|
24
|
+
interface SlotBoundaryProps {
|
|
25
|
+
title: string;
|
|
26
|
+
hint: string;
|
|
27
|
+
children?: ReactNode;
|
|
28
|
+
}
|
|
29
|
+
interface SlotBoundaryState {
|
|
30
|
+
error: Error | null;
|
|
31
|
+
}
|
|
32
|
+
/** Class-component boundary (React only catches render errors in class components). */
|
|
33
|
+
export declare class SlotBoundary extends Component<SlotBoundaryProps, SlotBoundaryState> {
|
|
34
|
+
state: SlotBoundaryState;
|
|
35
|
+
static getDerivedStateFromError(error: Error): SlotBoundaryState;
|
|
36
|
+
componentDidCatch(error: Error, info: ErrorInfo): void;
|
|
37
|
+
render(): ReactNode;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Wrap one slot component so a render crash renders a report instead of
|
|
41
|
+
* vanishing. The inner component keeps receiving every prop it got before
|
|
42
|
+
* (owner share + standard seats + the inject face), so this is transparent on
|
|
43
|
+
* the happy path.
|
|
44
|
+
*
|
|
45
|
+
* @param Inner - the registered slot component.
|
|
46
|
+
* @returns a component with the same props contract.
|
|
47
|
+
*/
|
|
48
|
+
export declare function withSlotBoundary<P extends object>(Inner: ComponentType<P>): ComponentType<P>;
|
|
49
|
+
export {};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `roundtable_status` tool view 的纯逻辑(第 4 批)。
|
|
3
|
+
*
|
|
4
|
+
* 与渲染分离的原因很实际:Node 的类型剥离**不支持 JSX**,所以放在 `.tsx` 里的
|
|
5
|
+
* 解析函数无法被零依赖单测直接 import。这里只留可测的判定,组件(tool-views.tsx)
|
|
6
|
+
* 只负责画。
|
|
7
|
+
*
|
|
8
|
+
* @module @y9931666/dsh-plugin-roundtable/client/tool-views-model
|
|
9
|
+
*/
|
|
10
|
+
/** Structural view of the owner block this view needs (no host type import). */
|
|
11
|
+
export interface ToolBlockLike {
|
|
12
|
+
kind?: string;
|
|
13
|
+
isError?: boolean;
|
|
14
|
+
call?: {
|
|
15
|
+
name?: string;
|
|
16
|
+
argsRaw?: string;
|
|
17
|
+
} | null;
|
|
18
|
+
content?: readonly {
|
|
19
|
+
type?: string;
|
|
20
|
+
text?: string;
|
|
21
|
+
}[];
|
|
22
|
+
}
|
|
23
|
+
/** Parsed subset of one `roundtable_status` payload. */
|
|
24
|
+
export interface StatusPayload {
|
|
25
|
+
meeting_name?: unknown;
|
|
26
|
+
mode?: unknown;
|
|
27
|
+
status?: unknown;
|
|
28
|
+
round?: unknown;
|
|
29
|
+
budget?: {
|
|
30
|
+
used_tokens?: unknown;
|
|
31
|
+
max_tokens?: unknown;
|
|
32
|
+
max_rounds?: unknown;
|
|
33
|
+
} | null;
|
|
34
|
+
nodes?: readonly {
|
|
35
|
+
key?: unknown;
|
|
36
|
+
status?: unknown;
|
|
37
|
+
activity?: unknown;
|
|
38
|
+
last_error?: unknown;
|
|
39
|
+
}[] | null;
|
|
40
|
+
pending_decisions?: readonly unknown[] | null;
|
|
41
|
+
pending_actions?: readonly unknown[] | null;
|
|
42
|
+
}
|
|
43
|
+
/** Flatten the text blocks of a settled tool result. */
|
|
44
|
+
export declare function blockTextOf(block: unknown): string;
|
|
45
|
+
/**
|
|
46
|
+
* Parse a `roundtable_status` result; `null` when it is anything else.
|
|
47
|
+
*
|
|
48
|
+
* Deliberately claims only this tool's own shape: a payload without a string
|
|
49
|
+
* `meeting_name` falls back to the generic rendering rather than being forced
|
|
50
|
+
* into a card that would show blanks.
|
|
51
|
+
*/
|
|
52
|
+
export declare function parseStatusPayload(text: string): StatusPayload | null;
|
|
53
|
+
/** Display a payload field without ever printing `undefined`. */
|
|
54
|
+
export declare function fieldText(value: unknown): string;
|
|
55
|
+
/**
|
|
56
|
+
* One expert node line: `key status/activity`, plus the failure note the node
|
|
57
|
+
* left behind (`last_error` is what makes "这位专家到底跑起来了没有" answerable,
|
|
58
|
+
* and `missing` means the host no longer knows that subagent at all).
|
|
59
|
+
*/
|
|
60
|
+
export declare function nodeLine(node: {
|
|
61
|
+
key?: unknown;
|
|
62
|
+
status?: unknown;
|
|
63
|
+
activity?: unknown;
|
|
64
|
+
last_error?: unknown;
|
|
65
|
+
}): string;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `roundtable_status` 的专属渲染(第 4 批)。
|
|
3
|
+
*
|
|
4
|
+
* 注册在 `tool.call.toolview` 上,key 是本插件自己的工具名。宿主的 key 域是
|
|
5
|
+
* 开放的("any wire tool name, **including a tool your own package registered**"),
|
|
6
|
+
* 且"registering is **additive** for your own tool" —— 未认领的 key 才回退到
|
|
7
|
+
* 通用 tool 行。owner 传入的是**已冻结的运行中/已结算节点**,所以这个视图是
|
|
8
|
+
* turn 已知内容的纯函数,无状态。
|
|
9
|
+
*
|
|
10
|
+
* 取数:settled 调用是 `ToolResultNode`(`content: ContentBlock[]`),running 时
|
|
11
|
+
* 只有 `argsRaw`。解析失败**一律回退为纯文本**——绝不显示空白卡片,那会比通用
|
|
12
|
+
* tool 行更糟。纯逻辑在 tool-views-model.ts(JSX 无法被零依赖测试直接加载)。
|
|
13
|
+
*
|
|
14
|
+
* @module @y9931666/dsh-plugin-roundtable/client/tool-views
|
|
15
|
+
*/
|
|
16
|
+
import { type StatusPayload } from './tool-views-model.ts';
|
|
17
|
+
/** Card body for a parsed status payload. */
|
|
18
|
+
export declare function StatusCard({ data }: {
|
|
19
|
+
data: StatusPayload;
|
|
20
|
+
}): JSX.Element;
|
|
21
|
+
/**
|
|
22
|
+
* Tool view for `roundtable_status`.
|
|
23
|
+
*
|
|
24
|
+
* Renders the card when the result parses, otherwise falls back to the raw
|
|
25
|
+
* text (and to `null` when there is nothing at all — the host's own call row
|
|
26
|
+
* still shows the running call).
|
|
27
|
+
*/
|
|
28
|
+
export declare function RoundTableStatusView(props: {
|
|
29
|
+
block?: unknown;
|
|
30
|
+
toolName?: string;
|
|
31
|
+
}): JSX.Element | null;
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire types shared by the browser topology tab: the meeting snapshot served
|
|
3
|
+
* by `/plugins/dsh-plugin-roundtable/state` and the RPC result envelope.
|
|
4
|
+
* @module dsh-plugin-roundtable/client/wire
|
|
5
|
+
*/
|
|
6
|
+
/** One RPC response envelope (structurally compatible with the host's RpcResult). */
|
|
7
|
+
export type RpcEnvelope<T> = {
|
|
8
|
+
ok: true;
|
|
9
|
+
value: T;
|
|
10
|
+
error?: never;
|
|
11
|
+
} | {
|
|
12
|
+
ok: false;
|
|
13
|
+
error: {
|
|
14
|
+
code: string;
|
|
15
|
+
message: string;
|
|
16
|
+
details?: unknown;
|
|
17
|
+
};
|
|
18
|
+
value?: never;
|
|
19
|
+
};
|
|
20
|
+
/** A tiny typed RPC caller over the plugin's own web route. */
|
|
21
|
+
export type RpcCaller = <T>(endpoint: string, payload: unknown) => Promise<RpcEnvelope<T>>;
|
|
22
|
+
/**
|
|
23
|
+
* POST one RPC call to the plugin's OWN web route.
|
|
24
|
+
*
|
|
25
|
+
* That route is mounted through the same `webServer` registration as the
|
|
26
|
+
* snapshot route, so the browser reaches it even when the host's generic
|
|
27
|
+
* connection channel is not mounted — which is what made the settings page
|
|
28
|
+
* report 「读取设置失败」. An unreachable or malformed answer is reported as a
|
|
29
|
+
* failure envelope instead of a rejected promise.
|
|
30
|
+
*/
|
|
31
|
+
export declare function callRpc<T>(endpoint: string, payload: unknown, signal?: AbortSignal): Promise<RpcEnvelope<T>>;
|
|
32
|
+
export interface WireNode {
|
|
33
|
+
id: string;
|
|
34
|
+
key: string;
|
|
35
|
+
role: string;
|
|
36
|
+
provider: string;
|
|
37
|
+
model: string;
|
|
38
|
+
status: string;
|
|
39
|
+
activity: string;
|
|
40
|
+
}
|
|
41
|
+
export interface WireEdge {
|
|
42
|
+
id: string;
|
|
43
|
+
from: string;
|
|
44
|
+
to: string;
|
|
45
|
+
direction: string;
|
|
46
|
+
}
|
|
47
|
+
export interface WireBudget {
|
|
48
|
+
maxRounds: number;
|
|
49
|
+
maxTokens: number;
|
|
50
|
+
usedRounds: number;
|
|
51
|
+
usedTokens: number;
|
|
52
|
+
/** 第 3 批:provider 上报的真实用量(0 = 此刻不可测)。 */
|
|
53
|
+
usedTokensReal?: number;
|
|
54
|
+
}
|
|
55
|
+
export interface WirePendingDecision {
|
|
56
|
+
id: string;
|
|
57
|
+
question: string;
|
|
58
|
+
options: string[];
|
|
59
|
+
}
|
|
60
|
+
/** One pending user action recorded by the Web UI, awaiting the captain. */
|
|
61
|
+
export interface WirePendingAction {
|
|
62
|
+
id: string;
|
|
63
|
+
kind: string;
|
|
64
|
+
nodeKey: string;
|
|
65
|
+
role: string;
|
|
66
|
+
provider: string;
|
|
67
|
+
model: string;
|
|
68
|
+
text: string;
|
|
69
|
+
}
|
|
70
|
+
/** Model entry for the expert-management dropdown (from host llm catalog). */
|
|
71
|
+
export interface WireModelOption {
|
|
72
|
+
id: string;
|
|
73
|
+
name: string;
|
|
74
|
+
}
|
|
75
|
+
/** Provider entry with its advertised models for the expert-management dropdown. */
|
|
76
|
+
export interface WireProviderOption {
|
|
77
|
+
id: string;
|
|
78
|
+
name: string;
|
|
79
|
+
models: WireModelOption[];
|
|
80
|
+
}
|
|
81
|
+
export interface WireMessage {
|
|
82
|
+
id: string;
|
|
83
|
+
from: string;
|
|
84
|
+
to: string;
|
|
85
|
+
ts: number;
|
|
86
|
+
}
|
|
87
|
+
/** One knowledge-base directory entry (阅览版: name/kind/format/size only). */
|
|
88
|
+
export interface WireKbEntry {
|
|
89
|
+
name: string;
|
|
90
|
+
kind: 'file' | 'dir';
|
|
91
|
+
ext: string;
|
|
92
|
+
size: number;
|
|
93
|
+
mtimeMs: number;
|
|
94
|
+
}
|
|
95
|
+
/** Knowledge-base listing returned by `roundtable/kb.list`. */
|
|
96
|
+
export interface WireKbListing {
|
|
97
|
+
path: string;
|
|
98
|
+
configured: boolean;
|
|
99
|
+
error: string;
|
|
100
|
+
files: WireKbEntry[];
|
|
101
|
+
}
|
|
102
|
+
/** 观点证据分级(C1):repro=可复现步骤;argument=论证链。 */
|
|
103
|
+
export interface WireReviewEvidence {
|
|
104
|
+
kind: 'repro' | 'argument';
|
|
105
|
+
text: string;
|
|
106
|
+
}
|
|
107
|
+
/** 针锋相对评审:一个观点(V0.2.2 三态 + 拆分)。 */
|
|
108
|
+
export interface WireReviewViewpoint {
|
|
109
|
+
id: string;
|
|
110
|
+
utteranceId: string;
|
|
111
|
+
nodeKey: string;
|
|
112
|
+
content: string;
|
|
113
|
+
/** 三态:pending/endorsed/rejected。 */
|
|
114
|
+
status: 'pending' | 'endorsed' | 'rejected';
|
|
115
|
+
/** 兼容派生(旧视图仍可读):status === 'endorsed'。 */
|
|
116
|
+
endorsed: boolean;
|
|
117
|
+
/** 派生:status === 'rejected'。 */
|
|
118
|
+
rejected: boolean;
|
|
119
|
+
/** 驳回理由(C2:驳回必填;前端在 rejected 状态下展示)。 */
|
|
120
|
+
rejectReason?: string;
|
|
121
|
+
/** 证据分级(C1)。 */
|
|
122
|
+
evidence?: WireReviewEvidence;
|
|
123
|
+
/** 原文引用子串(拆分观点可能有)。 */
|
|
124
|
+
quote?: string;
|
|
125
|
+
/** 维度标签(默认"其他")。 */
|
|
126
|
+
dimension: string;
|
|
127
|
+
/** 发言内序号:0=整条未拆分。 */
|
|
128
|
+
seq: number;
|
|
129
|
+
}
|
|
130
|
+
/** 针锋相对评审记录(快照携带,前端弹窗数据源)。 */
|
|
131
|
+
export interface WireReview {
|
|
132
|
+
status: string;
|
|
133
|
+
reviewPass: number;
|
|
134
|
+
maxReviewPass: number;
|
|
135
|
+
question: string;
|
|
136
|
+
plan: string;
|
|
137
|
+
viewpoints: WireReviewViewpoint[];
|
|
138
|
+
}
|
|
139
|
+
/** 一条匿名反馈(E1/E3:设置页列表展示)。 */
|
|
140
|
+
export interface WireFeedbackEntry {
|
|
141
|
+
id: string;
|
|
142
|
+
ts: number;
|
|
143
|
+
meetingId: string;
|
|
144
|
+
mode: string;
|
|
145
|
+
providers: string[];
|
|
146
|
+
models: string[];
|
|
147
|
+
usedRounds: number;
|
|
148
|
+
usedTokens: number;
|
|
149
|
+
rating: 'good' | 'meh' | 'bad';
|
|
150
|
+
note?: string;
|
|
151
|
+
}
|
|
152
|
+
export interface WireUtterance {
|
|
153
|
+
id: string;
|
|
154
|
+
from: string;
|
|
155
|
+
to: string;
|
|
156
|
+
text: string;
|
|
157
|
+
ts: number;
|
|
158
|
+
round: number;
|
|
159
|
+
}
|
|
160
|
+
export interface WireMeeting {
|
|
161
|
+
id: string;
|
|
162
|
+
name: string;
|
|
163
|
+
goal: string;
|
|
164
|
+
mode: string;
|
|
165
|
+
status: string;
|
|
166
|
+
round: number;
|
|
167
|
+
workspace: string;
|
|
168
|
+
captainSessionId: string;
|
|
169
|
+
/** 知识库目录(阅览版);空 = 未设置。 */
|
|
170
|
+
kbPath: string;
|
|
171
|
+
/** R2:本次会议选中的 skill 名称清单;空 = 未选。 */
|
|
172
|
+
skills: string[];
|
|
173
|
+
/** R2.2/D5:skill 传递方式(relay / direct)。 */
|
|
174
|
+
skillDelivery: string;
|
|
175
|
+
budget: WireBudget;
|
|
176
|
+
nodes: WireNode[];
|
|
177
|
+
edges: WireEdge[];
|
|
178
|
+
pendingDecisions: WirePendingDecision[];
|
|
179
|
+
pendingActions: WirePendingAction[];
|
|
180
|
+
review: WireReview | null;
|
|
181
|
+
digest: string;
|
|
182
|
+
messages: WireMessage[];
|
|
183
|
+
recent: WireUtterance[];
|
|
184
|
+
}
|
|
185
|
+
/** B3 用户自建角色预设(设置页维护;专家管理面板一键填充)。
|
|
186
|
+
* 与 host `types.ts` 的 `RolePreset` 逐字对应。 */
|
|
187
|
+
export interface WireRolePreset {
|
|
188
|
+
id: string;
|
|
189
|
+
name: string;
|
|
190
|
+
role: string;
|
|
191
|
+
/** 可选 provider 路由;必须与 model 同时存在才生效。 */
|
|
192
|
+
provider?: string;
|
|
193
|
+
/** 可选模型名;空 = 继承主持人。 */
|
|
194
|
+
model?: string;
|
|
195
|
+
}
|
|
196
|
+
/** B3+ 阵容预设的一位成员(与 host `types.ts` 的 `RoleSquadMember` 对应)。
|
|
197
|
+
* 阵容只回答"请哪几位专家",不描述会议怎么开。 */
|
|
198
|
+
export interface WireRoleSquadMember {
|
|
199
|
+
key: string;
|
|
200
|
+
role: string;
|
|
201
|
+
provider?: string;
|
|
202
|
+
model?: string;
|
|
203
|
+
}
|
|
204
|
+
/** B3+ 阵容预设(一次套用多位专家)。 */
|
|
205
|
+
export interface WireRoleSquad {
|
|
206
|
+
id: string;
|
|
207
|
+
name: string;
|
|
208
|
+
members: WireRoleSquadMember[];
|
|
209
|
+
}
|
|
210
|
+
export interface RoundTablePrefs {
|
|
211
|
+
defaultMode: 'orchestrated' | 'egalitarian' | 'redteam';
|
|
212
|
+
maxRounds: number;
|
|
213
|
+
maxTokens: number;
|
|
214
|
+
/** 互通开关:true=显示所有圆桌会议;false=仅显示当前对话开启的会议。 */
|
|
215
|
+
showAllMeetings: boolean;
|
|
216
|
+
/** 专家每轮输出 token 上限(模型请求 max_tokens),0 = 不限制。 */
|
|
217
|
+
expertMaxTokens: number;
|
|
218
|
+
/** 专家每轮最多提几条意见,0 = 不限制。 */
|
|
219
|
+
expertMaxOpinions: number;
|
|
220
|
+
/** E1/E4 反馈:会议结束后是否询问轻量反馈;false = 永久关闭。 */
|
|
221
|
+
feedbackEnabled: boolean;
|
|
222
|
+
/** R2.2/D5:skill 传递方式(relay=主持人中转;direct=专家自行调用)。 */
|
|
223
|
+
skillDelivery: 'relay' | 'direct';
|
|
224
|
+
/** R3:右栏隐藏的面板 id 清单;空 = 全部显示。 */
|
|
225
|
+
hiddenPanels: string[];
|
|
226
|
+
/** A1:画布图例已被用户关闭(true = 不显示)。默认 false。 */
|
|
227
|
+
legendHidden: boolean;
|
|
228
|
+
/** B3:用户自建角色预设(全局;不预置内置角色)。 */
|
|
229
|
+
rolePresets: WireRolePreset[];
|
|
230
|
+
/** B3+:用户自建阵容预设(全局;不预置内置阵容)。 */
|
|
231
|
+
squads: WireRoleSquad[];
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Poll the meeting snapshot. Without a session id the host lists every
|
|
235
|
+
* meeting under every workspace (互通开); with one it filters by captain
|
|
236
|
+
* session (互通关 — only meetings started by the current conversation).
|
|
237
|
+
*/
|
|
238
|
+
export declare function fetchMeetings(sessionId?: string): Promise<WireMeeting[]>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Locate the workspace directory owning a meeting directory (used by the RPC
|
|
3
|
+
* edge.set path, which arrives without a session context).
|
|
4
|
+
* @module dsh-plugin-roundtable/edge-helper
|
|
5
|
+
*/
|
|
6
|
+
/** Find the first workspace whose state root contains the given meeting. */
|
|
7
|
+
export declare function workspaceOfMeeting(stateDir: string, meetingId: string): Promise<string | undefined>;
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 宿主兼容与能力边界(Host compatibility boundary)。
|
|
3
|
+
*
|
|
4
|
+
* **所有与 DSH 版本相关的形状都集中在这个文件里。**
|
|
5
|
+
* 理由与做法直接借鉴社区项目 dsh-agent-teams 的 `src/harness-compat.ts`:
|
|
6
|
+
*
|
|
7
|
+
* > Keep version-specific shapes here: **API presence alone is not a promise of
|
|
8
|
+
* > support for future versions.**
|
|
9
|
+
*
|
|
10
|
+
* 我们的宿主是 **rc 线**(0.1.5-rc.2 → rc.3 → **0.2.0-rc.2**;`0.1.6-alpha.*`
|
|
11
|
+
* 是另一条未纳入的线),API 尚未冻结,破坏性变更属于常态 —— 0.2.0-rc.2 一轮
|
|
12
|
+
* 就动了两处真正破坏兼容的地方。所以在写任何 `ctx.get(...)` / `ctx.on(...)` /
|
|
13
|
+
* 服务方法调用之前,先问一句:**这个形状在别的 rc 上还成立吗?** 如果答案需要翻
|
|
14
|
+
* 源码,那它就应该写进本文件,而不是散进业务代码。
|
|
15
|
+
*
|
|
16
|
+
* 每轮升级的实测结论记在文末「6. 宿主契约变更实录」—— 那是本文件最值钱的部分。
|
|
17
|
+
*
|
|
18
|
+
* 两条铁律:
|
|
19
|
+
* 1. **探测绝不成为新的加载门禁**。这里没有 `inject`、没有静态导入宿主包,
|
|
20
|
+
* 缺失的能力一律降级(记录进审计表)——v0.2.36 的「整个界面消失」事故
|
|
21
|
+
* 就是可选能力被当成必需能力造成的。
|
|
22
|
+
* 2. **降级要留痕**。每个能力第一次被探测时记一条审计,`roundtable_status`
|
|
23
|
+
* 与 `scripts/doctor.mjs` 都能把它打出来,让"为什么某个功能没生效"
|
|
24
|
+
* 有一个能查的答案,而不是靠猜。
|
|
25
|
+
*
|
|
26
|
+
* @module dsh-plugin-roundtable/harness-compat
|
|
27
|
+
*/
|
|
28
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
29
|
+
/**
|
|
30
|
+
* 插件**要求**宿主提供的服务能力:少一个就装不起来。
|
|
31
|
+
*
|
|
32
|
+
* 这个数组必须与 `src/index.ts` 的 `inject`、`compatibility.json` 的
|
|
33
|
+
* `capabilities` 三者逐字一致 —— `scripts/compatibility.mjs` 会校验,
|
|
34
|
+
* 不一致直接失败。这样"支持哪些宿主"只有一处真话。
|
|
35
|
+
*/
|
|
36
|
+
export declare const REQUIRED_CAPABILITIES: readonly ["tools", "subagents", "agents", "systemPrompt"];
|
|
37
|
+
/** 可选能力:缺失只降级,绝不阻断加载。 */
|
|
38
|
+
export declare const OPTIONAL_CAPABILITIES: readonly ["connection", "llm", "skills", "userQuestions", "sessionProjections", "webServer", "workspaceRegistry"];
|
|
39
|
+
/** 一个能力探测点的静态描述。 */
|
|
40
|
+
export interface CapabilitySpec {
|
|
41
|
+
id: string;
|
|
42
|
+
kind: 'required' | 'optional';
|
|
43
|
+
/** 用来做什么。 */
|
|
44
|
+
purpose: string;
|
|
45
|
+
/** 缺失(或形状不符)时发生什么 —— 这一栏是运维价值的核心。 */
|
|
46
|
+
whenMissing: string;
|
|
47
|
+
/** 版本相关的证据说明。 */
|
|
48
|
+
evidence: string;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 本插件触碰过的**每一个**宿主能力探测点。
|
|
52
|
+
*
|
|
53
|
+
* 加新的探测点时同时更新这里:`scripts/doctor.mjs` 与
|
|
54
|
+
* `test/compatibility.test.mjs` 都以本表为准,漏登记会被测试拦下。
|
|
55
|
+
*/
|
|
56
|
+
export declare const CAPABILITY_SPECS: readonly CapabilitySpec[];
|
|
57
|
+
/** 一次能力探测的结果。 */
|
|
58
|
+
export type CapabilityState = 'not_probed' | 'available' | 'missing' | 'degraded';
|
|
59
|
+
/** 审计表里的一条。 */
|
|
60
|
+
export interface CapabilityAudit {
|
|
61
|
+
state: CapabilityState;
|
|
62
|
+
/** 人类可读的一句话,说明探测到了什么或为什么降级。 */
|
|
63
|
+
note: string;
|
|
64
|
+
ts: number;
|
|
65
|
+
}
|
|
66
|
+
/** 当前审计快照(给 roundtable_status / doctor 用)。 */
|
|
67
|
+
export declare function capabilityAudit(): ReadonlyMap<string, CapabilityAudit>;
|
|
68
|
+
/** 渲染成紧凑的一行行文本(诊断输出用)。 */
|
|
69
|
+
export declare function formatCapabilityAudit(): string;
|
|
70
|
+
/**
|
|
71
|
+
* 记录一次探测结果(**每个能力只保留第一条**)。
|
|
72
|
+
*
|
|
73
|
+
* 只记第一条是刻意的:探测点常在 tick / 轮询路径上,每次都记会把内存和日志
|
|
74
|
+
* 都吃掉;而"第一次看到它是什么状态"已经足够定位问题。
|
|
75
|
+
*/
|
|
76
|
+
export declare function noteCapability(id: string, state: CapabilityState, note: string): CapabilityState;
|
|
77
|
+
/** 测试用:清空审计表。 */
|
|
78
|
+
export declare function resetCapabilityAudit(): void;
|
|
79
|
+
/**
|
|
80
|
+
* 读一个**可选**宿主服务。
|
|
81
|
+
*
|
|
82
|
+
* 统一走 `ctx.get`(cordis 核心、非严格:缺失返回 `undefined`)而不是属性访问
|
|
83
|
+
* —— 后者在没有 `inject` 时会**直接抛错**:
|
|
84
|
+
* `cannot get property "connection" without inject`。
|
|
85
|
+
*/
|
|
86
|
+
export declare function optionalService<T>(ctx: Context, name: string): T | undefined;
|
|
87
|
+
/** 可选服务键的结构式候选(宿主可能改名;按序取第一个可用的)。 */
|
|
88
|
+
export declare const WEB_SERVER_KEYS: readonly ["webServer", "httpServer"];
|
|
89
|
+
export declare const WORKSPACE_KEYS: readonly ["workspaceRegistry", "workspace"];
|
|
90
|
+
/** webServer 服务面(只声明我们真正调用的部分)。
|
|
91
|
+
*
|
|
92
|
+
* `register` 的返回值刻意只声明为 `() => void`:宿主不同 rc 上返回过
|
|
93
|
+
* disposer 与 `unknown`,而调用处一律以 `ctx.effect(() => webServer.register(…))`
|
|
94
|
+
* 的形式**忽略返回值**——effect 自带卸载。声明成 `unknown` 会让
|
|
95
|
+
* `ctx.effect` 的重载解析失败(它要求回调返回具体 Effect,不接受 unknown),
|
|
96
|
+
* 所以这里保留"当它是清理函数"的写法。 */
|
|
97
|
+
export interface WebRouteHost {
|
|
98
|
+
register(route: {
|
|
99
|
+
kind: 'exact';
|
|
100
|
+
path: string;
|
|
101
|
+
handler: (req: import('node:http').IncomingMessage, res: import('node:http').ServerResponse) => Promise<void> | void;
|
|
102
|
+
}): () => void;
|
|
103
|
+
}
|
|
104
|
+
/** workspace 注册表面。 */
|
|
105
|
+
export interface WorkspaceListHost {
|
|
106
|
+
list(): {
|
|
107
|
+
title: string;
|
|
108
|
+
path: string;
|
|
109
|
+
}[];
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* 解析 webServer 服务面。
|
|
113
|
+
*
|
|
114
|
+
* 服务键是**结构式候选**而非固定名:宿主可能把 `webServer` 换成别的名字,
|
|
115
|
+
* 所以按 `WEB_SERVER_KEYS` 顺序探测。headless profile 下取不到属预期,
|
|
116
|
+
* 只降级不报错。
|
|
117
|
+
*/
|
|
118
|
+
export declare function webRouteHostOf(ctx: Context): WebRouteHost | undefined;
|
|
119
|
+
/** 解析 workspace 注册表面(同上,结构式候选 + 降级留痕)。 */
|
|
120
|
+
export declare function workspaceRegistryOf(ctx: Context): WorkspaceListHost | undefined;
|
|
121
|
+
/**
|
|
122
|
+
* 判定一个 `rpc.handle(...)` 返回值能不能当清理函数用。
|
|
123
|
+
*
|
|
124
|
+
* 宿主签名在 rc 线上变过:0.1.1 时代第三参 `{ authority }` 被移除,返回值在
|
|
125
|
+
* 不同版本里出现过 `disposer` / `undefined` / Promise。这里只做**形状判定**,
|
|
126
|
+
* 不 import 宿主类型:合法就交出去,不合法就交给调用方记一条降级。
|
|
127
|
+
*/
|
|
128
|
+
export declare function asDisposer(value: unknown): (() => void) | undefined;
|
|
129
|
+
/**
|
|
130
|
+
* 在可选的清理函数存在时注册一个 effect。
|
|
131
|
+
*
|
|
132
|
+
* `connection.rpc.handle` 的返回值形状随版本变化,直接 `ctx.effect(() => () =>
|
|
133
|
+
* release())` 会在返回值不是函数时静默留下一个永远不执行的清理器(通道泄漏)。
|
|
134
|
+
*/
|
|
135
|
+
export declare function effectWithOptionalDisposer(ctx: {
|
|
136
|
+
effect(callback: () => () => void, label?: string): unknown;
|
|
137
|
+
}, disposer: unknown, label: string): boolean;
|
|
138
|
+
/** 投影读取面:宿主只暴露 `snapshot(session, keys)`。 */
|
|
139
|
+
export interface ProjectionReadFace {
|
|
140
|
+
snapshot(session: unknown, keys: string[]): {
|
|
141
|
+
values?: Record<string, unknown>;
|
|
142
|
+
} | undefined;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* 读一个 live session 的投影值。
|
|
146
|
+
*
|
|
147
|
+
* **返回 `undefined`,绝不抛错**:测量用量是观察行为,不能因为宿主投影形状
|
|
148
|
+
* 变化就把 `roundtable_status` 弄崩 —— 与 `token-usage.ts` 的既有契约一致。
|
|
149
|
+
*/
|
|
150
|
+
export declare function projectionValuesOf(ctx: Context, session: unknown): Record<string, unknown> | undefined;
|
|
151
|
+
/**
|
|
152
|
+
* ## 0.2.0-rc.2 —— 两处真破坏(核对日期 2026-09-30)
|
|
153
|
+
*
|
|
154
|
+
* 从 0.1.5-rc.3 抬到 0.2.0-rc.2 后,**宿主侧 `tsc` 只有 4 个错误**,浏览器侧 0 个。
|
|
155
|
+
* 4 个错误归为两类,两类都不是「改一行签名」能解决的。
|
|
156
|
+
*
|
|
157
|
+
* ### ① `settings` 服务被重构成 `SettingsForms`
|
|
158
|
+
*
|
|
159
|
+
* | | 0.1.5-rc.3 | 0.2.0-rc.2 |
|
|
160
|
+
* | --- | --- | --- |
|
|
161
|
+
* | 形状 | `SettingsScope`:插件注册自己的命名空间 | `SettingsForms`:把 profile 配置投影成表单 |
|
|
162
|
+
* | API | `settings.register(ns, schema, { base })` | `configure` / `describe` / `update` / `replace` / `mutate` |
|
|
163
|
+
* | 插件自管偏好 | `scope.get` / `update` / `watch` | **没有对应物** |
|
|
164
|
+
*
|
|
165
|
+
* 编译期症状:
|
|
166
|
+
* `Property 'register' does not exist on type 'SettingsForms'`
|
|
167
|
+
* `Module '"@deepseek-ai/dsh-settings"' has no exported member 'SettingsScope'`
|
|
168
|
+
*
|
|
169
|
+
* **应对**:偏好改为自持久化(`src/preferences.ts` →
|
|
170
|
+
* `<DSH_HOME>/roundtable/preferences.json`),并同步从 `OPTIONAL_CAPABILITIES`、
|
|
171
|
+
* `CAPABILITY_SPECS`、`compatibility.json` 三处移除 `settings`。
|
|
172
|
+
*
|
|
173
|
+
* ⚠️ **不要再试图用 `ctx.inject(['settings'])` 注册命名空间** —— 那个能力在新模型
|
|
174
|
+
* 里不存在。插件现在的可配置面是它自己的 Cordis `Config`(Loader YAML 提供、宿主
|
|
175
|
+
* 自动生成配置页),而写 `Config` 会触发 entry 重载,不适合承载"改一个偏好"。
|
|
176
|
+
*
|
|
177
|
+
* ### ② `MessageSourceMap` 不再有 catch-all 的 `plugin` kind
|
|
178
|
+
*
|
|
179
|
+
* 基础表只剩 `user` / `model` / `tool` / `system-prompt`,其余由**生产者在自己
|
|
180
|
+
* 的模块里** `declare module '@deepseek-ai/dsh-llm'` 补上 —— 宿主内部插件
|
|
181
|
+
* (`tool-registry`、`ptc-mode`、`agent-message`、`subagent-settled` …)都是这么做的。
|
|
182
|
+
* 原文注释写得很直白:**"there is no shared catch-all `plugin` kind"**。
|
|
183
|
+
*
|
|
184
|
+
* 编译期症状:
|
|
185
|
+
* `Type '"plugin"' is not assignable to type '"user" | "model" | "tool" | …'`
|
|
186
|
+
*
|
|
187
|
+
* **应对**:`src/members.ts` 自声明 `roundtable` kind(`{ kind: 'roundtable'; plugin: string }`),
|
|
188
|
+
* 而不是退化成匿名的 `user` —— 转录消费者需要把"插件注入的提示"与"用户说的话"分开。
|
|
189
|
+
*
|
|
190
|
+
* ### 保持不变的(本轮逐项复核确认)
|
|
191
|
+
*
|
|
192
|
+
* `inject` 的四个必需服务、`ctx.subagents` 的派发与 `interruptByParent`、
|
|
193
|
+
* `ctx.agents.get`、`subagent/end` 与 `agent/request-error` 事件、
|
|
194
|
+
* `webServer.register` 的形状、`connection.rpc.handle` 的两参签名与 disposer
|
|
195
|
+
* 返回值、`ctx.skills` / `ctx.userQuestions` / `sessionProjections.snapshot(session, keys)`、
|
|
196
|
+
* 以及全部浏览器侧槽位(`conversation.view` / `settings.section` /
|
|
197
|
+
* `tool.call.toolview`)—— 一律原样可用。
|
|
198
|
+
*
|
|
199
|
+
* ### 环境侧的老教训仍然有效
|
|
200
|
+
*
|
|
201
|
+
* 升级后**先跑 `node scripts/doctor.mjs`**:cordis 必须是同一物理副本,否则
|
|
202
|
+
* `declare module` 合并失效,会出现几十处「Context 上不存在某属性」的假故障,
|
|
203
|
+
* 看起来像 API 全崩。本轮 doctor 一次通过(混装 ✓ / cordis 同一性 ✓)。
|
|
204
|
+
*/
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RoundTable for DeepSeek Harness — host plugin entry.
|
|
3
|
+
*
|
|
4
|
+
* A host-plane plugin that registers the `roundtable_*` tools and one usage
|
|
5
|
+
* section into the global system prompt. After installation any session can
|
|
6
|
+
* run a visualized round-table meeting through natural language: the model
|
|
7
|
+
* creates a meeting (it becomes the captain), adds expert nodes as durable
|
|
8
|
+
* continuable subagents, wires directed edges, collects contributions through
|
|
9
|
+
* the aggregation gateway, and asks the human when a decision is needed.
|
|
10
|
+
* The Web GUI shows the meeting as a topology tab via the `conversation.view`
|
|
11
|
+
* slot, fed by the `/plugins/dsh-plugin-roundtable/state` snapshot route.
|
|
12
|
+
*
|
|
13
|
+
* @module dsh-plugin-roundtable
|
|
14
|
+
*/
|
|
15
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
16
|
+
import z from '@deepseek-ai/schemastery';
|
|
17
|
+
export declare const name = "roundtable";
|
|
18
|
+
/**
|
|
19
|
+
* REQUIRED services only — and the list is load-gating, which is why it is
|
|
20
|
+
* short. cordis has no "optional inject" form (`Inject` is `string[] | Record`
|
|
21
|
+
* and the record form is only intercept config), so every name listed here
|
|
22
|
+
* keeps the whole plugin fiber PENDING until that service exists: no
|
|
23
|
+
* `roundtable_*` tools, no `/plugins/dsh-plugin-roundtable/*` routes and no GUI
|
|
24
|
+
* tab. A missing OPTIONAL capability listed here therefore presents to the user
|
|
25
|
+
* as "圆桌会议整个不见了 / 无法调用界面" with no error anywhere.
|
|
26
|
+
*
|
|
27
|
+
* `userQuestions` and `skills` are deliberately NOT listed: both are optional
|
|
28
|
+
* capabilities that the plugin reads live through `ctx.get(...)`:
|
|
29
|
+
* - skills.ts hard constraint #1 — the plugin MUST load in a profile without
|
|
30
|
+
* the skill service and degrade to an empty catalog;
|
|
31
|
+
* - tools.ts falls back to `decision: 'unavailable'` when the userQuestions
|
|
32
|
+
* service is absent (the captain then states the draft in words).
|
|
33
|
+
* v0.2.36 removed both from this list; v0.2.21 had already fixed the mirrored
|
|
34
|
+
* over-constraint on the browser half (`connection`).
|
|
35
|
+
*/
|
|
36
|
+
export declare const inject: string[];
|
|
37
|
+
/** Plugin configuration. */
|
|
38
|
+
export interface Config {
|
|
39
|
+
/** State directory name under the captain's workspace (default `.roundtable`). */
|
|
40
|
+
stateDir?: string;
|
|
41
|
+
/** `ctx.subagents` provider used to spawn nodes (default `spawn`). */
|
|
42
|
+
memberProvider?: string;
|
|
43
|
+
/** Meeting size cap in nodes (default `8`). */
|
|
44
|
+
maxNodes?: number;
|
|
45
|
+
/** Default collaboration mode (default `orchestrated`; `redteam` = 针锋相对评审). */
|
|
46
|
+
defaultMode?: 'orchestrated' | 'egalitarian' | 'redteam';
|
|
47
|
+
/** Node delegation depth cap (default `1`). */
|
|
48
|
+
memberMaxDepth?: number;
|
|
49
|
+
/** Prompt-section order for the usage policy (default `116`). */
|
|
50
|
+
promptSectionOrder?: number;
|
|
51
|
+
}
|
|
52
|
+
export declare const Config: z<Config>;
|
|
53
|
+
export declare function apply(ctx: Context, config: Config): void;
|