berry-agent 0.1.0-alpha.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 (401) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +96 -0
  3. package/dist/.api-emit.stamp +1 -0
  4. package/dist/.build-meta.json +6 -0
  5. package/dist/agent/events.js +1 -0
  6. package/dist/agent/index.js +2 -0
  7. package/dist/agent/loop.js +139 -0
  8. package/dist/agent/queue.js +119 -0
  9. package/dist/agent/stream.js +62 -0
  10. package/dist/agent/tools-batch.js +221 -0
  11. package/dist/agent/types.js +8 -0
  12. package/dist/api/berry-agent-llm.d.ts +18 -0
  13. package/dist/api/berry-agent.d.ts +9 -0
  14. package/dist/api/surface.json +1632 -0
  15. package/dist/api/tsconfig.paths.json +12 -0
  16. package/dist/api/typebox-compile.d.ts +2 -0
  17. package/dist/api/typebox-value.d.ts +2 -0
  18. package/dist/api/typebox.d.ts +2 -0
  19. package/dist/browser/cdp.js +256 -0
  20. package/dist/browser/codes.js +31 -0
  21. package/dist/browser/discover.js +107 -0
  22. package/dist/browser/engine.js +169 -0
  23. package/dist/browser/index.js +17 -0
  24. package/dist/browser/install.js +342 -0
  25. package/dist/browser/page.js +321 -0
  26. package/dist/browser/service.js +158 -0
  27. package/dist/browser/tools.js +198 -0
  28. package/dist/browser/types.js +81 -0
  29. package/dist/channels/ask-queue.js +82 -0
  30. package/dist/channels/commands.js +129 -0
  31. package/dist/channels/engine/cell.js +143 -0
  32. package/dist/channels/engine/diff.js +143 -0
  33. package/dist/channels/engine/engine.js +416 -0
  34. package/dist/channels/engine/index.js +8 -0
  35. package/dist/channels/engine/input-keys.js +86 -0
  36. package/dist/channels/engine/input.js +596 -0
  37. package/dist/channels/engine/memory-io.js +71 -0
  38. package/dist/channels/engine/process-io.js +38 -0
  39. package/dist/channels/engine/types.js +17 -0
  40. package/dist/channels/engine/width.js +122 -0
  41. package/dist/channels/index.js +15 -0
  42. package/dist/channels/registry.js +56 -0
  43. package/dist/channels/sdk/admit.js +29 -0
  44. package/dist/channels/sdk/backend.js +102 -0
  45. package/dist/channels/sdk/cursor.js +56 -0
  46. package/dist/channels/sdk/index.js +20 -0
  47. package/dist/channels/sdk/jsonl.js +208 -0
  48. package/dist/channels/sdk/protocol.js +24 -0
  49. package/dist/channels/sdk/schema.js +91 -0
  50. package/dist/channels/sdk/wire-core.js +446 -0
  51. package/dist/channels/service.js +169 -0
  52. package/dist/channels/tui/autocomplete/autocomplete.js +42 -0
  53. package/dist/channels/tui/autocomplete/file-mentions.js +106 -0
  54. package/dist/channels/tui/autocomplete/popup.js +148 -0
  55. package/dist/channels/tui/autocomplete/provider.js +7 -0
  56. package/dist/channels/tui/autocomplete/token.js +68 -0
  57. package/dist/channels/tui/backend/ansi-rows.js +211 -0
  58. package/dist/channels/tui/backend/main-screen.js +207 -0
  59. package/dist/channels/tui/backend/osc.js +91 -0
  60. package/dist/channels/tui/backend/transcript.js +230 -0
  61. package/dist/channels/tui/backend/tui-backend.js +915 -0
  62. package/dist/channels/tui/editor/editor-model.js +543 -0
  63. package/dist/channels/tui/editor/editor-view.js +140 -0
  64. package/dist/channels/tui/editor/editor.js +275 -0
  65. package/dist/channels/tui/editor/undo-stack.js +35 -0
  66. package/dist/channels/tui/editor/visual-lines.js +126 -0
  67. package/dist/channels/tui/editor/word-nav.js +106 -0
  68. package/dist/channels/tui/history/history-viewer.js +403 -0
  69. package/dist/channels/tui/index.js +3 -0
  70. package/dist/channels/tui/layout.js +167 -0
  71. package/dist/channels/tui/markdown/blocks.js +111 -0
  72. package/dist/channels/tui/markdown/inline.js +75 -0
  73. package/dist/channels/tui/markdown/markdown.js +182 -0
  74. package/dist/channels/tui/memory/memory-viewer.js +540 -0
  75. package/dist/channels/tui/overlay/alt-screen.js +105 -0
  76. package/dist/channels/tui/overlay/overlay.js +57 -0
  77. package/dist/channels/tui/overlay/select-confirm.js +156 -0
  78. package/dist/channels/tui/panels/todo-panel.js +54 -0
  79. package/dist/channels/tui/panels/tool-progress-panel.js +93 -0
  80. package/dist/channels/tui/scroll/scroll-view.js +254 -0
  81. package/dist/channels/tui/status/status-line.js +76 -0
  82. package/dist/channels/tui/text.js +38 -0
  83. package/dist/channels/tui/theme.js +41 -0
  84. package/dist/channels/types.js +11 -0
  85. package/dist/channels/ui-core.js +209 -0
  86. package/dist/checkpoint/capture.js +45 -0
  87. package/dist/checkpoint/codes.js +33 -0
  88. package/dist/checkpoint/command.js +82 -0
  89. package/dist/checkpoint/gate.js +48 -0
  90. package/dist/checkpoint/index.js +20 -0
  91. package/dist/checkpoint/restore.js +172 -0
  92. package/dist/checkpoint/store.js +247 -0
  93. package/dist/checkpoint/types.js +4 -0
  94. package/dist/checkpoint/walk.js +146 -0
  95. package/dist/compaction/ccr-tools.js +112 -0
  96. package/dist/compaction/ccr.js +84 -0
  97. package/dist/compaction/codes.js +21 -0
  98. package/dist/compaction/index.js +18 -0
  99. package/dist/compaction/policy.js +200 -0
  100. package/dist/compaction/service.js +422 -0
  101. package/dist/compaction/slots.js +121 -0
  102. package/dist/compaction/types.js +10 -0
  103. package/dist/context/codes.js +40 -0
  104. package/dist/context/events.js +160 -0
  105. package/dist/context/index.js +13 -0
  106. package/dist/context/logger.js +136 -0
  107. package/dist/context/scope.js +182 -0
  108. package/dist/context/workspace.js +104 -0
  109. package/dist/contracts/agent-events.d.ts +73 -0
  110. package/dist/contracts/agent-events.js +16 -0
  111. package/dist/contracts/api.d.ts +249 -0
  112. package/dist/contracts/api.js +299 -0
  113. package/dist/contracts/approval.d.ts +37 -0
  114. package/dist/contracts/approval.js +9 -0
  115. package/dist/contracts/env-ref.d.ts +41 -0
  116. package/dist/contracts/env-ref.js +32 -0
  117. package/dist/contracts/errors.d.ts +56 -0
  118. package/dist/contracts/errors.js +266 -0
  119. package/dist/contracts/events.d.ts +70 -0
  120. package/dist/contracts/events.js +329 -0
  121. package/dist/contracts/index.d.ts +32 -0
  122. package/dist/contracts/index.js +26 -0
  123. package/dist/contracts/llm.d.ts +275 -0
  124. package/dist/contracts/llm.js +12 -0
  125. package/dist/contracts/messages.d.ts +63 -0
  126. package/dist/contracts/messages.js +65 -0
  127. package/dist/contracts/redact.d.ts +46 -0
  128. package/dist/contracts/redact.js +223 -0
  129. package/dist/contracts/tools.d.ts +197 -0
  130. package/dist/contracts/tools.js +33 -0
  131. package/dist/contracts/types.d.ts +302 -0
  132. package/dist/contracts/types.js +50 -0
  133. package/dist/contracts/ui.d.ts +122 -0
  134. package/dist/contracts/ui.js +15 -0
  135. package/dist/conversation/agent-service.js +61 -0
  136. package/dist/conversation/approval-wiring.js +82 -0
  137. package/dist/conversation/backoff.js +38 -0
  138. package/dist/conversation/codes.js +47 -0
  139. package/dist/conversation/control-tools.js +102 -0
  140. package/dist/conversation/control.js +210 -0
  141. package/dist/conversation/driver.js +922 -0
  142. package/dist/conversation/index.js +12 -0
  143. package/dist/conversation/model-visible.js +169 -0
  144. package/dist/conversation/open-tools.js +126 -0
  145. package/dist/conversation/reseed.js +132 -0
  146. package/dist/conversation/sessions.js +215 -0
  147. package/dist/conversation/todo.js +203 -0
  148. package/dist/conversation/types.js +35 -0
  149. package/dist/conversation/wiring.js +204 -0
  150. package/dist/credentials/codes.js +59 -0
  151. package/dist/credentials/commands.js +186 -0
  152. package/dist/credentials/env-ref.js +34 -0
  153. package/dist/credentials/index.js +28 -0
  154. package/dist/credentials/migration.js +18 -0
  155. package/dist/credentials/oauth.js +266 -0
  156. package/dist/credentials/refresh.js +152 -0
  157. package/dist/credentials/secrets.js +118 -0
  158. package/dist/credentials/types.js +30 -0
  159. package/dist/exec/bash.js +279 -0
  160. package/dist/exec/codes.js +37 -0
  161. package/dist/exec/env.js +99 -0
  162. package/dist/exec/environment.js +39 -0
  163. package/dist/exec/git-guard.js +623 -0
  164. package/dist/exec/index.js +24 -0
  165. package/dist/exec/registry.js +120 -0
  166. package/dist/exec/spawn.js +281 -0
  167. package/dist/exec/tail.js +77 -0
  168. package/dist/exec/types.js +5 -0
  169. package/dist/goal/codes.js +33 -0
  170. package/dist/goal/command.js +175 -0
  171. package/dist/goal/fold.js +121 -0
  172. package/dist/goal/gates.js +122 -0
  173. package/dist/goal/index.js +22 -0
  174. package/dist/goal/migration.js +48 -0
  175. package/dist/goal/service.js +501 -0
  176. package/dist/goal/todo-tool.js +174 -0
  177. package/dist/goal/types.js +1 -0
  178. package/dist/goal/update-tool.js +46 -0
  179. package/dist/host/approval-cmd.js +276 -0
  180. package/dist/host/assembly.js +1146 -0
  181. package/dist/host/boot-failures.js +104 -0
  182. package/dist/host/budget-advisory.js +74 -0
  183. package/dist/host/budget-broadcast.js +50 -0
  184. package/dist/host/builtins.js +54 -0
  185. package/dist/host/cli.js +544 -0
  186. package/dist/host/codes.js +120 -0
  187. package/dist/host/config-schema.js +195 -0
  188. package/dist/host/conversation-stack.js +654 -0
  189. package/dist/host/core-plugins.js +1685 -0
  190. package/dist/host/credentials-cmd.js +42 -0
  191. package/dist/host/disclosure.js +30 -0
  192. package/dist/host/dispatch.js +105 -0
  193. package/dist/host/doors-cmd.js +154 -0
  194. package/dist/host/dump-config.js +44 -0
  195. package/dist/host/hook-dispatch-guard.js +27 -0
  196. package/dist/host/import-gate.js +153 -0
  197. package/dist/host/index.js +54 -0
  198. package/dist/host/issue-session.js +241 -0
  199. package/dist/host/loader.js +372 -0
  200. package/dist/host/main.js +161 -0
  201. package/dist/host/manifest.js +381 -0
  202. package/dist/host/mcp-entry.js +53 -0
  203. package/dist/host/plugin-boot.js +952 -0
  204. package/dist/host/plugin-context.js +672 -0
  205. package/dist/host/plugin-install.js +480 -0
  206. package/dist/host/plugin-reload.js +124 -0
  207. package/dist/host/plugin-store.js +462 -0
  208. package/dist/host/plugin-tools.js +359 -0
  209. package/dist/host/plugin-uninstall.js +257 -0
  210. package/dist/host/plugins-cmd.js +302 -0
  211. package/dist/host/plugins-command.js +130 -0
  212. package/dist/host/plugins-config.js +195 -0
  213. package/dist/host/prompt-sections.js +133 -0
  214. package/dist/host/run-entry.js +544 -0
  215. package/dist/host/runtime.js +209 -0
  216. package/dist/host/scheduler-tick.js +294 -0
  217. package/dist/host/serve-daemon.js +501 -0
  218. package/dist/host/serve-entry.js +279 -0
  219. package/dist/host/session-anchor.js +41 -0
  220. package/dist/host/sessions-cmd.js +219 -0
  221. package/dist/host/sessions-face.js +47 -0
  222. package/dist/host/settings-store.js +112 -0
  223. package/dist/host/signals.js +69 -0
  224. package/dist/host/single-instance.js +105 -0
  225. package/dist/host/subagent-factory.js +291 -0
  226. package/dist/host/testkit/harness.js +283 -0
  227. package/dist/host/testkit/index.js +14 -0
  228. package/dist/host/testkit/matrix.js +302 -0
  229. package/dist/host/tool-policy-store.js +177 -0
  230. package/dist/host/triggers.js +212 -0
  231. package/dist/host/tui-entry.js +216 -0
  232. package/dist/host/webui-bridge.js +165 -0
  233. package/dist/issue/codes.js +38 -0
  234. package/dist/issue/filter.js +146 -0
  235. package/dist/issue/github.js +116 -0
  236. package/dist/issue/index.js +17 -0
  237. package/dist/issue/mount.js +70 -0
  238. package/dist/issue/poll.js +58 -0
  239. package/dist/issue/service.js +341 -0
  240. package/dist/issue/tools.js +70 -0
  241. package/dist/issue/types.js +34 -0
  242. package/dist/issue/webhook.js +126 -0
  243. package/dist/llm/codes.js +77 -0
  244. package/dist/llm/complete.js +196 -0
  245. package/dist/llm/events.js +15 -0
  246. package/dist/llm/index.js +24 -0
  247. package/dist/llm/inflight.js +65 -0
  248. package/dist/llm/model-id.js +58 -0
  249. package/dist/llm/provider-face.d.ts +32 -0
  250. package/dist/llm/provider-face.js +34 -0
  251. package/dist/llm/recovery.js +146 -0
  252. package/dist/llm/runtime.js +46 -0
  253. package/dist/llm/stream-fn.js +147 -0
  254. package/dist/lsp/codes.js +31 -0
  255. package/dist/lsp/connection.js +147 -0
  256. package/dist/lsp/frame.js +110 -0
  257. package/dist/lsp/index.js +16 -0
  258. package/dist/lsp/inject.js +58 -0
  259. package/dist/lsp/instance.js +264 -0
  260. package/dist/lsp/service.js +522 -0
  261. package/dist/lsp/tools.js +53 -0
  262. package/dist/lsp/types.js +201 -0
  263. package/dist/mcp/bridge.js +222 -0
  264. package/dist/mcp/codes.js +21 -0
  265. package/dist/mcp/index.js +19 -0
  266. package/dist/mcp/jsonrpc.js +230 -0
  267. package/dist/mcp/service.js +125 -0
  268. package/dist/mcp/tools.js +145 -0
  269. package/dist/mcp/types.js +108 -0
  270. package/dist/memory/cite.js +131 -0
  271. package/dist/memory/codes.js +50 -0
  272. package/dist/memory/command.js +71 -0
  273. package/dist/memory/consolidate.js +219 -0
  274. package/dist/memory/cycle.js +109 -0
  275. package/dist/memory/dao.js +878 -0
  276. package/dist/memory/diff.js +238 -0
  277. package/dist/memory/extract.js +181 -0
  278. package/dist/memory/fts.js +58 -0
  279. package/dist/memory/index.js +42 -0
  280. package/dist/memory/inject.js +354 -0
  281. package/dist/memory/merge.js +178 -0
  282. package/dist/memory/migration.js +132 -0
  283. package/dist/memory/pollution.js +59 -0
  284. package/dist/memory/port.js +385 -0
  285. package/dist/memory/review.js +201 -0
  286. package/dist/memory/scan.js +89 -0
  287. package/dist/memory/tools.js +508 -0
  288. package/dist/memory/types.js +140 -0
  289. package/dist/obs/codes.js +38 -0
  290. package/dist/obs/db.js +115 -0
  291. package/dist/obs/index.js +20 -0
  292. package/dist/obs/rollup.js +61 -0
  293. package/dist/obs/service.js +363 -0
  294. package/dist/obs/session-tools.js +282 -0
  295. package/dist/obs/session-view.js +225 -0
  296. package/dist/obs/tool.js +97 -0
  297. package/dist/obs/types.js +1 -0
  298. package/dist/persist/audit.js +63 -0
  299. package/dist/persist/aux.js +39 -0
  300. package/dist/persist/codes.js +35 -0
  301. package/dist/persist/index.js +30 -0
  302. package/dist/persist/load-history.js +50 -0
  303. package/dist/persist/migrations.js +37 -0
  304. package/dist/persist/paths.js +108 -0
  305. package/dist/persist/persistence.js +229 -0
  306. package/dist/persist/schema.js +99 -0
  307. package/dist/persist/secret-box.js +95 -0
  308. package/dist/persist/store.js +706 -0
  309. package/dist/persist/write-behind.js +238 -0
  310. package/dist/safety/approval.js +171 -0
  311. package/dist/safety/bwrap.js +123 -0
  312. package/dist/safety/codes.js +57 -0
  313. package/dist/safety/danger.js +505 -0
  314. package/dist/safety/gate.js +226 -0
  315. package/dist/safety/index.js +24 -0
  316. package/dist/safety/presets.js +73 -0
  317. package/dist/safety/roots.js +139 -0
  318. package/dist/safety/sandbox.js +214 -0
  319. package/dist/safety/seatbelt.js +88 -0
  320. package/dist/safety/sensitive.js +34 -0
  321. package/dist/safety/tool-policy.js +203 -0
  322. package/dist/safety/types.js +13 -0
  323. package/dist/scheduler/codes.js +54 -0
  324. package/dist/scheduler/cron-backend.js +135 -0
  325. package/dist/scheduler/engine.js +280 -0
  326. package/dist/scheduler/gates.js +60 -0
  327. package/dist/scheduler/index.js +25 -0
  328. package/dist/scheduler/migration.js +22 -0
  329. package/dist/scheduler/runner.js +171 -0
  330. package/dist/scheduler/schedule.js +193 -0
  331. package/dist/scheduler/service.js +283 -0
  332. package/dist/scheduler/tick.js +139 -0
  333. package/dist/scheduler/types.js +1 -0
  334. package/dist/sdk/http.js +865 -0
  335. package/dist/sdk/index.js +22 -0
  336. package/dist/sdk/mcp.js +289 -0
  337. package/dist/sdk/plugin-route-registry.js +126 -0
  338. package/dist/sdk/plugin-routes.js +149 -0
  339. package/dist/sdk/security.js +116 -0
  340. package/dist/sdk/types.js +32 -0
  341. package/dist/session/budget.js +159 -0
  342. package/dist/session/codes.js +40 -0
  343. package/dist/session/derive.js +180 -0
  344. package/dist/session/event-data.js +1 -0
  345. package/dist/session/fork.js +72 -0
  346. package/dist/session/import-gates.js +148 -0
  347. package/dist/session/index.js +18 -0
  348. package/dist/session/recover.js +103 -0
  349. package/dist/session/session.js +279 -0
  350. package/dist/session/snapshot.js +107 -0
  351. package/dist/skills/agents.js +242 -0
  352. package/dist/skills/codes.js +51 -0
  353. package/dist/skills/discovery.js +266 -0
  354. package/dist/skills/frontmatter.js +215 -0
  355. package/dist/skills/index.js +28 -0
  356. package/dist/skills/load.js +118 -0
  357. package/dist/skills/manage.js +201 -0
  358. package/dist/skills/registry.js +138 -0
  359. package/dist/skills/render.js +124 -0
  360. package/dist/skills/sections.js +171 -0
  361. package/dist/skills/types.js +21 -0
  362. package/dist/subagent/codes.js +50 -0
  363. package/dist/subagent/declarative.js +55 -0
  364. package/dist/subagent/index.js +19 -0
  365. package/dist/subagent/notify.js +51 -0
  366. package/dist/subagent/provide.js +7 -0
  367. package/dist/subagent/registry.js +149 -0
  368. package/dist/subagent/service.js +338 -0
  369. package/dist/subagent/surface.js +44 -0
  370. package/dist/subagent/tool.js +153 -0
  371. package/dist/subagent/types.js +25 -0
  372. package/dist/tools/apply-patch.js +164 -0
  373. package/dist/tools/codes.js +109 -0
  374. package/dist/tools/fs.js +501 -0
  375. package/dist/tools/index.js +17 -0
  376. package/dist/tools/observed.js +99 -0
  377. package/dist/tools/pipeline.js +176 -0
  378. package/dist/tools/protected-read.js +54 -0
  379. package/dist/tools/registry.js +250 -0
  380. package/dist/tools/search.js +451 -0
  381. package/dist/tools/worktree.js +327 -0
  382. package/dist/web/codes.js +37 -0
  383. package/dist/web/gate.js +43 -0
  384. package/dist/web/hygiene.js +195 -0
  385. package/dist/web/index.js +16 -0
  386. package/dist/web/service.js +207 -0
  387. package/dist/web/ssrf-guard.js +44 -0
  388. package/dist/web/tool.js +76 -0
  389. package/dist/web/types.js +10 -0
  390. package/dist/webui/assets/index-B-t2O8gh.js +22 -0
  391. package/dist/webui/assets/index-DOlgSZ9Q.css +2 -0
  392. package/dist/webui/index.html +14 -0
  393. package/dist/webui/index.js +14 -0
  394. package/dist/webui/server.js +549 -0
  395. package/dist/webui/types.js +38 -0
  396. package/examples/README.md +26 -0
  397. package/examples/minimal-code-plugin/entry.js +43 -0
  398. package/examples/minimal-code-plugin/package.json +12 -0
  399. package/examples/pure-skill-pack/package.json +14 -0
  400. package/examples/pure-skill-pack/skills/markdown-table/SKILL.md +32 -0
  401. package/package.json +86 -0
