@tomsun28/pizza 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (382) hide show
  1. package/README.md +20 -143
  2. package/README.zh-CN.md +36 -0
  3. package/dist/bun/cli.d.ts +2 -0
  4. package/dist/bun/cli.js +6 -0
  5. package/dist/bun/register-bedrock.d.ts +1 -0
  6. package/dist/bun/register-bedrock.js +3 -0
  7. package/dist/cli/args.d.ts +48 -0
  8. package/dist/cli/args.js +330 -0
  9. package/dist/cli/config-selector.d.ts +13 -0
  10. package/dist/cli/config-selector.js +30 -0
  11. package/dist/cli/file-processor.d.ts +14 -0
  12. package/dist/cli/file-processor.js +82 -0
  13. package/dist/cli/initial-message.d.ts +17 -0
  14. package/dist/cli/initial-message.js +21 -0
  15. package/dist/cli/list-models.d.ts +8 -0
  16. package/dist/cli/list-models.js +96 -0
  17. package/dist/cli.d.ts +2 -0
  18. package/dist/cli.js +68 -0
  19. package/dist/config.d.ts +79 -0
  20. package/dist/config.js +223 -0
  21. package/dist/core/agent/index.d.ts +6 -0
  22. package/dist/core/agent/index.js +6 -0
  23. package/dist/core/agent/types.d.ts +202 -0
  24. package/dist/core/agent/types.js +51 -0
  25. package/dist/core/auth-storage.d.ts +135 -0
  26. package/dist/core/auth-storage.js +417 -0
  27. package/dist/core/bash-executor.d.ts +31 -0
  28. package/dist/core/bash-executor.js +107 -0
  29. package/dist/core/compaction/branch-summarization.d.ts +87 -0
  30. package/dist/core/compaction/branch-summarization.js +242 -0
  31. package/dist/core/compaction/compaction-engine.d.ts +40 -0
  32. package/dist/core/compaction/compaction-engine.js +292 -0
  33. package/dist/core/compaction/compaction.d.ts +106 -0
  34. package/dist/core/compaction/compaction.js +295 -0
  35. package/dist/core/compaction/index.d.ts +7 -0
  36. package/dist/core/compaction/index.js +7 -0
  37. package/dist/core/compaction/utils.d.ts +37 -0
  38. package/dist/core/compaction/utils.js +152 -0
  39. package/dist/core/defaults.d.ts +2 -0
  40. package/dist/core/defaults.js +1 -0
  41. package/dist/core/diagnostics.d.ts +14 -0
  42. package/dist/core/diagnostics.js +1 -0
  43. package/dist/core/event-bus.d.ts +8 -0
  44. package/dist/core/event-bus.js +24 -0
  45. package/dist/core/event-store/events.d.ts +465 -0
  46. package/dist/core/event-store/events.js +6 -0
  47. package/dist/core/event-store/index.d.ts +10 -0
  48. package/dist/core/event-store/index.js +10 -0
  49. package/dist/core/event-store/sqlite-store.d.ts +27 -0
  50. package/dist/core/event-store/sqlite-store.js +275 -0
  51. package/dist/core/event-store/store.d.ts +91 -0
  52. package/dist/core/event-store/store.js +7 -0
  53. package/dist/core/event-store/thread-scoped-store.d.ts +29 -0
  54. package/dist/core/event-store/thread-scoped-store.js +50 -0
  55. package/dist/core/event-store/types.d.ts +70 -0
  56. package/dist/core/event-store/types.js +7 -0
  57. package/dist/core/event-store/workspace.d.ts +37 -0
  58. package/dist/core/event-store/workspace.js +71 -0
  59. package/dist/core/exec.d.ts +28 -0
  60. package/dist/core/exec.js +74 -0
  61. package/dist/core/export-html/ansi-to-html.d.ts +21 -0
  62. package/dist/core/export-html/ansi-to-html.js +248 -0
  63. package/dist/core/export-html/index.d.ts +29 -0
  64. package/dist/core/export-html/index.js +186 -0
  65. package/dist/core/export-html/template.css +1017 -0
  66. package/dist/core/export-html/template.html +55 -0
  67. package/dist/core/export-html/template.js +1742 -0
  68. package/dist/core/export-html/tool-renderer.d.ts +39 -0
  69. package/dist/core/export-html/tool-renderer.js +94 -0
  70. package/dist/core/export-html/vendor/highlight.min.js +1213 -0
  71. package/dist/core/export-html/vendor/marked.min.js +6 -0
  72. package/dist/core/extensions/index.d.ts +12 -0
  73. package/dist/core/extensions/index.js +9 -0
  74. package/dist/core/extensions/loader.d.ts +24 -0
  75. package/dist/core/extensions/loader.js +492 -0
  76. package/dist/core/extensions/runner.d.ts +167 -0
  77. package/dist/core/extensions/runner.js +898 -0
  78. package/dist/core/extensions/session-context.d.ts +67 -0
  79. package/dist/core/extensions/session-context.js +272 -0
  80. package/dist/core/extensions/types.d.ts +1147 -0
  81. package/dist/core/extensions/types.js +44 -0
  82. package/dist/core/extensions/wrapper.d.ts +19 -0
  83. package/dist/core/extensions/wrapper.js +21 -0
  84. package/dist/core/footer-data-provider.d.ts +47 -0
  85. package/dist/core/footer-data-provider.js +321 -0
  86. package/dist/core/goal/index.d.ts +3 -0
  87. package/dist/core/goal/index.js +1 -0
  88. package/dist/core/goal/scheduler.d.ts +83 -0
  89. package/dist/core/goal/scheduler.js +154 -0
  90. package/dist/core/goal/types.d.ts +182 -0
  91. package/dist/core/goal/types.js +11 -0
  92. package/dist/core/index.d.ts +8 -0
  93. package/dist/core/index.js +8 -0
  94. package/dist/core/intent/classifier.d.ts +53 -0
  95. package/dist/core/intent/classifier.js +353 -0
  96. package/dist/core/intent/index.d.ts +8 -0
  97. package/dist/core/intent/index.js +8 -0
  98. package/dist/core/intent/tool-adapter.d.ts +31 -0
  99. package/dist/core/intent/tool-adapter.js +168 -0
  100. package/dist/core/intent/types.d.ts +71 -0
  101. package/dist/core/intent/types.js +6 -0
  102. package/dist/core/keybindings.d.ts +297 -0
  103. package/dist/core/keybindings.js +250 -0
  104. package/dist/core/messages.d.ts +30 -0
  105. package/dist/core/messages.js +134 -0
  106. package/dist/core/model-registry.d.ts +131 -0
  107. package/dist/core/model-registry.js +634 -0
  108. package/dist/core/model-resolver.d.ts +109 -0
  109. package/dist/core/model-resolver.js +486 -0
  110. package/dist/core/output-guard.d.ts +5 -0
  111. package/dist/core/output-guard.js +58 -0
  112. package/dist/core/package-manager.d.ts +196 -0
  113. package/dist/core/package-manager.js +1873 -0
  114. package/dist/core/projection/boundary-inferrer.d.ts +58 -0
  115. package/dist/core/projection/boundary-inferrer.js +122 -0
  116. package/dist/core/projection/event-to-message.d.ts +35 -0
  117. package/dist/core/projection/event-to-message.js +253 -0
  118. package/dist/core/projection/goal-projection.d.ts +67 -0
  119. package/dist/core/projection/goal-projection.js +339 -0
  120. package/dist/core/projection/index.d.ts +13 -0
  121. package/dist/core/projection/index.js +13 -0
  122. package/dist/core/projection/session-manager.d.ts +100 -0
  123. package/dist/core/projection/session-manager.js +331 -0
  124. package/dist/core/projection/session-projection.d.ts +58 -0
  125. package/dist/core/projection/session-projection.js +257 -0
  126. package/dist/core/projection/task-history.d.ts +13 -0
  127. package/dist/core/projection/task-history.js +61 -0
  128. package/dist/core/projection/timeline-projection.d.ts +82 -0
  129. package/dist/core/projection/timeline-projection.js +276 -0
  130. package/dist/core/projection/types.d.ts +69 -0
  131. package/dist/core/projection/types.js +6 -0
  132. package/dist/core/prompt-templates.d.ts +51 -0
  133. package/dist/core/prompt-templates.js +249 -0
  134. package/dist/core/resolve-config-value.d.ts +22 -0
  135. package/dist/core/resolve-config-value.js +125 -0
  136. package/dist/core/resource-loader.d.ts +193 -0
  137. package/dist/core/resource-loader.js +685 -0
  138. package/dist/core/runtime/ai-client.d.ts +12 -0
  139. package/dist/core/runtime/ai-client.js +153 -0
  140. package/dist/core/runtime/checkpoint.d.ts +12 -0
  141. package/dist/core/runtime/checkpoint.js +78 -0
  142. package/dist/core/runtime/index.d.ts +12 -0
  143. package/dist/core/runtime/index.js +12 -0
  144. package/dist/core/runtime/llm-types.d.ts +99 -0
  145. package/dist/core/runtime/llm-types.js +6 -0
  146. package/dist/core/runtime/local-runtime.d.ts +23 -0
  147. package/dist/core/runtime/local-runtime.js +59 -0
  148. package/dist/core/runtime/policies.d.ts +72 -0
  149. package/dist/core/runtime/policies.js +37 -0
  150. package/dist/core/runtime/reactor.d.ts +213 -0
  151. package/dist/core/runtime/reactor.js +992 -0
  152. package/dist/core/runtime/runtime.d.ts +191 -0
  153. package/dist/core/runtime/runtime.js +449 -0
  154. package/dist/core/runtime/types.d.ts +42 -0
  155. package/dist/core/runtime/types.js +1 -0
  156. package/dist/core/sdk.d.ts +12 -0
  157. package/dist/core/sdk.js +10 -0
  158. package/dist/core/session-context-builder.d.ts +9 -0
  159. package/dist/core/session-context-builder.js +87 -0
  160. package/dist/core/session-cwd.d.ts +18 -0
  161. package/dist/core/session-cwd.js +36 -0
  162. package/dist/core/session-facade-factory.d.ts +79 -0
  163. package/dist/core/session-facade-factory.js +460 -0
  164. package/dist/core/session-facade.d.ts +57 -0
  165. package/dist/core/session-facade.js +91 -0
  166. package/dist/core/session-listing.d.ts +30 -0
  167. package/dist/core/session-listing.js +168 -0
  168. package/dist/core/session-reader.d.ts +19 -0
  169. package/dist/core/session-reader.js +101 -0
  170. package/dist/core/session-ref.d.ts +7 -0
  171. package/dist/core/session-ref.js +25 -0
  172. package/dist/core/session-services.d.ts +51 -0
  173. package/dist/core/session-services.js +90 -0
  174. package/dist/core/session-stats.d.ts +43 -0
  175. package/dist/core/session-stats.js +41 -0
  176. package/dist/core/settings-manager.d.ts +236 -0
  177. package/dist/core/settings-manager.js +706 -0
  178. package/dist/core/skill-block-parser.d.ts +12 -0
  179. package/dist/core/skill-block-parser.js +15 -0
  180. package/dist/core/skills.d.ts +59 -0
  181. package/dist/core/skills.js +408 -0
  182. package/dist/core/slash-commands.d.ts +13 -0
  183. package/dist/core/slash-commands.js +17 -0
  184. package/dist/core/source-info.d.ts +17 -0
  185. package/dist/core/source-info.js +18 -0
  186. package/dist/core/system-prompt.d.ts +27 -0
  187. package/dist/core/system-prompt.js +179 -0
  188. package/dist/core/timings.d.ts +7 -0
  189. package/dist/core/timings.js +30 -0
  190. package/dist/core/tools/bash.d.ts +95 -0
  191. package/dist/core/tools/bash.js +513 -0
  192. package/dist/core/tools/builtin-commands.d.ts +75 -0
  193. package/dist/core/tools/builtin-commands.js +503 -0
  194. package/dist/core/tools/compat-commands.d.ts +12 -0
  195. package/dist/core/tools/compat-commands.js +1280 -0
  196. package/dist/core/tools/edit-diff.d.ts +59 -0
  197. package/dist/core/tools/edit-diff.js +263 -0
  198. package/dist/core/tools/edit.d.ts +49 -0
  199. package/dist/core/tools/edit.js +340 -0
  200. package/dist/core/tools/file-mutation-queue.d.ts +5 -0
  201. package/dist/core/tools/file-mutation-queue.js +36 -0
  202. package/dist/core/tools/find.d.ts +34 -0
  203. package/dist/core/tools/find.js +459 -0
  204. package/dist/core/tools/grep.d.ts +36 -0
  205. package/dist/core/tools/grep.js +422 -0
  206. package/dist/core/tools/index.d.ts +70 -0
  207. package/dist/core/tools/index.js +129 -0
  208. package/dist/core/tools/line-anchors.d.ts +33 -0
  209. package/dist/core/tools/line-anchors.js +151 -0
  210. package/dist/core/tools/ls.d.ts +36 -0
  211. package/dist/core/tools/ls.js +268 -0
  212. package/dist/core/tools/path-utils.d.ts +7 -0
  213. package/dist/core/tools/path-utils.js +80 -0
  214. package/dist/core/tools/read.d.ts +35 -0
  215. package/dist/core/tools/read.js +244 -0
  216. package/dist/core/tools/render-utils.d.ts +20 -0
  217. package/dist/core/tools/render-utils.js +48 -0
  218. package/dist/core/tools/session-split.d.ts +9 -0
  219. package/dist/core/tools/session-split.js +77 -0
  220. package/dist/core/tools/tool-definition-wrapper.d.ts +13 -0
  221. package/dist/core/tools/tool-definition-wrapper.js +32 -0
  222. package/dist/core/tools/truncate.d.ts +69 -0
  223. package/dist/core/tools/truncate.js +204 -0
  224. package/dist/core/tools/write.d.ts +25 -0
  225. package/dist/core/tools/write.js +211 -0
  226. package/dist/core/types/session-types.d.ts +123 -0
  227. package/dist/core/types/session-types.js +8 -0
  228. package/dist/index.d.ts +27 -0
  229. package/dist/index.js +38 -0
  230. package/dist/main.d.ts +11 -2
  231. package/dist/main.js +577 -149
  232. package/dist/modes/event-mapper.d.ts +115 -0
  233. package/dist/modes/event-mapper.js +200 -0
  234. package/dist/modes/gui/server.d.ts +14 -0
  235. package/dist/modes/gui/server.js +1032 -0
  236. package/dist/modes/index.d.ts +10 -0
  237. package/dist/modes/index.js +9 -0
  238. package/dist/modes/interactive/assets/clankolas.png +0 -0
  239. package/dist/modes/interactive/components/armin.d.ts +33 -0
  240. package/dist/modes/interactive/components/armin.js +328 -0
  241. package/dist/modes/interactive/components/assistant-message.d.ts +19 -0
  242. package/dist/modes/interactive/components/assistant-message.js +115 -0
  243. package/dist/modes/interactive/components/bash-execution.d.ts +33 -0
  244. package/dist/modes/interactive/components/bash-execution.js +169 -0
  245. package/dist/modes/interactive/components/bordered-loader.d.ts +15 -0
  246. package/dist/modes/interactive/components/bordered-loader.js +50 -0
  247. package/dist/modes/interactive/components/branch-summary-message.d.ts +15 -0
  248. package/dist/modes/interactive/components/branch-summary-message.js +41 -0
  249. package/dist/modes/interactive/components/brand-header.d.ts +33 -0
  250. package/dist/modes/interactive/components/brand-header.js +235 -0
  251. package/dist/modes/interactive/components/compaction-summary-message.d.ts +15 -0
  252. package/dist/modes/interactive/components/compaction-summary-message.js +42 -0
  253. package/dist/modes/interactive/components/config-selector.d.ts +70 -0
  254. package/dist/modes/interactive/components/config-selector.js +469 -0
  255. package/dist/modes/interactive/components/countdown-timer.d.ts +13 -0
  256. package/dist/modes/interactive/components/countdown-timer.js +27 -0
  257. package/dist/modes/interactive/components/custom-editor.d.ts +27 -0
  258. package/dist/modes/interactive/components/custom-editor.js +94 -0
  259. package/dist/modes/interactive/components/custom-message.d.ts +19 -0
  260. package/dist/modes/interactive/components/custom-message.js +73 -0
  261. package/dist/modes/interactive/components/daxnuts.d.ts +22 -0
  262. package/dist/modes/interactive/components/daxnuts.js +137 -0
  263. package/dist/modes/interactive/components/diff.d.ts +11 -0
  264. package/dist/modes/interactive/components/diff.js +132 -0
  265. package/dist/modes/interactive/components/dynamic-border.d.ts +14 -0
  266. package/dist/modes/interactive/components/dynamic-border.js +19 -0
  267. package/dist/modes/interactive/components/earendil-announcement.d.ts +4 -0
  268. package/dist/modes/interactive/components/earendil-announcement.js +39 -0
  269. package/dist/modes/interactive/components/extension-editor.d.ts +19 -0
  270. package/dist/modes/interactive/components/extension-editor.js +105 -0
  271. package/dist/modes/interactive/components/extension-input.d.ts +22 -0
  272. package/dist/modes/interactive/components/extension-input.js +54 -0
  273. package/dist/modes/interactive/components/extension-selector.d.ts +23 -0
  274. package/dist/modes/interactive/components/extension-selector.js +70 -0
  275. package/dist/modes/interactive/components/footer.d.ts +55 -0
  276. package/dist/modes/interactive/components/footer.js +207 -0
  277. package/dist/modes/interactive/components/index.d.ts +31 -0
  278. package/dist/modes/interactive/components/index.js +32 -0
  279. package/dist/modes/interactive/components/keybinding-hints.d.ts +7 -0
  280. package/dist/modes/interactive/components/keybinding-hints.js +21 -0
  281. package/dist/modes/interactive/components/login-dialog.d.ts +41 -0
  282. package/dist/modes/interactive/components/login-dialog.js +138 -0
  283. package/dist/modes/interactive/components/model-selector.d.ts +32 -0
  284. package/dist/modes/interactive/components/model-selector.js +209 -0
  285. package/dist/modes/interactive/components/oauth-selector.d.ts +18 -0
  286. package/dist/modes/interactive/components/oauth-selector.js +91 -0
  287. package/dist/modes/interactive/components/settings-selector.d.ts +57 -0
  288. package/dist/modes/interactive/components/settings-selector.js +299 -0
  289. package/dist/modes/interactive/components/show-images-selector.d.ts +9 -0
  290. package/dist/modes/interactive/components/show-images-selector.js +37 -0
  291. package/dist/modes/interactive/components/skill-invocation-message.d.ts +16 -0
  292. package/dist/modes/interactive/components/skill-invocation-message.js +44 -0
  293. package/dist/modes/interactive/components/theme-selector.d.ts +10 -0
  294. package/dist/modes/interactive/components/theme-selector.js +47 -0
  295. package/dist/modes/interactive/components/thinking-selector.d.ts +10 -0
  296. package/dist/modes/interactive/components/thinking-selector.js +50 -0
  297. package/dist/modes/interactive/components/timeline-view.d.ts +31 -0
  298. package/dist/modes/interactive/components/timeline-view.js +81 -0
  299. package/dist/modes/interactive/components/tool-execution.d.ts +64 -0
  300. package/dist/modes/interactive/components/tool-execution.js +305 -0
  301. package/dist/modes/interactive/components/tree-selector.d.ts +88 -0
  302. package/dist/modes/interactive/components/tree-selector.js +1072 -0
  303. package/dist/modes/interactive/components/user-message-selector.d.ts +29 -0
  304. package/dist/modes/interactive/components/user-message-selector.js +110 -0
  305. package/dist/modes/interactive/components/user-message.d.ts +9 -0
  306. package/dist/modes/interactive/components/user-message.js +27 -0
  307. package/dist/modes/interactive/components/visual-truncate.d.ts +23 -0
  308. package/dist/modes/interactive/components/visual-truncate.js +32 -0
  309. package/dist/modes/interactive/interactive-mode.d.ts +394 -0
  310. package/dist/modes/interactive/interactive-mode.js +4116 -0
  311. package/dist/modes/interactive/theme/dark.json +85 -0
  312. package/dist/modes/interactive/theme/light.json +84 -0
  313. package/dist/modes/interactive/theme/theme-schema.json +335 -0
  314. package/dist/modes/interactive/theme/theme.d.ts +80 -0
  315. package/dist/modes/interactive/theme/theme.js +973 -0
  316. package/dist/modes/print-mode.d.ts +27 -0
  317. package/dist/modes/print-mode.js +102 -0
  318. package/dist/modes/rpc/jsonl.d.ts +16 -0
  319. package/dist/modes/rpc/jsonl.js +48 -0
  320. package/dist/modes/rpc/rpc-client.d.ts +219 -0
  321. package/dist/modes/rpc/rpc-client.js +405 -0
  322. package/dist/modes/rpc/rpc-mode.d.ts +19 -0
  323. package/dist/modes/rpc/rpc-mode.js +381 -0
  324. package/dist/modes/rpc/rpc-types.d.ts +406 -0
  325. package/dist/modes/rpc/rpc-types.js +7 -0
  326. package/dist/package-manager-cli.d.ts +3 -0
  327. package/dist/package-manager-cli.js +233 -0
  328. package/dist/utils/changelog.d.ts +20 -0
  329. package/dist/utils/changelog.js +86 -0
  330. package/dist/utils/child-process.d.ts +10 -0
  331. package/dist/utils/child-process.js +77 -0
  332. package/dist/utils/clipboard-image.d.ts +10 -0
  333. package/dist/utils/clipboard-image.js +244 -0
  334. package/dist/utils/clipboard-native.d.ts +7 -0
  335. package/dist/utils/clipboard-native.js +13 -0
  336. package/dist/utils/clipboard.d.ts +1 -0
  337. package/dist/utils/clipboard.js +77 -0
  338. package/dist/utils/exif-orientation.d.ts +4 -0
  339. package/dist/utils/exif-orientation.js +157 -0
  340. package/dist/utils/frontmatter.d.ts +7 -0
  341. package/dist/utils/frontmatter.js +25 -0
  342. package/dist/utils/git.d.ts +25 -0
  343. package/dist/utils/git.js +162 -0
  344. package/dist/utils/image-convert.d.ts +8 -0
  345. package/dist/utils/image-convert.js +38 -0
  346. package/dist/utils/image-resize.d.ts +35 -0
  347. package/dist/utils/image-resize.js +136 -0
  348. package/dist/utils/mime.d.ts +1 -0
  349. package/dist/utils/mime.js +25 -0
  350. package/dist/utils/path-shims.d.ts +1 -0
  351. package/dist/utils/path-shims.js +90 -0
  352. package/dist/utils/paths.d.ts +6 -0
  353. package/dist/utils/paths.js +18 -0
  354. package/dist/utils/photon.d.ts +20 -0
  355. package/dist/utils/photon.js +120 -0
  356. package/dist/utils/shell.d.ts +29 -0
  357. package/dist/utils/shell.js +189 -0
  358. package/dist/utils/sleep.d.ts +4 -0
  359. package/dist/utils/sleep.js +16 -0
  360. package/dist/utils/tools-manager.d.ts +3 -0
  361. package/dist/utils/tools-manager.js +101 -0
  362. package/dist/vendor/bin/darwin-arm64/fd +0 -0
  363. package/dist/vendor/bin/darwin-arm64/rg +0 -0
  364. package/dist/vendor/bin/darwin-x64/fd +0 -0
  365. package/dist/vendor/bin/darwin-x64/rg +0 -0
  366. package/dist/vendor/bin/linux-arm64/fd +0 -0
  367. package/dist/vendor/bin/linux-arm64/rg +0 -0
  368. package/dist/vendor/bin/linux-x64/fd +0 -0
  369. package/dist/vendor/bin/linux-x64/rg +0 -0
  370. package/dist/vendor/bin/win32-arm64/fd.exe +0 -0
  371. package/dist/vendor/bin/win32-arm64/rg.exe +0 -0
  372. package/dist/vendor/bin/win32-x64/fd.exe +0 -0
  373. package/dist/vendor/bin/win32-x64/rg.exe +0 -0
  374. package/package.json +90 -26
  375. package/dist/extension/core.d.ts +0 -69
  376. package/dist/extension/core.js +0 -270
  377. package/dist/extension/core.js.map +0 -1
  378. package/dist/extension/index.d.ts +0 -14
  379. package/dist/extension/index.js +0 -374
  380. package/dist/extension/index.js.map +0 -1
  381. package/dist/main.js.map +0 -1
  382. package/themes/pizza.json +0 -87
