berry-agent-sdk 0.1.0-alpha.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.
Files changed (263) hide show
  1. package/README.md +78 -0
  2. package/dist/packages/berry-agent-sdk/src/client.d.ts +6 -0
  3. package/dist/packages/berry-agent-sdk/src/client.js +59 -0
  4. package/dist/packages/berry-agent-sdk/src/client.js.map +1 -0
  5. package/dist/packages/berry-agent-sdk/src/http.d.ts +24 -0
  6. package/dist/packages/berry-agent-sdk/src/http.js +232 -0
  7. package/dist/packages/berry-agent-sdk/src/http.js.map +1 -0
  8. package/dist/packages/berry-agent-sdk/src/index.d.ts +25 -0
  9. package/dist/packages/berry-agent-sdk/src/index.js +22 -0
  10. package/dist/packages/berry-agent-sdk/src/index.js.map +1 -0
  11. package/dist/packages/berry-agent-sdk/src/stdio.d.ts +23 -0
  12. package/dist/packages/berry-agent-sdk/src/stdio.js +238 -0
  13. package/dist/packages/berry-agent-sdk/src/stdio.js.map +1 -0
  14. package/dist/packages/berry-agent-sdk/src/types.d.ts +117 -0
  15. package/dist/packages/berry-agent-sdk/src/types.js +19 -0
  16. package/dist/packages/berry-agent-sdk/src/types.js.map +1 -0
  17. package/dist/src/agent/events.d.ts +11 -0
  18. package/dist/src/agent/events.js +2 -0
  19. package/dist/src/agent/events.js.map +1 -0
  20. package/dist/src/agent/index.d.ts +13 -0
  21. package/dist/src/agent/index.js +3 -0
  22. package/dist/src/agent/index.js.map +1 -0
  23. package/dist/src/agent/loop.d.ts +19 -0
  24. package/dist/src/agent/loop.js +140 -0
  25. package/dist/src/agent/loop.js.map +1 -0
  26. package/dist/src/agent/queue.d.ts +105 -0
  27. package/dist/src/agent/queue.js +120 -0
  28. package/dist/src/agent/queue.js.map +1 -0
  29. package/dist/src/agent/stream.d.ts +21 -0
  30. package/dist/src/agent/stream.js +80 -0
  31. package/dist/src/agent/stream.js.map +1 -0
  32. package/dist/src/agent/tools-batch.d.ts +49 -0
  33. package/dist/src/agent/tools-batch.js +222 -0
  34. package/dist/src/agent/tools-batch.js.map +1 -0
  35. package/dist/src/agent/types.d.ts +104 -0
  36. package/dist/src/agent/types.js +9 -0
  37. package/dist/src/agent/types.js.map +1 -0
  38. package/dist/src/channels/ask-queue.d.ts +44 -0
  39. package/dist/src/channels/ask-queue.js +83 -0
  40. package/dist/src/channels/ask-queue.js.map +1 -0
  41. package/dist/src/channels/commands.d.ts +56 -0
  42. package/dist/src/channels/commands.js +130 -0
  43. package/dist/src/channels/commands.js.map +1 -0
  44. package/dist/src/channels/engine/cell.d.ts +55 -0
  45. package/dist/src/channels/engine/cell.js +144 -0
  46. package/dist/src/channels/engine/cell.js.map +1 -0
  47. package/dist/src/channels/engine/diff.d.ts +3 -0
  48. package/dist/src/channels/engine/diff.js +144 -0
  49. package/dist/src/channels/engine/diff.js.map +1 -0
  50. package/dist/src/channels/engine/engine.d.ts +151 -0
  51. package/dist/src/channels/engine/engine.js +417 -0
  52. package/dist/src/channels/engine/engine.js.map +1 -0
  53. package/dist/src/channels/engine/index.d.ts +22 -0
  54. package/dist/src/channels/engine/index.js +9 -0
  55. package/dist/src/channels/engine/index.js.map +1 -0
  56. package/dist/src/channels/engine/input-keys.d.ts +39 -0
  57. package/dist/src/channels/engine/input-keys.js +87 -0
  58. package/dist/src/channels/engine/input-keys.js.map +1 -0
  59. package/dist/src/channels/engine/input.d.ts +174 -0
  60. package/dist/src/channels/engine/input.js +597 -0
  61. package/dist/src/channels/engine/input.js.map +1 -0
  62. package/dist/src/channels/engine/memory-io.d.ts +46 -0
  63. package/dist/src/channels/engine/memory-io.js +72 -0
  64. package/dist/src/channels/engine/memory-io.js.map +1 -0
  65. package/dist/src/channels/engine/process-io.d.ts +23 -0
  66. package/dist/src/channels/engine/process-io.js +39 -0
  67. package/dist/src/channels/engine/process-io.js.map +1 -0
  68. package/dist/src/channels/engine/types.d.ts +202 -0
  69. package/dist/src/channels/engine/types.js +18 -0
  70. package/dist/src/channels/engine/types.js.map +1 -0
  71. package/dist/src/channels/engine/width.d.ts +23 -0
  72. package/dist/src/channels/engine/width.js +123 -0
  73. package/dist/src/channels/engine/width.js.map +1 -0
  74. package/dist/src/channels/index.d.ts +25 -0
  75. package/dist/src/channels/index.js +16 -0
  76. package/dist/src/channels/index.js.map +1 -0
  77. package/dist/src/channels/registry.d.ts +33 -0
  78. package/dist/src/channels/registry.js +57 -0
  79. package/dist/src/channels/registry.js.map +1 -0
  80. package/dist/src/channels/sdk/admit.d.ts +32 -0
  81. package/dist/src/channels/sdk/admit.js +30 -0
  82. package/dist/src/channels/sdk/admit.js.map +1 -0
  83. package/dist/src/channels/sdk/backend.d.ts +19 -0
  84. package/dist/src/channels/sdk/backend.js +103 -0
  85. package/dist/src/channels/sdk/backend.js.map +1 -0
  86. package/dist/src/channels/sdk/cursor.d.ts +51 -0
  87. package/dist/src/channels/sdk/cursor.js +57 -0
  88. package/dist/src/channels/sdk/cursor.js.map +1 -0
  89. package/dist/src/channels/sdk/index.d.ts +20 -0
  90. package/dist/src/channels/sdk/index.js +21 -0
  91. package/dist/src/channels/sdk/index.js.map +1 -0
  92. package/dist/src/channels/sdk/jsonl.d.ts +47 -0
  93. package/dist/src/channels/sdk/jsonl.js +201 -0
  94. package/dist/src/channels/sdk/jsonl.js.map +1 -0
  95. package/dist/src/channels/sdk/protocol.d.ts +297 -0
  96. package/dist/src/channels/sdk/protocol.js +25 -0
  97. package/dist/src/channels/sdk/protocol.js.map +1 -0
  98. package/dist/src/channels/sdk/schema.d.ts +12 -0
  99. package/dist/src/channels/sdk/schema.js +92 -0
  100. package/dist/src/channels/sdk/schema.js.map +1 -0
  101. package/dist/src/channels/sdk/wire-core.d.ts +199 -0
  102. package/dist/src/channels/sdk/wire-core.js +447 -0
  103. package/dist/src/channels/sdk/wire-core.js.map +1 -0
  104. package/dist/src/channels/service.d.ts +66 -0
  105. package/dist/src/channels/service.js +170 -0
  106. package/dist/src/channels/service.js.map +1 -0
  107. package/dist/src/channels/tui/autocomplete/autocomplete.d.ts +32 -0
  108. package/dist/src/channels/tui/autocomplete/autocomplete.js +43 -0
  109. package/dist/src/channels/tui/autocomplete/autocomplete.js.map +1 -0
  110. package/dist/src/channels/tui/autocomplete/file-mentions.d.ts +18 -0
  111. package/dist/src/channels/tui/autocomplete/file-mentions.js +107 -0
  112. package/dist/src/channels/tui/autocomplete/file-mentions.js.map +1 -0
  113. package/dist/src/channels/tui/autocomplete/popup.d.ts +47 -0
  114. package/dist/src/channels/tui/autocomplete/popup.js +149 -0
  115. package/dist/src/channels/tui/autocomplete/popup.js.map +1 -0
  116. package/dist/src/channels/tui/autocomplete/provider.d.ts +38 -0
  117. package/dist/src/channels/tui/autocomplete/provider.js +8 -0
  118. package/dist/src/channels/tui/autocomplete/provider.js.map +1 -0
  119. package/dist/src/channels/tui/autocomplete/token.d.ts +22 -0
  120. package/dist/src/channels/tui/autocomplete/token.js +69 -0
  121. package/dist/src/channels/tui/autocomplete/token.js.map +1 -0
  122. package/dist/src/channels/tui/backend/ansi-rows.d.ts +86 -0
  123. package/dist/src/channels/tui/backend/ansi-rows.js +209 -0
  124. package/dist/src/channels/tui/backend/ansi-rows.js.map +1 -0
  125. package/dist/src/channels/tui/backend/main-screen.d.ts +90 -0
  126. package/dist/src/channels/tui/backend/main-screen.js +208 -0
  127. package/dist/src/channels/tui/backend/main-screen.js.map +1 -0
  128. package/dist/src/channels/tui/backend/osc.d.ts +79 -0
  129. package/dist/src/channels/tui/backend/osc.js +92 -0
  130. package/dist/src/channels/tui/backend/osc.js.map +1 -0
  131. package/dist/src/channels/tui/backend/transcript.d.ts +98 -0
  132. package/dist/src/channels/tui/backend/transcript.js +231 -0
  133. package/dist/src/channels/tui/backend/transcript.js.map +1 -0
  134. package/dist/src/channels/tui/backend/tui-backend.d.ts +324 -0
  135. package/dist/src/channels/tui/backend/tui-backend.js +916 -0
  136. package/dist/src/channels/tui/backend/tui-backend.js.map +1 -0
  137. package/dist/src/channels/tui/editor/editor-model.d.ts +141 -0
  138. package/dist/src/channels/tui/editor/editor-model.js +544 -0
  139. package/dist/src/channels/tui/editor/editor-model.js.map +1 -0
  140. package/dist/src/channels/tui/editor/editor-view.d.ts +36 -0
  141. package/dist/src/channels/tui/editor/editor-view.js +141 -0
  142. package/dist/src/channels/tui/editor/editor-view.js.map +1 -0
  143. package/dist/src/channels/tui/editor/editor.d.ts +50 -0
  144. package/dist/src/channels/tui/editor/editor.js +276 -0
  145. package/dist/src/channels/tui/editor/editor.js.map +1 -0
  146. package/dist/src/channels/tui/editor/undo-stack.d.ts +22 -0
  147. package/dist/src/channels/tui/editor/undo-stack.js +36 -0
  148. package/dist/src/channels/tui/editor/undo-stack.js.map +1 -0
  149. package/dist/src/channels/tui/editor/visual-lines.d.ts +39 -0
  150. package/dist/src/channels/tui/editor/visual-lines.js +127 -0
  151. package/dist/src/channels/tui/editor/visual-lines.js.map +1 -0
  152. package/dist/src/channels/tui/editor/word-nav.d.ts +10 -0
  153. package/dist/src/channels/tui/editor/word-nav.js +107 -0
  154. package/dist/src/channels/tui/editor/word-nav.js.map +1 -0
  155. package/dist/src/channels/tui/history/history-viewer.d.ts +133 -0
  156. package/dist/src/channels/tui/history/history-viewer.js +404 -0
  157. package/dist/src/channels/tui/history/history-viewer.js.map +1 -0
  158. package/dist/src/channels/tui/index.d.ts +16 -0
  159. package/dist/src/channels/tui/index.js +4 -0
  160. package/dist/src/channels/tui/index.js.map +1 -0
  161. package/dist/src/channels/tui/markdown/blocks.d.ts +42 -0
  162. package/dist/src/channels/tui/markdown/blocks.js +112 -0
  163. package/dist/src/channels/tui/markdown/blocks.js.map +1 -0
  164. package/dist/src/channels/tui/markdown/inline.d.ts +24 -0
  165. package/dist/src/channels/tui/markdown/inline.js +76 -0
  166. package/dist/src/channels/tui/markdown/inline.js.map +1 -0
  167. package/dist/src/channels/tui/markdown/markdown.d.ts +34 -0
  168. package/dist/src/channels/tui/markdown/markdown.js +183 -0
  169. package/dist/src/channels/tui/markdown/markdown.js.map +1 -0
  170. package/dist/src/channels/tui/memory/memory-viewer.d.ts +235 -0
  171. package/dist/src/channels/tui/memory/memory-viewer.js +541 -0
  172. package/dist/src/channels/tui/memory/memory-viewer.js.map +1 -0
  173. package/dist/src/channels/tui/overlay/alt-screen.d.ts +79 -0
  174. package/dist/src/channels/tui/overlay/alt-screen.js +106 -0
  175. package/dist/src/channels/tui/overlay/alt-screen.js.map +1 -0
  176. package/dist/src/channels/tui/overlay/overlay.d.ts +53 -0
  177. package/dist/src/channels/tui/overlay/overlay.js +58 -0
  178. package/dist/src/channels/tui/overlay/overlay.js.map +1 -0
  179. package/dist/src/channels/tui/overlay/select-confirm.d.ts +73 -0
  180. package/dist/src/channels/tui/overlay/select-confirm.js +157 -0
  181. package/dist/src/channels/tui/overlay/select-confirm.js.map +1 -0
  182. package/dist/src/channels/tui/panels/todo-panel.d.ts +24 -0
  183. package/dist/src/channels/tui/panels/todo-panel.js +55 -0
  184. package/dist/src/channels/tui/panels/todo-panel.js.map +1 -0
  185. package/dist/src/channels/tui/panels/tool-progress-panel.d.ts +37 -0
  186. package/dist/src/channels/tui/panels/tool-progress-panel.js +94 -0
  187. package/dist/src/channels/tui/panels/tool-progress-panel.js.map +1 -0
  188. package/dist/src/channels/tui/scroll/scroll-view.d.ts +96 -0
  189. package/dist/src/channels/tui/scroll/scroll-view.js +255 -0
  190. package/dist/src/channels/tui/scroll/scroll-view.js.map +1 -0
  191. package/dist/src/channels/tui/status/status-line.d.ts +46 -0
  192. package/dist/src/channels/tui/status/status-line.js +77 -0
  193. package/dist/src/channels/tui/status/status-line.js.map +1 -0
  194. package/dist/src/channels/tui/theme.d.ts +27 -0
  195. package/dist/src/channels/tui/theme.js +42 -0
  196. package/dist/src/channels/tui/theme.js.map +1 -0
  197. package/dist/src/channels/types.d.ts +84 -0
  198. package/dist/src/channels/types.js +12 -0
  199. package/dist/src/channels/types.js.map +1 -0
  200. package/dist/src/channels/ui-core.d.ts +80 -0
  201. package/dist/src/channels/ui-core.js +210 -0
  202. package/dist/src/channels/ui-core.js.map +1 -0
  203. package/dist/src/context/codes.d.ts +1 -0
  204. package/dist/src/context/codes.js +41 -0
  205. package/dist/src/context/codes.js.map +1 -0
  206. package/dist/src/context/events.d.ts +62 -0
  207. package/dist/src/context/events.js +161 -0
  208. package/dist/src/context/events.js.map +1 -0
  209. package/dist/src/context/index.d.ts +16 -0
  210. package/dist/src/context/index.js +14 -0
  211. package/dist/src/context/index.js.map +1 -0
  212. package/dist/src/context/logger.d.ts +67 -0
  213. package/dist/src/context/logger.js +137 -0
  214. package/dist/src/context/logger.js.map +1 -0
  215. package/dist/src/context/scope.d.ts +78 -0
  216. package/dist/src/context/scope.js +183 -0
  217. package/dist/src/context/scope.js.map +1 -0
  218. package/dist/src/context/workspace.d.ts +8 -0
  219. package/dist/src/context/workspace.js +105 -0
  220. package/dist/src/context/workspace.js.map +1 -0
  221. package/dist/src/contracts/agent-events.d.ts +73 -0
  222. package/dist/src/contracts/agent-events.js +17 -0
  223. package/dist/src/contracts/agent-events.js.map +1 -0
  224. package/dist/src/contracts/api.d.ts +249 -0
  225. package/dist/src/contracts/api.js +334 -0
  226. package/dist/src/contracts/api.js.map +1 -0
  227. package/dist/src/contracts/approval.d.ts +37 -0
  228. package/dist/src/contracts/approval.js +10 -0
  229. package/dist/src/contracts/approval.js.map +1 -0
  230. package/dist/src/contracts/env-ref.d.ts +41 -0
  231. package/dist/src/contracts/env-ref.js +33 -0
  232. package/dist/src/contracts/env-ref.js.map +1 -0
  233. package/dist/src/contracts/errors.d.ts +56 -0
  234. package/dist/src/contracts/errors.js +267 -0
  235. package/dist/src/contracts/errors.js.map +1 -0
  236. package/dist/src/contracts/events.d.ts +70 -0
  237. package/dist/src/contracts/events.js +330 -0
  238. package/dist/src/contracts/events.js.map +1 -0
  239. package/dist/src/contracts/index.d.ts +32 -0
  240. package/dist/src/contracts/index.js +27 -0
  241. package/dist/src/contracts/index.js.map +1 -0
  242. package/dist/src/contracts/llm.d.ts +278 -0
  243. package/dist/src/contracts/llm.js +13 -0
  244. package/dist/src/contracts/llm.js.map +1 -0
  245. package/dist/src/contracts/messages.d.ts +63 -0
  246. package/dist/src/contracts/messages.js +66 -0
  247. package/dist/src/contracts/messages.js.map +1 -0
  248. package/dist/src/contracts/redact.d.ts +46 -0
  249. package/dist/src/contracts/redact.js +224 -0
  250. package/dist/src/contracts/redact.js.map +1 -0
  251. package/dist/src/contracts/tools.d.ts +198 -0
  252. package/dist/src/contracts/tools.js +35 -0
  253. package/dist/src/contracts/tools.js.map +1 -0
  254. package/dist/src/contracts/types.d.ts +304 -0
  255. package/dist/src/contracts/types.js +51 -0
  256. package/dist/src/contracts/types.js.map +1 -0
  257. package/dist/src/contracts/ui.d.ts +122 -0
  258. package/dist/src/contracts/ui.js +16 -0
  259. package/dist/src/contracts/ui.js.map +1 -0
  260. package/dist/src/sdk/types.d.ts +144 -0
  261. package/dist/src/sdk/types.js +33 -0
  262. package/dist/src/sdk/types.js.map +1 -0
  263. package/package.json +29 -0
