@xyz-agent/extension-protocol 0.4.0 → 0.5.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/dist/index.d.mts CHANGED
@@ -49,6 +49,14 @@ interface GuiComponentProps {
49
49
  /** 列表树——替代 TUI 的 ⎿ ├─ └─ 缩进 */
50
50
  'list-tree': {
51
51
  items: TreeItem[];
52
+ /** 行首显示弱化序号(1/2/3…,mono tabular-nums)。扁平有序清单用(todo);
53
+ * 自带编号的文本(goal criteria "1. xxx")不要开,避免双重编号 */
54
+ numbered?: boolean;
55
+ };
56
+ /** 垂直组合容器——无视觉样式的透明分组。宿主壳层(WidgetArea)承担卡壳/head/折叠
57
+ * 后,widget 内容需要多组件组合时的组合根(替代「无头 card」的语义滥用) */
58
+ 'group': {
59
+ children: GuiComponent[];
52
60
  };
53
61
  /** 双列网格——替代 TUI 的 │ 列分隔 */
54
62
  'columns': {
@@ -73,6 +81,31 @@ interface GuiRenderResult {
73
81
  /** 版本协商,前端检测,不认识降级 ansi-text */
74
82
  v: typeof PROTOCOL_VERSION;
75
83
  component: GuiComponent;
84
+ /**
85
+ * widget 宿主元数据(M17 对话流 widget 面板消费):标题/状态点/进度计数由
86
+ * 宿主壳层统一渲染成单一 head(含折叠交互),extension 不再用 card 原语
87
+ * 的 header 表达这些(壳层 head 与 payload card header 双头重复的根因修复)。
88
+ * 可选:不发时宿主 fallback 到 viewId 标题、无状态点/进度。
89
+ */
90
+ meta?: WidgetMeta;
91
+ }
92
+ /** widget 宿主元数据——head 渲染契约(title + 状态点 + 进度 + 折叠 chevron)。 */
93
+ interface WidgetMeta {
94
+ /** head 标题(todo → "Todo";goal → slug) */
95
+ title: string;
96
+ /** head 状态点语义:running=accent / done=success / failed=danger / idle=neutral 弱点 */
97
+ status?: 'running' | 'done' | 'failed' | 'idle';
98
+ /** head 进度(mini bar + 计数文本);progress-bar 原语从 body 移入 head 的承载 */
99
+ progress?: {
100
+ /** fill 比例 = current/total */
101
+ current: number;
102
+ total: number;
103
+ /** 计数显示文本(head 空间有限,extension 全权格式化:todo "2/5"、goal "42%")。
104
+ * 缺省 `${current}/${total}` */
105
+ label?: string;
106
+ /** fill 语义色(预算阈值映射);缺省按 meta.status(done→success,否则 accent) */
107
+ severity?: 'ok' | 'warn' | 'danger';
108
+ };
76
109
  }
77
110
  interface StatItem {
78
111
  label?: string;
@@ -135,23 +168,26 @@ interface GuiContext {
135
168
  */
136
169
  declare function isGuiCapable(ctx: GuiContext): boolean;
137
170
  /**
138
- * 构造 GuiRenderResult,放进 details.__gui__。
171
+ * 构造 GuiRenderResult。当前主用途是 guiSetWidget 的载荷(M17 对话流 widget 面板);
172
+ * details.__gui__(tool result 通道)为遗留兼容路径,todo/goal 已不再使用。
139
173
  * stripUndefined 确保序列化不含 undefined(JSON.stringify 会丢弃 undefined 字段)。
140
174
  */
141
- declare function guiResult(component: GuiComponent): GuiRenderResult;
175
+ declare function guiResult(component: GuiComponent, meta?: WidgetMeta): GuiRenderResult;
142
176
  /**
143
177
  * 构造 GuiComponent,带类型推断。
144
178
  * 类型参数 T 约束 props 到对应类型的 props 形状。
145
179
  */
146
180
  declare function guiComponent<T extends GuiComponentType>(type: T, props: GuiComponentProps[T]): GuiComponent<T>;
147
181
  /**
148
- * 设置 GUI widget。RPC 模式下用 marker 编码 GuiComponent JSON 进 string[],
149
- * runtime event-adapter 检测 marker 解码为结构化 WS 帧。
150
- * TUI 模式下此函数无操作(extension 应在 TUI 分支调原生 ctx.ui.setWidget 传 Component factory)。
182
+ * 设置 GUI widget。RPC 模式下用 marker 编码 GuiRenderResult JSON 进 string[],
183
+ * runtime event-adapter 检测 marker 解码为结构化 WS 帧(component + meta)。
184
+ * 本函数无 isGui 守卫(仅查 ctx.ui?.setWidget 存在性),调用方需先判定
185
+ * isGuiCapable(ctx)——TUI 模式误调会把 marker 编码行推给原生 widget 造成乱码。
151
186
  *
152
- * undefined 清除 widget。
187
+ * meta(标题/状态/进度)由宿主壳层渲染成统一 head;extension 不再用 card 原语
188
+ * header 表达这些。传 undefined 清除 widget。
153
189
  */
154
- declare function guiSetWidget(ctx: GuiContext, key: string, component: GuiComponent | undefined): void;
190
+ declare function guiSetWidget(ctx: GuiContext, key: string, result: GuiRenderResult | undefined): void;
155
191
  /**
156
192
  * 从 details 中提取 GuiRenderResult。前端统一用此函数读取 __gui__,
157
193
  * 集中校验版本号,避免散落的 as 断言。
@@ -163,6 +199,13 @@ declare function extractGui(details: Record<string, unknown> | undefined): GuiRe
163
199
  * 不校验 type 是否为已知值(GuiComponentRenderer 对未知 type 有 AnsiText 降级)。
164
200
  */
165
201
  declare function isGuiComponent(value: unknown): value is GuiComponent;
202
+ /**
203
+ * v1.1 wire 格式校验:判断 unknown 值是否为合法 GuiRenderResult 信封
204
+ * (v === PROTOCOL_VERSION + component 是合法 GuiComponent)。meta 可选不校验深度。
205
+ * event-adapter 据此区分 v1.1 信封(解包 component + meta)与 v1 裸 component
206
+ * (旧版 extension 发出的 wire 格式,兼容窗口内两种并存)。
207
+ */
208
+ declare function isGuiRenderResult(value: unknown): value is GuiRenderResult;
166
209
 
167
210
  /**
168
211
  * ask-user extension 的富交互类型定义。
@@ -266,4 +309,4 @@ declare function getAskUserOther(answers: AskUserAnswers, question: AskUserQuest
266
309
  */
267
310
  declare function isAskUserQuestion(value: unknown): value is AskUserQuestion;
268
311
 
269
- export { ASK_USER_MARKER, type AskUserAnswers, type AskUserOption, type AskUserQuestion, GUI_WIDGET_MARKER, type GuiComponent, type GuiComponentProps, type GuiComponentType, type GuiContext, type GuiRenderResult, PROTOCOL_VERSION, type StatItem, type TreeItem, type TreeItemIcon, askUserInteract, extractGui, getAskUserAnswer, getAskUserOther, guiComponent, guiResult, guiSetWidget, isAskUserQuestion, isGuiCapable, isGuiComponent };
312
+ export { ASK_USER_MARKER, type AskUserAnswers, type AskUserOption, type AskUserQuestion, GUI_WIDGET_MARKER, type GuiComponent, type GuiComponentProps, type GuiComponentType, type GuiContext, type GuiRenderResult, PROTOCOL_VERSION, type StatItem, type TreeItem, type TreeItemIcon, type WidgetMeta, askUserInteract, extractGui, getAskUserAnswer, getAskUserOther, guiComponent, guiResult, guiSetWidget, isAskUserQuestion, isGuiCapable, isGuiComponent, isGuiRenderResult };
package/dist/index.mjs CHANGED
@@ -8,19 +8,21 @@ var GUI_WIDGET_MARKER = "\0XYZ_GUI_WIDGET:";
8
8
  function isGuiCapable(ctx) {
9
9
  return ctx.mode === "rpc";
10
10
  }
11
- function guiResult(component) {
12
- return {
11
+ function guiResult(component, meta) {
12
+ const result = {
13
13
  v: PROTOCOL_VERSION,
14
14
  component: stripUndefined(component)
15
15
  };
16
+ if (meta !== void 0) result.meta = stripUndefined(meta);
17
+ return result;
16
18
  }
17
19
  function guiComponent(type, props) {
18
20
  return { type, props };
19
21
  }
20
- function guiSetWidget(ctx, key, component) {
22
+ function guiSetWidget(ctx, key, result) {
21
23
  if (!ctx.ui?.setWidget) return;
22
- if (component) {
23
- const encoded = [GUI_WIDGET_MARKER + JSON.stringify(stripUndefined(component))];
24
+ if (result) {
25
+ const encoded = [GUI_WIDGET_MARKER + JSON.stringify(stripUndefined(result))];
24
26
  ctx.ui.setWidget(key, encoded);
25
27
  } else {
26
28
  ctx.ui.setWidget(key, void 0);
@@ -38,6 +40,11 @@ function isGuiComponent(value) {
38
40
  const obj = value;
39
41
  return typeof obj.type === "string" && obj.props !== null && obj.props !== void 0 && typeof obj.props === "object";
40
42
  }
43
+ function isGuiRenderResult(value) {
44
+ if (value === null || typeof value !== "object") return false;
45
+ const obj = value;
46
+ return obj.v === PROTOCOL_VERSION && isGuiComponent(obj.component);
47
+ }
41
48
  function stripUndefined(obj) {
42
49
  if (obj === null || obj === void 0) return obj;
43
50
  if (typeof obj !== "object") return obj;
@@ -118,5 +125,6 @@ export {
118
125
  guiSetWidget,
119
126
  isAskUserQuestion,
120
127
  isGuiCapable,
121
- isGuiComponent
128
+ isGuiComponent,
129
+ isGuiRenderResult
122
130
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xyz-agent/extension-protocol",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Extension GUI rendering protocol: types and helpers for pi extension dual-mode (TUI/GUI) rendering",
5
5
  "main": "dist/index.mjs",
6
6
  "module": "dist/index.mjs",