@@ -0,0 +1,94 @@
1
+ import { Editor } from "@earendil-works/pi-tui";
2
+ /** Strip ANSI escape sequences for visible-text checks. */
3
+ function stripAnsi(str) {
4
+ return str.replace(/\x1b\[[0-9;]*m/g, "");
5
+ }
6
+ /** Check if a rendered line is a plain border (all ─ characters). */
7
+ function isPlainBorder(line) {
8
+ const stripped = stripAnsi(line);
9
+ return stripped.length > 2 && /^─+$/.test(stripped);
10
+ }
11
+ /**
12
+ * Custom editor that handles app-level keybindings for coding-agent.
13
+ */
14
+ export class CustomEditor extends Editor {
15
+ constructor(tui, theme, keybindings, options) {
16
+ super(tui, theme, options);
17
+ this.actionHandlers = new Map();
18
+ this.keybindings = keybindings;
19
+ }
20
+ /**
21
+ * Register a handler for an app action.
22
+ */
23
+ onAction(action, handler) {
24
+ this.actionHandlers.set(action, handler);
25
+ }
26
+ handleInput(data) {
27
+ // Check extension-registered shortcuts first
28
+ if (this.onExtensionShortcut?.(data)) {
29
+ return;
30
+ }
31
+ // Check for paste image keybinding
32
+ if (this.keybindings.matches(data, "app.clipboard.pasteImage")) {
33
+ this.onPasteImage?.();
34
+ return;
35
+ }
36
+ // Check app keybindings first
37
+ // Escape/interrupt - only if autocomplete is NOT active
38
+ if (this.keybindings.matches(data, "app.interrupt")) {
39
+ if (!this.isShowingAutocomplete()) {
40
+ // Use dynamic onEscape if set, otherwise registered handler
41
+ const handler = this.onEscape ?? this.actionHandlers.get("app.interrupt");
42
+ if (handler) {
43
+ handler();
44
+ return;
45
+ }
46
+ }
47
+ // Let parent handle escape for autocomplete cancellation
48
+ super.handleInput(data);
49
+ return;
50
+ }
51
+ // Exit (Ctrl+D) - only when editor is empty
52
+ if (this.keybindings.matches(data, "app.exit")) {
53
+ if (this.getText().length === 0) {
54
+ const handler = this.onCtrlD ?? this.actionHandlers.get("app.exit");
55
+ if (handler)
56
+ handler();
57
+ return;
58
+ }
59
+ // Fall through to editor handling for delete-char-forward when not empty
60
+ }
61
+ // Check all other app actions
62
+ for (const [action, handler] of this.actionHandlers) {
63
+ if (action !== "app.interrupt" && action !== "app.exit" && this.keybindings.matches(data, action)) {
64
+ handler();
65
+ return;
66
+ }
67
+ }
68
+ // Pass to parent for editor handling
69
+ super.handleInput(data);
70
+ }
71
+ /**
72
+ * Override render to add cyber-style corner brackets on border lines.
73
+ * The parent Editor renders plain ─── lines; we replace the first and
74
+ * last simple border lines with angular corners (┌┐ / └┘).
75
+ * Scroll indicators and content lines are passed through unchanged.
76
+ */
77
+ render(width) {
78
+ const lines = super.render(width);
79
+ if (width < 4 || lines.length < 2)
80
+ return lines;
81
+ // Top border: first line if it's a plain border
82
+ if (isPlainBorder(lines[0])) {
83
+ lines[0] = this.borderColor("┌") + this.borderColor("─").repeat(width - 2) + this.borderColor("┐");
84
+ }
85
+ // Bottom border: scan backwards from end for the last plain border
86
+ for (let i = lines.length - 1; i >= 1; i--) {
87
+ if (isPlainBorder(lines[i])) {
88
+ lines[i] = this.borderColor("└") + this.borderColor("─").repeat(width - 2) + this.borderColor("┘");
89
+ break;
90
+ }
91
+ }
92
+ return lines;
93
+ }
94
+ }
@@ -0,0 +1,19 @@
1
+ import { Container, type MarkdownTheme } from "@earendil-works/pi-tui";
2
+ import type { MessageRenderer } from "../../../core/extensions/types.js";
3
+ import type { CustomMessage } from "../../../core/messages.js";
4
+ /**
5
+ * Component that renders a custom message entry from extensions.
6
+ * Uses distinct styling to differentiate from user messages.
7
+ */
8
+ export declare class CustomMessageComponent extends Container {
9
+ private message;
10
+ private customRenderer?;
11
+ private box;
12
+ private customComponent?;
13
+ private markdownTheme;
14
+ private _expanded;
15
+ constructor(message: CustomMessage<unknown>, customRenderer?: MessageRenderer, markdownTheme?: MarkdownTheme);
16
+ setExpanded(expanded: boolean): void;
17
+ invalidate(): void;
18
+ private rebuild;
19
+ }
@@ -0,0 +1,73 @@
1
+ import { Box, Container, Markdown, Spacer, Text } from "@earendil-works/pi-tui";
2
+ import { getMarkdownTheme, theme } from "../theme/theme.js";
3
+ /**
4
+ * Component that renders a custom message entry from extensions.
5
+ * Uses distinct styling to differentiate from user messages.
6
+ */
7
+ export class CustomMessageComponent extends Container {
8
+ constructor(message, customRenderer, markdownTheme = getMarkdownTheme()) {
9
+ super();
10
+ this._expanded = false;
11
+ this.message = message;
12
+ this.customRenderer = customRenderer;
13
+ this.markdownTheme = markdownTheme;
14
+ this.addChild(new Spacer(1));
15
+ // Create box with purple background (used for default rendering)
16
+ this.box = new Box(1, 1, (t) => theme.bg("customMessageBg", t));
17
+ this.rebuild();
18
+ }
19
+ setExpanded(expanded) {
20
+ if (this._expanded !== expanded) {
21
+ this._expanded = expanded;
22
+ this.rebuild();
23
+ }
24
+ }
25
+ invalidate() {
26
+ super.invalidate();
27
+ this.rebuild();
28
+ }
29
+ rebuild() {
30
+ // Remove previous content component
31
+ if (this.customComponent) {
32
+ this.removeChild(this.customComponent);
33
+ this.customComponent = undefined;
34
+ }
35
+ this.removeChild(this.box);
36
+ // Try custom renderer first - it handles its own styling
37
+ if (this.customRenderer) {
38
+ try {
39
+ const component = this.customRenderer(this.message, { expanded: this._expanded }, theme);
40
+ if (component) {
41
+ // Custom renderer provides its own styled component
42
+ this.customComponent = component;
43
+ this.addChild(component);
44
+ return;
45
+ }
46
+ }
47
+ catch {
48
+ // Fall through to default rendering
49
+ }
50
+ }
51
+ // Default rendering uses our box
52
+ this.addChild(this.box);
53
+ this.box.clear();
54
+ // Default rendering: label + content
55
+ const label = theme.fg("customMessageLabel", `\x1b[1m[${this.message.customType}]\x1b[22m`);
56
+ this.box.addChild(new Text(label, 0, 0));
57
+ this.box.addChild(new Spacer(1));
58
+ // Extract text content
59
+ let text;
60
+ if (typeof this.message.content === "string") {
61
+ text = this.message.content;
62
+ }
63
+ else {
64
+ text = this.message.content
65
+ .filter((c) => c.type === "text")
66
+ .map((c) => c.text)
67
+ .join("\n");
68
+ }
69
+ this.box.addChild(new Markdown(text, 0, 0, this.markdownTheme, {
70
+ color: (text) => theme.fg("customMessageText", text),
71
+ }));
72
+ }
73
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * POWERED BY DAXNUTS - Easter egg for OpenCode + Kimi K2.5
3
+ *
4
+ * A heartfelt tribute to dax (@thdxr) for providing free Kimi K2.5 access via OpenCode.
5
+ */
6
+ import type { Component, TUI } from "@earendil-works/pi-tui";
7
+ export declare class DaxnutsComponent implements Component {
8
+ private ui;
9
+ private image;
10
+ private interval;
11
+ private tick;
12
+ private maxTicks;
13
+ private cachedLines;
14
+ private cachedWidth;
15
+ private cachedTick;
16
+ constructor(ui: TUI);
17
+ invalidate(): void;
18
+ private startAnimation;
19
+ private stopAnimation;
20
+ render(width: number): string[];
21
+ dispose(): void;
22
+ }
@@ -0,0 +1,137 @@
1
+ /**
2
+ * POWERED BY DAXNUTS - Easter egg for OpenCode + Kimi K2.5
3
+ *
4
+ * A heartfelt tribute to dax (@thdxr) for providing free Kimi K2.5 access via OpenCode.
5
+ */
6
+ import { theme } from "../theme/theme.js";
7
+ // 32x32 RGB image of dax, hex encoded (3 bytes per pixel)
8
+ const DAX_HEX = "bbbab8b9b9b6b9b8b5bcbbb8b8b7b4b7b5b2b6b5b2b8b7b4b7b6b3b6b4b1bdbcb8bab8b6bbb8b5b8b5b1bbb8b4c2bebbc1bebac0bdbabfbcb9c1bebabfbebbc0bfbcc0bdbabbb8b5c1bfbcbfbcb8bbb9b6bfbcb8c2bfbcc1bfbcbfbbb8bdb9b6b8b7b5b9b8b5b8b8b5b5b5b2b6b5b2b8b7b4b9b8b5b9b8b5b6b5b3bab8b5bcbab7bbb9b6bbb8b5bfb9b5bdb2abbcb0a8beb2aabeb5afbfbab6bebab7c0bfbcbebdbabebbb8c0bdbabfbebbc2bebbbdbab7c3c0bdc3c0bdc1bebbc2bebabfbcb8bab9b6b7b6b3b2b1aeb6b5b2b5b4b1b5b4b2b6b5b2b7b6b4b9b8b6b7b6b3bbbab7b2afaba5988fb49e90b09481b79a88b39683b09583b7a395bfb6b0c0bdbabdbbb8bebcb9c1bfbcc0bebbbdbab7bebbb8c2bfbcc0bdbac0bcb9bdb9b6c0bcb8b5b4b2b4b3b0bab9b6b9b9b6b5b4b1b5b4b1b6b5b3b9b8b5b9b8b6b9b8b6b2aeaa968174a6836eaa856eab846eaf8973ac8973b08f79b18f7ab39786b7a89dbbb3aebfbab6c2c0bdbebcb9bfbdbac3c1bdc2bebbc0bcb9bdb9b6c1bdbabfbbb8b4b3b0b9b8b5b8b7b5b4b3b1b5b4b1b8b7b4b8b7b5bab9b6bbbab7b1afad8c7a719d735ca47860a87d65a98069ae8972ae8c75af8d77aa826ba98067aa8974b39e90b6a79dbbb2adc0bdbac1bfbdbfbbb8c1bdb9bebab6c0bdb9bfbbb8c1bdbab4b2b0b7b6b4b7b6b3b4b2b0bab9b7b6b5b2b6b5b2bab9b6bab9b6958c87977663aa836bac8772b08f7aad8c77b2917db0917db0907cac8971a77d64a87f67ac8972b29887b8a89dbfbab5bfbdbac1bebac0bcb9c0bcb9c0bcb9c1bebabebab7b8b7b4b7b6b4b5b4b1b5b4b2b7b6b3b5b4b2bab9b7bab9b6b4b1ada88f7fad8973ae8d78b19684b19685b29786b69a89b29582b1917daa856ea87e66a97e66ad866ea9826baf9280b8ada6bdbbb8bebab7bfbbb8c1bdbabfbbb8bcb8b4bcb8b5b6b4b2b7b5b3b6b5b2b8b7b4b3b2afb8b7b4b6b5b2b3b2b0b3a59aab856fad8d78b0917eb19886b49b8bb49a89b39785b0917eaf8f7cab866fa77d65a77a61a87d64a9816ab08f79b5a296c1bcb8c3bfbcc2bebbbebab7bfbbb7bdbab6c2bebab8b7b4b7b6b4b6b5b3b7b6b3b6b5b2b9b8b6b4b3b1b6b1acac8f7ca9826bae8f7aaf9583b49c8cb49c8bb79d8cb59987b19380ad8e79ae8c77af8e78ac8771a3775faa826bae8972b39888bbb6b2bebbb8bfbbb8bfbbb8c0bdb9bebbb7c0bdb9b6b5b2b9b8b5b4b3b1b8b7b5b4b3b0b7b6b4b6b5b3b1a7a0aa8772a77d65a88570b49887b19b8d9c887c907a6d987f71aa907faf917daf8e7aad8c78ac8b77a8836ca9836cac8770b49b8abdb6b2c0bcb9c0bdb9bfbbb8bebab7bfbcb9bebab7b9b8b6b5b4b2b9b8b5b8b7b5b8b7b4b7b6b4b5b4b2b3a9a2ad8973a1755da9856fb398858c776a65544b776358725d526e594d9c7f6eb1907ba68672ad8e7aab8771ac856db18f79b3a092beb9b5c1bdbabdb9b5bebab7bfbbb7bebab7bcb9b6b7b6b4b6b6b3b8b7b4b5b4b2b8b6b4b7b6b3b4b3b0b4aba4a6826ba3775fb08e79b19584a88e7daa8e7db29481ad8f7c997e6da38674ac8d79ac8e7aae917f9a7c6a896a599a7c6ab3a398c1bdbabdb9b6bcb8b5bebab6bebab7bdb9b5bdb9b6b5b4b1b7b5b3b5b4b2b7b6b3b7b6b4b3b3b0b3b2b0b4aca5a7846fa97f68ae8f7bae9383b59c8bb2937fae8e79ac8b76af927eaf927eb29683b39885b2988891786a72594c6e594d978d86bdbab7bab7b3c0bcb9c0bcb9bebab7bebbb7bdb9b6b3b2b0b4b3b0b5b4b2b4b4b1b4b3b1b4b3b1b4b3b0b6ada5aa8670a57a62ad8e7ab29b8cb69d8dab856fa9826aa88069ab8771af907db49987b19684b29886b59987b39480b09787b5a9a1bcb8b5bebab7bdb9b5bebab7bfbbb8bfbbb7bbb7b4b3b2afb8b7b5b8b7b5b3b2b0b5b4b2b6b5b3b6b4b1afa299a98975a9826baf907cb39988b49a89af8e7aac8973aa856eaf8c74b1917dae907dac907db39988b29785b49785b7a090b9aca3bfbab7bcb8b5bdb9b6bcb8b4bcb8b5bdb9b5bcb8b4b5b4b2b6b5b3b4b3b0b4b3b0b9b8b5b8b6b4908b88887467aa8f7ea78976ad8973b08b74b59885b69e8eb29888b1917cb1917db1937fae907cb19686b39a8ab29886b59b8ab8a192b6aaa3b7b2afbcb8b4bcb8b5bbb7b4c0bcb9bebab7c0bcb9b6b5b2b6b5b3b4b3b0bab9b7b7b6b4b1b0ae7b716ba083709b806f716158967764b08870b29481b69b8ab69f8fb39a89b69f90b49d8db39a89b29988b49c8cb6a090b8a496baa49593867f8f8986bfbbb7bdb9b5bcb7b4bab6b3b9b5b2bab6b2b4b3b1b3b3b0b6b5b3b8b7b5b4b2b0a7a5a38f837dae917ea084725a504c63544da28370b39784b59e8db2a093a698909b918b998e8790857e95877dad998bb39c8cb5a091b9a2938d827c95908dbebab6bbb7b3bdbab7bbb7b4bdb9b6bbb7b4b4b3b0b5b4b1b8b7b5b6b5b3b8b8b5b4b2af968f8ab29a8bab9485544b483a323073655d96887f70655f61595547403e453e3c453f3d57504f655e5b90847db39c8db7a090b6a09189807aaba6a3bdb9b6c0bcb9bebab7bcb7b4bebab7bbb7b4b3b2b0b6b5b3b2b1afb7b6b4b8b7b4b5b4b1aeaba8b5a89fac998d4d44412d25244d46444e4744322b293a3230423937433a37352d2a59504c534b48524a48988a81b59f8fb19c8d827974b2afacbdb9b5bcb8b4bdb9b5bcb8b5bdb9b6bab6b2b8b7b5b5b4b2b6b6b3b9b8b5b7b6b3b6b5b2b8b6b3b9b4b1b2a9a26c64612d25242d2625312a28352d2c453d3a78675c8d7a6ea09792aea6a0615854332b29524a479f8e82b09d90a49b96c1bdb9bebab7bfbbb8bbb8b4b9b5b1b8b4b0b9b4b0b7b6b4b8b7b5b8b7b4b6b5b3b8b6b3bab9b6b9b8b5b4b3b0b7b5b2a5a29f453d3b261e1d261f1e2e2625413936857268977865b19482b5a69caca5a07c7572453d3b746963a0948cc5bfbbc0bbb8beb9b6bbb7b3bbb6b3b7b3afb8b4b0b9b5b1b7b6b3b6b5b3b5b4b2b5b4b2b7b6b3b7b6b3b8b6b3b4b2afb7b6b3b3b1ae6d6765251f1e1e18172a22212d2523443b3971625ab19888b09482a89182877e792c25243e3634766d6abeb9b5bfbbb7bebab6bcb7b3bbb6b3b9b5b1b7b3afb8b4b0b4b3b0b5b4b1b5b4b1b4b3b1b5b4b2b8b6b4b5b3b0b9b6b4b5b4b1b6b4b27f79762a2322221c1b2d2524221b1a443e3c47413f6f676281766f867971675e5a3e37352a222166605dbab7b3bdb9b5beb9b5bcb7b3bcb7b3b9b4b0bab6b2bab6b2b5b3b0b6b4b2b3b2afb7b6b3b4b4b1b4b3b0b6b4b1b5b4b1b4b3b0b9b6b29a8c8252474230292828201f181212322c2c231e1d1c16162c26252923222d26252d2523332b2a8e8885bcb8b5bcb7b3bbb6b2bcb7b3b9b4b1b9b5b1b7b2afb7b2ae7a838e9b9b9caeadacb3b2b0b3b2afb7b7b4b6b5b3b6b6b3b7b6b3b9ada4a991808e7b6f50453f2b24231a14142923221f19181d17161f18182620201d17162a22215d5654b7b3b0bbb7b3bbb6b2b8b4b0bab5b1bbb6b2bab5b1b8b4b0bab6b22c496b4c5d735f68766e727a828285929090adaba8b7b2aeb6a59ab39682a28470a387748e76674e403a1a14141d1716181211221c1c1f1918221c1b2f2827342d2c8d8884bab6b3b9b5b2bab5b1bab5b1b9b4b0bab6b2b8b4b0b9b4b0b7b2ae325e8b365f8a3a5d833f5b7a545f70646469706b6aa08f84b08e78b18e769f7e689e7f6b9e816d907766584940362d2a1c1615201b1a1a1413201a1a251e1d393331a39e9bbab5b1bcb7b3bab6b2b8b3afb8b4b0b9b4b0b9b4b1bab5b2b5b0ac3d6c9843729d44719c426e98415f805a64716f6a699d8677b1927eb3947faa89749d7a649f7f6ba487749e837186716454463f2c25231e181837302e3a33317a7471beb9b6bcb8b4bbb6b2b6b2aebab5b1b9b5b1b8b3afbab6b2b6b1adb5aeaa4877a14c7aa44e7ba345719a3a5d80586b7f767475927b6eb1927faf8e79b08e78a78169a07861a17f6aa58570a688749b83738270666f66618a8480a49e99b7b2aebab6b2bcb8b4b9b5b1b7b2aebab5b1b9b4b0b6b1aeb6b1adb2aca8b2aca84876a04a78a2517fa74771973a5d80405c7a6161677c695fac8a75b08d77b4917aaf8971ad876fa5816aa6846ea78670a98a76ac9484ab9f96b2aca8bdb8b4bcb7b3bcb8b4bcb8b4b8b3afb7b2aeb9b4b0b8b3afb8b2aeb6afabb3aeaab2aeaa4878a14b7aa34c7ba44a759b3d63873b5f825b67766f5f569c7e6caf8c77b18f79b28f78b5927caf8e78a98872aa8a76a98a76ac917fada199b7b0acb9b3afbfb9b5c1bab6bdb6b2b8b3afbab5b1b9b4b0b6afabb7b1adb3ada9b3aeaab0aba8";
9
+ const WIDTH = 32;
10
+ const HEIGHT = 32;
11
+ function parseImage() {
12
+ const pixels = [];
13
+ for (let y = 0; y < HEIGHT; y++) {
14
+ const row = [];
15
+ for (let x = 0; x < WIDTH; x++) {
16
+ const idx = (y * WIDTH + x) * 6;
17
+ const r = parseInt(DAX_HEX.slice(idx, idx + 2), 16);
18
+ const g = parseInt(DAX_HEX.slice(idx + 2, idx + 4), 16);
19
+ const b = parseInt(DAX_HEX.slice(idx + 4, idx + 6), 16);
20
+ row.push([r, g, b]);
21
+ }
22
+ pixels.push(row);
23
+ }
24
+ return pixels;
25
+ }
26
+ function rgb(r, g, b, bg = false) {
27
+ return `\x1b[${bg ? 48 : 38};2;${r};${g};${b}m`;
28
+ }
29
+ const RESET = "\x1b[0m";
30
+ function buildImage() {
31
+ const pixels = parseImage();
32
+ const lines = [];
33
+ // Use half-block chars: ▄ with bg=top pixel, fg=bottom pixel
34
+ for (let row = 0; row < HEIGHT; row += 2) {
35
+ let line = "";
36
+ for (let x = 0; x < WIDTH; x++) {
37
+ const top = pixels[row][x];
38
+ const bottom = pixels[row + 1]?.[x] ?? top;
39
+ line += `${rgb(bottom[0], bottom[1], bottom[2])}${rgb(top[0], top[1], top[2], true)}▄`;
40
+ }
41
+ line += RESET;
42
+ lines.push(line);
43
+ }
44
+ return lines;
45
+ }
46
+ export class DaxnutsComponent {
47
+ constructor(ui) {
48
+ this.interval = null;
49
+ this.tick = 0;
50
+ this.maxTicks = 25; // ~2 seconds at 80ms
51
+ this.cachedLines = [];
52
+ this.cachedWidth = 0;
53
+ this.cachedTick = -1;
54
+ this.ui = ui;
55
+ this.image = buildImage();
56
+ this.startAnimation();
57
+ }
58
+ invalidate() {
59
+ this.cachedWidth = 0;
60
+ }
61
+ startAnimation() {
62
+ this.interval = setInterval(() => {
63
+ this.tick++;
64
+ if (this.tick >= this.maxTicks) {
65
+ this.stopAnimation();
66
+ }
67
+ this.cachedWidth = 0;
68
+ this.ui.requestRender();
69
+ }, 80);
70
+ }
71
+ stopAnimation() {
72
+ if (this.interval) {
73
+ clearInterval(this.interval);
74
+ this.interval = null;
75
+ }
76
+ }
77
+ render(width) {
78
+ if (width === this.cachedWidth && this.cachedTick === this.tick) {
79
+ return this.cachedLines;
80
+ }
81
+ const t = theme;
82
+ const lines = [];
83
+ const center = (s) => {
84
+ const visible = s.replace(/\x1b\[[0-9;]*m/g, "").length;
85
+ const left = Math.max(0, Math.floor((width - visible) / 2));
86
+ return " ".repeat(left) + s;
87
+ };
88
+ lines.push("");
89
+ // Scanline reveal effect: show rows progressively
90
+ const revealedRows = Math.min(this.image.length, Math.floor((this.tick / this.maxTicks) * (this.image.length + 3)));
91
+ for (let i = 0; i < this.image.length; i++) {
92
+ if (i < revealedRows) {
93
+ lines.push(center(this.image[i]));
94
+ }
95
+ else {
96
+ // Show scan line
97
+ if (i === revealedRows) {
98
+ const scanline = "▓".repeat(WIDTH);
99
+ lines.push(center(rgb(100, 200, 255) + scanline + RESET));
100
+ }
101
+ else {
102
+ lines.push(center(" ".repeat(WIDTH)));
103
+ }
104
+ }
105
+ }
106
+ lines.push("");
107
+ // Fade in text after image is revealed
108
+ const textPhase = Math.max(0, this.tick - this.maxTicks * 0.6);
109
+ if (textPhase > 0 || this.tick >= this.maxTicks) {
110
+ lines.push(center(t.fg("accent", "Free Kimi K2.5 via OpenCode Zen")));
111
+ lines.push(center(t.fg("success", '"Powered by daxnuts"')));
112
+ lines.push(center(t.fg("muted", "— @thdxr")));
113
+ }
114
+ else {
115
+ lines.push("");
116
+ lines.push("");
117
+ lines.push("");
118
+ }
119
+ lines.push("");
120
+ if (textPhase > 2 || this.tick >= this.maxTicks) {
121
+ lines.push(center(t.fg("dim", "Try OpenCode")));
122
+ lines.push(center(t.fg("mdLink", "https://mistral.ai/news/mistral-vibe-2-0")));
123
+ }
124
+ else {
125
+ lines.push("");
126
+ lines.push("");
127
+ }
128
+ lines.push("");
129
+ this.cachedLines = lines;
130
+ this.cachedWidth = width;
131
+ this.cachedTick = this.tick;
132
+ return lines;
133
+ }
134
+ dispose() {
135
+ this.stopAnimation();
136
+ }
137
+ }
@@ -0,0 +1,11 @@
1
+ export interface RenderDiffOptions {
2
+ /** File path (unused, kept for API compatibility) */
3
+ filePath?: string;
4
+ }
5
+ /**
6
+ * Render a diff string with colored lines and intra-line change highlighting.
7
+ * - Context lines: dim/gray
8
+ * - Removed lines: red, with inverse on changed tokens
9
+ * - Added lines: green, with inverse on changed tokens
10
+ */
11
+ export declare function renderDiff(diffText: string, _options?: RenderDiffOptions): string;
@@ -0,0 +1,132 @@
1
+ import * as Diff from "diff";
2
+ import { theme } from "../theme/theme.js";
3
+ /**
4
+ * Parse diff line to extract prefix, line number, and content.
5
+ * Format: "+123 content" or "-123 content" or " 123 content" or " ..."
6
+ */
7
+ function parseDiffLine(line) {
8
+ const match = line.match(/^([+-\s])(\s*\d*)\s(.*)$/);
9
+ if (!match)
10
+ return null;
11
+ return { prefix: match[1], lineNum: match[2], content: match[3] };
12
+ }
13
+ /**
14
+ * Replace tabs with spaces for consistent rendering.
15
+ */
16
+ function replaceTabs(text) {
17
+ return text.replace(/\t/g, " ");
18
+ }
19
+ /**
20
+ * Compute word-level diff and render with inverse on changed parts.
21
+ * Uses diffWords which groups whitespace with adjacent words for cleaner highlighting.
22
+ * Strips leading whitespace from inverse to avoid highlighting indentation.
23
+ */
24
+ function renderIntraLineDiff(oldContent, newContent) {
25
+ const wordDiff = Diff.diffWords(oldContent, newContent);
26
+ let removedLine = "";
27
+ let addedLine = "";
28
+ let isFirstRemoved = true;
29
+ let isFirstAdded = true;
30
+ for (const part of wordDiff) {
31
+ if (part.removed) {
32
+ let value = part.value;
33
+ // Strip leading whitespace from the first removed part
34
+ if (isFirstRemoved) {
35
+ const leadingWs = value.match(/^(\s*)/)?.[1] || "";
36
+ value = value.slice(leadingWs.length);
37
+ removedLine += leadingWs;
38
+ isFirstRemoved = false;
39
+ }
40
+ if (value) {
41
+ removedLine += theme.inverse(value);
42
+ }
43
+ }
44
+ else if (part.added) {
45
+ let value = part.value;
46
+ // Strip leading whitespace from the first added part
47
+ if (isFirstAdded) {
48
+ const leadingWs = value.match(/^(\s*)/)?.[1] || "";
49
+ value = value.slice(leadingWs.length);
50
+ addedLine += leadingWs;
51
+ isFirstAdded = false;
52
+ }
53
+ if (value) {
54
+ addedLine += theme.inverse(value);
55
+ }
56
+ }
57
+ else {
58
+ removedLine += part.value;
59
+ addedLine += part.value;
60
+ }
61
+ }
62
+ return { removedLine, addedLine };
63
+ }
64
+ /**
65
+ * Render a diff string with colored lines and intra-line change highlighting.
66
+ * - Context lines: dim/gray
67
+ * - Removed lines: red, with inverse on changed tokens
68
+ * - Added lines: green, with inverse on changed tokens
69
+ */
70
+ export function renderDiff(diffText, _options = {}) {
71
+ const lines = diffText.split("\n");
72
+ const result = [];
73
+ let i = 0;
74
+ while (i < lines.length) {
75
+ const line = lines[i];
76
+ const parsed = parseDiffLine(line);
77
+ if (!parsed) {
78
+ result.push(theme.fg("toolDiffContext", line));
79
+ i++;
80
+ continue;
81
+ }
82
+ if (parsed.prefix === "-") {
83
+ // Collect consecutive removed lines
84
+ const removedLines = [];
85
+ while (i < lines.length) {
86
+ const p = parseDiffLine(lines[i]);
87
+ if (!p || p.prefix !== "-")
88
+ break;
89
+ removedLines.push({ lineNum: p.lineNum, content: p.content });
90
+ i++;
91
+ }
92
+ // Collect consecutive added lines
93
+ const addedLines = [];
94
+ while (i < lines.length) {
95
+ const p = parseDiffLine(lines[i]);
96
+ if (!p || p.prefix !== "+")
97
+ break;
98
+ addedLines.push({ lineNum: p.lineNum, content: p.content });
99
+ i++;
100
+ }
101
+ // Only do intra-line diffing when there's exactly one removed and one added line
102
+ // (indicating a single line modification). Otherwise, show lines as-is.
103
+ if (removedLines.length === 1 && addedLines.length === 1) {
104
+ const removed = removedLines[0];
105
+ const added = addedLines[0];
106
+ const { removedLine, addedLine } = renderIntraLineDiff(replaceTabs(removed.content), replaceTabs(added.content));
107
+ result.push(theme.fg("toolDiffRemoved", `-${removed.lineNum} ${removedLine}`));
108
+ result.push(theme.fg("toolDiffAdded", `+${added.lineNum} ${addedLine}`));
109
+ }
110
+ else {
111
+ // Show all removed lines first, then all added lines
112
+ for (const removed of removedLines) {
113
+ result.push(theme.fg("toolDiffRemoved", `-${removed.lineNum} ${replaceTabs(removed.content)}`));
114
+ }
115
+ for (const added of addedLines) {
116
+ result.push(theme.fg("toolDiffAdded", `+${added.lineNum} ${replaceTabs(added.content)}`));
117
+ }
118
+ }
119
+ }
120
+ else if (parsed.prefix === "+") {
121
+ // Standalone added line
122
+ result.push(theme.fg("toolDiffAdded", `+${parsed.lineNum} ${replaceTabs(parsed.content)}`));
123
+ i++;
124
+ }
125
+ else {
126
+ // Context line
127
+ result.push(theme.fg("toolDiffContext", ` ${parsed.lineNum} ${replaceTabs(parsed.content)}`));
128
+ i++;
129
+ }
130
+ }
131
+ return result.join("\n");
132
+ }
@@ -0,0 +1,14 @@
1
+ import type { Component } from "@earendil-works/pi-tui";
2
+ /**
3
+ * Dynamic border component that adjusts to viewport width.
4
+ *
5
+ * Note: When used from extensions loaded via jiti, the global `theme` may be undefined
6
+ * because jiti creates a separate module cache. Always pass an explicit color
7
+ * function when using DynamicBorder in components exported for extension use.
8
+ */
9
+ export declare class DynamicBorder implements Component {
10
+ private color;
11
+ constructor(color?: (str: string) => string);
12
+ invalidate(): void;
13
+ render(width: number): string[];
14
+ }
@@ -0,0 +1,19 @@
1
+ import { theme } from "../theme/theme.js";
2
+ /**
3
+ * Dynamic border component that adjusts to viewport width.
4
+ *
5
+ * Note: When used from extensions loaded via jiti, the global `theme` may be undefined
6
+ * because jiti creates a separate module cache. Always pass an explicit color
7
+ * function when using DynamicBorder in components exported for extension use.
8
+ */
9
+ export class DynamicBorder {
10
+ constructor(color = (str) => theme.fg("border", str)) {
11
+ this.color = color;
12
+ }
13
+ invalidate() {
14
+ // No cached state to invalidate currently
15
+ }
16
+ render(width) {
17
+ return [this.color("─".repeat(Math.max(1, width)))];
18
+ }
19
+ }
@@ -0,0 +1,4 @@
1
+ import { Container } from "@earendil-works/pi-tui";
2
+ export declare class EarendilAnnouncementComponent extends Container {
3
+ constructor();
4
+ }
@@ -0,0 +1,39 @@
1
+ import * as fs from "node:fs";
2
+ import { Container, Image, Spacer, Text } from "@earendil-works/pi-tui";
3
+ import { getBundledInteractiveAssetPath } from "../../../config.js";
4
+ import { theme } from "../theme/theme.js";
5
+ import { DynamicBorder } from "./dynamic-border.js";
6
+ const BLOG_URL = "https://mariozechner.at/posts/2026-04-08-ive-sold-out/";
7
+ const IMAGE_FILENAME = "clankolas.png";
8
+ let cachedImageBase64;
9
+ let attemptedImageLoad = false;
10
+ function loadImageBase64() {
11
+ if (attemptedImageLoad) {
12
+ return cachedImageBase64;
13
+ }
14
+ attemptedImageLoad = true;
15
+ try {
16
+ cachedImageBase64 = fs.readFileSync(getBundledInteractiveAssetPath(IMAGE_FILENAME)).toString("base64");
17
+ }
18
+ catch {
19
+ cachedImageBase64 = undefined;
20
+ }
21
+ return cachedImageBase64;
22
+ }
23
+ export class EarendilAnnouncementComponent extends Container {
24
+ constructor() {
25
+ super();
26
+ this.addChild(new DynamicBorder((text) => theme.fg("accent", text)));
27
+ this.addChild(new Text(theme.bold(theme.fg("accent", "Welcome to Pizza")), 1, 0));
28
+ this.addChild(new Spacer(1));
29
+ this.addChild(new Text(theme.fg("muted", "Read the blog post:"), 1, 0));
30
+ this.addChild(new Text(theme.fg("mdLink", BLOG_URL), 1, 0));
31
+ this.addChild(new Spacer(1));
32
+ const imageBase64 = loadImageBase64();
33
+ if (imageBase64) {
34
+ this.addChild(new Image(imageBase64, "image/png", { fallbackColor: (text) => theme.fg("muted", text) }, { maxWidthCells: 56, filename: IMAGE_FILENAME }));
35
+ this.addChild(new Spacer(1));
36
+ }
37
+ this.addChild(new DynamicBorder((text) => theme.fg("accent", text)));
38
+ }
39
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Multi-line editor component for extensions.
3
+ * Supports Ctrl+G for external editor.
4
+ */
5
+ import { Container, type EditorOptions, type Focusable, type TUI } from "@earendil-works/pi-tui";
6
+ import type { KeybindingsManager } from "../../../core/keybindings.js";
7
+ export declare class ExtensionEditorComponent extends Container implements Focusable {
8
+ private editor;
9
+ private onSubmitCallback;
10
+ private onCancelCallback;
11
+ private tui;
12
+ private keybindings;
13
+ private _focused;
14
+ get focused(): boolean;
15
+ set focused(value: boolean);
16
+ constructor(tui: TUI, keybindings: KeybindingsManager, title: string, prefill: string | undefined, onSubmit: (value: string) => void, onCancel: () => void, options?: EditorOptions);
17
+ handleInput(keyData: string): void;
18
+ private openExternalEditor;
19
+ }