@cjhyy/code-shell-core 0.5.0-rc.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (484) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +162 -0
  3. package/dist/agent/coordinator.d.ts +49 -0
  4. package/dist/agent/coordinator.js +77 -0
  5. package/dist/arena/arena.d.ts +43 -0
  6. package/dist/arena/arena.js +334 -0
  7. package/dist/arena/context/context-tools.d.ts +16 -0
  8. package/dist/arena/context/context-tools.js +231 -0
  9. package/dist/arena/detect-mode.d.ts +20 -0
  10. package/dist/arena/detect-mode.js +78 -0
  11. package/dist/arena/digest-builder.d.ts +25 -0
  12. package/dist/arena/digest-builder.js +120 -0
  13. package/dist/arena/index.d.ts +29 -0
  14. package/dist/arena/index.js +29 -0
  15. package/dist/arena/iterate/convergence.d.ts +25 -0
  16. package/dist/arena/iterate/convergence.js +103 -0
  17. package/dist/arena/iterate/formats/index.d.ts +22 -0
  18. package/dist/arena/iterate/formats/index.js +283 -0
  19. package/dist/arena/iterate/index.d.ts +11 -0
  20. package/dist/arena/iterate/index.js +9 -0
  21. package/dist/arena/iterate/iterative-arena.d.ts +23 -0
  22. package/dist/arena/iterate/iterative-arena.js +237 -0
  23. package/dist/arena/iterate/parse.d.ts +42 -0
  24. package/dist/arena/iterate/parse.js +123 -0
  25. package/dist/arena/iterate/phases/argue.d.ts +22 -0
  26. package/dist/arena/iterate/phases/argue.js +159 -0
  27. package/dist/arena/iterate/phases/revise.d.ts +16 -0
  28. package/dist/arena/iterate/phases/revise.js +62 -0
  29. package/dist/arena/iterate/phases/tournament.d.ts +34 -0
  30. package/dist/arena/iterate/phases/tournament.js +113 -0
  31. package/dist/arena/iterate/tools/web-tools.d.ts +13 -0
  32. package/dist/arena/iterate/tools/web-tools.js +54 -0
  33. package/dist/arena/iterate/types.d.ts +152 -0
  34. package/dist/arena/iterate/types.js +8 -0
  35. package/dist/arena/ledger.d.ts +47 -0
  36. package/dist/arena/ledger.js +151 -0
  37. package/dist/arena/lenses/architecture.d.ts +5 -0
  38. package/dist/arena/lenses/architecture.js +22 -0
  39. package/dist/arena/lenses/engineering.d.ts +5 -0
  40. package/dist/arena/lenses/engineering.js +22 -0
  41. package/dist/arena/lenses/general.d.ts +5 -0
  42. package/dist/arena/lenses/general.js +20 -0
  43. package/dist/arena/lenses/index.d.ts +16 -0
  44. package/dist/arena/lenses/index.js +47 -0
  45. package/dist/arena/lenses/product.d.ts +5 -0
  46. package/dist/arena/lenses/product.js +22 -0
  47. package/dist/arena/model-presets.d.ts +23 -0
  48. package/dist/arena/model-presets.js +44 -0
  49. package/dist/arena/phases/adjudication.d.ts +24 -0
  50. package/dist/arena/phases/adjudication.js +144 -0
  51. package/dist/arena/phases/build-consensus.d.ts +29 -0
  52. package/dist/arena/phases/build-consensus.js +86 -0
  53. package/dist/arena/phases/claim-registry.d.ts +26 -0
  54. package/dist/arena/phases/claim-registry.js +60 -0
  55. package/dist/arena/phases/cross-review.d.ts +45 -0
  56. package/dist/arena/phases/cross-review.js +224 -0
  57. package/dist/arena/phases/debate-rounds.d.ts +27 -0
  58. package/dist/arena/phases/debate-rounds.js +162 -0
  59. package/dist/arena/phases/participant-research.d.ts +38 -0
  60. package/dist/arena/phases/participant-research.js +317 -0
  61. package/dist/arena/phases/planning-detail-expansion.d.ts +38 -0
  62. package/dist/arena/phases/planning-detail-expansion.js +121 -0
  63. package/dist/arena/planner.d.ts +27 -0
  64. package/dist/arena/planner.js +312 -0
  65. package/dist/arena/providers/docs.d.ts +6 -0
  66. package/dist/arena/providers/docs.js +108 -0
  67. package/dist/arena/providers/git.d.ts +8 -0
  68. package/dist/arena/providers/git.js +174 -0
  69. package/dist/arena/providers/index.d.ts +32 -0
  70. package/dist/arena/providers/index.js +132 -0
  71. package/dist/arena/providers/none.d.ts +7 -0
  72. package/dist/arena/providers/none.js +11 -0
  73. package/dist/arena/providers/repo.d.ts +6 -0
  74. package/dist/arena/providers/repo.js +255 -0
  75. package/dist/arena/render/session.d.ts +17 -0
  76. package/dist/arena/render/session.js +190 -0
  77. package/dist/arena/render/terminal.d.ts +34 -0
  78. package/dist/arena/render/terminal.js +286 -0
  79. package/dist/arena/strategies/discussion.d.ts +25 -0
  80. package/dist/arena/strategies/discussion.js +143 -0
  81. package/dist/arena/strategies/index.d.ts +15 -0
  82. package/dist/arena/strategies/index.js +28 -0
  83. package/dist/arena/strategies/language-wrapper.d.ts +17 -0
  84. package/dist/arena/strategies/language-wrapper.js +102 -0
  85. package/dist/arena/strategies/lens-wrapper.d.ts +16 -0
  86. package/dist/arena/strategies/lens-wrapper.js +236 -0
  87. package/dist/arena/strategies/planning.d.ts +30 -0
  88. package/dist/arena/strategies/planning.js +225 -0
  89. package/dist/arena/strategies/review.d.ts +26 -0
  90. package/dist/arena/strategies/review.js +168 -0
  91. package/dist/arena/strategies/utils.d.ts +39 -0
  92. package/dist/arena/strategies/utils.js +647 -0
  93. package/dist/arena/tools/selector.d.ts +17 -0
  94. package/dist/arena/tools/selector.js +61 -0
  95. package/dist/arena/transitions.d.ts +48 -0
  96. package/dist/arena/transitions.js +92 -0
  97. package/dist/arena/types.d.ts +508 -0
  98. package/dist/arena/types.js +27 -0
  99. package/dist/cli/agent-server-stdio.d.ts +32 -0
  100. package/dist/cli/agent-server-stdio.js +116 -0
  101. package/dist/colorizer.d.ts +23 -0
  102. package/dist/colorizer.js +12 -0
  103. package/dist/context/compaction.d.ts +116 -0
  104. package/dist/context/compaction.js +534 -0
  105. package/dist/context/manager.d.ts +145 -0
  106. package/dist/context/manager.js +423 -0
  107. package/dist/context/token-counter.d.ts +27 -0
  108. package/dist/context/token-counter.js +91 -0
  109. package/dist/context/tool-result-storage.d.ts +96 -0
  110. package/dist/context/tool-result-storage.js +296 -0
  111. package/dist/cost-tracker.d.ts +64 -0
  112. package/dist/cost-tracker.js +314 -0
  113. package/dist/cron/scheduler.d.ts +34 -0
  114. package/dist/cron/scheduler.js +115 -0
  115. package/dist/data/deepseek-models.json +46 -0
  116. package/dist/data/gemini-models.json +67 -0
  117. package/dist/data/openai-models.json +175 -0
  118. package/dist/data/openrouter-models.d.ts +35 -0
  119. package/dist/data/openrouter-models.js +36 -0
  120. package/dist/data/openrouter-models.json +4626 -0
  121. package/dist/data/openrouter-sync.d.ts +16 -0
  122. package/dist/data/openrouter-sync.js +53 -0
  123. package/dist/data/static-catalogs.d.ts +25 -0
  124. package/dist/data/static-catalogs.js +26 -0
  125. package/dist/data/zai-models.json +56 -0
  126. package/dist/engine/cost-store.d.ts +22 -0
  127. package/dist/engine/cost-store.js +15 -0
  128. package/dist/engine/engine.d.ts +295 -0
  129. package/dist/engine/engine.js +1467 -0
  130. package/dist/engine/model-facade.d.ts +24 -0
  131. package/dist/engine/model-facade.js +194 -0
  132. package/dist/engine/parse-task.d.ts +59 -0
  133. package/dist/engine/parse-task.js +135 -0
  134. package/dist/engine/patch-orphaned-tools.d.ts +52 -0
  135. package/dist/engine/patch-orphaned-tools.js +95 -0
  136. package/dist/engine/query.d.ts +50 -0
  137. package/dist/engine/query.js +107 -0
  138. package/dist/engine/runtime.d.ts +50 -0
  139. package/dist/engine/runtime.js +59 -0
  140. package/dist/engine/streaming-tool-queue.d.ts +34 -0
  141. package/dist/engine/streaming-tool-queue.js +61 -0
  142. package/dist/engine/token-budget.d.ts +22 -0
  143. package/dist/engine/token-budget.js +40 -0
  144. package/dist/engine/tool-summary.d.ts +13 -0
  145. package/dist/engine/tool-summary.js +35 -0
  146. package/dist/engine/turn-loop.d.ts +122 -0
  147. package/dist/engine/turn-loop.js +602 -0
  148. package/dist/engine/turn-state.d.ts +20 -0
  149. package/dist/engine/turn-state.js +17 -0
  150. package/dist/exceptions.d.ts +61 -0
  151. package/dist/exceptions.js +116 -0
  152. package/dist/git/utils.d.ts +35 -0
  153. package/dist/git/utils.js +98 -0
  154. package/dist/git/worktree.d.ts +36 -0
  155. package/dist/git/worktree.js +139 -0
  156. package/dist/hooks/events.d.ts +114 -0
  157. package/dist/hooks/events.js +4 -0
  158. package/dist/hooks/inject.d.ts +19 -0
  159. package/dist/hooks/inject.js +29 -0
  160. package/dist/hooks/registry.d.ts +15 -0
  161. package/dist/hooks/registry.js +84 -0
  162. package/dist/hooks/shell-runner.d.ts +45 -0
  163. package/dist/hooks/shell-runner.js +173 -0
  164. package/dist/index.d.ts +117 -0
  165. package/dist/index.js +145 -0
  166. package/dist/llm/api-key-sanitize.d.ts +22 -0
  167. package/dist/llm/api-key-sanitize.js +81 -0
  168. package/dist/llm/capabilities/index.d.ts +20 -0
  169. package/dist/llm/capabilities/index.js +39 -0
  170. package/dist/llm/capabilities/rules.d.ts +26 -0
  171. package/dist/llm/capabilities/rules.js +215 -0
  172. package/dist/llm/capabilities/types.d.ts +114 -0
  173. package/dist/llm/capabilities/types.js +24 -0
  174. package/dist/llm/client-base.d.ts +29 -0
  175. package/dist/llm/client-base.js +137 -0
  176. package/dist/llm/client-factory.d.ts +10 -0
  177. package/dist/llm/client-factory.js +29 -0
  178. package/dist/llm/model-cache.d.ts +21 -0
  179. package/dist/llm/model-cache.js +46 -0
  180. package/dist/llm/model-fetcher.d.ts +29 -0
  181. package/dist/llm/model-fetcher.js +282 -0
  182. package/dist/llm/model-pool.d.ts +95 -0
  183. package/dist/llm/model-pool.js +246 -0
  184. package/dist/llm/provider-catalog.d.ts +32 -0
  185. package/dist/llm/provider-catalog.js +50 -0
  186. package/dist/llm/provider-kinds.d.ts +21 -0
  187. package/dist/llm/provider-kinds.js +132 -0
  188. package/dist/llm/providers/anthropic.d.ts +19 -0
  189. package/dist/llm/providers/anthropic.js +267 -0
  190. package/dist/llm/providers/openai.d.ts +64 -0
  191. package/dist/llm/providers/openai.js +606 -0
  192. package/dist/llm/retry.d.ts +12 -0
  193. package/dist/llm/retry.js +17 -0
  194. package/dist/llm/stream-watchdog.d.ts +42 -0
  195. package/dist/llm/stream-watchdog.js +70 -0
  196. package/dist/llm/token-counter.d.ts +17 -0
  197. package/dist/llm/token-counter.js +36 -0
  198. package/dist/llm/types.d.ts +37 -0
  199. package/dist/llm/types.js +4 -0
  200. package/dist/logging/logger.d.ts +109 -0
  201. package/dist/logging/logger.js +390 -0
  202. package/dist/logging/sanitize-messages.d.ts +42 -0
  203. package/dist/logging/sanitize-messages.js +150 -0
  204. package/dist/logging/session-recorder.d.ts +90 -0
  205. package/dist/logging/session-recorder.js +304 -0
  206. package/dist/lsp/client.d.ts +41 -0
  207. package/dist/lsp/client.js +166 -0
  208. package/dist/lsp/manager.d.ts +40 -0
  209. package/dist/lsp/manager.js +124 -0
  210. package/dist/lsp/servers.d.ts +16 -0
  211. package/dist/lsp/servers.js +60 -0
  212. package/dist/migrate-models.d.ts +45 -0
  213. package/dist/migrate-models.js +179 -0
  214. package/dist/onboarding.d.ts +189 -0
  215. package/dist/onboarding.js +625 -0
  216. package/dist/plugins/gitOps.d.ts +32 -0
  217. package/dist/plugins/gitOps.js +62 -0
  218. package/dist/plugins/installedPlugins.d.ts +15 -0
  219. package/dist/plugins/installedPlugins.js +56 -0
  220. package/dist/plugins/knownMarketplaces.d.ts +10 -0
  221. package/dist/plugins/knownMarketplaces.js +46 -0
  222. package/dist/plugins/loadPluginHooks.d.ts +52 -0
  223. package/dist/plugins/loadPluginHooks.js +162 -0
  224. package/dist/plugins/marketplaceManager.d.ts +49 -0
  225. package/dist/plugins/marketplaceManager.js +142 -0
  226. package/dist/plugins/parseMarketplaceInput.d.ts +16 -0
  227. package/dist/plugins/parseMarketplaceInput.js +73 -0
  228. package/dist/plugins/pluginCommandHook.d.ts +54 -0
  229. package/dist/plugins/pluginCommandHook.js +180 -0
  230. package/dist/plugins/pluginCommandsLoader.d.ts +25 -0
  231. package/dist/plugins/pluginCommandsLoader.js +114 -0
  232. package/dist/plugins/pluginInstaller.d.ts +36 -0
  233. package/dist/plugins/pluginInstaller.js +228 -0
  234. package/dist/plugins/schemas.d.ts +9 -0
  235. package/dist/plugins/schemas.js +136 -0
  236. package/dist/plugins/types.d.ts +75 -0
  237. package/dist/plugins/types.js +7 -0
  238. package/dist/plugins/varRewrite.d.ts +42 -0
  239. package/dist/plugins/varRewrite.js +129 -0
  240. package/dist/preset/index.d.ts +60 -0
  241. package/dist/preset/index.js +159 -0
  242. package/dist/product/define.d.ts +60 -0
  243. package/dist/product/define.js +123 -0
  244. package/dist/product/index.d.ts +5 -0
  245. package/dist/product/index.js +4 -0
  246. package/dist/product/types.d.ts +111 -0
  247. package/dist/product/types.js +21 -0
  248. package/dist/prompt/composer.d.ts +49 -0
  249. package/dist/prompt/composer.js +168 -0
  250. package/dist/prompt/instruction-scanner.d.ts +54 -0
  251. package/dist/prompt/instruction-scanner.js +187 -0
  252. package/dist/prompt/section-cache.d.ts +15 -0
  253. package/dist/prompt/section-cache.js +31 -0
  254. package/dist/prompt/section-loader.d.ts +26 -0
  255. package/dist/prompt/section-loader.js +53 -0
  256. package/dist/prompt/sections/base.md +35 -0
  257. package/dist/prompt/sections/coding.md +31 -0
  258. package/dist/prompt/sections/orchestration.md +16 -0
  259. package/dist/prompt/sections/tone.md +9 -0
  260. package/dist/protocol/chat-session-manager.d.ts +33 -0
  261. package/dist/protocol/chat-session-manager.js +65 -0
  262. package/dist/protocol/chat-session.d.ts +49 -0
  263. package/dist/protocol/chat-session.js +86 -0
  264. package/dist/protocol/client.d.ts +104 -0
  265. package/dist/protocol/client.js +260 -0
  266. package/dist/protocol/factories.d.ts +93 -0
  267. package/dist/protocol/factories.js +64 -0
  268. package/dist/protocol/helpers.d.ts +42 -0
  269. package/dist/protocol/helpers.js +55 -0
  270. package/dist/protocol/index.d.ts +4 -0
  271. package/dist/protocol/index.js +4 -0
  272. package/dist/protocol/server.d.ts +80 -0
  273. package/dist/protocol/server.js +855 -0
  274. package/dist/protocol/transport.d.ts +37 -0
  275. package/dist/protocol/transport.js +85 -0
  276. package/dist/protocol/types.d.ts +221 -0
  277. package/dist/protocol/types.js +61 -0
  278. package/dist/remote/bridge.d.ts +37 -0
  279. package/dist/remote/bridge.js +103 -0
  280. package/dist/run/ArtifactTracker.d.ts +38 -0
  281. package/dist/run/ArtifactTracker.js +132 -0
  282. package/dist/run/CheckpointWriter.d.ts +53 -0
  283. package/dist/run/CheckpointWriter.js +135 -0
  284. package/dist/run/EngineRunner.d.ts +72 -0
  285. package/dist/run/EngineRunner.js +119 -0
  286. package/dist/run/Evaluator.d.ts +56 -0
  287. package/dist/run/Evaluator.js +62 -0
  288. package/dist/run/FileRunStore.d.ts +39 -0
  289. package/dist/run/FileRunStore.js +176 -0
  290. package/dist/run/Heartbeat.d.ts +54 -0
  291. package/dist/run/Heartbeat.js +123 -0
  292. package/dist/run/RunApprovalBackend.d.ts +53 -0
  293. package/dist/run/RunApprovalBackend.js +85 -0
  294. package/dist/run/RunLock.d.ts +40 -0
  295. package/dist/run/RunLock.js +98 -0
  296. package/dist/run/RunManager.d.ts +82 -0
  297. package/dist/run/RunManager.js +587 -0
  298. package/dist/run/RunQueue.d.ts +27 -0
  299. package/dist/run/RunQueue.js +73 -0
  300. package/dist/run/RunStore.d.ts +25 -0
  301. package/dist/run/RunStore.js +9 -0
  302. package/dist/run/factory.d.ts +63 -0
  303. package/dist/run/factory.js +51 -0
  304. package/dist/run/index.d.ts +17 -0
  305. package/dist/run/index.js +23 -0
  306. package/dist/run/types.d.ts +136 -0
  307. package/dist/run/types.js +28 -0
  308. package/dist/runtime/safe-spawn.d.ts +118 -0
  309. package/dist/runtime/safe-spawn.js +268 -0
  310. package/dist/services/analytics.d.ts +29 -0
  311. package/dist/services/analytics.js +84 -0
  312. package/dist/services/auto-dream.d.ts +49 -0
  313. package/dist/services/auto-dream.js +124 -0
  314. package/dist/services/diagnostics.d.ts +41 -0
  315. package/dist/services/diagnostics.js +99 -0
  316. package/dist/services/extract-memories.d.ts +31 -0
  317. package/dist/services/extract-memories.js +71 -0
  318. package/dist/services/index.d.ts +11 -0
  319. package/dist/services/index.js +17 -0
  320. package/dist/services/memory-orchestrator.d.ts +60 -0
  321. package/dist/services/memory-orchestrator.js +133 -0
  322. package/dist/services/notifier.d.ts +25 -0
  323. package/dist/services/notifier.js +69 -0
  324. package/dist/services/oauth.d.ts +27 -0
  325. package/dist/services/oauth.js +153 -0
  326. package/dist/services/session-memory.d.ts +37 -0
  327. package/dist/services/session-memory.js +81 -0
  328. package/dist/session/file-history.d.ts +41 -0
  329. package/dist/session/file-history.js +115 -0
  330. package/dist/session/memory.d.ts +104 -0
  331. package/dist/session/memory.js +310 -0
  332. package/dist/session/session-manager.d.ts +41 -0
  333. package/dist/session/session-manager.js +261 -0
  334. package/dist/session/transcript.d.ts +39 -0
  335. package/dist/session/transcript.js +186 -0
  336. package/dist/settings/manager.d.ts +36 -0
  337. package/dist/settings/manager.js +187 -0
  338. package/dist/settings/schema.d.ts +1219 -0
  339. package/dist/settings/schema.js +246 -0
  340. package/dist/skills/frontmatter.d.ts +13 -0
  341. package/dist/skills/frontmatter.js +70 -0
  342. package/dist/skills/index.d.ts +7 -0
  343. package/dist/skills/index.js +6 -0
  344. package/dist/skills/scanner.d.ts +31 -0
  345. package/dist/skills/scanner.js +171 -0
  346. package/dist/state.d.ts +160 -0
  347. package/dist/state.js +267 -0
  348. package/dist/tool-system/builtin/agent-notifications.d.ts +84 -0
  349. package/dist/tool-system/builtin/agent-notifications.js +197 -0
  350. package/dist/tool-system/builtin/agent-registry.d.ts +67 -0
  351. package/dist/tool-system/builtin/agent-registry.js +126 -0
  352. package/dist/tool-system/builtin/agent-transcript-translator.d.ts +22 -0
  353. package/dist/tool-system/builtin/agent-transcript-translator.js +160 -0
  354. package/dist/tool-system/builtin/agent.d.ts +16 -0
  355. package/dist/tool-system/builtin/agent.js +364 -0
  356. package/dist/tool-system/builtin/apply-patch/applier.d.ts +26 -0
  357. package/dist/tool-system/builtin/apply-patch/applier.js +250 -0
  358. package/dist/tool-system/builtin/apply-patch/index.d.ts +20 -0
  359. package/dist/tool-system/builtin/apply-patch/index.js +101 -0
  360. package/dist/tool-system/builtin/apply-patch/parser.d.ts +17 -0
  361. package/dist/tool-system/builtin/apply-patch/parser.js +212 -0
  362. package/dist/tool-system/builtin/apply-patch/seek-sequence.d.ts +18 -0
  363. package/dist/tool-system/builtin/apply-patch/seek-sequence.js +123 -0
  364. package/dist/tool-system/builtin/apply-patch/types.d.ts +49 -0
  365. package/dist/tool-system/builtin/apply-patch/types.js +13 -0
  366. package/dist/tool-system/builtin/arena.d.ts +31 -0
  367. package/dist/tool-system/builtin/arena.js +416 -0
  368. package/dist/tool-system/builtin/ask-user.d.ts +20 -0
  369. package/dist/tool-system/builtin/ask-user.js +99 -0
  370. package/dist/tool-system/builtin/bash.d.ts +21 -0
  371. package/dist/tool-system/builtin/bash.js +149 -0
  372. package/dist/tool-system/builtin/brief.d.ts +6 -0
  373. package/dist/tool-system/builtin/brief.js +41 -0
  374. package/dist/tool-system/builtin/config.d.ts +6 -0
  375. package/dist/tool-system/builtin/config.js +67 -0
  376. package/dist/tool-system/builtin/cron.d.ts +10 -0
  377. package/dist/tool-system/builtin/cron.js +61 -0
  378. package/dist/tool-system/builtin/edit.d.ts +6 -0
  379. package/dist/tool-system/builtin/edit.js +100 -0
  380. package/dist/tool-system/builtin/file-cache.d.ts +11 -0
  381. package/dist/tool-system/builtin/file-cache.js +39 -0
  382. package/dist/tool-system/builtin/glob.d.ts +7 -0
  383. package/dist/tool-system/builtin/glob.js +76 -0
  384. package/dist/tool-system/builtin/grep.d.ts +7 -0
  385. package/dist/tool-system/builtin/grep.js +150 -0
  386. package/dist/tool-system/builtin/index.d.ts +20 -0
  387. package/dist/tool-system/builtin/index.js +449 -0
  388. package/dist/tool-system/builtin/lsp.d.ts +6 -0
  389. package/dist/tool-system/builtin/lsp.js +141 -0
  390. package/dist/tool-system/builtin/mcp-tools.d.ts +10 -0
  391. package/dist/tool-system/builtin/mcp-tools.js +102 -0
  392. package/dist/tool-system/builtin/memory.d.ts +26 -0
  393. package/dist/tool-system/builtin/memory.js +226 -0
  394. package/dist/tool-system/builtin/notebook-edit.d.ts +6 -0
  395. package/dist/tool-system/builtin/notebook-edit.js +124 -0
  396. package/dist/tool-system/builtin/plan.d.ts +15 -0
  397. package/dist/tool-system/builtin/plan.js +55 -0
  398. package/dist/tool-system/builtin/powershell.d.ts +11 -0
  399. package/dist/tool-system/builtin/powershell.js +64 -0
  400. package/dist/tool-system/builtin/read.d.ts +6 -0
  401. package/dist/tool-system/builtin/read.js +70 -0
  402. package/dist/tool-system/builtin/remote-trigger.d.ts +6 -0
  403. package/dist/tool-system/builtin/remote-trigger.js +54 -0
  404. package/dist/tool-system/builtin/repl.d.ts +11 -0
  405. package/dist/tool-system/builtin/repl.js +82 -0
  406. package/dist/tool-system/builtin/send-message.d.ts +6 -0
  407. package/dist/tool-system/builtin/send-message.js +47 -0
  408. package/dist/tool-system/builtin/skill-prompt.d.ts +20 -0
  409. package/dist/tool-system/builtin/skill-prompt.js +52 -0
  410. package/dist/tool-system/builtin/skill.d.ts +9 -0
  411. package/dist/tool-system/builtin/skill.js +55 -0
  412. package/dist/tool-system/builtin/sleep.d.ts +6 -0
  413. package/dist/tool-system/builtin/sleep.js +33 -0
  414. package/dist/tool-system/builtin/task.d.ts +48 -0
  415. package/dist/tool-system/builtin/task.js +139 -0
  416. package/dist/tool-system/builtin/tool-search.d.ts +11 -0
  417. package/dist/tool-system/builtin/tool-search.js +90 -0
  418. package/dist/tool-system/builtin/web-fetch.d.ts +10 -0
  419. package/dist/tool-system/builtin/web-fetch.js +328 -0
  420. package/dist/tool-system/builtin/web-search.d.ts +25 -0
  421. package/dist/tool-system/builtin/web-search.js +174 -0
  422. package/dist/tool-system/builtin/worktree.d.ts +10 -0
  423. package/dist/tool-system/builtin/worktree.js +95 -0
  424. package/dist/tool-system/builtin/write.d.ts +6 -0
  425. package/dist/tool-system/builtin/write.js +36 -0
  426. package/dist/tool-system/context.d.ts +165 -0
  427. package/dist/tool-system/context.js +18 -0
  428. package/dist/tool-system/executor.d.ts +49 -0
  429. package/dist/tool-system/executor.js +495 -0
  430. package/dist/tool-system/investigation-guard.d.ts +46 -0
  431. package/dist/tool-system/investigation-guard.js +155 -0
  432. package/dist/tool-system/mcp-manager.d.ts +67 -0
  433. package/dist/tool-system/mcp-manager.js +249 -0
  434. package/dist/tool-system/permission.d.ts +111 -0
  435. package/dist/tool-system/permission.js +774 -0
  436. package/dist/tool-system/registry.d.ts +32 -0
  437. package/dist/tool-system/registry.js +131 -0
  438. package/dist/tool-system/sandbox/bwrap.d.ts +13 -0
  439. package/dist/tool-system/sandbox/bwrap.js +63 -0
  440. package/dist/tool-system/sandbox/index.d.ts +78 -0
  441. package/dist/tool-system/sandbox/index.js +222 -0
  442. package/dist/tool-system/sandbox/off.d.ts +2 -0
  443. package/dist/tool-system/sandbox/off.js +8 -0
  444. package/dist/tool-system/sandbox/seatbelt.d.ts +18 -0
  445. package/dist/tool-system/sandbox/seatbelt.js +109 -0
  446. package/dist/tool-system/task-guard.d.ts +29 -0
  447. package/dist/tool-system/task-guard.js +70 -0
  448. package/dist/tool-system/validation.d.ts +5 -0
  449. package/dist/tool-system/validation.js +39 -0
  450. package/dist/types.d.ts +376 -0
  451. package/dist/types.js +4 -0
  452. package/dist/updater.d.ts +65 -0
  453. package/dist/updater.js +405 -0
  454. package/dist/utils/debug.d.ts +41 -0
  455. package/dist/utils/debug.js +110 -0
  456. package/dist/utils/earlyInput.d.ts +43 -0
  457. package/dist/utils/earlyInput.js +166 -0
  458. package/dist/utils/env.d.ts +24 -0
  459. package/dist/utils/env.js +104 -0
  460. package/dist/utils/envUtils.d.ts +51 -0
  461. package/dist/utils/envUtils.js +135 -0
  462. package/dist/utils/execFileNoThrow.d.ts +39 -0
  463. package/dist/utils/execFileNoThrow.js +74 -0
  464. package/dist/utils/format.d.ts +44 -0
  465. package/dist/utils/format.js +236 -0
  466. package/dist/utils/intl.d.ts +22 -0
  467. package/dist/utils/intl.js +83 -0
  468. package/dist/utils/lockfile.d.ts +15 -0
  469. package/dist/utils/lockfile.js +30 -0
  470. package/dist/utils/memoize.d.ts +19 -0
  471. package/dist/utils/memoize.js +14 -0
  472. package/dist/utils/semver.d.ts +6 -0
  473. package/dist/utils/semver.js +13 -0
  474. package/dist/utils/sliceAnsi.d.ts +12 -0
  475. package/dist/utils/sliceAnsi.js +62 -0
  476. package/dist/utils/systemTheme.d.ts +40 -0
  477. package/dist/utils/systemTheme.js +108 -0
  478. package/dist/utils/task-sanitizer.d.ts +6 -0
  479. package/dist/utils/task-sanitizer.js +24 -0
  480. package/dist/utils/theme.d.ts +93 -0
  481. package/dist/utils/theme.js +544 -0
  482. package/dist/utils/toolDisplay.d.ts +31 -0
  483. package/dist/utils/toolDisplay.js +188 -0
  484. package/package.json +72 -0
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Context manager — three-tier context management.
3
+ *
4
+ * Tier 1: microcompact (sync, zero-cost) — clear old tool_result content
5
+ * Tier 2: LLM summary (async) — generate summary of older messages via model call
6
+ * Tier 3: window compact (sync, emergency) — aggressive truncation fallback
7
+ */
8
+ import type { Message } from "../types.js";
9
+ export interface ContextManagerConfig {
10
+ maxTokens: number;
11
+ compactAtRatio: number;
12
+ summarizeAtRatio: number;
13
+ maxToolResultChars: number;
14
+ /**
15
+ * Lower bound, as a ratio of maxTokens, below which microcompact will not
16
+ * run. CC's external (non-cache-edit) path is "autocompact handles context
17
+ * pressure"; mirror that by leaving early-turn context alone so a model
18
+ * with a 1M window doesn't see its first-3-rounds Read results wiped at
19
+ * 23k tokens. Raising the floor also keeps prompt-cache prefixes warm in
20
+ * short sessions.
21
+ */
22
+ microcompactFloorRatio: number;
23
+ /**
24
+ * Most-recent compactable rounds microcompact keeps untouched. Auto-derived
25
+ * from maxTokens when not set explicitly: bigger window → keep more.
26
+ */
27
+ microcompactKeepRecent?: number;
28
+ }
29
+ /**
30
+ * Async function type for LLM summarization calls.
31
+ * Injected by the Engine so the ContextManager doesn't depend on LLM directly.
32
+ */
33
+ export type SummarizeFn = (prompt: string) => Promise<string>;
34
+ export type CompactStrategy = "micro" | "summary" | "window" | "snip" | "emergency";
35
+ export type OnCompactFn = (info: {
36
+ strategy: CompactStrategy;
37
+ before: number;
38
+ after: number;
39
+ }) => void;
40
+ export declare class ContextManager {
41
+ private config;
42
+ private toolCallHashes;
43
+ private summarizeFn;
44
+ private consecutiveSummaryFailures;
45
+ private lastSummary;
46
+ /** Last known actual token count from API usage data. */
47
+ private lastActualTokens;
48
+ /** Message count at the time lastActualTokens was recorded. */
49
+ private lastActualAtMessageCount;
50
+ /** Path to session transcript — passed to summary compaction for on-demand access. */
51
+ private transcriptPath;
52
+ /** Notified whenever any compaction tier fires, including microcompact. */
53
+ private onCompact;
54
+ /**
55
+ * Tool-result persistence state. Created lazily once we know where to
56
+ * write files (i.e. once setTranscriptPath has been called).
57
+ * `null` = persistence has been explicitly disabled.
58
+ */
59
+ private replacementState;
60
+ private toolResultsDir;
61
+ constructor(config?: Partial<ContextManagerConfig>);
62
+ setOnCompact(fn: OnCompactFn): void;
63
+ /**
64
+ * Record actual token usage from API response.
65
+ * Used for hybrid estimation: actual + estimate for new messages.
66
+ */
67
+ recordActualUsage(inputTokens: number, messageCount: number): void;
68
+ /**
69
+ * Best-effort token estimate: uses actual API usage as base if available,
70
+ * plus estimation for messages added since the last API call.
71
+ */
72
+ private estimateTokensHybrid;
73
+ /**
74
+ * Set the summarize function (injected by Engine).
75
+ */
76
+ setSummarizeFn(fn: SummarizeFn): void;
77
+ /**
78
+ * Set the transcript path so compaction can reference it. The
79
+ * tool-results directory lives alongside the transcript file:
80
+ * <transcriptDir>/tool-results/<toolUseId>.txt
81
+ */
82
+ setTranscriptPath(path: string): void;
83
+ /**
84
+ * Initialize tool-result-persistence state from already-loaded messages.
85
+ * Call this once per session, after setTranscriptPath, when resuming so
86
+ * the manager re-enters the same "frozen decision" state it had on the
87
+ * previous run. Without this, a resumed session would re-evaluate
88
+ * every result against the current threshold and might flip choices.
89
+ */
90
+ initReplacementStateFromMessages(messages: Message[]): void;
91
+ /**
92
+ * Apply progressive context management (sync path).
93
+ * For Tier 2 (LLM summary), call manageAsync instead.
94
+ */
95
+ manage(messages: Message[]): Message[];
96
+ /**
97
+ * Async context management — attempts LLM summarization before falling back.
98
+ * Call this when you have access to the LLM (between turns).
99
+ */
100
+ manageAsync(messages: Message[]): Promise<Message[]>;
101
+ /**
102
+ * Persist large tool_result blocks to disk and replace them with a
103
+ * preview + filepath. No-op when transcript path hasn't been set
104
+ * (e.g. unit tests that exercise compaction directly without a session).
105
+ */
106
+ private persistLargeToolResults;
107
+ /**
108
+ * Truncate oversized tool results in messages.
109
+ */
110
+ private truncateToolResults;
111
+ /**
112
+ * Reactive compaction check — call during streaming to detect if
113
+ * token usage is approaching the limit mid-turn.
114
+ * Returns true if emergency compaction should be triggered.
115
+ */
116
+ shouldReactiveCompact(messages: Message[], currentResponseTokens: number): boolean;
117
+ /**
118
+ * Check if context is approaching limits.
119
+ */
120
+ checkLimits(messages: Message[]): {
121
+ tokens: number;
122
+ ratio: number;
123
+ needsCompact: boolean;
124
+ needsEmergency: boolean;
125
+ };
126
+ /**
127
+ * Deduplicate tool calls by hashing arguments.
128
+ */
129
+ deduplicateToolCalls(calls: Array<{
130
+ toolName: string;
131
+ args: Record<string, unknown>;
132
+ }>): {
133
+ toExecute: typeof calls;
134
+ cached: Array<{
135
+ toolName: string;
136
+ args: Record<string, unknown>;
137
+ result: string;
138
+ }>;
139
+ };
140
+ /**
141
+ * Record a tool call result for dedup tracking.
142
+ */
143
+ recordToolResult(toolName: string, args: Record<string, unknown>, result: string): void;
144
+ private hashCall;
145
+ }
@@ -0,0 +1,423 @@
1
+ /**
2
+ * Context manager — three-tier context management.
3
+ *
4
+ * Tier 1: microcompact (sync, zero-cost) — clear old tool_result content
5
+ * Tier 2: LLM summary (async) — generate summary of older messages via model call
6
+ * Tier 3: window compact (sync, emergency) — aggressive truncation fallback
7
+ */
8
+ import { estimateTokens, microcompact, snipCompact, windowCompact, truncateToolResult, buildSummarizationPrompt, applySummaryCompaction, applyToolResultBudget, extractAnchoredSummary, } from "./compaction.js";
9
+ import { applyToolResultPersistence, createContentReplacementState, reconstructContentReplacementState, resolveToolResultsDir, } from "./tool-result-storage.js";
10
+ import { logger } from "../logging/logger.js";
11
+ const DEFAULT_CONFIG = {
12
+ // 0.85 ≈ effectiveContextWindow − reserved-output buffer (CC's
13
+ // autoCompactThreshold pattern: window − 13k buffer − 20k output budget
14
+ // ≈ 0.83 on a 200k window, 0.97 on 1M). 0.6 was wasting 40% of any model
15
+ // with a window over ~150k.
16
+ maxTokens: 200_000,
17
+ compactAtRatio: 0.85,
18
+ summarizeAtRatio: 0.92,
19
+ maxToolResultChars: 30_000,
20
+ // 0.7 leaves micro idle until the prompt is ~70% full. Below this we
21
+ // let tool_results stay intact: under-pressure context doesn't need
22
+ // micro and wiping early Read/Bash output just forces the model to
23
+ // re-fetch the same files later. CC's external path triggers around
24
+ // 70-75% of the window; this matches it. Was 0.5 — on a 200k model
25
+ // that fired at 100k where a long-but-not-overloaded conversation
26
+ // (~130k tokens) tripped micro every single turn, with the cleared
27
+ // 8 rounds promptly replaced by 5 fresh ones so the next turn was
28
+ // back at 130k and the cycle repeated. 0.7 → 140k floor, leaving
29
+ // realistic headroom before we start churning.
30
+ microcompactFloorRatio: 0.7,
31
+ };
32
+ /**
33
+ * Default keepRecent for microcompact, scaled to the model's context window.
34
+ * Mirrors CC's "keep recent 5" baseline but lets a 1M-window model retain
35
+ * proportionally more tool_result detail before clearing kicks in.
36
+ */
37
+ function defaultKeepRecent(maxTokens) {
38
+ return Math.max(5, Math.floor(maxTokens / 100_000));
39
+ }
40
+ export class ContextManager {
41
+ config;
42
+ toolCallHashes = new Map();
43
+ summarizeFn;
44
+ consecutiveSummaryFailures = 0;
45
+ lastSummary;
46
+ /** Last known actual token count from API usage data. */
47
+ lastActualTokens;
48
+ /** Message count at the time lastActualTokens was recorded. */
49
+ lastActualAtMessageCount;
50
+ /** Path to session transcript — passed to summary compaction for on-demand access. */
51
+ transcriptPath;
52
+ /** Notified whenever any compaction tier fires, including microcompact. */
53
+ onCompact;
54
+ /**
55
+ * Tool-result persistence state. Created lazily once we know where to
56
+ * write files (i.e. once setTranscriptPath has been called).
57
+ * `null` = persistence has been explicitly disabled.
58
+ */
59
+ replacementState;
60
+ toolResultsDir;
61
+ constructor(config) {
62
+ this.config = { ...DEFAULT_CONFIG, ...config };
63
+ }
64
+ setOnCompact(fn) {
65
+ this.onCompact = fn;
66
+ }
67
+ /**
68
+ * Record actual token usage from API response.
69
+ * Used for hybrid estimation: actual + estimate for new messages.
70
+ */
71
+ recordActualUsage(inputTokens, messageCount) {
72
+ this.lastActualTokens = inputTokens;
73
+ this.lastActualAtMessageCount = messageCount;
74
+ }
75
+ /**
76
+ * Best-effort token estimate: uses actual API usage as base if available,
77
+ * plus estimation for messages added since the last API call.
78
+ */
79
+ estimateTokensHybrid(messages) {
80
+ if (this.lastActualTokens !== undefined &&
81
+ this.lastActualAtMessageCount !== undefined &&
82
+ this.lastActualAtMessageCount < messages.length) {
83
+ const newMessages = messages.slice(this.lastActualAtMessageCount);
84
+ const newTokens = estimateTokens(newMessages);
85
+ return this.lastActualTokens + newTokens;
86
+ }
87
+ return estimateTokens(messages);
88
+ }
89
+ /**
90
+ * Set the summarize function (injected by Engine).
91
+ */
92
+ setSummarizeFn(fn) {
93
+ this.summarizeFn = fn;
94
+ }
95
+ /**
96
+ * Set the transcript path so compaction can reference it. The
97
+ * tool-results directory lives alongside the transcript file:
98
+ * <transcriptDir>/tool-results/<toolUseId>.txt
99
+ */
100
+ setTranscriptPath(path) {
101
+ this.transcriptPath = path;
102
+ this.toolResultsDir = resolveToolResultsDir(path);
103
+ }
104
+ /**
105
+ * Initialize tool-result-persistence state from already-loaded messages.
106
+ * Call this once per session, after setTranscriptPath, when resuming so
107
+ * the manager re-enters the same "frozen decision" state it had on the
108
+ * previous run. Without this, a resumed session would re-evaluate
109
+ * every result against the current threshold and might flip choices.
110
+ */
111
+ initReplacementStateFromMessages(messages) {
112
+ this.replacementState = reconstructContentReplacementState(messages);
113
+ }
114
+ /**
115
+ * Apply progressive context management (sync path).
116
+ * For Tier 2 (LLM summary), call manageAsync instead.
117
+ */
118
+ manage(messages) {
119
+ let result = messages;
120
+ // Tier 0a: Persist large tool_results to disk + replace with preview.
121
+ // Runs before any in-context truncation so the model gets a real
122
+ // filepath it can Read back, not a silent head/tail truncation.
123
+ result = this.persistLargeToolResults(result);
124
+ // Tier 0b: Hard truncate any oversized tool_result that survived
125
+ // persistence (e.g. persistence disabled, FS write failed, or a
126
+ // block was already frozen "don't persist" on a prior pass).
127
+ result = this.truncateToolResults(result);
128
+ // Tier 0c: Aggregate tool result budget (per-message) — char-level
129
+ // backstop for messages still over the limit after persistence.
130
+ result = applyToolResultBudget(result);
131
+ // Tier 1: microcompact — fingerprint old whitelisted tool_results.
132
+ // Only runs above the floor ratio: under-pressure context keeps full
133
+ // detail so the model isn't forced to re-Read files it just looked at.
134
+ const preTier1Tokens = this.estimateTokensHybrid(result);
135
+ if (preTier1Tokens > this.config.maxTokens * this.config.microcompactFloorRatio) {
136
+ const keepRecentN = this.config.microcompactKeepRecent ?? defaultKeepRecent(this.config.maxTokens);
137
+ // Capture rounds/tools synchronously from microcompact's onClear, but
138
+ // defer the token re-estimate until AFTER `result` has been reassigned
139
+ // to the compacted array — onClear fires before microcompact returns,
140
+ // so reading `result` inside it would see the pre-compact reference.
141
+ let clearedInfo = null;
142
+ result = microcompact(result, {
143
+ keepRecentN,
144
+ onClear: (info) => {
145
+ clearedInfo = info;
146
+ },
147
+ });
148
+ if (clearedInfo) {
149
+ const after = this.estimateTokensHybrid(result);
150
+ logger.info("context.microcompact", {
151
+ before: preTier1Tokens,
152
+ after,
153
+ keepRecentN,
154
+ clearedRounds: clearedInfo.clearedRounds,
155
+ toolNames: clearedInfo.toolNames,
156
+ });
157
+ this.onCompact?.({ strategy: "micro", before: preTier1Tokens, after });
158
+ }
159
+ }
160
+ // Hybrid token estimation walks every message; we cache it across the
161
+ // tier checks below and only recompute after a compaction shrinks `result`.
162
+ let tokens = this.estimateTokensHybrid(result);
163
+ // Tiers run in increasing severity. Each tier short-circuits its own
164
+ // arm but the next tier still runs if we're still above the next gate
165
+ // — a single pass can escalate micro → summary-replay → snip → window
166
+ // → emergency when the model just dumped a flood of tool_results.
167
+ //
168
+ // Severity gates (fractions of maxTokens):
169
+ // compactAtRatio — start non-micro compaction (try summary first,
170
+ // else snip; snip is the cheapest sync option)
171
+ // compactAtRatio + 0.05 — snip wasn't enough, do a window compact
172
+ // summarizeAtRatio — emergency window (smallest keep-tail)
173
+ const snipGate = this.config.maxTokens * this.config.compactAtRatio;
174
+ const windowGate = this.config.maxTokens * (this.config.compactAtRatio + 0.05);
175
+ const emergencyGate = this.config.maxTokens * this.config.summarizeAtRatio;
176
+ // Tier 2: prefer replaying a cached summary; otherwise snip
177
+ if (tokens > snipGate) {
178
+ const before = tokens;
179
+ if (this.lastSummary) {
180
+ const keepN = Math.max(8, Math.floor(result.length * 0.3));
181
+ result = applySummaryCompaction(result, this.lastSummary, keepN, this.transcriptPath);
182
+ this.lastSummary = undefined;
183
+ tokens = this.estimateTokensHybrid(result);
184
+ this.onCompact?.({ strategy: "summary", before, after: tokens });
185
+ }
186
+ else {
187
+ result = snipCompact(result, 3, 8);
188
+ tokens = this.estimateTokensHybrid(result);
189
+ this.onCompact?.({ strategy: "snip", before, after: tokens });
190
+ }
191
+ }
192
+ // Tier 2b: snip didn't free enough — fall back to window compact
193
+ if (tokens > windowGate) {
194
+ const before = tokens;
195
+ const keepN = Math.max(10, Math.floor(result.length * 0.4));
196
+ result = windowCompact(result, keepN);
197
+ tokens = this.estimateTokensHybrid(result);
198
+ this.onCompact?.({ strategy: "window", before, after: tokens });
199
+ }
200
+ // Tier 3: emergency window with a tiny tail — last resort before the
201
+ // request would otherwise blow the model's context.
202
+ if (tokens > emergencyGate) {
203
+ const before = tokens;
204
+ result = windowCompact(result, 6);
205
+ tokens = this.estimateTokensHybrid(result);
206
+ this.onCompact?.({ strategy: "emergency", before, after: tokens });
207
+ }
208
+ return result;
209
+ }
210
+ /**
211
+ * Async context management — attempts LLM summarization before falling back.
212
+ * Call this when you have access to the LLM (between turns).
213
+ */
214
+ async manageAsync(messages) {
215
+ let result = messages;
216
+ // Tier 0a: Persist large tool_results to disk + replace with preview.
217
+ result = this.persistLargeToolResults(result);
218
+ // Tier 0b: Hard truncate oversized tool_result blocks that weren't
219
+ // persisted (persistence disabled, FS error, or already frozen).
220
+ result = this.truncateToolResults(result);
221
+ // Tier 0c: Aggregate tool result budget (per-message)
222
+ result = applyToolResultBudget(result);
223
+ // Tier 1: microcompact — see manage() for the rationale on the floor.
224
+ const preTier1Tokens = this.estimateTokensHybrid(result);
225
+ if (preTier1Tokens > this.config.maxTokens * this.config.microcompactFloorRatio) {
226
+ const keepRecentN = this.config.microcompactKeepRecent ?? defaultKeepRecent(this.config.maxTokens);
227
+ // See manage(): onClear fires synchronously before microcompact returns,
228
+ // so defer the token re-estimate until result is reassigned.
229
+ let clearedInfo = null;
230
+ result = microcompact(result, {
231
+ keepRecentN,
232
+ onClear: (info) => {
233
+ clearedInfo = info;
234
+ },
235
+ });
236
+ if (clearedInfo) {
237
+ const after = this.estimateTokensHybrid(result);
238
+ logger.info("context.microcompact", {
239
+ before: preTier1Tokens,
240
+ after,
241
+ keepRecentN,
242
+ clearedRounds: clearedInfo.clearedRounds,
243
+ toolNames: clearedInfo.toolNames,
244
+ });
245
+ this.onCompact?.({ strategy: "micro", before: preTier1Tokens, after });
246
+ }
247
+ }
248
+ const tokens = this.estimateTokensHybrid(result);
249
+ const ratio = tokens / this.config.maxTokens;
250
+ // Tier 2: LLM summary if approaching limit
251
+ if (ratio >= this.config.compactAtRatio &&
252
+ this.summarizeFn &&
253
+ this.consecutiveSummaryFailures < 3) {
254
+ try {
255
+ const keepRecentN = Math.max(8, Math.floor(result.length * 0.3));
256
+ const messagesToSummarize = result.slice(1, -keepRecentN); // skip first (userContext) and recent
257
+ if (messagesToSummarize.length > 3) {
258
+ // Rolling summary: if a prior summary is already anchored in the
259
+ // messages (from an earlier compaction in this session or in a
260
+ // resumed session), feed it back so the LLM merges-updates rather
261
+ // than re-summarizes from scratch — preserves info that would
262
+ // otherwise erode across successive compactions.
263
+ const priorSummary = extractAnchoredSummary(result) ?? this.lastSummary;
264
+ const prompt = buildSummarizationPrompt(messagesToSummarize, priorSummary);
265
+ const summary = await this.summarizeFn(prompt);
266
+ if (summary && summary.length > 50) {
267
+ result = applySummaryCompaction(result, summary, keepRecentN, this.transcriptPath);
268
+ this.consecutiveSummaryFailures = 0;
269
+ this.lastSummary = summary;
270
+ const after = estimateTokens(result);
271
+ logger.info("context.summary_compact", {
272
+ before: tokens,
273
+ after,
274
+ summaryLen: summary.length,
275
+ rolling: priorSummary !== undefined,
276
+ });
277
+ this.onCompact?.({ strategy: "summary", before: tokens, after });
278
+ return result;
279
+ }
280
+ }
281
+ }
282
+ catch (err) {
283
+ this.consecutiveSummaryFailures++;
284
+ logger.warn("context.summary_failed", {
285
+ failures: this.consecutiveSummaryFailures,
286
+ error: err.message,
287
+ });
288
+ }
289
+ }
290
+ // Reuse the `tokens` we already computed above. We only get here if the
291
+ // LLM summary path didn't fire (no summarizeFn, too many failures, or it
292
+ // threw) — fall back to the same severity ladder as manage().
293
+ let live = tokens;
294
+ const snipGate = this.config.maxTokens * this.config.compactAtRatio;
295
+ const windowGate = this.config.maxTokens * (this.config.compactAtRatio + 0.05);
296
+ const emergencyGate = this.config.maxTokens * this.config.summarizeAtRatio;
297
+ // Tier 2 fallback: snip first (cheapest sync option)
298
+ if (live > snipGate) {
299
+ const before = live;
300
+ result = snipCompact(result, 3, 8);
301
+ live = this.estimateTokensHybrid(result);
302
+ this.onCompact?.({ strategy: "snip", before, after: live });
303
+ }
304
+ // Tier 2b: window compact when snip didn't free enough
305
+ if (live > windowGate) {
306
+ const before = live;
307
+ const keepN = Math.max(10, Math.floor(result.length * 0.4));
308
+ result = windowCompact(result, keepN);
309
+ live = this.estimateTokensHybrid(result);
310
+ this.onCompact?.({ strategy: "window", before, after: live });
311
+ }
312
+ // Tier 3: Emergency
313
+ if (live > emergencyGate) {
314
+ const before = live;
315
+ result = windowCompact(result, 6);
316
+ live = this.estimateTokensHybrid(result);
317
+ this.onCompact?.({ strategy: "emergency", before, after: live });
318
+ }
319
+ return result;
320
+ }
321
+ /**
322
+ * Persist large tool_result blocks to disk and replace them with a
323
+ * preview + filepath. No-op when transcript path hasn't been set
324
+ * (e.g. unit tests that exercise compaction directly without a session).
325
+ */
326
+ persistLargeToolResults(messages) {
327
+ if (!this.toolResultsDir)
328
+ return messages;
329
+ if (!this.replacementState) {
330
+ this.replacementState = createContentReplacementState();
331
+ }
332
+ return applyToolResultPersistence(messages, {
333
+ toolResultsDir: this.toolResultsDir,
334
+ state: this.replacementState,
335
+ onPersist: (info) => {
336
+ logger.info("context.tool_result_persisted", info);
337
+ },
338
+ });
339
+ }
340
+ /**
341
+ * Truncate oversized tool results in messages.
342
+ */
343
+ truncateToolResults(messages) {
344
+ const maxChars = this.config.maxToolResultChars;
345
+ let modified = false;
346
+ const result = messages.map((msg) => {
347
+ if (!Array.isArray(msg.content))
348
+ return msg;
349
+ const newContent = msg.content.map((block) => {
350
+ if (block.type === "tool_result" && typeof block.content === "string") {
351
+ if (block.content.length > maxChars) {
352
+ modified = true;
353
+ return { ...block, content: truncateToolResult(block.content, maxChars) };
354
+ }
355
+ }
356
+ return block;
357
+ });
358
+ return modified ? { ...msg, content: newContent } : msg;
359
+ });
360
+ return result;
361
+ }
362
+ /**
363
+ * Reactive compaction check — call during streaming to detect if
364
+ * token usage is approaching the limit mid-turn.
365
+ * Returns true if emergency compaction should be triggered.
366
+ */
367
+ shouldReactiveCompact(messages, currentResponseTokens) {
368
+ const msgTokens = this.estimateTokensHybrid(messages);
369
+ const total = msgTokens + currentResponseTokens;
370
+ // Trigger at the same gate as the emergency tier — keeps the streaming
371
+ // reactive check aligned with the post-turn ladder.
372
+ return total > this.config.maxTokens * this.config.summarizeAtRatio;
373
+ }
374
+ /**
375
+ * Check if context is approaching limits.
376
+ */
377
+ checkLimits(messages) {
378
+ const tokens = this.estimateTokensHybrid(messages);
379
+ const ratio = tokens / this.config.maxTokens;
380
+ return {
381
+ tokens,
382
+ ratio,
383
+ needsCompact: ratio >= this.config.compactAtRatio,
384
+ needsEmergency: ratio >= this.config.summarizeAtRatio,
385
+ };
386
+ }
387
+ /**
388
+ * Deduplicate tool calls by hashing arguments.
389
+ */
390
+ deduplicateToolCalls(calls) {
391
+ const toExecute = [];
392
+ const cached = [];
393
+ for (const call of calls) {
394
+ const hash = this.hashCall(call.toolName, call.args);
395
+ const existing = this.toolCallHashes.get(hash);
396
+ if (existing && existing.count >= 2) {
397
+ cached.push({ ...call, result: existing.lastResult });
398
+ existing.count++;
399
+ }
400
+ else {
401
+ toExecute.push(call);
402
+ }
403
+ }
404
+ return { toExecute, cached };
405
+ }
406
+ /**
407
+ * Record a tool call result for dedup tracking.
408
+ */
409
+ recordToolResult(toolName, args, result) {
410
+ const hash = this.hashCall(toolName, args);
411
+ const existing = this.toolCallHashes.get(hash);
412
+ if (existing) {
413
+ existing.count++;
414
+ existing.lastResult = result;
415
+ }
416
+ else {
417
+ this.toolCallHashes.set(hash, { count: 1, lastResult: result });
418
+ }
419
+ }
420
+ hashCall(toolName, args) {
421
+ return `${toolName}:${JSON.stringify(args)}`;
422
+ }
423
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Token counter — more accurate token estimation.
3
+ *
4
+ * Uses a character-based heuristic tuned per language/content type,
5
+ * with cache-aware accounting for prompt caching.
6
+ */
7
+ import type { Message } from "../types.js";
8
+ /**
9
+ * Estimate token count for a string, detecting content type.
10
+ */
11
+ export declare function estimateStringTokens(text: string): number;
12
+ /**
13
+ * Estimate token count for a message array.
14
+ */
15
+ export declare function estimateMessagesTokens(messages: Message[]): number;
16
+ /**
17
+ * Context window usage report.
18
+ */
19
+ export interface ContextUsage {
20
+ usedTokens: number;
21
+ maxTokens: number;
22
+ usagePercent: number;
23
+ systemPromptTokens: number;
24
+ messagesTokens: number;
25
+ headroom: number;
26
+ }
27
+ export declare function calculateContextUsage(messages: Message[], systemPrompt: string, maxTokens: number): ContextUsage;
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Token counter — more accurate token estimation.
3
+ *
4
+ * Uses a character-based heuristic tuned per language/content type,
5
+ * with cache-aware accounting for prompt caching.
6
+ */
7
+ /**
8
+ * Token-to-character ratios by content type.
9
+ * These are empirical averages from Claude/GPT tokenizers.
10
+ */
11
+ const RATIOS = {
12
+ english: 4.0, // ~4 chars per token for English prose
13
+ code: 3.2, // ~3.2 chars per token for code (more tokens per char)
14
+ json: 3.5, // JSON structures
15
+ mixed: 3.6, // Mixed content (typical for tool results)
16
+ cjk: 1.5, // CJK characters: ~1.5 chars per token
17
+ };
18
+ /**
19
+ * Estimate token count for a string, detecting content type.
20
+ */
21
+ export function estimateStringTokens(text) {
22
+ if (!text)
23
+ return 0;
24
+ // Detect CJK content ratio
25
+ const cjkChars = (text.match(/[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff\uac00-\ud7af]/g) ?? []).length;
26
+ const cjkRatio = cjkChars / text.length;
27
+ if (cjkRatio > 0.3) {
28
+ // Weighted average for mixed CJK/ASCII
29
+ const cjkTokens = cjkChars / RATIOS.cjk;
30
+ const otherChars = text.length - cjkChars;
31
+ const otherTokens = otherChars / RATIOS.english;
32
+ return Math.ceil(cjkTokens + otherTokens);
33
+ }
34
+ // Detect code
35
+ const codeIndicators = ["{", "}", "(", ")", ";", "=>", "import ", "function ", "class ", "const "];
36
+ const codeScore = codeIndicators.reduce((s, ind) => s + (text.includes(ind) ? 1 : 0), 0);
37
+ if (codeScore >= 3)
38
+ return Math.ceil(text.length / RATIOS.code);
39
+ if (text.startsWith("{") || text.startsWith("["))
40
+ return Math.ceil(text.length / RATIOS.json);
41
+ return Math.ceil(text.length / RATIOS.english);
42
+ }
43
+ /**
44
+ * Estimate token count for a message array.
45
+ */
46
+ export function estimateMessagesTokens(messages) {
47
+ let total = 0;
48
+ for (const msg of messages) {
49
+ // Per-message overhead (role, formatting) ≈ 4 tokens
50
+ total += 4;
51
+ if (typeof msg.content === "string") {
52
+ total += estimateStringTokens(msg.content);
53
+ }
54
+ else if (Array.isArray(msg.content)) {
55
+ for (const block of msg.content) {
56
+ total += estimateBlockTokens(block);
57
+ }
58
+ }
59
+ }
60
+ return total;
61
+ }
62
+ /**
63
+ * Estimate tokens for a content block.
64
+ */
65
+ function estimateBlockTokens(block) {
66
+ let tokens = 2; // Block overhead
67
+ if (block.text)
68
+ tokens += estimateStringTokens(block.text);
69
+ if (block.content && typeof block.content === "string") {
70
+ tokens += estimateStringTokens(block.content);
71
+ }
72
+ if (block.input) {
73
+ tokens += estimateStringTokens(JSON.stringify(block.input));
74
+ }
75
+ if (block.name)
76
+ tokens += estimateStringTokens(block.name);
77
+ return tokens;
78
+ }
79
+ export function calculateContextUsage(messages, systemPrompt, maxTokens) {
80
+ const systemPromptTokens = estimateStringTokens(systemPrompt);
81
+ const messagesTokens = estimateMessagesTokens(messages);
82
+ const usedTokens = systemPromptTokens + messagesTokens;
83
+ return {
84
+ usedTokens,
85
+ maxTokens,
86
+ usagePercent: (usedTokens / maxTokens) * 100,
87
+ systemPromptTokens,
88
+ messagesTokens,
89
+ headroom: maxTokens - usedTokens,
90
+ };
91
+ }