@zhushanwen/subagent-engine-sdk 0.4.0 → 0.5.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 (90) hide show
  1. package/dist/{chunk-7I4XGL5J.js → chunk-BBWUC2EE.js} +2 -2
  2. package/dist/{chunk-3K2P2CM2.js → chunk-CNQTJJF5.js} +1 -1
  3. package/dist/{chunk-DSQ7JQKM.js → chunk-GSW3DMN6.js} +5 -5
  4. package/dist/{chunk-BBVZK5DL.js → chunk-M3SZTDNQ.js} +20 -20
  5. package/dist/{chunk-HYES77BR.js → chunk-MSAJXIP4.js} +2 -2
  6. package/dist/{chunk-FJT23P7T.js → chunk-QOEXD2FT.js} +1 -1
  7. package/dist/{chunk-LKPVN3N6.js → chunk-W3BKI2BP.js} +3 -3
  8. package/dist/{chunk-WS4WAZVR.js → chunk-WMDMXP2F.js} +2 -2
  9. package/dist/{chunk-GT6YLLN4.js → chunk-X24IVQKJ.js} +5 -5
  10. package/dist/{chunk-365AUV6N.js → chunk-YE472JOO.js} +2 -2
  11. package/dist/{contract-types-C71Sqq8d.d.cts → contract-types-Dsvy79r3.d.cts} +9 -10
  12. package/dist/{contract-types-C71Sqq8d.d.ts → contract-types-Dsvy79r3.d.ts} +9 -10
  13. package/dist/data-dir.cjs +6 -6
  14. package/dist/data-dir.d.cts +4 -4
  15. package/dist/data-dir.d.ts +4 -4
  16. package/dist/data-dir.js +3 -3
  17. package/dist/env.cjs +20 -20
  18. package/dist/env.d.cts +12 -5
  19. package/dist/env.d.ts +12 -5
  20. package/dist/env.js +1 -1
  21. package/dist/{error-codes-D5YlWaBx.d.ts → error-codes-DMGeUUUm.d.ts} +12 -12
  22. package/dist/{error-codes-CiOO3PMg.d.cts → error-codes-pT7RYTqQ.d.cts} +12 -12
  23. package/dist/index.cjs +42 -42
  24. package/dist/index.d.cts +3 -3
  25. package/dist/index.d.ts +3 -3
  26. package/dist/index.js +12 -12
  27. package/dist/journal-io.d.cts +1 -1
  28. package/dist/journal-io.d.ts +1 -1
  29. package/dist/journal-replay.d.cts +1 -1
  30. package/dist/journal-replay.d.ts +1 -1
  31. package/dist/kill-chain.d.cts +2 -2
  32. package/dist/kill-chain.d.ts +2 -2
  33. package/dist/kill-chain.js +2 -2
  34. package/dist/logs/stderr-rotation.cjs +2 -2
  35. package/dist/logs/stderr-rotation.d.cts +1 -1
  36. package/dist/logs/stderr-rotation.d.ts +1 -1
  37. package/dist/logs/stderr-rotation.js +1 -1
  38. package/dist/nesting-guard.cjs +2 -2
  39. package/dist/nesting-guard.d.cts +2 -2
  40. package/dist/nesting-guard.d.ts +2 -2
  41. package/dist/nesting-guard.js +1 -1
  42. package/dist/node-executor.cjs +2 -2
  43. package/dist/node-executor.d.cts +5 -5
  44. package/dist/node-executor.d.ts +5 -5
  45. package/dist/node-executor.js +2 -2
  46. package/dist/port-contract.d.cts +1 -1
  47. package/dist/port-contract.d.ts +1 -1
  48. package/dist/protocol/index.cjs +2 -2
  49. package/dist/protocol/index.d.cts +5 -5
  50. package/dist/protocol/index.d.ts +5 -5
  51. package/dist/protocol/index.js +1 -1
  52. package/dist/relay-env.cjs +5 -5
  53. package/dist/relay-env.d.cts +5 -5
  54. package/dist/relay-env.d.ts +5 -5
  55. package/dist/relay-env.js +1 -1
  56. package/dist/spawn.cjs +1 -1
  57. package/dist/spawn.d.cts +2 -2
  58. package/dist/spawn.d.ts +2 -2
  59. package/dist/spawn.js +1 -1
  60. package/dist/ui-channels.cjs +2 -2
  61. package/dist/ui-channels.js +1 -1
  62. package/package.json +2 -4
  63. package/src/best-effort.ts +0 -37
  64. package/src/cli-entry.ts +0 -82
  65. package/src/data-dir.ts +0 -89
  66. package/src/env.ts +0 -265
  67. package/src/error-message.ts +0 -22
  68. package/src/index.ts +0 -63
  69. package/src/journal-io.ts +0 -82
  70. package/src/journal-replay.ts +0 -436
  71. package/src/kill-chain.ts +0 -265
  72. package/src/logger.ts +0 -105
  73. package/src/logs/stderr-rotation.ts +0 -166
  74. package/src/nesting-guard.ts +0 -140
  75. package/src/node-executor.ts +0 -272
  76. package/src/paths.ts +0 -48
  77. package/src/port-contract.ts +0 -150
  78. package/src/protocol/contract-types.ts +0 -379
  79. package/src/protocol/engine-protocol.ts +0 -91
  80. package/src/protocol/error-codes.ts +0 -180
  81. package/src/protocol/frames.ts +0 -143
  82. package/src/protocol/index.ts +0 -12
  83. package/src/protocol/methods.ts +0 -237
  84. package/src/protocol/reverse-channels.ts +0 -123
  85. package/src/protocol/schema.ts +0 -185
  86. package/src/relay-env.ts +0 -60
  87. package/src/schema-emulation.ts +0 -192
  88. package/src/spawn.ts +0 -246
  89. package/src/ui-channels.ts +0 -219
  90. package/src/ui-types.ts +0 -101