@@ -0,0 +1,112 @@
1
+ import { Type } from 'typebox';
2
+ import { deriveMessages } from '../session/index.js';
3
+ import { CCR_MARKER_PREFIX, ccrDirectoryOf } from './ccr.js';
4
+ /** 渲染预算 56KiB(05 §2.1 分段续取律定值——留界外余量给尾部账,常态不触 append 刀) */
5
+ const RENDER_BUDGET_CHARS = 56 * 1024;
6
+ /** 内容块面 → 纯文本(string 直通;块数组 text 块取文本、他块 JSON 形——渲染面保真不猜) */
7
+ function textOf(content) {
8
+ if (typeof content === 'string')
9
+ return content;
10
+ return content
11
+ .map((block) => {
12
+ const b = block;
13
+ return b.type === 'text' && typeof b.text === 'string' ? b.text : JSON.stringify(block);
14
+ })
15
+ .join('\n');
16
+ }
17
+ /** 投影消息 → 可读文本行(模型消费形——角色标注 + 工具调用/结果结构呈现) */
18
+ function renderProjected(message) {
19
+ switch (message.type) {
20
+ case 'user':
21
+ return `[user] ${textOf(message.content)}`;
22
+ case 'assistant': {
23
+ const parts = [`[assistant] ${textOf(message.content)}`];
24
+ for (const call of message.toolCalls) {
25
+ parts.push(` · 工具调用 ${call.toolName}(${call.toolCallId}) 参数: ${call.arguments}`);
26
+ }
27
+ if (message.errorMessage !== undefined)
28
+ parts.push(` · 错误: ${message.errorMessage}`);
29
+ return parts.join('\n');
30
+ }
31
+ case 'toolResult':
32
+ return `[${message.isError ? 'toolResult·出错' : 'toolResult'} ${message.toolName}] ${textOf(message.output)}`;
33
+ }
34
+ }
35
+ /** 归档目录形(hash 缺省消费面):空目录诚实明示 */
36
+ function directoryText(events) {
37
+ const entries = ccrDirectoryOf(events);
38
+ if (entries.length === 0)
39
+ return '本会话暂无 CCR 归档(未压缩过,或遮蔽段早于 CCR 机制引入——批前历史不可回取)。';
40
+ const lines = entries.map((e) => `${CCR_MARKER_PREFIX}${e.hash}>> ${e.messages} 条消息 / ${e.chars} 字符`);
41
+ return `本会话已归档压缩段(hash 传入 ccr_retrieve 可取回原文):\n${lines.join('\n')}`;
42
+ }
43
+ /** 区间命中形:事件切片重导 + 分段续取窗口(冷读闸 M1——至少渲染一条 + 预算累加) */
44
+ function rangeText(events, start, end, fromMessage, budget) {
45
+ const slice = events.filter((event) => event.seq >= start && event.seq <= end);
46
+ const messages = deriveMessages(slice);
47
+ if (messages.length === 0)
48
+ return '区间不可读:遮蔽区间内无可重导的消息(事件残缺或形态不规则)。';
49
+ const from = Math.max(0, Math.min(fromMessage, messages.length - 1));
50
+ const rendered = [];
51
+ let used = 0;
52
+ let taken = 0;
53
+ for (let i = from; i < messages.length; i += 1) {
54
+ const line = renderProjected(messages[i]);
55
+ // 至少渲染一条(首条无条件收);随后累加至预算即止——尾部恒可续取
56
+ if (taken > 0 && used + line.length > budget)
57
+ break;
58
+ rendered.push(line);
59
+ used += line.length;
60
+ taken += 1;
61
+ }
62
+ const total = messages.length;
63
+ const tail = from + taken < total
64
+ ? `(已渲染 ${from + taken}/${total} 条——续取传 fromMessage=${from + taken} 可取余下)`
65
+ : `(已渲染 ${from + taken}/${total} 条,本段已取尽)`;
66
+ return `${rendered.join('\n\n')}\n\n${tail}`;
67
+ }
68
+ /** ccr_retrieve 工具工厂(装载位/测试唯一入口)——单件定义数组(族位形,obs/control 同构) */
69
+ export function createCcrRetrieveTool(deps) {
70
+ const budget = deps.renderBudgetChars ?? RENDER_BUDGET_CHARS;
71
+ return [
72
+ {
73
+ name: 'ccr_retrieve',
74
+ description: '取回本会话压缩归档段的原文(可逆压缩——摘要是有损呈现、原文无损归档)。' +
75
+ `上下文里形如 ${CCR_MARKER_PREFIX}哈希>> 的标记即归档锚:把哈希传入本工具即得该段原文。` +
76
+ '不传 hash 返回归档目录(逐段哈希/消息数/字符数)。' +
77
+ '大段自动分窗:返回尾部标注「已渲染 X/N 条」,传 fromMessage=X 续取余下。' +
78
+ '只读本会话历史(曾可见内容,非新信息);哈希不在归档集时如实回报原因。',
79
+ parameters: Type.Object({
80
+ hash: Type.Optional(Type.String({ description: '归档哈希(<<ccr:…>> 标记内的 16 位十六进制串;缺省返回目录)' })),
81
+ fromMessage: Type.Optional(Type.Number({ description: '续取位(区间内消息 0 基序——分窗续取用;缺省 0)' })),
82
+ }, { additionalProperties: false }),
83
+ effect: 'read',
84
+ execute: async (args) => {
85
+ const events = deps.events();
86
+ const hash = args.hash;
87
+ if (hash === undefined)
88
+ return { content: [{ type: 'text', text: directoryText(events) }] };
89
+ // 命中匹配:只认本会话 surface 事件的存储哈希(归属结构性免疫——伪标记必 miss 零副作用)
90
+ const hit = events.find((event) => event.type === 'compaction/surface' && event.data.ccrHash === hash);
91
+ if (hit === undefined) {
92
+ return {
93
+ content: [
94
+ {
95
+ type: 'text',
96
+ text: `未找到哈希 ${hash} 的归档段。可能原因:哈希不在本会话归档集` +
97
+ '(标记来自其他来源或已损坏)、或该段遮蔽早于 CCR 机制引入(批前历史不可回取)。' +
98
+ '可先不传 hash 查看本会话归档目录核对。',
99
+ },
100
+ ],
101
+ };
102
+ }
103
+ const op = hit.surfaceOp;
104
+ if (op === undefined) {
105
+ return { content: [{ type: 'text', text: '区间不可读:归档事件缺少区间信封(数据形态异常)。' }] };
106
+ }
107
+ const fromMessage = typeof args.fromMessage === 'number' && Number.isFinite(args.fromMessage) ? args.fromMessage : 0;
108
+ return { content: [{ type: 'text', text: rangeText(events, op.start, op.end, fromMessage, budget) }] };
109
+ },
110
+ },
111
+ ];
112
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * compaction — CCR 可逆压缩纯函数件(05 §2.1「压缩可逆性 CCR」子节——2026-09-11
3
+ * 立题批落码;立题档《00-立题-压缩可逆性CCR-20260911》+ 冷读闸 M1-M7 修订形)。
4
+ *
5
+ * 机制三面(第四面「两路一形」由 fiveStep 共用自动获得):
6
+ * - 归档映射:ccrHashOf = sha256(遮蔽区间投影消息序列规范化 JSON——**含 seq
7
+ * 位**〔冷读闸 M4:内容+序寻址,fork 平移后同内容异哈希;兑换按存储哈希
8
+ * 匹配不重算比对〕) 前 16 hex。events 表即归档 store(零新增存储位);
9
+ * - 标记段:摘要载体尾部 host 追加(非摘要算法产物);当次标记行 + **目录
10
+ * 恒链**(此前历次 surface 事件全量——旧载体被遮蔽后历史哈希仍可达);
11
+ * 文案不点名工具(冷读闸 M5:无工具面形态下点名即对模型的空承诺);
12
+ * - 目录源:从 surface 事件重建(孤儿摘要无映射不入目录——冷读闸 M2 自愈
13
+ * 三径之一);CCR 批前历史事件 ccrHash 缺席不列(冷读闸 M6:无检索键
14
+ * 不可回取)。
15
+ *
16
+ * 纯函数零 I/O(events 读面由调用方注入)。
17
+ */
18
+ import { createHash } from 'node:crypto';
19
+ /** CCR 标记行前缀(<<ccr:HASH>> ——标记段构造与剥离的判据锚) */
20
+ export const CCR_MARKER_PREFIX = '<<ccr:';
21
+ /**
22
+ * 规范序列化:对象键递归排序的确定性 JSON(哈希源的单义形——ProjectedMessage
23
+ * 构造路径键序天然可异,键序差不应改哈希;含 seq 位——冷读闸 M4 定形)。
24
+ */
25
+ function canonicalJson(value) {
26
+ return JSON.stringify(value, (_key, val) => {
27
+ if (val !== null && typeof val === 'object' && !Array.isArray(val)) {
28
+ const record = val;
29
+ const sorted = {};
30
+ for (const key of Object.keys(record).sort())
31
+ sorted[key] = record[key];
32
+ return sorted;
33
+ }
34
+ return val;
35
+ });
36
+ }
37
+ /**
38
+ * 归档哈希:遮蔽区间投影消息序列 → sha256 前 16 hex。
39
+ * 确定性:同序列同哈希;seq 变(fork 平移/区间漂移)即异——兑换按存储哈希
40
+ * 匹配、不重算比对(重算比对会在 fork 会话全数 miss)。
41
+ */
42
+ export function ccrHashOf(occluded) {
43
+ return createHash('sha256').update(canonicalJson(occluded)).digest('hex').slice(0, 16);
44
+ }
45
+ /** 目录重建:surface 事件 → 检索面条目(seq 序 = 时间序;批前缺 ccrHash 位者跳过) */
46
+ export function ccrDirectoryOf(events) {
47
+ const entries = [];
48
+ for (const event of events) {
49
+ if (event.type !== 'compaction/surface')
50
+ continue;
51
+ const data = event.data;
52
+ // 兼容位(05 §1.1 ccrHash?):CCR 批前历史事件缺席——无检索键不可回取,不列
53
+ if (typeof data.ccrHash !== 'string')
54
+ continue;
55
+ if (typeof data.occludedMessages !== 'number' || typeof data.occludedChars !== 'number')
56
+ continue;
57
+ entries.push({ hash: data.ccrHash, messages: data.occludedMessages, chars: data.occludedChars });
58
+ }
59
+ return entries;
60
+ }
61
+ /** 标记行(单条):`<<ccr:HASH>> 原文已归档(N 条消息 / M 字符)` */
62
+ function ccrMarkerLine(entry) {
63
+ return `${CCR_MARKER_PREFIX}${entry.hash}>> 原文已归档(${entry.messages} 条消息 / ${entry.chars} 字符)`;
64
+ }
65
+ /**
66
+ * 标记段追加:摘要正文 + `\n\n` + 目录全量标记行(时间序,当次条目由调用方
67
+ * 末位并入——目录恒链)。标记段不计入摘要预算(机制面固定开销非摘要正文)。
68
+ */
69
+ export function withCcrSection(summaryBody, entries) {
70
+ if (entries.length === 0)
71
+ return summaryBody;
72
+ return `${summaryBody}\n\n${entries.map(ccrMarkerLine).join('\n')}`;
73
+ }
74
+ /**
75
+ * 标记段剥离:首条 `<<ccr:` 行起截断(previousSummaryText 迭代链消费——目录
76
+ * 行是机制噪声非摘要素材)。无标记行原样返回(CCR 批前载体兼容)。
77
+ */
78
+ export function stripCcrSection(text) {
79
+ const lines = text.split('\n');
80
+ const cut = lines.findIndex((line) => line.startsWith(CCR_MARKER_PREFIX));
81
+ if (cut === -1)
82
+ return text;
83
+ return lines.slice(0, cut).join('\n').trimEnd();
84
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * compaction 域错误码注册(02 §5.3 COMPACTION_ 族——2026-09-09 U4 规范
3
+ * 先行批明列两码;03 §2.2 第十二面/§2.7 两动词行)。
4
+ *
5
+ * 两码同为槽位占用拒(单席位先到占的执法位)——装载窗 only 的窗外拒
6
+ * 复用 PLUGIN_WINDOW_CLOSED(host 既有码,不在本册)。本文件由模块公开面
7
+ * index.ts 引入(注册纪律:import 发生才注册)。
8
+ */
9
+ import { registerErrorCodes } from '../contracts/index.js';
10
+ registerErrorCodes([
11
+ {
12
+ code: 'COMPACTION_CONFIG_TAKEN',
13
+ module: 'compaction',
14
+ description: '数值配置槽席位已占拒(03 §2.7 ctx.compaction.setConfig——单席位先到占、后到拒;配置主权单源:两插件各设阈值 = 用户装配面错误,fail-loud 拒不静默 last-wins)',
15
+ },
16
+ {
17
+ code: 'COMPACTION_SUMMARIZER_TAKEN',
18
+ module: 'compaction',
19
+ description: '摘要 provider 槽席位已占拒(03 §2.7 ctx.compaction.registerSummarizer——单席位先到占;溢出兜底恒宿主缺省算法系既有立法,槽不可及)',
20
+ },
21
+ ]);
@@ -0,0 +1,18 @@
1
+ /**
2
+ * compaction 模块公开面(L3 宿主固定件——02 篇席 9,随裁决①入宿主;机制真源 05 篇 §2.1/§2.3)。
3
+ *
4
+ * 本批落码:五步骨架两事件形(摘要普通 append + compaction/surface 正门信封)
5
+ * + 阈值/溢出双触发路 + 全局串行队列 + per-session 防抖分账(帽 256 空闲逐出)。
6
+ * host 装配四件(阈值配置/触发器接线/complete 通道 provide/防抖参数)随 host 批。
7
+ * 2026-09-09 U4 批:槽位化三类型(SummarizerFn/SessionBeforeCompactInput)+
8
+ * COMPACTION_ 码族注册(import 发生才注册——公开面引入即注册纪律)+ U4-3
9
+ * 装配件(席位容器 slots——createCompactionSlots 席位状态机 + 值链归因铸造
10
+ * 两律机制件,host 装配层消费)。
11
+ */
12
+ import './codes.js';
13
+ export * from './types.js';
14
+ export { BEFORE_COMPACT_ATTRIB, createCompactionSlots, forgeBeforeCompactIdentity, markBeforeCompactRewrite, } from './slots.js';
15
+ export { SUMMARY_PREFIX, buildSummaryPrompt, evaluateThreshold, inCooldown, planFromRange, planSegment, previousSummaryText, summaryBudgetFor, validateAdjustedRange, } from './policy.js';
16
+ export { createCompactionService } from './service.js';
17
+ export { CCR_MARKER_PREFIX, ccrDirectoryOf, ccrHashOf, stripCcrSection, withCcrSection, } from './ccr.js';
18
+ export { createCcrRetrieveTool } from './ccr-tools.js';
@@ -0,0 +1,200 @@
1
+ import { stripCcrSection } from './ccr.js';
2
+ /** 摘要载体前缀(防注入标记:模型可辨框架文本与用户话语;提取前次摘要时剥除) */
3
+ export const SUMMARY_PREFIX = '[COMPACTION-SUMMARY]';
4
+ /* ---------------- 阈值判定(05 §2.1「阈值」段单源) ---------------- */
5
+ /**
6
+ * 阈值判定:真 token 计量主判(provider 报的 input 真值),投影字符数仅作
7
+ * 无真值时的保守兜底(字符/4 估算——换算不稳定,真值可用时不猜)。
8
+ * 返回 fire(是否触发)+ basis 三件(阈值路落 compaction/start 的判据快照)。
9
+ */
10
+ export function evaluateThreshold(input) {
11
+ // 无真值且投影为零(空会话)——无从判阈,null = 不触发也无判据可记
12
+ if (input.usageInput === null && input.projectedChars === 0)
13
+ return null;
14
+ const effectiveWindow = input.contextWindow ?? input.config.fallbackWindowTokens;
15
+ if (effectiveWindow <= 0)
16
+ return null; // 防御:非正窗口无从比较
17
+ // 真值可用时不猜——估算仅兜底(chars/4:粗略 4 字符/token 换算)
18
+ const estTokens = input.usageInput !== null ? input.usageInput : Math.ceil(input.projectedChars / 4);
19
+ return {
20
+ basis: input.usageInput !== null ? 'usage' : 'estimate',
21
+ estTokens,
22
+ effectiveWindow,
23
+ fire: estTokens / effectiveWindow >= input.config.thresholdRatio,
24
+ };
25
+ }
26
+ /* ---------------- 区间规划(05 §2.1「区间规划三则」+ 边缘纪律) ---------------- */
27
+ /**
28
+ * 区间规划:在合法跨度(终点 ≤ 最近完整 turn 边界;起点对齐 turn 边界)内按
29
+ * 三则细化——head 保首个完整 turn(任务锚;切点须 turn/start 对齐——正门对齐
30
+ * 律的结构推论)、tail 保末 tailKeep 条、最小条数保护(head+tail 之外中段
31
+ * ≥ 1 条放不下即不压)。
32
+ *
33
+ * 返回 null = 诚实无操作(区间不足/日志无闭合 turn/骨架不规则);规划输入
34
+ * 须为互斥锁内新投影(service 全局串行队列保证——排队等待期间他路压缩可能
35
+ * 已改写投影,规划与落账同账零迟滞窗)。
36
+ */
37
+ export function planSegment(input) {
38
+ const { events, messages, tailKeep } = input;
39
+ // 终点界桩:最近完整 turn 边界(无闭合 turn = 无可压区间)
40
+ let boundary = -1;
41
+ for (let i = events.length - 1; i >= 0; i--) {
42
+ if (events[i].type === 'turn/end') {
43
+ boundary = events[i].seq;
44
+ break;
45
+ }
46
+ }
47
+ if (boundary < 0)
48
+ return null;
49
+ // 最小条数保护:head(首 turn 投影消息 ≥ 1 条)+ 中段 ≥ 1 条 + tail tailKeep 条
50
+ if (messages.length < tailKeep + 2)
51
+ return null;
52
+ // tail 锚:末 tailKeep 条的首条消息 seq——遮蔽不得侵入
53
+ const tailAnchor = messages[messages.length - tailKeep].seq;
54
+ const end = Math.min(boundary, tailAnchor - 1);
55
+ // 起点两形:既有遮蔽 → 紧接上次遮蔽终点(正门对齐律第三形——连续压缩切点,
56
+ // 不论该位置事件类型);无遮蔽 → head 保首个完整 turn(首个 turn/end + 1,
57
+ // 该位置须是 turn/start——正门对齐律第二形;无 turn 骨架的裸消息流诚实跳过)
58
+ let lastOcclusionEnd = -1;
59
+ let firstTurnEnd = -1;
60
+ for (const event of events) {
61
+ if (event.surfaceOp && event.surfaceOp.end > lastOcclusionEnd)
62
+ lastOcclusionEnd = event.surfaceOp.end;
63
+ if (firstTurnEnd < 0 && event.type === 'turn/end')
64
+ firstTurnEnd = event.seq;
65
+ }
66
+ let start;
67
+ if (lastOcclusionEnd >= 0) {
68
+ start = lastOcclusionEnd + 1;
69
+ // 起点撞载体(连续压缩紧邻前指令事件的形态)→ 跳过载体链即止(载体是
70
+ // 结构指令事件非 turn 体;其后首位即 turn 单元首位——真实 driver 形为随
71
+ // turn 的 user/message。原「进到下一个 turn/start 对齐位」在真实形会把
72
+ // user/message 留在区间外拆散其 turn——U4-3 装配批集成勘正)
73
+ if (events[start]?.surfaceOp) {
74
+ let next = start;
75
+ while (next < events.length && events[next].surfaceOp)
76
+ next++;
77
+ if (next >= events.length || next > end)
78
+ return null;
79
+ start = next;
80
+ }
81
+ }
82
+ else {
83
+ if (firstTurnEnd < 0)
84
+ return null; // 防御(boundary ≥ 0 已保证存在——死码注明不删)
85
+ // 起点对齐 turn 单元边界(05 §2.1 边缘纪律 5):首 turn/end 后一位即次
86
+ // turn 单元首位——真实 driver 形该位是随 turn 的 user/message〔提交先落
87
+ // 消息后起 turn〕、合成形是 turn/start,两者皆完整 turn 单元首位。原
88
+ // 「该位置须是 turn/start」系合成形状的过强表述,真实日志形下永假(阈值
89
+ // 路生产从未可规划——U4-3 装配批 e2e 抓获勘正)
90
+ start = firstTurnEnd + 1;
91
+ }
92
+ if (start > end)
93
+ return null; // 中段空(tail 窗已压到头/仅单闭合 turn)
94
+ // 防嵌套律的规划面推论:区间须整段避开一切 surfaceOp 载体(载体永不可被遮——
95
+ // 正门防嵌套校验会拒写)。终点收在起点后最近载体之前(前次摘要载体恰在其前,
96
+ // 天然并入区间——迭代链承接面)
97
+ const carrierAbove = events.find((e) => e.seq > start && e.surfaceOp);
98
+ const effectiveEnd = carrierAbove !== undefined ? Math.min(end, carrierAbove.seq - 1) : end;
99
+ if (start > effectiveEnd)
100
+ return null;
101
+ // 区间内投影消息与字符量(字符尺与 fold.chars 同源:逐消息 JSON 长度和)
102
+ const result = planFromRange(start, effectiveEnd, messages);
103
+ if (result.occludedMessages < 1)
104
+ return null; // 防御:区间内无投影消息(纯骨架区间不值得压)
105
+ return result;
106
+ }
107
+ /**
108
+ * 区间 → SegmentPlan(素材三件宿主重算单源——planSegment 尾部与 U4 调整途
109
+ * 共用:调整案的 occluded/occludedMessages/occludedChars 恒宿主按区间从投影
110
+ * 重算,不信载荷〔区间主权 = 唯一采用面〕)。区间内投影消息可空——调用方
111
+ * 自查(planSegment 视为 null、调整途视为非法调整)。
112
+ */
113
+ export function planFromRange(start, end, messages) {
114
+ const occluded = messages.filter((m) => m.seq >= start && m.seq <= end);
115
+ const occludedChars = occluded.reduce((sum, m) => sum + JSON.stringify(m).length, 0);
116
+ return { start, end, occludedMessages: occluded.length, occludedChars, occluded };
117
+ }
118
+ /* ---------------- 调整值校验(U4 调整途——05 §2.1 槽位化第 3 层) ---------------- */
119
+ /**
120
+ * 调整值校验器(「调整值过宿主同一规划校验器」的码面单源):调整案区间须
121
+ * 落在宿主原案区间内——宿主原案已过规划全律(turn 边界/tail 界/起点对齐/避
122
+ * 载体),子区间天然合法;扩界不合法(扩 tail/扩进载体区属越权——界桩移动是
123
+ * 配置槽射程〔tailKeep 等〕非调整途)。
124
+ */
125
+ export function validateAdjustedRange(adjusted, host) {
126
+ return adjusted.start >= host.start && adjusted.end <= host.end && adjusted.start <= adjusted.end;
127
+ }
128
+ /* ---------------- 摘要预算(字符制——05 §2.1「摘要参数」) ---------------- */
129
+ /** 摘要目标长度:被遮蔽字符量 × 压缩率,钳在 [min, max] 字符区间 */
130
+ export function summaryBudgetFor(occludedChars, config) {
131
+ const target = Math.ceil(occludedChars * config.summaryRatio);
132
+ return Math.min(Math.max(target, config.summaryMinChars), config.summaryMaxChars);
133
+ }
134
+ /* ---------------- 迭代链(05 §2.1「迭代链」段) ---------------- */
135
+ /**
136
+ * 前次摘要提取:倒扫日志取末条 source='compaction' 的 user/message(其自身
137
+ * 多已被后续遮蔽——读事件本体而非投影;前次既被遮蔽,其内容唯经并入新摘要
138
+ * 存活)。剥除载体前缀返回正文;无前次摘要返回 null。
139
+ */
140
+ export function previousSummaryText(events) {
141
+ for (let i = events.length - 1; i >= 0; i--) {
142
+ const event = events[i];
143
+ if (event.type !== 'user/message')
144
+ continue;
145
+ const data = event.data;
146
+ if (data.source !== 'compaction')
147
+ continue;
148
+ const text = plainTextOf(data.content);
149
+ if (text === null || text.length === 0)
150
+ continue; // 载体形坏(防御)——继续倒扫
151
+ // 前缀剥除 + CCR 标记段剥离(05 §2.1 压缩可逆性——目录行是机制噪声非
152
+ // 摘要素材,迭代链提示词只喂摘要正文;批前载体无标记段原样兼容)
153
+ if (!text.startsWith(SUMMARY_PREFIX))
154
+ return stripCcrSection(text).trim();
155
+ return stripCcrSection(text.slice(SUMMARY_PREFIX.length)).trim();
156
+ }
157
+ return null;
158
+ }
159
+ /** 内容块面 → 纯文本(string 原样;块数组取 text 块拼接——摘要载体只会有文本) */
160
+ function plainTextOf(content) {
161
+ if (typeof content === 'string')
162
+ return content;
163
+ if (Array.isArray(content)) {
164
+ return content
165
+ .map((block) => block.type === 'text' ? String(block.text) : '')
166
+ .join('');
167
+ }
168
+ return null;
169
+ }
170
+ /* ---------------- 摘要提示词(05 §2.1「摘要参数」五段结构) ---------------- */
171
+ /**
172
+ * 摘要提示词组装:五段结构(任务概述/关键决策/未竟事项/工具与文件痕迹/下一步
173
+ * 建议)+ 迭代链前次摘要并入 + 目标长度预算行。对话原文以 JSON 透传(complete
174
+ * 通道对素材自行取舍——投影消息形即对话真身)。
175
+ */
176
+ export function buildSummaryPrompt(input) {
177
+ const transcript = JSON.stringify(input.occluded, null, 2);
178
+ const previous = input.previousSummary
179
+ ? `\n\n## 前次压缩摘要(迭代链——此前历史已并入其中,本摘要须承接不可丢)\n${input.previousSummary}`
180
+ : '';
181
+ return [
182
+ '请将以下对话压缩为一份上下文摘要,供后续轮次代替被压缩的原文使用。',
183
+ `目标长度:不超过 ${input.maxChars} 字符。`,
184
+ `摘要须按五段结构组织:`,
185
+ '1. 任务概述:用户在做什么、目标是什么;',
186
+ '2. 关键决策:已确定的技术/方案决策及其理由;',
187
+ '3. 未竟事项:已开始未完成的工作、待验证的假设;',
188
+ '4. 工具与文件痕迹:已用工具、已读写的关键文件路径与结果要点;',
189
+ '5. 下一步建议:紧接着最该做的事。',
190
+ '只输出摘要正文,不要输出其他说明。' + previous,
191
+ '',
192
+ '## 待压缩对话(投影消息 JSON)',
193
+ transcript,
194
+ ].join('\n');
195
+ }
196
+ /* ---------------- 冷却判定(防抖三件之一) ---------------- */
197
+ /** 冷却判定:距上次成功压缩不足 cooldownMs → true(抑制触发) */
198
+ export function inCooldown(lastCompactAt, nowMs, config) {
199
+ return lastCompactAt !== null && nowMs - lastCompactAt < config.cooldownMs;
200
+ }