mindweave 0.0.1 → 2.1.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 (481) hide show
  1. package/LICENSE +190 -0
  2. package/README.md +171 -14
  3. package/dist/alternator/chassis/cache.js +47 -0
  4. package/dist/alternator/chassis/cache.js.map +1 -0
  5. package/dist/alternator/chassis/domRefs.js +53 -0
  6. package/dist/alternator/chassis/domRefs.js.map +1 -0
  7. package/dist/alternator/chassis/extractWorker.js +65 -0
  8. package/dist/alternator/chassis/extractWorker.js.map +1 -0
  9. package/dist/alternator/chassis/graph.js +221 -0
  10. package/dist/alternator/chassis/graph.js.map +1 -0
  11. package/dist/alternator/chassis/index.js +463 -0
  12. package/dist/alternator/chassis/index.js.map +1 -0
  13. package/dist/alternator/chassis/isolation.js +336 -0
  14. package/dist/alternator/chassis/isolation.js.map +1 -0
  15. package/dist/alternator/chassis/langCases.js +69 -0
  16. package/dist/alternator/chassis/langCases.js.map +1 -0
  17. package/dist/alternator/chassis/lsp.js +469 -0
  18. package/dist/alternator/chassis/lsp.js.map +1 -0
  19. package/dist/alternator/chassis/markup.js +262 -0
  20. package/dist/alternator/chassis/markup.js.map +1 -0
  21. package/dist/alternator/chassis/provision.js +198 -0
  22. package/dist/alternator/chassis/provision.js.map +1 -0
  23. package/dist/alternator/chassis/rank.js +72 -0
  24. package/dist/alternator/chassis/rank.js.map +1 -0
  25. package/dist/alternator/chassis/servers.js +215 -0
  26. package/dist/alternator/chassis/servers.js.map +1 -0
  27. package/dist/alternator/chassis/treesitter.js +608 -0
  28. package/dist/alternator/chassis/treesitter.js.map +1 -0
  29. package/dist/alternator/chassis/types.js +24 -0
  30. package/dist/alternator/chassis/types.js.map +1 -0
  31. package/dist/alternator/lane.js +67 -0
  32. package/dist/alternator/lane.js.map +1 -0
  33. package/dist/cli/App.js +2586 -0
  34. package/dist/cli/App.js.map +1 -0
  35. package/dist/cli/altScreen.js +67 -0
  36. package/dist/cli/altScreen.js.map +1 -0
  37. package/dist/cli/approvalChannel.js +72 -0
  38. package/dist/cli/approvalChannel.js.map +1 -0
  39. package/dist/cli/attachments.js +188 -0
  40. package/dist/cli/attachments.js.map +1 -0
  41. package/dist/cli/bootstrap.js +279 -0
  42. package/dist/cli/bootstrap.js.map +1 -0
  43. package/dist/cli/chatAnchor.js +94 -0
  44. package/dist/cli/chatAnchor.js.map +1 -0
  45. package/dist/cli/commandArgs.js +79 -0
  46. package/dist/cli/commandArgs.js.map +1 -0
  47. package/dist/cli/commandRoute.js +78 -0
  48. package/dist/cli/commandRoute.js.map +1 -0
  49. package/dist/cli/compaction.js +69 -0
  50. package/dist/cli/compaction.js.map +1 -0
  51. package/dist/cli/components/ApprovalBox.js +100 -0
  52. package/dist/cli/components/ApprovalBox.js.map +1 -0
  53. package/dist/cli/components/BlockView.js +128 -0
  54. package/dist/cli/components/BlockView.js.map +1 -0
  55. package/dist/cli/components/FirstRunFrame.js +41 -0
  56. package/dist/cli/components/FirstRunFrame.js.map +1 -0
  57. package/dist/cli/components/KeyManager.js +197 -0
  58. package/dist/cli/components/KeyManager.js.map +1 -0
  59. package/dist/cli/components/KeySetup.js +125 -0
  60. package/dist/cli/components/KeySetup.js.map +1 -0
  61. package/dist/cli/components/MenuFrame.js +24 -0
  62. package/dist/cli/components/MenuFrame.js.map +1 -0
  63. package/dist/cli/components/Picker.js +82 -0
  64. package/dist/cli/components/Picker.js.map +1 -0
  65. package/dist/cli/components/PromptInput.js +509 -0
  66. package/dist/cli/components/PromptInput.js.map +1 -0
  67. package/dist/cli/components/SubagentView.js +86 -0
  68. package/dist/cli/components/SubagentView.js.map +1 -0
  69. package/dist/cli/components/ToolGroup.js +60 -0
  70. package/dist/cli/components/ToolGroup.js.map +1 -0
  71. package/dist/cli/components/ToolLine.js +123 -0
  72. package/dist/cli/components/ToolLine.js.map +1 -0
  73. package/dist/cli/components/TrustGate.js +37 -0
  74. package/dist/cli/components/TrustGate.js.map +1 -0
  75. package/dist/cli/costView.js +40 -0
  76. package/dist/cli/costView.js.map +1 -0
  77. package/dist/cli/frameRate.js +30 -0
  78. package/dist/cli/frameRate.js.map +1 -0
  79. package/dist/cli/framebuffer/paint.js +165 -0
  80. package/dist/cli/framebuffer/paint.js.map +1 -0
  81. package/dist/cli/framebuffer/parse.js +266 -0
  82. package/dist/cli/framebuffer/parse.js.map +1 -0
  83. package/dist/cli/framebuffer/screen.js +196 -0
  84. package/dist/cli/framebuffer/screen.js.map +1 -0
  85. package/dist/cli/framebuffer/writer.js +139 -0
  86. package/dist/cli/framebuffer/writer.js.map +1 -0
  87. package/dist/cli/groupReveal.js +51 -0
  88. package/dist/cli/groupReveal.js.map +1 -0
  89. package/dist/cli/help.js +55 -0
  90. package/dist/cli/help.js.map +1 -0
  91. package/dist/cli/inputView.js +105 -0
  92. package/dist/cli/inputView.js.map +1 -0
  93. package/dist/cli/keyManager.js +65 -0
  94. package/dist/cli/keyManager.js.map +1 -0
  95. package/dist/cli/keySetup.js +35 -0
  96. package/dist/cli/keySetup.js.map +1 -0
  97. package/dist/cli/keyStore.js +73 -0
  98. package/dist/cli/keyStore.js.map +1 -0
  99. package/dist/cli/markdown.js +460 -0
  100. package/dist/cli/markdown.js.map +1 -0
  101. package/dist/cli/messageQueue.js +96 -0
  102. package/dist/cli/messageQueue.js.map +1 -0
  103. package/dist/cli/modes.js +90 -0
  104. package/dist/cli/modes.js.map +1 -0
  105. package/dist/cli/mouse.js +78 -0
  106. package/dist/cli/mouse.js.map +1 -0
  107. package/dist/cli/pasteAssembler.js +44 -0
  108. package/dist/cli/pasteAssembler.js.map +1 -0
  109. package/dist/cli/pathComplete.js +39 -0
  110. package/dist/cli/pathComplete.js.map +1 -0
  111. package/dist/cli/perfLog.js +90 -0
  112. package/dist/cli/perfLog.js.map +1 -0
  113. package/dist/cli/reveal.js +32 -0
  114. package/dist/cli/reveal.js.map +1 -0
  115. package/dist/cli/revealPace.js +59 -0
  116. package/dist/cli/revealPace.js.map +1 -0
  117. package/dist/cli/sessionCarry.js +19 -0
  118. package/dist/cli/sessionCarry.js.map +1 -0
  119. package/dist/cli/smoothScroll.js +74 -0
  120. package/dist/cli/smoothScroll.js.map +1 -0
  121. package/dist/cli/startupArgs.js +96 -0
  122. package/dist/cli/startupArgs.js.map +1 -0
  123. package/dist/cli/terminalRestore.js +34 -0
  124. package/dist/cli/terminalRestore.js.map +1 -0
  125. package/dist/cli/toolDisplay.js +219 -0
  126. package/dist/cli/toolDisplay.js.map +1 -0
  127. package/dist/cli/toolItems.js +65 -0
  128. package/dist/cli/toolItems.js.map +1 -0
  129. package/dist/cli/transcript.js +351 -0
  130. package/dist/cli/transcript.js.map +1 -0
  131. package/dist/cli/trust.js +79 -0
  132. package/dist/cli/trust.js.map +1 -0
  133. package/dist/cli/updateCheck.js +107 -0
  134. package/dist/cli/updateCheck.js.map +1 -0
  135. package/dist/cli/version.js +39 -0
  136. package/dist/cli/version.js.map +1 -0
  137. package/dist/cli/viewport.js +179 -0
  138. package/dist/cli/viewport.js.map +1 -0
  139. package/dist/cli/virtualWindow.js +103 -0
  140. package/dist/cli/virtualWindow.js.map +1 -0
  141. package/dist/cli/workingVerb.js +37 -0
  142. package/dist/cli/workingVerb.js.map +1 -0
  143. package/dist/cli/wrap.js +145 -0
  144. package/dist/cli/wrap.js.map +1 -0
  145. package/dist/drivers/anthropic/cachePoints.js +77 -0
  146. package/dist/drivers/anthropic/cachePoints.js.map +1 -0
  147. package/dist/drivers/anthropic/client.js +432 -0
  148. package/dist/drivers/anthropic/client.js.map +1 -0
  149. package/dist/drivers/anthropic/index.js +10 -0
  150. package/dist/drivers/anthropic/index.js.map +1 -0
  151. package/dist/drivers/anthropic/manifest.js +221 -0
  152. package/dist/drivers/anthropic/manifest.js.map +1 -0
  153. package/dist/drivers/cerebras/client.js +69 -0
  154. package/dist/drivers/cerebras/client.js.map +1 -0
  155. package/dist/drivers/cerebras/index.js +5 -0
  156. package/dist/drivers/cerebras/index.js.map +1 -0
  157. package/dist/drivers/cerebras/manifest.js +140 -0
  158. package/dist/drivers/cerebras/manifest.js.map +1 -0
  159. package/dist/drivers/clientId.js +41 -0
  160. package/dist/drivers/clientId.js.map +1 -0
  161. package/dist/drivers/contextOverflow.js +77 -0
  162. package/dist/drivers/contextOverflow.js.map +1 -0
  163. package/dist/drivers/deepseek/client.js +168 -0
  164. package/dist/drivers/deepseek/client.js.map +1 -0
  165. package/dist/drivers/deepseek/index.js +16 -0
  166. package/dist/drivers/deepseek/index.js.map +1 -0
  167. package/dist/drivers/deepseek/inlineTools.js +46 -0
  168. package/dist/drivers/deepseek/inlineTools.js.map +1 -0
  169. package/dist/drivers/deepseek/manifest.js +166 -0
  170. package/dist/drivers/deepseek/manifest.js.map +1 -0
  171. package/dist/drivers/gemini/client.js +38 -0
  172. package/dist/drivers/gemini/client.js.map +1 -0
  173. package/dist/drivers/gemini/index.js +5 -0
  174. package/dist/drivers/gemini/index.js.map +1 -0
  175. package/dist/drivers/gemini/manifest.js +150 -0
  176. package/dist/drivers/gemini/manifest.js.map +1 -0
  177. package/dist/drivers/glm/client.js +90 -0
  178. package/dist/drivers/glm/client.js.map +1 -0
  179. package/dist/drivers/glm/index.js +9 -0
  180. package/dist/drivers/glm/index.js.map +1 -0
  181. package/dist/drivers/glm/manifest.js +183 -0
  182. package/dist/drivers/glm/manifest.js.map +1 -0
  183. package/dist/drivers/groq/client.js +80 -0
  184. package/dist/drivers/groq/client.js.map +1 -0
  185. package/dist/drivers/groq/index.js +5 -0
  186. package/dist/drivers/groq/index.js.map +1 -0
  187. package/dist/drivers/groq/manifest.js +160 -0
  188. package/dist/drivers/groq/manifest.js.map +1 -0
  189. package/dist/drivers/kimi/client.js +82 -0
  190. package/dist/drivers/kimi/client.js.map +1 -0
  191. package/dist/drivers/kimi/index.js +9 -0
  192. package/dist/drivers/kimi/index.js.map +1 -0
  193. package/dist/drivers/kimi/manifest.js +168 -0
  194. package/dist/drivers/kimi/manifest.js.map +1 -0
  195. package/dist/drivers/meta/client.js +30 -0
  196. package/dist/drivers/meta/client.js.map +1 -0
  197. package/dist/drivers/meta/index.js +5 -0
  198. package/dist/drivers/meta/index.js.map +1 -0
  199. package/dist/drivers/meta/manifest.js +101 -0
  200. package/dist/drivers/meta/manifest.js.map +1 -0
  201. package/dist/drivers/minimax/client.js +36 -0
  202. package/dist/drivers/minimax/client.js.map +1 -0
  203. package/dist/drivers/minimax/index.js +5 -0
  204. package/dist/drivers/minimax/index.js.map +1 -0
  205. package/dist/drivers/minimax/manifest.js +120 -0
  206. package/dist/drivers/minimax/manifest.js.map +1 -0
  207. package/dist/drivers/mistral/client.js +54 -0
  208. package/dist/drivers/mistral/client.js.map +1 -0
  209. package/dist/drivers/mistral/index.js +5 -0
  210. package/dist/drivers/mistral/index.js.map +1 -0
  211. package/dist/drivers/mistral/manifest.js +118 -0
  212. package/dist/drivers/mistral/manifest.js.map +1 -0
  213. package/dist/drivers/openai/client.js +290 -0
  214. package/dist/drivers/openai/client.js.map +1 -0
  215. package/dist/drivers/openai/index.js +9 -0
  216. package/dist/drivers/openai/index.js.map +1 -0
  217. package/dist/drivers/openai/manifest.js +133 -0
  218. package/dist/drivers/openai/manifest.js.map +1 -0
  219. package/dist/drivers/openaiCompat/wire.js +493 -0
  220. package/dist/drivers/openaiCompat/wire.js.map +1 -0
  221. package/dist/drivers/partialTurn.js +23 -0
  222. package/dist/drivers/partialTurn.js.map +1 -0
  223. package/dist/drivers/providerError.js +181 -0
  224. package/dist/drivers/providerError.js.map +1 -0
  225. package/dist/drivers/qwen/client.js +93 -0
  226. package/dist/drivers/qwen/client.js.map +1 -0
  227. package/dist/drivers/qwen/index.js +9 -0
  228. package/dist/drivers/qwen/index.js.map +1 -0
  229. package/dist/drivers/qwen/manifest.js +146 -0
  230. package/dist/drivers/qwen/manifest.js.map +1 -0
  231. package/dist/drivers/registry.js +177 -0
  232. package/dist/drivers/registry.js.map +1 -0
  233. package/dist/drivers/retryPolicy.js +129 -0
  234. package/dist/drivers/retryPolicy.js.map +1 -0
  235. package/dist/drivers/searchBlocks.js +61 -0
  236. package/dist/drivers/searchBlocks.js.map +1 -0
  237. package/dist/drivers/types.js +2 -0
  238. package/dist/drivers/types.js.map +1 -0
  239. package/dist/drivers/xai/client.js +63 -0
  240. package/dist/drivers/xai/client.js.map +1 -0
  241. package/dist/drivers/xai/index.js +5 -0
  242. package/dist/drivers/xai/index.js.map +1 -0
  243. package/dist/drivers/xai/manifest.js +137 -0
  244. package/dist/drivers/xai/manifest.js.map +1 -0
  245. package/dist/dynamo/_probe.tmp.js +20 -0
  246. package/dist/dynamo/_probe.tmp.js.map +1 -0
  247. package/dist/dynamo/cacheBreak.js +88 -0
  248. package/dist/dynamo/cacheBreak.js.map +1 -0
  249. package/dist/dynamo/contextWindow.js +243 -0
  250. package/dist/dynamo/contextWindow.js.map +1 -0
  251. package/dist/dynamo/engine.js +2011 -0
  252. package/dist/dynamo/engine.js.map +1 -0
  253. package/dist/dynamo/guard.js +132 -0
  254. package/dist/dynamo/guard.js.map +1 -0
  255. package/dist/dynamo/liveMeter.js +58 -0
  256. package/dist/dynamo/liveMeter.js.map +1 -0
  257. package/dist/dynamo/model.js +172 -0
  258. package/dist/dynamo/model.js.map +1 -0
  259. package/dist/dynamo/planArtifact.js +125 -0
  260. package/dist/dynamo/planArtifact.js.map +1 -0
  261. package/dist/dynamo/pricing.js +140 -0
  262. package/dist/dynamo/pricing.js.map +1 -0
  263. package/dist/dynamo/prompt.js +264 -0
  264. package/dist/dynamo/prompt.js.map +1 -0
  265. package/dist/dynamo/spend.js +45 -0
  266. package/dist/dynamo/spend.js.map +1 -0
  267. package/dist/dynamo/verify.js +483 -0
  268. package/dist/dynamo/verify.js.map +1 -0
  269. package/dist/governor/forbidden.js +181 -0
  270. package/dist/governor/forbidden.js.map +1 -0
  271. package/dist/governor/freshness.js +83 -0
  272. package/dist/governor/freshness.js.map +1 -0
  273. package/dist/governor/frontmatter.js +38 -0
  274. package/dist/governor/frontmatter.js.map +1 -0
  275. package/dist/governor/glob.js +75 -0
  276. package/dist/governor/glob.js.map +1 -0
  277. package/dist/governor/index.js +87 -0
  278. package/dist/governor/index.js.map +1 -0
  279. package/dist/governor/rules.js +80 -0
  280. package/dist/governor/rules.js.map +1 -0
  281. package/dist/governor/scope.js +91 -0
  282. package/dist/governor/scope.js.map +1 -0
  283. package/dist/governor/skills.js +176 -0
  284. package/dist/governor/skills.js.map +1 -0
  285. package/dist/governor/types.js +16 -0
  286. package/dist/governor/types.js.map +1 -0
  287. package/dist/governor/write.js +182 -0
  288. package/dist/governor/write.js.map +1 -0
  289. package/dist/index.js +89 -0
  290. package/dist/index.js.map +1 -0
  291. package/dist/mcp/catalog.js +232 -0
  292. package/dist/mcp/catalog.js.map +1 -0
  293. package/dist/mcp/config.js +116 -0
  294. package/dist/mcp/config.js.map +1 -0
  295. package/dist/mcp/configWrite.js +254 -0
  296. package/dist/mcp/configWrite.js.map +1 -0
  297. package/dist/mcp/connection.js +504 -0
  298. package/dist/mcp/connection.js.map +1 -0
  299. package/dist/mcp/deferred.js +104 -0
  300. package/dist/mcp/deferred.js.map +1 -0
  301. package/dist/mcp/discover.js +128 -0
  302. package/dist/mcp/discover.js.map +1 -0
  303. package/dist/mcp/manager.js +679 -0
  304. package/dist/mcp/manager.js.map +1 -0
  305. package/dist/mcp/paramHeaders.js +163 -0
  306. package/dist/mcp/paramHeaders.js.map +1 -0
  307. package/dist/mcp/prompts.js +136 -0
  308. package/dist/mcp/prompts.js.map +1 -0
  309. package/dist/mcp/protocol.js +171 -0
  310. package/dist/mcp/protocol.js.map +1 -0
  311. package/dist/mcp/resources.js +119 -0
  312. package/dist/mcp/resources.js.map +1 -0
  313. package/dist/mcp/resultStore.js +180 -0
  314. package/dist/mcp/resultStore.js.map +1 -0
  315. package/dist/mcp/subscriptions.js +74 -0
  316. package/dist/mcp/subscriptions.js.map +1 -0
  317. package/dist/mcp/transport/headerValue.js +40 -0
  318. package/dist/mcp/transport/headerValue.js.map +1 -0
  319. package/dist/mcp/transport/http.js +321 -0
  320. package/dist/mcp/transport/http.js.map +1 -0
  321. package/dist/mcp/transport/stdio.js +234 -0
  322. package/dist/mcp/transport/stdio.js.map +1 -0
  323. package/dist/mcp/transport/types.js +27 -0
  324. package/dist/mcp/transport/types.js.map +1 -0
  325. package/dist/mcp/trust.js +98 -0
  326. package/dist/mcp/trust.js.map +1 -0
  327. package/dist/mcp/trustStore.js +55 -0
  328. package/dist/mcp/trustStore.js.map +1 -0
  329. package/dist/memory/autoMemory.js +340 -0
  330. package/dist/memory/autoMemory.js.map +1 -0
  331. package/dist/memory/compaction.js +513 -0
  332. package/dist/memory/compaction.js.map +1 -0
  333. package/dist/memory/images.js +173 -0
  334. package/dist/memory/images.js.map +1 -0
  335. package/dist/memory/presence.js +59 -0
  336. package/dist/memory/presence.js.map +1 -0
  337. package/dist/memory/projectNotes.js +247 -0
  338. package/dist/memory/projectNotes.js.map +1 -0
  339. package/dist/memory/restore.js +72 -0
  340. package/dist/memory/restore.js.map +1 -0
  341. package/dist/memory/session.js +472 -0
  342. package/dist/memory/session.js.map +1 -0
  343. package/dist/memory/sessionMemory.js +142 -0
  344. package/dist/memory/sessionMemory.js.map +1 -0
  345. package/dist/memory/sessionMemoryCompact.js +136 -0
  346. package/dist/memory/sessionMemoryCompact.js.map +1 -0
  347. package/dist/memory/store.js +217 -0
  348. package/dist/memory/store.js.map +1 -0
  349. package/dist/memory/types.js +14 -0
  350. package/dist/memory/types.js.map +1 -0
  351. package/dist/memory/workingSet.js +383 -0
  352. package/dist/memory/workingSet.js.map +1 -0
  353. package/dist/project/context.js +425 -0
  354. package/dist/project/context.js.map +1 -0
  355. package/dist/tools/approval.js +189 -0
  356. package/dist/tools/approval.js.map +1 -0
  357. package/dist/tools/askUser.js +103 -0
  358. package/dist/tools/askUser.js.map +1 -0
  359. package/dist/tools/atomicWrite.js +151 -0
  360. package/dist/tools/atomicWrite.js.map +1 -0
  361. package/dist/tools/backgroundShells.js +468 -0
  362. package/dist/tools/backgroundShells.js.map +1 -0
  363. package/dist/tools/captureSweep.js +77 -0
  364. package/dist/tools/captureSweep.js.map +1 -0
  365. package/dist/tools/chassisMux.js +92 -0
  366. package/dist/tools/chassisMux.js.map +1 -0
  367. package/dist/tools/checkpoints.js +328 -0
  368. package/dist/tools/checkpoints.js.map +1 -0
  369. package/dist/tools/codeIntel.js +267 -0
  370. package/dist/tools/codeIntel.js.map +1 -0
  371. package/dist/tools/deferredNative.js +121 -0
  372. package/dist/tools/deferredNative.js.map +1 -0
  373. package/dist/tools/detail.js +135 -0
  374. package/dist/tools/detail.js.map +1 -0
  375. package/dist/tools/diagnostics.js +174 -0
  376. package/dist/tools/diagnostics.js.map +1 -0
  377. package/dist/tools/edit.js +167 -0
  378. package/dist/tools/edit.js.map +1 -0
  379. package/dist/tools/editCore.js +283 -0
  380. package/dist/tools/editCore.js.map +1 -0
  381. package/dist/tools/editFile.js +183 -0
  382. package/dist/tools/editFile.js.map +1 -0
  383. package/dist/tools/editRipple.js +126 -0
  384. package/dist/tools/editRipple.js.map +1 -0
  385. package/dist/tools/editTarget.js +131 -0
  386. package/dist/tools/editTarget.js.map +1 -0
  387. package/dist/tools/editWindow.js +49 -0
  388. package/dist/tools/editWindow.js.map +1 -0
  389. package/dist/tools/eol.js +56 -0
  390. package/dist/tools/eol.js.map +1 -0
  391. package/dist/tools/exitPlan.js +175 -0
  392. package/dist/tools/exitPlan.js.map +1 -0
  393. package/dist/tools/focus.js +42 -0
  394. package/dist/tools/focus.js.map +1 -0
  395. package/dist/tools/gitignore.js +148 -0
  396. package/dist/tools/gitignore.js.map +1 -0
  397. package/dist/tools/glob.js +134 -0
  398. package/dist/tools/glob.js.map +1 -0
  399. package/dist/tools/governorTools.js +258 -0
  400. package/dist/tools/governorTools.js.map +1 -0
  401. package/dist/tools/grep.js +450 -0
  402. package/dist/tools/grep.js.map +1 -0
  403. package/dist/tools/guard.js +220 -0
  404. package/dist/tools/guard.js.map +1 -0
  405. package/dist/tools/killTree.js +215 -0
  406. package/dist/tools/killTree.js.map +1 -0
  407. package/dist/tools/listDir.js +143 -0
  408. package/dist/tools/listDir.js.map +1 -0
  409. package/dist/tools/mcpAdd.js +176 -0
  410. package/dist/tools/mcpAdd.js.map +1 -0
  411. package/dist/tools/mcpResources.js +116 -0
  412. package/dist/tools/mcpResources.js.map +1 -0
  413. package/dist/tools/mcpSearch.js +123 -0
  414. package/dist/tools/mcpSearch.js.map +1 -0
  415. package/dist/tools/multiEdit.js +168 -0
  416. package/dist/tools/multiEdit.js.map +1 -0
  417. package/dist/tools/paths.js +225 -0
  418. package/dist/tools/paths.js.map +1 -0
  419. package/dist/tools/posixShell.js +123 -0
  420. package/dist/tools/posixShell.js.map +1 -0
  421. package/dist/tools/readFile.js +371 -0
  422. package/dist/tools/readFile.js.map +1 -0
  423. package/dist/tools/readSymbol.js +145 -0
  424. package/dist/tools/readSymbol.js.map +1 -0
  425. package/dist/tools/registry.js +120 -0
  426. package/dist/tools/registry.js.map +1 -0
  427. package/dist/tools/replaceSymbol.js +141 -0
  428. package/dist/tools/replaceSymbol.js.map +1 -0
  429. package/dist/tools/results.js +15 -0
  430. package/dist/tools/results.js.map +1 -0
  431. package/dist/tools/ripgrep.js +145 -0
  432. package/dist/tools/ripgrep.js.map +1 -0
  433. package/dist/tools/runCommand.js +633 -0
  434. package/dist/tools/runCommand.js.map +1 -0
  435. package/dist/tools/saveMemory.js +102 -0
  436. package/dist/tools/saveMemory.js.map +1 -0
  437. package/dist/tools/screenshot.js +200 -0
  438. package/dist/tools/screenshot.js.map +1 -0
  439. package/dist/tools/screenshotWin.js +227 -0
  440. package/dist/tools/screenshotWin.js.map +1 -0
  441. package/dist/tools/search.js +121 -0
  442. package/dist/tools/search.js.map +1 -0
  443. package/dist/tools/sessionTools.js +187 -0
  444. package/dist/tools/sessionTools.js.map +1 -0
  445. package/dist/tools/shellCheckpoint.js +123 -0
  446. package/dist/tools/shellCheckpoint.js.map +1 -0
  447. package/dist/tools/shellLint.js +102 -0
  448. package/dist/tools/shellLint.js.map +1 -0
  449. package/dist/tools/shellTools.js +203 -0
  450. package/dist/tools/shellTools.js.map +1 -0
  451. package/dist/tools/spanCore.js +78 -0
  452. package/dist/tools/spanCore.js.map +1 -0
  453. package/dist/tools/subagent.js +224 -0
  454. package/dist/tools/subagent.js.map +1 -0
  455. package/dist/tools/subagentReport.js +114 -0
  456. package/dist/tools/subagentReport.js.map +1 -0
  457. package/dist/tools/tempSweep.js +118 -0
  458. package/dist/tools/tempSweep.js.map +1 -0
  459. package/dist/tools/todo.js +117 -0
  460. package/dist/tools/todo.js.map +1 -0
  461. package/dist/tools/types.js +2 -0
  462. package/dist/tools/types.js.map +1 -0
  463. package/dist/tools/untrusted.js +46 -0
  464. package/dist/tools/untrusted.js.map +1 -0
  465. package/dist/tools/useSkill.js +62 -0
  466. package/dist/tools/useSkill.js.map +1 -0
  467. package/dist/tools/walk.js +152 -0
  468. package/dist/tools/walk.js.map +1 -0
  469. package/dist/tools/web.js +61 -0
  470. package/dist/tools/web.js.map +1 -0
  471. package/dist/tools/webFetch.js +444 -0
  472. package/dist/tools/webFetch.js.map +1 -0
  473. package/dist/tools/webSearch.js +130 -0
  474. package/dist/tools/webSearch.js.map +1 -0
  475. package/dist/tools/workspace.js +212 -0
  476. package/dist/tools/workspace.js.map +1 -0
  477. package/dist/tools/workspaceDiscover.js +216 -0
  478. package/dist/tools/workspaceDiscover.js.map +1 -0
  479. package/dist/tools/writeFile.js +162 -0
  480. package/dist/tools/writeFile.js.map +1 -0
  481. package/package.json +74 -28