@@ -1,219 +0,0 @@
1
- // src/ui-channels.ts
2
- //
3
- // UI channel 提取(marker 解析)+ channel 注册表(引擎侧原语,自 core
4
- // execution/ui-channels.ts 移入 @zhushanwen/subagent-engine-sdk,实现体逐字等价;
5
- // round1-reuse R1:core execution 副本与 pi 引擎 CLI 副本自本模块 re-export 收编,
6
- // 消逐字等价双副本——core → SDK、pi → SDK 均正向合法)。
7
- //
8
- // channel 是扩展协议自定义的业务路由标识,由 NUL 前缀 marker 标记。
9
- // 已知 marker(来自 @xyz-agent/extension-protocol):
10
- // - ASK_USER_MARKER = "\0XYZ_ASK_USER" 走 select method,出现在 title
11
- // (options[0] = JSON payload {questions, allowCancel})
12
- // - GUI_WIDGET_MARKER = "\0XYZ_GUI_WIDGET:" 走 setWidget method,出现在 widgetLines[0]
13
- // (同行 marker 后紧跟 JSON payload {component})
14
- //
15
- // channel 提取位置随 method 变(.fix-plans/00-master-summary.md §一冲突 2):
16
- // - select → 从 title 解析 NUL 前缀(payload 从 options[0] 取)
17
- // - setWidget → 从 widgetLines[0] 解析 NUL 前缀(payload 从同行 marker 后取)
18
- // - 其他 method → 无 channel(返回 {})
19
- //
20
- // channel 名规范化:去 "XYZ_" 命名空间前缀,去尾部 ":",小写化。
21
- // XYZ_ASK_USER → ask_user
22
- // XYZ_GUI_WIDGET → gui_widget
23
- //
24
- // 本模块是协议层工具(method/marker 都是协议概念),不感知业务。
25
-
26
- /** NUL 前缀字符。Pi extension-protocol 用 NUL(\0)标记控制行,
27
- * 避免与用户可见文本冲突。 */
28
- const NUL = "\0";
29
-
30
- /** channel 提取结果。channel 无 NUL 前缀、字段缺失、JSON parse 失败时
31
- * channel 与 channelPayload 均为 undefined(返回 {})。 */
32
- export interface ParsedChannel {
33
- /** 规范化后的 channel 名(如 "ask_user"、"gui_widget")。
34
- * 无 marker 或解析失败时为 undefined。 */
35
- channel?: string;
36
- /** marker 标记的结构化 payload(已 JSON.parse)。
37
- * ask_user: {questions, allowCancel};gui_widget: {component}。
38
- * payload 来源缺失或 JSON parse 失败时为 undefined(channel 仍可解析)。 */
39
- channelPayload?: unknown;
40
- }
41
-
42
- /** parseChannel 入参的最小形状。
43
- * method 是判别字段;按 method 不同,对应字段(select 的 title/options、
44
- * setWidget 的 widgetLines)可选出现。其他 method 的字段统称 [key:string]。 */
45
- export interface ExtensionUiRequestLike {
46
- method: string;
47
- /** select method:title 字段(可能含 ASK_USER_MARKER NUL 前缀)。 */
48
- title?: string;
49
- /** select method:options 数组(options[0] 可能是 channel payload 的 JSON)。 */
50
- options?: string[];
51
- /** setWidget method:widgetKey 字段。 */
52
- widgetKey?: string;
53
- /** setWidget method:widgetLines 数组(widgetLines[0] 可能含 GUI_WIDGET_MARKER)。 */
54
- widgetLines?: string[] | undefined;
55
- /** 其他 method 的任意字段(容错:允许测试和未来扩展传入额外字段)。 */
56
- [key: string]: unknown;
57
- }
58
-
59
- /** channel handler 签名:接收 UiRequest,返回 UiResponse。
60
- * 具体类型定义在 session-runner.ts(W2 工作),此处用最小形状避免循环依赖。
61
- * handler 实现方按 channel 注册,由 session-runner 按 req.channel 分派。 */
62
- export type ChannelHandler = (req: unknown) => Promise<unknown>;
63
-
64
- /** channel 注册表接口。职责单一:只管业务路由,不管排队、不管透传判定。
65
- * - register(channel, handler):注册 channel 对应的 handler(同名覆盖)
66
- * - resolve(channel):取 channel 对应的 handler,未注册返回 undefined
67
- * - list():列举所有已注册 channel 名 */
68
- export interface UiChannelRegistry {
69
- register(channel: string, handler: ChannelHandler): void;
70
- resolve(channel: string): ChannelHandler | undefined;
71
- list(): string[];
72
- }
73
-
74
- /** 规范化 channel 名。
75
- * 输入是 NUL 前缀后的字面量(如 "XYZ_ASK_USER"、"XYZ_GUI_WIDGET:")。
76
- * 规则:
77
- * 1. 去 "XYZ_" 命名空间前缀(协议命名空间标识,非业务语义)
78
- * 2. 去尾部 ":"(GUI_WIDGET 等"行内 payload"型 marker 的分隔符)
79
- * 3. 小写化(XYZ_ASK_USER → ask_user)
80
- *
81
- * 例:
82
- * "XYZ_ASK_USER" → "ask_user"
83
- * "XYZ_GUI_WIDGET:" → "gui_widget"
84
- * "FOO_BAR" → "foo_bar"(无 XYZ_ 前缀也容忍,去前缀仅当字面量以 XYZ_ 开头) */
85
- function normalizeChannelName(markerLiteral: string): string {
86
- let name = markerLiteral;
87
- // 去 "XYZ_" 命名空间前缀(仅当以此开头)
88
- if (name.startsWith("XYZ_")) {
89
- name = name.slice("XYZ_".length);
90
- }
91
- // 去尾部 ":"(行内 payload 型 marker 的分隔符)
92
- if (name.endsWith(":")) {
93
- name = name.slice(0, -1);
94
- }
95
- return name.toLowerCase();
96
- }
97
-
98
- /** 从 marker 字面量字符串解析 channel 名。
99
- * 输入 str 形如 "\0XYZ_ASK_USER"(marker 占满整个字段,payload 在别处)。
100
- * 无 NUL 前缀返回 undefined。 */
101
- function parseMarkerFromField(str: string): string | undefined {
102
- if (!str.startsWith(NUL)) return undefined;
103
- // 去掉 NUL 前缀,取剩余字面量作为 marker literal
104
- const literal = str.slice(NUL.length);
105
- if (literal === "") return undefined;
106
- return normalizeChannelName(literal);
107
- }
108
-
109
- /** 从 marker + 行内 payload 字符串解析 channel 名 + payload。
110
- * 输入 str 形如 "\0XYZ_GUI_WIDGET:{...json...}"(marker 与 payload 在同一行)。
111
- * 无 NUL 前缀返回 undefined。
112
- * payload 解析失败时不抛(返回 channel 名,payload 由调用方处理)。 */
113
- function parseInlineMarkerFromField(str: string): { channel: string } | undefined {
114
- if (!str.startsWith(NUL)) return undefined;
115
- const rest = str.slice(NUL.length);
116
- // marker literal 与 payload 的分界:第一个 ":" 或行尾
117
- // GUI_WIDGET_MARKER 格式为 "\0XYZ_GUI_WIDGET:" + json,分界是 ":"
118
- const colonIdx = rest.indexOf(":");
119
- let literal: string;
120
- if (colonIdx >= 0) {
121
- literal = rest.slice(0, colonIdx + 1); // 含 ":",normalizeChannelName 会去尾部 ":"
122
- } else {
123
- literal = rest;
124
- }
125
- if (literal === "") return undefined;
126
- return { channel: normalizeChannelName(literal) };
127
- }
128
-
129
- /** 从 select.title 解析 channel(payload 从 options[0] 取)。
130
- * - title 无 NUL 前缀 → undefined
131
- * - title 含 marker → channel 名;payload 从 options[0] JSON.parse(失败/缺失 → undefined) */
132
- function parseFromMarkerString(
133
- title: string | undefined,
134
- options: string[] | undefined,
135
- ): ParsedChannel {
136
- if (title === undefined) return {};
137
- const channel = parseMarkerFromField(title);
138
- if (channel === undefined) return {};
139
- // payload 从 options[0] 取(ask_user 协议:title 是 marker,options[0] 是 JSON payload)
140
- let payload: unknown;
141
- if (options !== undefined && options.length > 0) {
142
- try {
143
- payload = JSON.parse(options[0]);
144
- } catch {
145
- payload = undefined; // JSON parse 失败:不抛,channel 仍解析
146
- }
147
- }
148
- return { channel, channelPayload: payload };
149
- }
150
-
151
- /** 从 setWidget.widgetLines[0] 解析 channel(payload 从同行 marker 后取)。
152
- * - widgetLines 缺失/空数组/首行无 NUL 前缀 → undefined
153
- * - 首行含 marker → channel 名;payload 从 marker 后的 JSON 取(失败 → undefined) */
154
- function parseFromMarkerArray(
155
- widgetLines: string[] | undefined,
156
- ): ParsedChannel {
157
- if (widgetLines === undefined || widgetLines.length === 0) return {};
158
- const firstLine = widgetLines[0];
159
- if (typeof firstLine !== "string") return {};
160
- const parsed = parseInlineMarkerFromField(firstLine);
161
- if (parsed === undefined) return {};
162
- // payload 从 marker 后的 JSON 取(GUI_WIDGET 协议:marker 与 payload 同行)
163
- let payload: unknown;
164
- const rest = firstLine.slice(NUL.length);
165
- const colonIdx = rest.indexOf(":");
166
- if (colonIdx >= 0) {
167
- const jsonStr = rest.slice(colonIdx + 1);
168
- if (jsonStr !== "") {
169
- try {
170
- payload = JSON.parse(jsonStr);
171
- } catch {
172
- payload = undefined; // JSON parse 失败:不抛,channel 仍解析
173
- }
174
- }
175
- }
176
- return { channel: parsed.channel, channelPayload: payload };
177
- }
178
-
179
- /** 按 method 分派解析 channel。
180
- *
181
- * - select → 从 title 解析 NUL 前缀(payload 从 options[0])
182
- * - setWidget → 从 widgetLines[0] 解析 NUL 前缀(payload 从同行 marker 后)
183
- * - 其他 method → {}(无 channel 提取位置)
184
- *
185
- * 边界(均不抛错):
186
- * - title/widgetLines 字段缺失 → {}
187
- * - 无 NUL 前缀 → {}
188
- * - JSON parse 失败 → channel 仍解析,channelPayload 为 undefined
189
- *
190
- * @param req ExtensionUiRequestLike(method + 对应字段)
191
- * @returns ParsedChannel(channel/channelPayload 可选) */
192
- export function parseChannel(req: ExtensionUiRequestLike): ParsedChannel {
193
- switch (req.method) {
194
- case "select":
195
- return parseFromMarkerString(req.title, req.options);
196
- case "setWidget":
197
- return parseFromMarkerArray(req.widgetLines);
198
- default:
199
- return {};
200
- }
201
- }
202
-
203
- /** 创建 channel 注册表实例。
204
- * 进程级单例(通常由 SubagentService 持有一个实例,跨所有子进程共享)。
205
- * register 同名 channel 会覆盖旧 handler。 */
206
- export function createUiChannelRegistry(): UiChannelRegistry {
207
- const handlers = new Map<string, ChannelHandler>();
208
- return {
209
- register(channel: string, handler: ChannelHandler): void {
210
- handlers.set(channel, handler);
211
- },
212
- resolve(channel: string): ChannelHandler | undefined {
213
- return handlers.get(channel);
214
- },
215
- list(): string[] {
216
- return Array.from(handlers.keys());
217
- },
218
- };
219
- }
package/src/ui-types.ts DELETED
@@ -1,101 +0,0 @@
1
- // src/ui-types.ts
2
- //
3
- // UI 请求/响应契约类型(自 core execution/dialog-queue.ts :94/:113/:150/:159 迁入
4
- // @zhushanwen/subagent-engine-sdk,结构等价)。迁移处置(impl-plan §2.1 类型闭包表
5
- // R3 S-A / R4-S③):**UiMethod / UiRequest / UiResponse / UiRequestHandler 入 SDK
6
- // 类型闭包**——该模块是三类型的规范来源(dialog-queue.ts:87 注释自证);`UiMethod`
7
- // 是 `UiRequest.method` 的依赖类型(:94,R4-S③ 补录,包外零消费方)。队列实现本体
8
- // 留 core;core 侧改再导出 SDK 类型(`export type { ... } from
9
- // "@zhushanwen/subagent-engine-sdk"`,§2.7 MF-X2 既定决策,引用切换归 W2/W7);
10
- // 双向可赋值断言挂 core typecheck 断言族。
11
- //
12
- // 协议消费面:反向通道 host/askUser 的载荷携带 UiRequest(reverse-channels.ts),
13
- // 两阶段结果 = UiResponse(ack 先行、结果异步到达,R9-2)。
14
-
15
- /** Pi extension_ui_request 的方法枚举(dialog + fire-and-forget 两类)。
16
- * dialog 类:select/confirm/input/editor(占输入焦点,等响应)。
17
- * fire-and-forget 类:notify/setStatus/setWidget/setTitle/set_editor_text(纯展示/写入)。
18
- * (string & {}) 兜底:Pi 未来新增 method 或未知 method 走字符串字面量类型。 */
19
- export type UiMethod =
20
- | "select"
21
- | "confirm"
22
- | "input"
23
- | "editor"
24
- | "notify"
25
- | "setStatus"
26
- | "setWidget"
27
- | "setTitle"
28
- | "set_editor_text"
29
- | (string & {});
30
-
31
- /** UI 请求(引擎侧构造后经 host/askUser 送达宿主 handler)。
32
- *
33
- * method 是判别字段,决定排队策略(dialog 排队)和业务路由(channel 分发)。
34
- * method 特定字段按 method 可选出现(与 ExtensionUiRequest 1:1,由引擎侧
35
- * ui-request-queue 从 ExtensionUiRequest 平铺构造)。channel/channelPayload 由
36
- * parseChannel 填充。
37
- *
38
- * 契约来源:.fix-plans/00-master-summary.md §二 2.2。 */
39
- export interface UiRequest {
40
- /** Pi rpc-types.ts 的 method(select/confirm/input/editor 为 dialog 类)。 */
41
- method: UiMethod;
42
- /** 请求 id(从 extension_ui_request envelope 顶层提取,用于 response 关联)。 */
43
- id: string;
44
- // method 特定字段(按 method 可选,与 ExtensionUiRequest 1:1)
45
- title?: string;
46
- options?: string[];
47
- message?: string;
48
- placeholder?: string;
49
- prefill?: string;
50
- notifyType?: string;
51
- statusKey?: string;
52
- statusText?: string | undefined;
53
- widgetKey?: string;
54
- widgetLines?: string[] | undefined;
55
- widgetPlacement?: "aboveEditor" | "belowEditor";
56
- text?: string;
57
- timeout?: number;
58
- /** channel 名(从 method 对应字段的 NUL 前缀解析)。
59
- * select → 从 title 解析;setWidget → 从 widgetLines[0] 解析;其他 → undefined。
60
- * 已知值:"ask_user"(select)、"gui_widget"(setWidget)。handler 按 channel 分发。 */
61
- channel?: string;
62
- /** channel 解析后的结构化 payload(已 JSON.parse)。
63
- * ask_user: {questions, allowCancel};gui_widget: {component};无 channel: undefined。 */
64
- channelPayload?: unknown;
65
- /** 内部元数据字段:发起该 UI 请求的子进程 pid(由引擎侧 ui-request-queue 从
66
- * child.pid 填入——session-runner 已随协议化重构删除,填充点现住 pi 引擎包)。
67
- * L2 队列据此关联 rejectChildDialogs(子进程退出时批量取消,见
68
- * notifyChildProcessExited 的接线链)。
69
- * 下划线前缀表示内部字段,非 Pi 协议字段,不参与 stdin 回写。 */
70
- _childPid?: number;
71
- }
72
-
73
- /** UI 响应(handler 返回,session-runner 按 shape 回写 stdin)。
74
- * - {value}: select/input/editor 的答案
75
- * - {confirmed}: confirm 的答案
76
- * - {cancelled}: 取消(child close / handler 抛错 / 用户取消)
77
- * - {ack}: fire-and-forget(当前不透传到 TUI,留作协议完整) */
78
- export type UiResponse =
79
- | { value: string }
80
- | { confirmed: boolean }
81
- | { cancelled: true }
82
- | { ack: true };
83
-
84
- /** UiResponse 载荷结构判定(四成员判别;形态对齐 reverse-channels 的
85
- * isHostStreamDeltaParams 先例)。消费方:引擎侧应答落位前守卫,防宿主畸形帧
86
- * 静默流入 UI 队列(S7:askUser 应答跨界无守卫)。 */
87
- export function isUiResponse(value: unknown): value is UiResponse {
88
- if (typeof value !== "object" || value === null) return false;
89
- const v = value as Record<string, unknown>;
90
- return (
91
- typeof v.value === "string" ||
92
- typeof v.confirmed === "boolean" ||
93
- v.cancelled === true ||
94
- v.ack === true
95
- );
96
- }
97
-
98
- /** UI 请求 handler 签名(单函数,按 req.method 内部路由)。
99
- * 实现方负责:channel 业务路由(ask_user → AskUserComponent)+ 默认转发(ctx.ui.*)。
100
- * 抛错由调用方(DialogGlobalQueue / session-runner)兜底为 {cancelled:true}。 */
101
- export type UiRequestHandler = (req: UiRequest) => Promise<UiResponse>;