@@ -0,0 +1,104 @@
1
+ /**
2
+ * agent 件 — loop 骨架的类型面(04 篇 §2 回调面 11 项 + 入口两式签名)。
3
+ *
4
+ * loop 是纯机制:全部策略经注入回调表达、全部状态经事件与投影回流——
5
+ * conversation 是缺省供给方(组装回调并注入),loop 不知道 conversation 存在。
6
+ * 类型独立成件:loop.ts 只留双 while 骨架本体(≤150 行形态铁律的码面兑现)。
7
+ */
8
+ import type { AgentMessage } from '../contracts/index.js';
9
+ import type { AssistantMessage, LlmContext, Message, StreamFn, ThinkingLevel, ToolResultMessage } from '../contracts/index.js';
10
+ import type { AgentTool, AgentToolCall, AgentToolResult, ToolUpdateCallback } from '../contracts/index.js';
11
+ import type { AgentEvent, AgentEventSink } from './events.js';
12
+ /** loop 运行上下文(messages 是活数组——loop 读写、驱动侧共享同引用) */
13
+ export interface AgentContext {
14
+ /** 系统提示词(每次请求组装进 LlmContext) */
15
+ systemPrompt?: string;
16
+ /** 会话消息活数组(种子/流终值/工具结果都在此累积) */
17
+ messages: AgentMessage[];
18
+ /** 本 run 可用工具集(缺省空——纯对话 run) */
19
+ tools?: AgentTool[];
20
+ /**
21
+ * 闸①幂等账本(04 §2 call_id 幂等决策):call_id → 既有结果消息。挂
22
+ * context(driver 终身单实例持有)→ 批内 + 跨轮 + 重试续入三域同律共享
23
+ * (重试续入 = 新 startRun 同 context——已执行条目直接回执既有结果)。
24
+ * 只持既有结果消息的引用(消息本就活在 messages 数组——零复制零逐出);
25
+ * 超帽丢尾腿与中止配对腿不进账本(未执行条目无「既有结果」可回执)。
26
+ * 懒初始化(executeToolBatch 首达建账)。
27
+ */
28
+ toolResultLedger?: Map<string, ToolResultMessage>;
29
+ }
30
+ /** beforeToolCall 决策(守门行安装点):block = 不执行直接回错误结果;terminate 记账批内一致裁决 */
31
+ export interface BeforeToolCallDecision {
32
+ /** 拒因(进 isError 结果 content;守门 deny 面) */
33
+ block?: string;
34
+ /** 终止旗标——批内全 terminate 才 terminate(单件否决不放大) */
35
+ terminate?: boolean;
36
+ }
37
+ /** turn 间换装变更(prepareNextTurn 返回——换 context/model/thinkingLevel 的唯一时机) */
38
+ export interface TurnAdjustment {
39
+ /** 换模型(下一 turn 起生效) */
40
+ model?: string;
41
+ /** 换思考档位(下一 turn 起生效) */
42
+ thinkingLevel?: ThinkingLevel;
43
+ }
44
+ /**
45
+ * loop 回调面(04 §2 全部注入点——缺省供给方 conversation)。
46
+ * loop 层零重试:失败即 run failed;turn auto-retry/overflow 兜底归 conversation 件。
47
+ */
48
+ export interface AgentLoopConfig {
49
+ /** 流式调用体(永不抛——契约见 contracts/llm.ts StreamFn;金样回放轨 seam) */
50
+ streamFn: StreamFn;
51
+ /** 模型 id(prepareNextTurn 可逐轮换装) */
52
+ model: string;
53
+ /** 思考档位(会话态投影入 run——run 内经 prepareNextTurn 可换) */
54
+ thinkingLevel?: ThinkingLevel;
55
+ /** timeline 消息 → LLM 消息转写(自定义角色降写、瞬态注入剥离;null = 剥离) */
56
+ convertToLlm: (message: AgentMessage) => Message | Message[] | null;
57
+ /** 请求组装最后关口(记忆检索瞬态注入在此挂) */
58
+ transformContext?: (context: LlmContext) => LlmContext | Promise<LlmContext>;
59
+ /**
60
+ * 每次模型请求前钩(03 §2.4 agent_pre_step 发射窗——04 §2/§5):loop
61
+ * while 体顶、steering 消费与 turn_start 之前调用;返回 'stop' 即本 turn
62
+ * 不起模型请求、run 以 stopReason 'stop' 收 completed(预算刹停不产生
63
+ * dangling turn)。驱动侧分派 waterfall(载荷 PreStepInput——提醒注入
64
+ * 槽 + 刹车位)。
65
+ */
66
+ preModelRequest?: (context: AgentContext) => 'stop' | void | Promise<'stop' | void>;
67
+ /** 凭证取用(缺省 undefined 走 llm 层持久化凭证链) */
68
+ getApiKey?: (model: string) => string | undefined;
69
+ /** turn 终止裁决(停止词、预算尽、打断——返回 true 优雅停 completed) */
70
+ shouldStopAfterTurn?: (context: AgentContext, lastMessage: AssistantMessage) => boolean | Promise<boolean>;
71
+ /** turn 间准备(todo 同段回显/goal 轮间沉淀注入窗 + 换装唯一时机) */
72
+ prepareNextTurn?: (context: AgentContext) => void | TurnAdjustment | Promise<void | TurnAdjustment>;
73
+ /** busy 注入通道取件(每 turn 顶查——返回空数组即无) */
74
+ getSteeringMessages?: () => AgentMessage[];
75
+ /** idle 起跑通道取件(自然停候选时查——空即 run 收 completed) */
76
+ getFollowUpMessages?: () => AgentMessage[];
77
+ /** 工具调用前置钩子(守门行安装点;可返回 block 拒因或 terminate 旗标) */
78
+ beforeToolCall?: (toolCall: AgentToolCall, context: AgentContext) => BeforeToolCallDecision | void | Promise<BeforeToolCallDecision | void>;
79
+ /** 工具结果后置钩子(字段级整体替换——返回新消息替换默认组装形) */
80
+ afterToolCall?: (toolCall: AgentToolCall, result: AgentToolResult, message: AgentContext['messages'][number], context: AgentContext) => AgentMessage | void | Promise<AgentMessage | void>;
81
+ /** 工具执行体替换点(测试注金样 seam 同族;缺省走 tool.execute) */
82
+ toolExecution?: (tool: AgentTool, toolCallId: string, arguments_: Record<string, unknown>, signal?: AbortSignal, onUpdate?: ToolUpdateCallback) => Promise<AgentToolResult>;
83
+ /** 活体事件汇(10 型内存直推) */
84
+ onEvent?: AgentEventSink;
85
+ /** 中止信号(透传 streamFn 与工具 execute——协作面) */
86
+ signal?: AbortSignal;
87
+ /**
88
+ * 单响应工具批调用数上限(04 §2 闸②):单次模型响应的工具批超帽即丢尾
89
+ * ——被丢 calls 逐个配对 isError toolResult(原因注明超限)+ 丢弃计数暴露
90
+ * (ToolBatchOutcome.droppedCount,非静默)。缺省
91
+ * DEFAULT_MAX_TOOL_CALLS_PER_RESPONSE(32);负值按 0 处理(0 = 拒全批)。
92
+ */
93
+ maxToolCallsPerResponse?: number;
94
+ }
95
+ /** run 结算(终态恰三值——Job 结算、审批对收口、预算记账截断的锚) */
96
+ export interface RunResult {
97
+ status: import('./events.js').RunStatus;
98
+ /** 末次流终态(诊断面;status 三值与 stopReason 的映射见 loop.ts endRun) */
99
+ stopReason?: import('../contracts/llm.js').StopReason;
100
+ /** stopReason=error 时的错误文本(终值消息 errorMessage 同源) */
101
+ errorMessage?: string;
102
+ }
103
+ /** 活体事件发射器(loop 与辅助件共用的小闭包形——void/Promise 双形兼容) */
104
+ export type EmitFn = (event: AgentEvent) => void;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * agent 件 — loop 骨架的类型面(04 篇 §2 回调面 11 项 + 入口两式签名)。
3
+ *
4
+ * loop 是纯机制:全部策略经注入回调表达、全部状态经事件与投影回流——
5
+ * conversation 是缺省供给方(组装回调并注入),loop 不知道 conversation 存在。
6
+ * 类型独立成件:loop.ts 只留双 while 骨架本体(≤150 行形态铁律的码面兑现)。
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../src/agent/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * 提问队列(07 §4.3 提问队列机制正文——2026-09-06 channels 纵切批补写):
3
+ * 阻塞原语(confirm/select/input)与审批 ask 统一入 per-session FIFO——
4
+ * 队首才呈现、应答即出队、后继顶上(「无并存态」即此律)。
5
+ *
6
+ * 收口三则(规范同条):会话关闭按 sessionId 清队(余项按取消语义收场——
7
+ * 保守值同撤销面);run 打断信号穿透队内该 run 发起的 ask(signal 由调用方
8
+ * ui-core 携带,队列不感知 run);队列是内存态、崩溃即丢(durable 真相在
9
+ * 审批日志不在队列——与 04 §4 PendingMessageQueue 同纪)。
10
+ *
11
+ * 队列持在通道核、呈现形态归后端(TUI overlay 是队首呈现之一)——本类只管
12
+ * 排序与收口,backend 编舞(竞速/撤销说明行)归 ui-core。
13
+ */
14
+ import type { AskKind } from './types.js';
15
+ /** 队项钩子:start = 晋升队首(发后端);cancel = 取消收场(含在飞态——保守值 + 撤销归 ui-core) */
16
+ export interface AskHooks {
17
+ /** 晋升队首:真正发给后端(overlay 占焦等呈现态由此起) */
18
+ readonly start: () => void;
19
+ /** 取消收场:排队中(未 start)与在飞(已 start 未 settle)两态都可达——保守值结算 + 后端撤销 */
20
+ readonly cancel: () => void;
21
+ }
22
+ /**
23
+ * 提问队列(per-session FIFO)。同会话严格串行(队首在飞时后继排队);
24
+ * 异会话队列独立(各自队首并行——呈现并存的裁决归后端 overlay 层)。
25
+ */
26
+ export declare class AskQueue {
27
+ private readonly sessions;
28
+ private ensure;
29
+ /** 入队:会话队列空闲即直晋队首(start 同步调用——FIFO 无空转窗);否则排队 */
30
+ enqueue(sessionId: string, kind: AskKind, hooks: AskHooks): void;
31
+ /**
32
+ * 队首落定(应答/保守值收场都算——由 ui-core 在 promise 链尾调用):
33
+ * 出队、后继顶上。未知会话/已清队 no-op(clearSession 后迟到落定不炸)。
34
+ */
35
+ settled(sessionId: string): void;
36
+ /**
37
+ * 会话收口(04 §9 归属围栏通道侧执法):清排队项 + 取消在飞队首——
38
+ * 全部走 cancel(保守值同撤销面:confirm→false / select·input→''、
39
+ * approval→cancelled 语义由 ui-core 落)。
40
+ */
41
+ clearSession(sessionId: string): void;
42
+ /** 观察面:会话在飞+排队项 kind 序列(测试与 /help 类诊断面消费) */
43
+ pending(sessionId: string): readonly AskKind[];
44
+ }
@@ -0,0 +1,83 @@
1
+ /**
2
+ * 提问队列(07 §4.3 提问队列机制正文——2026-09-06 channels 纵切批补写):
3
+ * 阻塞原语(confirm/select/input)与审批 ask 统一入 per-session FIFO——
4
+ * 队首才呈现、应答即出队、后继顶上(「无并存态」即此律)。
5
+ *
6
+ * 收口三则(规范同条):会话关闭按 sessionId 清队(余项按取消语义收场——
7
+ * 保守值同撤销面);run 打断信号穿透队内该 run 发起的 ask(signal 由调用方
8
+ * ui-core 携带,队列不感知 run);队列是内存态、崩溃即丢(durable 真相在
9
+ * 审批日志不在队列——与 04 §4 PendingMessageQueue 同纪)。
10
+ *
11
+ * 队列持在通道核、呈现形态归后端(TUI overlay 是队首呈现之一)——本类只管
12
+ * 排序与收口,backend 编舞(竞速/撤销说明行)归 ui-core。
13
+ */
14
+ /**
15
+ * 提问队列(per-session FIFO)。同会话严格串行(队首在飞时后继排队);
16
+ * 异会话队列独立(各自队首并行——呈现并存的裁决归后端 overlay 层)。
17
+ */
18
+ export class AskQueue {
19
+ sessions = new Map();
20
+ ensure(sessionId) {
21
+ let q = this.sessions.get(sessionId);
22
+ if (q === undefined) {
23
+ q = { pending: [], active: null };
24
+ this.sessions.set(sessionId, q);
25
+ }
26
+ return q;
27
+ }
28
+ /** 入队:会话队列空闲即直晋队首(start 同步调用——FIFO 无空转窗);否则排队 */
29
+ enqueue(sessionId, kind, hooks) {
30
+ const q = this.ensure(sessionId);
31
+ if (q.active === null) {
32
+ q.active = { kind, hooks };
33
+ hooks.start();
34
+ }
35
+ else {
36
+ q.pending.push({ kind, hooks });
37
+ }
38
+ }
39
+ /**
40
+ * 队首落定(应答/保守值收场都算——由 ui-core 在 promise 链尾调用):
41
+ * 出队、后继顶上。未知会话/已清队 no-op(clearSession 后迟到落定不炸)。
42
+ */
43
+ settled(sessionId) {
44
+ const q = this.sessions.get(sessionId);
45
+ if (q === undefined)
46
+ return;
47
+ if (q.active === null)
48
+ return; // 空转(迟到落定)——幂等
49
+ const next = q.pending.shift();
50
+ if (next === undefined) {
51
+ q.active = null; // 队列清空(会话条目留存——防高频重建;clearSession 才真清)
52
+ }
53
+ else {
54
+ q.active = next;
55
+ next.hooks.start();
56
+ }
57
+ }
58
+ /**
59
+ * 会话收口(04 §9 归属围栏通道侧执法):清排队项 + 取消在飞队首——
60
+ * 全部走 cancel(保守值同撤销面:confirm→false / select·input→''、
61
+ * approval→cancelled 语义由 ui-core 落)。
62
+ */
63
+ clearSession(sessionId) {
64
+ const q = this.sessions.get(sessionId);
65
+ if (q === undefined)
66
+ return;
67
+ const all = q.active === null ? [...q.pending] : [q.active, ...q.pending];
68
+ q.pending.length = 0;
69
+ q.active = null;
70
+ this.sessions.delete(sessionId);
71
+ // 逐项 cancel:在飞与排队同语义收场(cancel 实现须幂等——settled 迟到不双结)
72
+ for (const item of all)
73
+ item.hooks.cancel();
74
+ }
75
+ /** 观察面:会话在飞+排队项 kind 序列(测试与 /help 类诊断面消费) */
76
+ pending(sessionId) {
77
+ const q = this.sessions.get(sessionId);
78
+ if (q === undefined)
79
+ return [];
80
+ return q.active === null ? q.pending.map((p) => p.kind) : [q.active.kind, ...q.pending.map((p) => p.kind)];
81
+ }
82
+ }
83
+ //# sourceMappingURL=ask-queue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ask-queue.js","sourceRoot":"","sources":["../../../../../src/channels/ask-queue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * 命令面注册表与分发(03 §2.2 registerCommand 签名定形 + §2.7 冲突律;
3
+ * 2026-09-06 channels 纵切批)。
4
+ *
5
+ * 两律:①后写胜出——命令名是可换实现位(用户插件覆盖 core: 同名命令 =
6
+ * 显式换装正道),撞名不拒、胜出即生效;②词法违例拒——命令名主段连字符式
7
+ * + 可选冒号子段,非法名拒绝注册(CHANNEL_COMMAND_INVALID——与
8
+ * AGENT_ROLE_INVALID 同构:撞名不拒、格式拒)。
9
+ */
10
+ import type { Disposer } from '../context/index.js';
11
+ import type { CommandArgs, CommandHandler, CommandSpec } from './types.js';
12
+ /**
13
+ * 命令面注册表。注册即生效(03 §2.1——下一次消费点重取,不待重启);
14
+ * 全部方法同步(注册/查询/解析零 I/O,分发是唯一异步面)。
15
+ */
16
+ export declare class CommandRegistry {
17
+ private readonly commands;
18
+ /** 注册代币发生器(每注册一枚新 token——disposer 校验「自己仍是现任」用) */
19
+ private tokenSeed;
20
+ /**
21
+ * 注册命令(后写胜出)。词法违例抛 CHANNEL_COMMAND_INVALID;撞名静默覆盖
22
+ * (03 §2.7:胜出即生效无拒码)。
23
+ *
24
+ * @returns disposer——注销该命令;若已被后写覆盖则 no-op(不误注接任者)
25
+ */
26
+ register(name: string, handler: CommandHandler, description?: string): Disposer;
27
+ /** 命令清单(/help 与 @-mention 补全面的消费面——注册序) */
28
+ list(): readonly CommandSpec[];
29
+ /** 按名查询(分发前置——后写胜出者即现任) */
30
+ get(name: string): CommandSpec | undefined;
31
+ /**
32
+ * 解析输入行(同步纯函数面):`/name rest...` → { name, args };
33
+ * 非 `/` 开头返回 null(普通消息路——去哪归驱动侧/conversation 裁决,
34
+ * 命令面只报「不是命令」)。
35
+ */
36
+ parse(input: string): {
37
+ name: string;
38
+ args: CommandArgs;
39
+ } | null;
40
+ /**
41
+ * 分发输入行:命中注册命令 → 执行 handler 返回 true;未命中(非命令形或
42
+ * 名不在册)返回 false——「未注册的 /词 怎么处置(提示未知命令 or 当普通
43
+ * 消息进 run)」是驱动侧语义,归 conversation 件。
44
+ *
45
+ * sessionId 位(ix-2 新建):发起会话透传进 CommandArgs(CLI 面缺席)——
46
+ * 插件命令 handler 可显式携带(ctx.ui opts.sessionId 透传),ambient 自动
47
+ * 锚另由 host 侧 ALS 承载(两轨并行——显式位是插件可见面、ALS 是零自觉面)。
48
+ */
49
+ dispatch(input: string, sessionId?: string): Promise<boolean>;
50
+ }
51
+ /**
52
+ * 引号感知词切分(03 §2.2 定形:shell 词法的最小实现——不进 glob/变量展开)。
53
+ * 规则:裸词按空白切;'单引号' 保字面(内部再无转义);"双引号" 保内部空格;
54
+ * 引号未闭合按行尾收口(宽容收场——终端输入无第二行可续)。
55
+ */
56
+ export declare function tokenize(raw: string): string[];
@@ -0,0 +1,130 @@
1
+ /**
2
+ * 命令面注册表与分发(03 §2.2 registerCommand 签名定形 + §2.7 冲突律;
3
+ * 2026-09-06 channels 纵切批)。
4
+ *
5
+ * 两律:①后写胜出——命令名是可换实现位(用户插件覆盖 core: 同名命令 =
6
+ * 显式换装正道),撞名不拒、胜出即生效;②词法违例拒——命令名主段连字符式
7
+ * + 可选冒号子段,非法名拒绝注册(CHANNEL_COMMAND_INVALID——与
8
+ * AGENT_ROLE_INVALID 同构:撞名不拒、格式拒)。
9
+ */
10
+ import { BaseError } from '../contracts/index.js';
11
+ /** 命令名词法(03 §2.2 定形:^[a-z][a-z0-9-]*(:[a-z0-9-]+)?$——/memory-export 与 /skill:name 实况同形) */
12
+ const COMMAND_NAME_RE = /^[a-z][a-z0-9-]*(?::[a-z0-9-]+)?$/;
13
+ /**
14
+ * 命令面注册表。注册即生效(03 §2.1——下一次消费点重取,不待重启);
15
+ * 全部方法同步(注册/查询/解析零 I/O,分发是唯一异步面)。
16
+ */
17
+ export class CommandRegistry {
18
+ commands = new Map();
19
+ /** 注册代币发生器(每注册一枚新 token——disposer 校验「自己仍是现任」用) */
20
+ tokenSeed = 0;
21
+ /**
22
+ * 注册命令(后写胜出)。词法违例抛 CHANNEL_COMMAND_INVALID;撞名静默覆盖
23
+ * (03 §2.7:胜出即生效无拒码)。
24
+ *
25
+ * @returns disposer——注销该命令;若已被后写覆盖则 no-op(不误注接任者)
26
+ */
27
+ register(name, handler, description) {
28
+ if (!COMMAND_NAME_RE.test(name)) {
29
+ throw new BaseError('CHANNEL_COMMAND_INVALID', `命令名词法违例:${JSON.stringify(name)}(主段连字符式 + 可选冒号子段,小写)`);
30
+ }
31
+ const token = { seed: this.tokenSeed++ };
32
+ this.commands.set(name, { name, handler, description, token });
33
+ return () => {
34
+ // 只有现任可注(token 相等 = 未被后写覆盖)——后写的接任者不因旧 disposer 被误注
35
+ const current = this.commands.get(name);
36
+ if (current !== undefined && current.token === token) {
37
+ this.commands.delete(name);
38
+ }
39
+ };
40
+ }
41
+ /** 命令清单(/help 与 @-mention 补全面的消费面——注册序) */
42
+ list() {
43
+ return [...this.commands.values()].map(({ token: _token, ...spec }) => spec);
44
+ }
45
+ /** 按名查询(分发前置——后写胜出者即现任) */
46
+ get(name) {
47
+ const entry = this.commands.get(name);
48
+ return entry === undefined
49
+ ? undefined
50
+ : { name: entry.name, handler: entry.handler, description: entry.description };
51
+ }
52
+ /**
53
+ * 解析输入行(同步纯函数面):`/name rest...` → { name, args };
54
+ * 非 `/` 开头返回 null(普通消息路——去哪归驱动侧/conversation 裁决,
55
+ * 命令面只报「不是命令」)。
56
+ */
57
+ parse(input) {
58
+ if (!input.startsWith('/'))
59
+ return null;
60
+ // 首空白分割命令名与实参原文(命令名自身无空白——词法保证)
61
+ const rest = input.slice(1);
62
+ const sep = rest.search(/\s/);
63
+ const name = sep === -1 ? rest : rest.slice(0, sep);
64
+ const raw = sep === -1 ? '' : rest.slice(sep + 1).trim();
65
+ if (!COMMAND_NAME_RE.test(name))
66
+ return null;
67
+ return { name, args: { raw, argv: tokenize(raw) } };
68
+ }
69
+ /**
70
+ * 分发输入行:命中注册命令 → 执行 handler 返回 true;未命中(非命令形或
71
+ * 名不在册)返回 false——「未注册的 /词 怎么处置(提示未知命令 or 当普通
72
+ * 消息进 run)」是驱动侧语义,归 conversation 件。
73
+ *
74
+ * sessionId 位(ix-2 新建):发起会话透传进 CommandArgs(CLI 面缺席)——
75
+ * 插件命令 handler 可显式携带(ctx.ui opts.sessionId 透传),ambient 自动
76
+ * 锚另由 host 侧 ALS 承载(两轨并行——显式位是插件可见面、ALS 是零自觉面)。
77
+ */
78
+ async dispatch(input, sessionId) {
79
+ const parsed = this.parse(input);
80
+ if (parsed === null)
81
+ return false;
82
+ const spec = this.commands.get(parsed.name);
83
+ if (spec === undefined)
84
+ return false;
85
+ await spec.handler(sessionId !== undefined ? { ...parsed.args, sessionId } : parsed.args);
86
+ return true;
87
+ }
88
+ }
89
+ /**
90
+ * 引号感知词切分(03 §2.2 定形:shell 词法的最小实现——不进 glob/变量展开)。
91
+ * 规则:裸词按空白切;'单引号' 保字面(内部再无转义);"双引号" 保内部空格;
92
+ * 引号未闭合按行尾收口(宽容收场——终端输入无第二行可续)。
93
+ */
94
+ export function tokenize(raw) {
95
+ const out = [];
96
+ let current = '';
97
+ let hasCurrent = false;
98
+ let quote = null;
99
+ for (const ch of raw) {
100
+ if (quote !== null) {
101
+ if (ch === quote) {
102
+ quote = null; // 引号闭合——段继续累积(拼接态 "ab'cd ef'" 保空格)
103
+ }
104
+ else {
105
+ current += ch;
106
+ }
107
+ continue;
108
+ }
109
+ if (ch === '"' || ch === "'") {
110
+ quote = ch;
111
+ hasCurrent = true; // 空引号段 '' 也是一段(与裸词不同——显式空串)
112
+ continue;
113
+ }
114
+ if (ch === ' ' || ch === '\t') {
115
+ if (hasCurrent) {
116
+ out.push(current);
117
+ current = '';
118
+ hasCurrent = false;
119
+ }
120
+ continue;
121
+ }
122
+ current += ch;
123
+ hasCurrent = true;
124
+ }
125
+ // 行尾:未闭合引号宽容收口(current 原样成段);尾段在
126
+ if (hasCurrent)
127
+ out.push(current);
128
+ return out;
129
+ }
130
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../../../../../src/channels/commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * 缓冲件(07 篇 §4.1 自研引擎节件 3——批 10b 引擎核心)。
3
+ *
4
+ * cell 网格模型:每格「码点面 + 样式 + 列宽」三元;宽字符续格与主流终端
5
+ * 续格形同构(差分按格直比无需行结构感知);多码点字素覆写摘痕防新旧混叠;
6
+ * 字素面参与差分自证(同首码点不同字素不得判等——grapheme 存整素串,格直比
7
+ * 即字素比对,结构自证)。帧路径零分配:网格跨帧复用、clear 只摘格、
8
+ * resize 是唯一重分配点。
9
+ */
10
+ import type { Cell, CellBuffer, CellStyle, CursorState } from './types.js';
11
+ /** 全缺省样式常量(格的缺省样式——比较归一用,冻结防漂) */
12
+ export declare const EMPTY_STYLE: Readonly<CellStyle>;
13
+ /** 样式相等(缺省位归一比较——undefined 与 false 同为缺省) */
14
+ export declare function styleEquals(a: CellStyle, b: CellStyle): boolean;
15
+ /**
16
+ * 单格相等(差分按格直比原语):null 归一到默认空格格后三元比对——
17
+ * 「写入的缺省空格」与「未写格」判等(不产生假变更帧);
18
+ * 续格(width 0)与空格格判不等(续格是宽字素一部分,占位语义不可丢)。
19
+ */
20
+ export declare function cellEquals(a: Cell | null, b: Cell | null): boolean;
21
+ /**
22
+ * CellGrid——CellBuffer 协议实装(一维数组行主序网格;行 / 列界外静默吸收)。
23
+ *
24
+ * 摘痕算法(setCell 内执法):覆写区 [col, col+w) 内既有格若属某宽字素
25
+ * (首格或续格),先整字摘除(首格 + 全部续格)再写新字素——防「旧宽字素
26
+ * 右半残留在新字素续格下」的新旧混叠。
27
+ */
28
+ export declare class CellGrid implements CellBuffer {
29
+ columns: number;
30
+ rows: number;
31
+ /** 网格(行主序一维;null = 未写格——语义投影为缺省空格) */
32
+ private grid;
33
+ /** 本帧光标声明终值(末次声明为准;clearCursor 置 null) */
34
+ private cursorState;
35
+ constructor(columns?: number, rows?: number);
36
+ /** 摘格清屏(网格结构复用零分配——帧间清屏 / 全量重绘入口) */
37
+ clear(): void;
38
+ getCell(row: number, col: number): Cell | null;
39
+ setCell(row: number, col: number, grapheme: string, style?: CellStyle): void;
40
+ writeText(row: number, col: number, text: string, style?: CellStyle): number;
41
+ setCursor(row: number, col: number): void;
42
+ clearCursor(): void;
43
+ get cursor(): CursorState | null;
44
+ /**
45
+ * 几何变更(唯一重分配点):网格整体弃置重分配、内容不搬运——
46
+ * 「resize 弃旧换新(不做原地搬运——宽字符 reflow 后必失真)」的缓冲侧
47
+ * 承接,清屏 + 全量重绘兜底归引擎编排件(批 10c)。
48
+ */
49
+ resize(columns: number, rows: number): void;
50
+ /**
51
+ * 摘痕原语:把 [col, col+span) 区间(含右邻溢出格——被覆字素可能右探一格)
52
+ * 内牵连的既有宽字素整字摘除。逐格查:续格回溯首格、首格顺摘续格。
53
+ */
54
+ private eraseWideGraphemes;
55
+ }
@@ -0,0 +1,144 @@
1
+ import { graphemeWidth, splitGraphemes } from './width.js';
2
+ /** 全缺省样式常量(格的缺省样式——比较归一用,冻结防漂) */
3
+ export const EMPTY_STYLE = Object.freeze({});
4
+ /** 默认格(未写格的语义投影:缺省空格——cellEquals 归一基准) */
5
+ const DEFAULT_CELL = Object.freeze({
6
+ grapheme: ' ',
7
+ style: EMPTY_STYLE,
8
+ width: 1,
9
+ });
10
+ /** 样式相等(缺省位归一比较——undefined 与 false 同为缺省) */
11
+ export function styleEquals(a, b) {
12
+ return ((a.fg ?? null) === (b.fg ?? null) &&
13
+ (a.bg ?? null) === (b.bg ?? null) &&
14
+ !!a.bold === !!b.bold &&
15
+ !!a.italic === !!b.italic &&
16
+ !!a.underline === !!b.underline &&
17
+ !!a.dim === !!b.dim &&
18
+ !!a.inverse === !!b.inverse);
19
+ }
20
+ /**
21
+ * 单格相等(差分按格直比原语):null 归一到默认空格格后三元比对——
22
+ * 「写入的缺省空格」与「未写格」判等(不产生假变更帧);
23
+ * 续格(width 0)与空格格判不等(续格是宽字素一部分,占位语义不可丢)。
24
+ */
25
+ export function cellEquals(a, b) {
26
+ const na = a ?? DEFAULT_CELL;
27
+ const nb = b ?? DEFAULT_CELL;
28
+ return na.grapheme === nb.grapheme && na.width === nb.width && styleEquals(na.style, nb.style);
29
+ }
30
+ /**
31
+ * CellGrid——CellBuffer 协议实装(一维数组行主序网格;行 / 列界外静默吸收)。
32
+ *
33
+ * 摘痕算法(setCell 内执法):覆写区 [col, col+w) 内既有格若属某宽字素
34
+ * (首格或续格),先整字摘除(首格 + 全部续格)再写新字素——防「旧宽字素
35
+ * 右半残留在新字素续格下」的新旧混叠。
36
+ */
37
+ export class CellGrid {
38
+ columns;
39
+ rows;
40
+ /** 网格(行主序一维;null = 未写格——语义投影为缺省空格) */
41
+ grid;
42
+ /** 本帧光标声明终值(末次声明为准;clearCursor 置 null) */
43
+ cursorState = null;
44
+ constructor(columns = 80, rows = 24) {
45
+ this.columns = columns;
46
+ this.rows = rows;
47
+ this.grid = new Array(columns * rows).fill(null);
48
+ }
49
+ /** 摘格清屏(网格结构复用零分配——帧间清屏 / 全量重绘入口) */
50
+ clear() {
51
+ this.grid.fill(null);
52
+ this.cursorState = null;
53
+ }
54
+ getCell(row, col) {
55
+ if (row < 0 || row >= this.rows || col < 0 || col >= this.columns)
56
+ return null;
57
+ return this.grid[row * this.columns + col] ?? null; // noUncheckedIndexedAccess 归一
58
+ }
59
+ setCell(row, col, grapheme, style = EMPTY_STYLE) {
60
+ // 越界写静默吸收(渲染契约「越界写由缓冲吸收」——组件可信任缓冲兜底)
61
+ if (row < 0 || row >= this.rows || col < 0 || col >= this.columns)
62
+ return;
63
+ const width = graphemeWidth(grapheme);
64
+ if (width === 0)
65
+ return; // 零宽字素不占格(splitGraphemes 已合流,防御位)
66
+ // 摘痕:覆写区内既有宽字素整字摘除(见类注——防新旧混叠)
67
+ this.eraseWideGraphemes(row, col, width);
68
+ // 写首格 + 续格(宽字素右界越界时续格截断丢弃——缓冲兜底;渲染层
69
+ // truncateToWidth 已保证整字不跨界,此为双保险)
70
+ const base = row * this.columns;
71
+ this.grid[base + col] = { grapheme, style, width: width };
72
+ if (width === 2 && col + 1 < this.columns) {
73
+ this.grid[base + col + 1] = { grapheme: '', style, width: 0 };
74
+ }
75
+ }
76
+ writeText(row, col, text, style) {
77
+ let cursor = col;
78
+ for (const g of splitGraphemes(text)) {
79
+ this.setCell(row, cursor, g, style);
80
+ cursor += graphemeWidth(g);
81
+ }
82
+ return cursor;
83
+ }
84
+ setCursor(row, col) {
85
+ this.cursorState = { row, col, visible: true };
86
+ }
87
+ clearCursor() {
88
+ this.cursorState = null;
89
+ }
90
+ get cursor() {
91
+ return this.cursorState;
92
+ }
93
+ /**
94
+ * 几何变更(唯一重分配点):网格整体弃置重分配、内容不搬运——
95
+ * 「resize 弃旧换新(不做原地搬运——宽字符 reflow 后必失真)」的缓冲侧
96
+ * 承接,清屏 + 全量重绘兜底归引擎编排件(批 10c)。
97
+ */
98
+ resize(columns, rows) {
99
+ this.columns = columns;
100
+ this.rows = rows;
101
+ this.grid = new Array(columns * rows).fill(null);
102
+ this.cursorState = null;
103
+ }
104
+ /**
105
+ * 摘痕原语:把 [col, col+span) 区间(含右邻溢出格——被覆字素可能右探一格)
106
+ * 内牵连的既有宽字素整字摘除。逐格查:续格回溯首格、首格顺摘续格。
107
+ */
108
+ eraseWideGraphemes(row, col, span) {
109
+ const base = row * this.columns;
110
+ for (let i = col; i <= Math.min(col + span, this.columns - 1); i++) {
111
+ const cell = this.grid[base + i];
112
+ if (!cell)
113
+ continue;
114
+ if (cell.width === 0) {
115
+ // 续格:回溯其首格并整字摘除
116
+ let head = i - 1;
117
+ while (head >= 0) {
118
+ const probe = this.grid[base + head];
119
+ if (probe && probe.width !== 0)
120
+ break;
121
+ head--;
122
+ }
123
+ if (head >= 0 && this.grid[base + head]?.width === 2) {
124
+ this.grid[base + head] = null;
125
+ // 顺摘首格右侧全部续格(可能多格?——续格恰一格,但防御性扫到非续格止)
126
+ let tail = head + 1;
127
+ while (tail < this.columns && this.grid[base + tail]?.width === 0) {
128
+ this.grid[base + tail] = null;
129
+ tail++;
130
+ }
131
+ }
132
+ this.grid[base + i] = null;
133
+ }
134
+ else if (cell.width === 2) {
135
+ // 首格:摘自己 + 右侧续格
136
+ this.grid[base + i] = null;
137
+ if (i + 1 < this.columns && this.grid[base + i + 1]?.width === 0) {
138
+ this.grid[base + i + 1] = null;
139
+ }
140
+ }
141
+ }
142
+ }
143
+ }
144
+ //# sourceMappingURL=cell.js.map