@@ -0,0 +1,179 @@
1
+ /**
2
+ * viewport.ts — which transcript blocks are actually on screen.
3
+ *
4
+ * In the alternate screen there is no terminal scrollback to lean on: the app
5
+ * owns every row, so it must decide for itself what fits between the pinned
6
+ * header and the pinned footer.
7
+ *
8
+ * The obvious approach — hand every block to a fixed-height, `overflow: hidden`
9
+ * flex box and let the layout engine clip — DOES NOT WORK, and it fails in the
10
+ * worst possible direction. Measured against Ink 5.2.1 / Yoga 3.2.1:
11
+ *
12
+ * - Children default to `flexShrink: 1`, so an overfull column does not clip at
13
+ * all, it COMPRESSES: 30 one-line blocks in a 17-row box rendered as
14
+ * `block-00, block-02, block-04…` — a strided sample with rows silently
15
+ * dropped out of the middle.
16
+ * - With `flexShrink: 0` the blocks stay whole, but every layout tried
17
+ * (`column-reverse`, `column` + `justifyContent: flex-end`, plain `column`)
18
+ * clips the END of the layout — which is the NEWEST message. The reply you
19
+ * just received is the first thing to disappear off the bottom.
20
+ *
21
+ * So the slice is computed here instead, walking BACKWARD from the newest block
22
+ * and taking blocks until the next one would not fit. The heights are estimated
23
+ * rather than measured — Ink can only measure by rendering, and rendering to
24
+ * decide what to render is a loop — so the estimate deliberately errs HIGH:
25
+ * over-estimating leaves a blank row at the top (harmless), under-estimating
26
+ * would push the pinned footer off the bottom (the bug this file exists to
27
+ * prevent).
28
+ */
29
+ import { renderMarkdown } from "./markdown.js";
30
+ import { collapseAdjacent } from "./toolItems.js";
31
+ import { GROUP_MAX_ROWS } from "./components/ToolGroup.js";
32
+ /**
33
+ * The newest blocks that fit in `maxRows`, oldest-first (render order).
34
+ *
35
+ * `scrollBack` skips that many blocks from the newest end, which is how paging
36
+ * up works: the window slides toward older history without the block list or
37
+ * the estimator needing to know anything about scrolling.
38
+ */
39
+ export function visibleBlocks(all, columns, maxRows, scrollBack = 0) {
40
+ if (maxRows <= 0 || all.length === 0)
41
+ return { blocks: [], hiddenAbove: 0 };
42
+ // Anything scrolled past is simply not a candidate — the window's newest end.
43
+ const end = Math.max(0, all.length - clampScroll(all.length, scrollBack));
44
+ const taken = [];
45
+ let used = 0;
46
+ for (let i = end - 1; i >= 0; i--) {
47
+ const block = all[i];
48
+ const height = blockHeight(block, columns, isTight(all, i));
49
+ // Always take at least one block: a single block taller than the whole
50
+ // viewport must still render (clipped) rather than leaving a blank screen.
51
+ if (taken.length > 0 && used + height > maxRows)
52
+ break;
53
+ taken.push(block);
54
+ used += height;
55
+ }
56
+ taken.reverse();
57
+ return { blocks: taken, hiddenAbove: end - taken.length };
58
+ }
59
+ /**
60
+ * Whether block `i` hugs the one above it (no blank line between).
61
+ *
62
+ * Exported because the height estimate and the actual render MUST agree: if the
63
+ * renderer hugs a row the estimate padded, the arithmetic drifts by a line per
64
+ * tool call and the footer walks off the bottom. One definition, used by both.
65
+ */
66
+ export function isTight(all, i) {
67
+ const block = all[i];
68
+ const prev = i > 0 ? all[i - 1] : undefined;
69
+ return !!block && block.kind === "tool" && !!prev && prev.kind === "tool";
70
+ }
71
+ /** Clamp a scroll offset so paging can never run past either end of history. */
72
+ export function clampScroll(total, scrollBack) {
73
+ if (!Number.isFinite(scrollBack) || scrollBack <= 0)
74
+ return 0;
75
+ // One block must always remain visible, so the newest end can always be found.
76
+ return Math.min(Math.floor(scrollBack), Math.max(0, total - 1));
77
+ }
78
+ /**
79
+ * Rows one block occupies, matching BlockView's structure (margins included).
80
+ *
81
+ * Kept deliberately close to BlockView: when a block type's rendering changes,
82
+ * this is the other half of that change. A drifted estimate degrades (a blank
83
+ * row, or a partially clipped top block) rather than breaking, which is why the
84
+ * coupling is acceptable — but it IS coupling, so the cases are in the same
85
+ * order as the switch in BlockView.tsx.
86
+ */
87
+ export function blockHeight(block, columns, tight = false) {
88
+ const textWidth = Math.max(8, columns - 4);
89
+ const top = tight ? 0 : 1;
90
+ switch (block.kind) {
91
+ case "user":
92
+ return 1 + wrappedLines(block.text, textWidth);
93
+ case "assistant":
94
+ if (!block.text)
95
+ return 0; // BlockView renders null
96
+ return 1 + countLines(renderMarkdown(block.text, textWidth));
97
+ case "tool": {
98
+ const branch = block.status !== "running" ? branchLineCount(block) : 0;
99
+ return top + 1 + branch;
100
+ }
101
+ case "tools": {
102
+ // Header, plus (once done) the calls listed under it, capped — see ToolGroup.
103
+ if (!block.done)
104
+ return top + 1;
105
+ const listed = collapseAdjacent(block.items).length;
106
+ const shown = Math.min(listed, GROUP_MAX_ROWS);
107
+ return top + 1 + shown + (listed > shown ? 1 : 0);
108
+ }
109
+ case "subagent": {
110
+ const items = collapseAdjacent(block.items).length;
111
+ const summary = block.done && block.summary ? 1 : 0;
112
+ return top + 1 + items + summary;
113
+ }
114
+ case "error":
115
+ return 1 + wrappedLines(block.text, textWidth);
116
+ case "completion":
117
+ return 1 + 1; // marginTop + a single truncated line
118
+ case "note":
119
+ return wrappedLines(`· ${block.text}`, Math.max(8, columns));
120
+ case "context":
121
+ return 1 + 1 + 1; // marginTop + one truncated line + marginBottom
122
+ }
123
+ }
124
+ /** The `⎿` branch rows under a resolved tool row (detail wins over summary). */
125
+ function branchLineCount(block) {
126
+ if (block.detail)
127
+ return countLines(block.detail);
128
+ return block.summary ? 1 : 0;
129
+ }
130
+ function countLines(s) {
131
+ return s === "" ? 0 : s.split("\n").length;
132
+ }
133
+ /**
134
+ * Rows a string takes when word-wrapped to `width` (pure).
135
+ *
136
+ * Greedy word wrapping, matching how Ink wraps `<Text wrap="wrap">`, because the
137
+ * cheap `ceil(length / width)` under-counts exactly when it matters: a line of
138
+ * long words breaks earlier than its character count suggests, and under-counting
139
+ * is the direction that pushes the footer off screen.
140
+ */
141
+ export function wrappedLines(text, width) {
142
+ if (width <= 0)
143
+ return 1;
144
+ let rows = 0;
145
+ for (const line of text.split("\n")) {
146
+ if (line === "") {
147
+ rows += 1;
148
+ continue;
149
+ }
150
+ let col = 0;
151
+ for (const word of line.split(/\s+/).filter(Boolean)) {
152
+ // A word longer than the line wraps across as many rows as it needs.
153
+ // `rows` counts only COMPLETED rows and `col` carries the row still being
154
+ // filled, so this takes the floor and lets the trailing check below close
155
+ // the partial row — taking the ceiling here counts that last row twice.
156
+ if (word.length > width) {
157
+ if (col > 0) {
158
+ rows += 1;
159
+ col = 0;
160
+ }
161
+ rows += Math.floor(word.length / width);
162
+ col = word.length % width;
163
+ continue;
164
+ }
165
+ const needed = col === 0 ? word.length : col + 1 + word.length;
166
+ if (needed > width) {
167
+ rows += 1;
168
+ col = word.length;
169
+ }
170
+ else {
171
+ col = needed;
172
+ }
173
+ }
174
+ if (col > 0 || rows === 0)
175
+ rows += 1;
176
+ }
177
+ return Math.max(1, rows);
178
+ }
179
+ //# sourceMappingURL=viewport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viewport.js","sourceRoot":"","sources":["../../src/cli/viewport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * virtualWindow.ts — which transcript blocks are worth handing to the renderer.
3
+ *
4
+ * THE PROBLEM THIS SOLVES, measured before it existed: the transcript rendered in
5
+ * FULL inside a clipped viewport, so a 150-block conversation laid out ~2,100 rows
6
+ * on every frame in order to show about 30 of them. Cost tracks total rendered rows
7
+ * and goes superlinear — bare Ink, no Mindweave code involved:
8
+ *
9
+ * 700 rows -> 8.1 ms/frame
10
+ * 1000 rows -> 52.8 ms/frame
11
+ * 2100 rows -> 109.1 ms/frame
12
+ *
13
+ * Against Ink's 32ms frame throttle, that is the typing lag and the scroll stutter.
14
+ * Memoizing the block components removed the markdown work but not this: Yoga still
15
+ * lays out every node it is given, whether or not React re-rendered it.
16
+ *
17
+ * Gemini CLI hit the same wall and answered it the same way — for its alternate-buffer
18
+ * path it renders through a VirtualizedList that keeps a cumulative offsets array and
19
+ * draws only the slice covering the viewport. This is that idea, in the shape this
20
+ * codebase already has.
21
+ *
22
+ * WHY THIS IS SAFE, given that an earlier attempt at virtualization is exactly why the
23
+ * scroll mechanism was frozen. That attempt ESTIMATED each block's height and rendered
24
+ * only what it thought would fit, so any drift between the estimate and the real render
25
+ * made content shift around, and it scrolled a whole block per step so a long block
26
+ * jumped the view past its own contents.
27
+ *
28
+ * This one does neither:
29
+ *
30
+ * - It estimates NOTHING. It is given exact, already-measured row heights, and the
31
+ * caller renders nothing it has not measured (see App.tsx: a block is measured on
32
+ * the frame it first appears, which it always does at the bottom of the transcript
33
+ * before it can scroll anywhere).
34
+ * - It does not scroll. `scrollUp`, `chatLayout` and the negative-margin slide are
35
+ * untouched. The blocks outside the window are replaced by SPACERS of their exact
36
+ * summed height, so `contentHeight` is identical to what it was when every block
37
+ * was rendered in full, and therefore so is `marginTop`. The scroll mechanism
38
+ * cannot tell the difference; only Yoga's workload changes.
39
+ */
40
+ /**
41
+ * How many blocks beyond each edge of the viewport to keep mounted.
42
+ *
43
+ * Not a performance knob — a correctness margin. A block is measured on the frame it
44
+ * is rendered, so keeping a couple in hand on each side means the ones about to come
45
+ * into view are already mounted and measured rather than appearing on the frame they
46
+ * are first needed. Two is enough because the caller never virtualizes a block it has
47
+ * not already measured.
48
+ */
49
+ export const OVERSCAN_BLOCKS = 2;
50
+ /**
51
+ * The blocks covering rows `[shift, shift + rows)` of the transcript, plus overscan.
52
+ *
53
+ * @param heights exact rendered height of every block, in rows, in transcript order
54
+ * @param shift first visible content row (from `chatLayout`: `maxScroll - scrolled`)
55
+ * @param rows viewport height in rows
56
+ */
57
+ export function virtualWindow(heights, shift, rows) {
58
+ if (heights.length === 0)
59
+ return { start: 0, end: 0, padTop: 0, padBottom: 0 };
60
+ // A viewport of no rows still has to name a block, or the caller renders an empty
61
+ // transcript and the screen goes blank with nothing to explain it. Same reasoning as
62
+ // chatLayout's own clamp, and the same failure it is avoiding.
63
+ const height = Math.max(1, rows);
64
+ const top = Math.max(0, shift);
65
+ const bottom = top + height;
66
+ // Walk once, accumulating offsets. A binary search over a prefix-sum array would be
67
+ // asymptotically better and is what a list of thousands would need; this list is
68
+ // capped at SCROLLBACK_BLOCKS (150), where one pass over a number array is far
69
+ // cheaper than the allocation the prefix-sum table would cost every frame.
70
+ let first = -1;
71
+ let last = -1;
72
+ let offset = 0;
73
+ for (let i = 0; i < heights.length; i++) {
74
+ const start = offset;
75
+ const end = offset + (heights[i] ?? 0);
76
+ // Overlap, not containment: a block taller than the whole viewport contains no
77
+ // visible edge and would be skipped by a containment test — leaving a hole exactly
78
+ // where the biggest thing on screen should be.
79
+ if (end > top && start < bottom) {
80
+ if (first === -1)
81
+ first = i;
82
+ last = i;
83
+ }
84
+ offset = end;
85
+ }
86
+ // Nothing overlaps: the offset is past the end of the content (a stale measurement
87
+ // during a resize can do this for a frame). Anchor to the last block rather than
88
+ // rendering nothing, so the newest output stays on screen while it settles.
89
+ if (first === -1) {
90
+ first = heights.length - 1;
91
+ last = heights.length - 1;
92
+ }
93
+ const start = Math.max(0, first - OVERSCAN_BLOCKS);
94
+ const end = Math.min(heights.length, last + 1 + OVERSCAN_BLOCKS);
95
+ let padTop = 0;
96
+ for (let i = 0; i < start; i++)
97
+ padTop += heights[i] ?? 0;
98
+ let padBottom = 0;
99
+ for (let i = end; i < heights.length; i++)
100
+ padBottom += heights[i] ?? 0;
101
+ return { start, end, padTop, padBottom };
102
+ }
103
+ //# sourceMappingURL=virtualWindow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"virtualWindow.js","sourceRoot":"","sources":["../../src/cli/virtualWindow.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAcH;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC;AAEjC;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAAC,OAA0B,EAAE,KAAa,EAAE,IAAY;IACnF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC;IAE/E,kFAAkF;IAClF,qFAAqF;IACrF,+DAA+D;IAC/D,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IACjC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC;IAE5B,oFAAoF;IACpF,iFAAiF;IACjF,+EAA+E;IAC/E,2EAA2E;IAC3E,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC;IACf,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC;IACd,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,KAAK,GAAG,MAAM,CAAC;QACrB,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACvC,+EAA+E;QAC/E,mFAAmF;QACnF,+CAA+C;QAC/C,IAAI,GAAG,GAAG,GAAG,IAAI,KAAK,GAAG,MAAM,EAAE,CAAC;YAChC,IAAI,KAAK,KAAK,CAAC,CAAC;gBAAE,KAAK,GAAG,CAAC,CAAC;YAC5B,IAAI,GAAG,CAAC,CAAC;QACX,CAAC;QACD,MAAM,GAAG,GAAG,CAAC;IACf,CAAC;IAED,mFAAmF;IACnF,iFAAiF;IACjF,4EAA4E;IAC5E,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;QACjB,KAAK,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;QAC3B,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC;IAC5B,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,GAAG,eAAe,CAAC,CAAC;IACnD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,GAAG,CAAC,GAAG,eAAe,CAAC,CAAC;IAEjE,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE;QAAE,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAC1D,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,KAAK,IAAI,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,SAAS,IAAI,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAExE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * workingVerb.ts — the word the status line shows while a turn runs.
3
+ *
4
+ * `Working…` on every turn of every session is a label, not a signal: it says the
5
+ * thing the spinner already says. A word that differs per turn tells you at a glance
6
+ * that this is a NEW turn and not the last one still going — which is the one thing
7
+ * the line is there to answer.
8
+ *
9
+ * Held for the whole turn, derived from the turn's start time rather than stored, so
10
+ * the once-a-second re-render cannot make it flicker between words. Pure, so the
11
+ * choice is testable without a clock.
12
+ */
13
+ /** Present participles only, and none that claim progress the harness cannot see
14
+ * ("Almost done", "Finishing") — those would be a guess dressed as a status. */
15
+ const VERBS = [
16
+ "Scampering",
17
+ "Tinkering",
18
+ "Rummaging",
19
+ "Untangling",
20
+ "Puzzling",
21
+ "Burrowing",
22
+ "Whirring",
23
+ "Pondering",
24
+ "Noodling",
25
+ "Sifting",
26
+ "Weaving",
27
+ "Chewing",
28
+ ];
29
+ /** The verb for the turn that began at `startedAt`. Stable for that whole turn. */
30
+ export function workingVerb(startedAt) {
31
+ // Milliseconds, not seconds: two turns started in the same second still differ.
32
+ const i = Math.abs(Math.floor(startedAt)) % VERBS.length;
33
+ return VERBS[i];
34
+ }
35
+ /** Exposed for the test — the pool must stay free of progress claims. */
36
+ export const WORKING_VERBS = VERBS;
37
+ //# sourceMappingURL=workingVerb.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workingVerb.js","sourceRoot":"","sources":["../../src/cli/workingVerb.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;iFACiF;AACjF,MAAM,KAAK,GAAG;IACZ,YAAY;IACZ,WAAW;IACX,WAAW;IACX,YAAY;IACZ,UAAU;IACV,WAAW;IACX,UAAU;IACV,WAAW;IACX,UAAU;IACV,SAAS;IACT,SAAS;IACT,SAAS;CACV,CAAC;AAEF,mFAAmF;AACnF,MAAM,UAAU,WAAW,CAAC,SAAiB;IAC3C,gFAAgF;IAChF,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;IACzD,OAAO,KAAK,CAAC,CAAC,CAAE,CAAC;AACnB,CAAC;AAED,yEAAyE;AACzE,MAAM,CAAC,MAAM,aAAa,GAAsB,KAAK,CAAC"}
@@ -0,0 +1,145 @@
1
+ /**
2
+ * wrap.ts — word-wrap ANSI-styled text ourselves, because Ink's own `wrap="wrap"`
3
+ * has a real bug: some continuation lines come out indented by one stray space,
4
+ * others don't. Confirmed with a bare Ink render, no Mindweave code involved —
5
+ * `<Text wrap="wrap">` on a plain sentence at width 20 produced:
6
+ *
7
+ * sentence that should
8
+ * wrap cleanly across ← extra leading space
9
+ * two or three lines ← extra leading space
10
+ * without issue
11
+ *
12
+ * lines 2 and 5 clean, 3 and 4 not — same input, same call, inconsistent. That
13
+ * rules out anything in BlockView's own Box structure; it is Ink/wrap-ansi's
14
+ * wrapping itself. Rather than depend on the library IT happens to use
15
+ * internally (an undeclared transitive dependency that could vanish on the next
16
+ * `npm install`), this wraps the text before Ink ever sees it and renders each
17
+ * line as its own row — nothing left for Ink's wrapper to get inconsistent about.
18
+ */
19
+ // Strips ANSI SGR codes (chalk's coloring) so width is measured on what's
20
+ // actually visible, not the escape bytes around it.
21
+ const ANSI_RE = /\x1b\[[0-9;]*m/g;
22
+ /**
23
+ * Text as at most `maxRows` RENDERED rows, saying so when it had to cut (pure).
24
+ *
25
+ * Rendered rows, not newlines: one 400-column line is several rows on screen, and
26
+ * counting newlines would call it short and let it blow the frame anyway.
27
+ *
28
+ * This exists because an unbounded prompt is not a cosmetic problem. Anything drawn in
29
+ * the footer that grows past the terminal's height makes Ink abandon its normal
30
+ * erase-and-redraw, after which the screen tears and the app is unusable — measured,
31
+ * from a 40-step plan passed as an overlay title.
32
+ */
33
+ export function clipRows(text, width, maxRows) {
34
+ const rows = wrapAnsi(text, Math.max(8, width));
35
+ if (rows.length <= maxRows)
36
+ return rows;
37
+ // Say it was cut. A silently truncated question is one the user answers without
38
+ // having read it.
39
+ return [...rows.slice(0, Math.max(1, maxRows - 1)), `… (${rows.length - (maxRows - 1)} more lines above)`];
40
+ }
41
+ function visibleWidth(s) {
42
+ return s.replace(ANSI_RE, "").length;
43
+ }
44
+ /**
45
+ * Greedy word-wrap of ANSI-styled text to `width` columns (pure).
46
+ *
47
+ * Existing newlines are respected as hard breaks (a markdown reply's paragraph
48
+ * spacing survives). Splitting on whitespace in the ORIGINAL string is safe even
49
+ * with embedded ANSI: an escape sequence (`\x1b[...m`) is only digits and
50
+ * semicolons, so it can never contain the whitespace being split on, and a
51
+ * "word" that comes out of the split keeps whatever styling wraps it intact.
52
+ *
53
+ * A single word wider than `width` (an unbroken run with no spaces, or a long
54
+ * styled token) still has to break somewhere. It hard-breaks on the PLAIN text
55
+ * rather than carry ANSI codes through the cut, which could otherwise sever an
56
+ * escape sequence or leave a color open past the end of its own line — losing
57
+ * that one word's styling is a far smaller cost than corrupting the line after it.
58
+ */
59
+ export function wrapAnsi(text, width) {
60
+ const w = Math.max(1, width);
61
+ const out = [];
62
+ for (const line of text.split("\n")) {
63
+ out.push(...wrapLine(line, w));
64
+ }
65
+ return out;
66
+ }
67
+ /**
68
+ * A list item's marker, as `markdown.ts` renders one: optional nesting indent, then
69
+ * `•` or `3.`, then a space. Deliberately NOT `-`/`*`/`+` — our own renderer emits
70
+ * the bullet character, and a raw `-` at the start of a line is far more often a diff
71
+ * removal or literal command output, where hanging text under it would be wrong.
72
+ */
73
+ const LIST_MARKER_RE = /^\s*(?:•|\d+[.)])\s/;
74
+ /**
75
+ * How far a wrapped list item's continuation rows are indented, in columns.
76
+ *
77
+ * Without it the second row of an item starts in the bullet's own column, so
78
+ * "settings." under "• Font picker — let users choose…" reads as a new item rather
79
+ * than the rest of the previous one. Capped so a narrow terminal keeps usable room.
80
+ */
81
+ function hangingIndent(line, width) {
82
+ const m = LIST_MARKER_RE.exec(line.replace(ANSI_RE, ""));
83
+ return m ? Math.min(m[0].length, Math.max(0, width - 8)) : 0;
84
+ }
85
+ function wrapLine(line, width) {
86
+ const hang = hangingIndent(line, width);
87
+ const pad = " ".repeat(hang);
88
+ const lines = [];
89
+ // The first row starts at the margin; every row after it hangs under the item's text.
90
+ const push = (s) => lines.push(lines.length === 0 ? s : pad + s);
91
+ const room = () => (lines.length === 0 ? width : width - hang);
92
+ const words = line.split(/(\s+)/).filter((w) => w !== "");
93
+ let cur = "";
94
+ let curWidth = 0;
95
+ for (const word of words) {
96
+ const isSpace = /^\s+$/.test(word);
97
+ const wWidth = visibleWidth(word);
98
+ if (isSpace) {
99
+ // A run of spaces mid-line is kept (markdown text rarely has one, but
100
+ // dropping it would be presumptuous); one that would start a wrapped
101
+ // line is dropped — the exact leading-space bug this file exists to avoid.
102
+ if (cur === "")
103
+ continue;
104
+ if (curWidth + wWidth > room()) {
105
+ push(cur);
106
+ cur = "";
107
+ curWidth = 0;
108
+ continue;
109
+ }
110
+ cur += word;
111
+ curWidth += wWidth;
112
+ continue;
113
+ }
114
+ if (wWidth > room()) {
115
+ // Wider than a whole line by itself: flush what's pending, then hard-break
116
+ // the plain text (see the function comment for why styling is dropped here).
117
+ if (cur !== "") {
118
+ push(cur);
119
+ cur = "";
120
+ curWidth = 0;
121
+ }
122
+ const plain = word.replace(ANSI_RE, "");
123
+ let i = 0;
124
+ while (i < plain.length) {
125
+ const take = room();
126
+ push(plain.slice(i, i + take));
127
+ i += take;
128
+ }
129
+ continue;
130
+ }
131
+ if (curWidth + wWidth > room()) {
132
+ push(cur);
133
+ cur = word;
134
+ curWidth = wWidth;
135
+ }
136
+ else {
137
+ cur += word;
138
+ curWidth += wWidth;
139
+ }
140
+ }
141
+ if (cur !== "")
142
+ push(cur);
143
+ return lines.length > 0 ? lines : [""];
144
+ }
145
+ //# sourceMappingURL=wrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrap.js","sourceRoot":"","sources":["../../src/cli/wrap.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * cachePoints.ts — where to put Anthropic's cache breakpoints, and why more than one.
3
+ *
4
+ * A breakpoint does not scan the whole conversation for a prior cache entry. It walks
5
+ * backward at most **20 content blocks**, and if it finds nothing in that window it
6
+ * misses — silently, with no error and no signal in the response beyond a
7
+ * `cache_read_input_tokens` of zero that looks exactly like a cold start.
8
+ *
9
+ * That limit is a poor fit for an agentic loop specifically. A round with three
10
+ * parallel tool calls adds three `tool_use` blocks and three `tool_result` blocks; two
11
+ * such rounds and the next request's single breakpoint is already looking past its own
12
+ * window at the entry it needs. The conversation keeps growing, every request keeps
13
+ * paying full price for all of it, and nothing anywhere says so.
14
+ *
15
+ * So a single breakpoint at the stable prefix is not enough. This spreads the available
16
+ * budget backward through the conversation as a LADDER, close enough together that the
17
+ * next request always lands within a window of one of them.
18
+ *
19
+ * Pure and unit-tested, because the failure it prevents is invisible at runtime: there
20
+ * is no observation a live session can make that distinguishes "cache missed because of
21
+ * the lookback window" from "cache missed because this is a new conversation".
22
+ */
23
+ /**
24
+ * Content blocks between consecutive breakpoints.
25
+ *
26
+ * 15 rather than 20: the limit is a hard 20, and the next request appends its own
27
+ * blocks before its breakpoint goes looking. Sitting exactly at the limit means any
28
+ * growth at all overshoots it, so the margin is the point.
29
+ */
30
+ export const BLOCK_SPACING = 15;
31
+ /**
32
+ * Anthropic allows 4 `cache_control` breakpoints per request. One is spent on the
33
+ * system prompt (which also covers the tool definitions ahead of it), leaving three
34
+ * for the conversation.
35
+ */
36
+ export const MAX_BREAKPOINTS = 4;
37
+ export const MESSAGE_BREAKPOINTS = MAX_BREAKPOINTS - 1;
38
+ /**
39
+ * Which message indexes should carry a breakpoint, given each message's block count.
40
+ *
41
+ * Returns indexes in ASCENDING order. The last message is always included: it is the
42
+ * stable-prefix boundary the whole request shape is built around, and the one entry the
43
+ * next request most wants to find.
44
+ *
45
+ * Walking BACKWARD from the end is deliberate. The recent end of the conversation is
46
+ * where the next request will look, so when the budget runs out it should run out at
47
+ * the far end — an unreachable breakpoint deep in history buys nothing.
48
+ */
49
+ export function cacheBreakpoints(blockCounts, budget = MESSAGE_BREAKPOINTS) {
50
+ if (blockCounts.length === 0 || budget <= 0)
51
+ return [];
52
+ const picked = [blockCounts.length - 1];
53
+ let sinceLast = 0;
54
+ // From the message before the last one, backward. `sinceLast` counts the blocks
55
+ // BETWEEN the previous breakpoint and here, which is exactly the distance the next
56
+ // request's lookback has to cover.
57
+ for (let i = blockCounts.length - 2; i >= 0 && picked.length < budget; i--) {
58
+ sinceLast += Math.max(0, blockCounts[i] ?? 0);
59
+ if (sinceLast >= BLOCK_SPACING) {
60
+ picked.push(i);
61
+ sinceLast = 0;
62
+ }
63
+ }
64
+ return picked.reverse();
65
+ }
66
+ /**
67
+ * Whether a conversation is long enough for the extra breakpoints to matter.
68
+ *
69
+ * Below the spacing there is only one place a breakpoint can usefully go, and spending
70
+ * the budget anyway would mark blocks a single window already reaches. Cheap to ask,
71
+ * and it keeps short sessions rendering exactly as they did before.
72
+ */
73
+ export function needsLadder(blockCounts) {
74
+ const total = blockCounts.reduce((n, c) => n + Math.max(0, c), 0);
75
+ return total > BLOCK_SPACING;
76
+ }
77
+ //# sourceMappingURL=cachePoints.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cachePoints.js","sourceRoot":"","sources":["../../../src/drivers/anthropic/cachePoints.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,EAAE,CAAC;AAEhC;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC;AACjC,MAAM,CAAC,MAAM,mBAAmB,GAAG,eAAe,GAAG,CAAC,CAAC;AAEvD;;;;;;;;;;GAUG;AACH,MAAM,UAAU,gBAAgB,CAAC,WAA8B,EAAE,MAAM,GAAG,mBAAmB;IAC3F,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IAEvD,MAAM,MAAM,GAAa,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAClD,IAAI,SAAS,GAAG,CAAC,CAAC;IAElB,gFAAgF;IAChF,mFAAmF;IACnF,mCAAmC;IACnC,KAAK,IAAI,CAAC,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC3E,SAAS,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAC9C,IAAI,SAAS,IAAI,aAAa,EAAE,CAAC;YAC/B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACf,SAAS,GAAG,CAAC,CAAC;QAChB,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC,OAAO,EAAE,CAAC;AAC1B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,WAA8B;IACxD,MAAM,KAAK,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAClE,OAAO,KAAK,GAAG,aAAa,CAAC;AAC/B,CAAC"}