@pi-unipi/unipi 3.0.0-alpha.2 → 3.0.0-alpha.21

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 (359) hide show
  1. package/CHANGELOG.md +292 -0
  2. package/README.md +8 -11
  3. package/docs/prefix-cache-architecture.md +14 -0
  4. package/package.json +22 -24
  5. package/packages/ask-user/README.md +55 -107
  6. package/packages/ask-user/ask-ui.ts +306 -732
  7. package/packages/ask-user/clipboard.ts +50 -0
  8. package/packages/ask-user/config.ts +74 -78
  9. package/packages/ask-user/package.json +2 -2
  10. package/packages/ask-user/questions.ts +151 -0
  11. package/packages/ask-user/skills/ask-user/SKILL.md +59 -133
  12. package/packages/ask-user/tools.ts +198 -432
  13. package/packages/autocomplete/package.json +1 -1
  14. package/packages/autocomplete/src/constants.ts +38 -43
  15. package/packages/autocomplete/src/sorting.ts +8 -0
  16. package/packages/background-tasks/package.json +2 -2
  17. package/packages/background-tasks/src/config.ts +0 -73
  18. package/packages/background-tasks/src/index.ts +20 -16
  19. package/packages/background-tasks/src/registry.ts +1 -171
  20. package/packages/background-tasks/src/types.ts +0 -32
  21. package/packages/btw/README.md +13 -56
  22. package/packages/btw/extensions/btw.ts +403 -1796
  23. package/packages/btw/package.json +5 -2
  24. package/packages/btw/skills/btw/SKILL.md +7 -143
  25. package/packages/compactor/README.md +56 -287
  26. package/packages/compactor/package.json +5 -9
  27. package/packages/compactor/skills/compactor/SKILL.md +13 -20
  28. package/packages/compactor/src/card.ts +90 -0
  29. package/packages/compactor/src/commands/index.ts +73 -130
  30. package/packages/compactor/src/compaction/compact-args.ts +5 -3
  31. package/packages/compactor/src/compaction/filter-noise.ts +1 -1
  32. package/packages/compactor/src/compaction/hooks.ts +487 -311
  33. package/packages/compactor/src/compaction/source.ts +178 -0
  34. package/packages/compactor/src/compaction/summarize.ts +586 -52
  35. package/packages/compactor/src/config/manager.ts +130 -127
  36. package/packages/compactor/src/config/schema.ts +32 -48
  37. package/packages/compactor/src/index.ts +40 -431
  38. package/packages/compactor/src/info-screen.ts +44 -190
  39. package/packages/compactor/src/session/recall-blocks.ts +1 -1
  40. package/packages/compactor/src/stats.ts +76 -0
  41. package/packages/compactor/src/tools/context-budget.ts +17 -34
  42. package/packages/compactor/src/tools/ctx-doctor.ts +45 -36
  43. package/packages/compactor/src/tools/register.ts +29 -269
  44. package/packages/compactor/src/types.ts +47 -186
  45. package/packages/core/README.md +25 -0
  46. package/packages/core/child-agent.ts +1 -0
  47. package/packages/core/command-echo.ts +63 -0
  48. package/packages/core/compaction-context.ts +41 -0
  49. package/packages/core/constants.ts +8 -38
  50. package/packages/core/events.ts +0 -53
  51. package/packages/core/fusion-status.ts +4 -0
  52. package/packages/core/global.d.ts +10 -0
  53. package/packages/core/harness-messages.ts +392 -0
  54. package/packages/core/index.ts +14 -0
  55. package/packages/core/kanboard-status.ts +49 -0
  56. package/packages/core/long-horizon-owner-status.ts +46 -0
  57. package/packages/core/model-cache.ts +81 -7
  58. package/packages/core/package.json +6 -3
  59. package/packages/core/src/attach/detect.ts +163 -0
  60. package/packages/core/src/child-agent/child-args.ts +31 -0
  61. package/packages/core/src/child-agent/delivery.ts +41 -0
  62. package/packages/core/src/child-agent/index.ts +5 -0
  63. package/packages/core/src/child-agent/readers.ts +203 -0
  64. package/packages/core/src/child-agent/runtime.ts +584 -0
  65. package/packages/core/src/evidence.ts +78 -0
  66. package/packages/core/src/hints/browser.ts +278 -0
  67. package/packages/core/src/hints/crab-data.ts +19 -0
  68. package/packages/core/src/hints/index.ts +865 -0
  69. package/packages/core/src/hints/lines.ts +607 -0
  70. package/packages/core/src/hints/store.ts +120 -0
  71. package/packages/core/src/jev/chatter.ts +24 -0
  72. package/packages/core/src/jev/settings.ts +177 -14
  73. package/packages/core/src/package-colors.ts +2 -0
  74. package/packages/core/src/settings/catalog.ts +39 -15
  75. package/packages/core/src/settings/engine.ts +48 -2
  76. package/packages/core/src/settings/hub.ts +83 -20
  77. package/packages/core/src/settings/open.ts +49 -0
  78. package/packages/core/src/settings/schema.ts +27 -7
  79. package/packages/core/src/tui/hub-kit.ts +18 -5
  80. package/packages/core/src/tui/kit.ts +198 -0
  81. package/packages/core/src/tui/progress.ts +73 -0
  82. package/packages/core/src/turn/arbiter.ts +290 -0
  83. package/packages/footer/README.md +4 -6
  84. package/packages/footer/package.json +3 -3
  85. package/packages/footer/src/glance-editor.ts +19 -11
  86. package/packages/footer/src/help.ts +1 -1
  87. package/packages/footer/src/index.ts +36 -3
  88. package/packages/footer/src/presets.ts +3 -4
  89. package/packages/footer/src/rendering/icons.ts +0 -20
  90. package/packages/footer/src/segments/compactor.ts +52 -142
  91. package/packages/footer/src/segments/status-ext.ts +0 -1
  92. package/packages/fusion/README.md +14 -4
  93. package/packages/fusion/package.json +4 -3
  94. package/packages/fusion/src/child-args.ts +1 -0
  95. package/packages/fusion/src/index.ts +161 -8
  96. package/packages/fusion/src/pi-settings.ts +57 -0
  97. package/packages/fusion/src/picker.ts +186 -51
  98. package/packages/fusion/src/preset.ts +56 -2
  99. package/packages/fusion/src/prompts.ts +1 -1
  100. package/packages/fusion/src/sidekick-runtime.ts +1 -420
  101. package/packages/fusion/src/tools.ts +107 -128
  102. package/packages/fusion/src/transcript.ts +27 -85
  103. package/packages/info-screen/package.json +2 -2
  104. package/packages/input-shortcuts/README.md +18 -30
  105. package/packages/input-shortcuts/package.json +2 -2
  106. package/packages/input-shortcuts/src/burst.ts +88 -0
  107. package/packages/input-shortcuts/src/chord-overlay.ts +20 -70
  108. package/packages/input-shortcuts/src/cleared-input.ts +97 -0
  109. package/packages/input-shortcuts/src/index.ts +99 -193
  110. package/packages/input-shortcuts/src/last-response.ts +40 -0
  111. package/packages/input-shortcuts/src/registers.ts +8 -23
  112. package/packages/input-shortcuts/src/types.ts +4 -16
  113. package/packages/input-shortcuts/src/undo-redo.ts +59 -47
  114. package/packages/kanboard/README.md +51 -47
  115. package/packages/kanboard/index.ts +293 -55
  116. package/packages/kanboard/package.json +8 -8
  117. package/packages/kanboard/skills/kanboard/SKILL.md +61 -27
  118. package/packages/kanboard/src/badges.ts +93 -0
  119. package/packages/kanboard/src/bin.ts +4 -2
  120. package/packages/kanboard/src/commands.ts +218 -84
  121. package/packages/kanboard/src/debug.ts +20 -0
  122. package/packages/kanboard/src/guard.ts +267 -109
  123. package/packages/kanboard/src/monitor.ts +330 -0
  124. package/packages/kanboard/src/notice-buffer.ts +74 -0
  125. package/packages/kanboard/src/progress.ts +27 -0
  126. package/packages/kanboard/src/reminders.ts +234 -0
  127. package/packages/kanboard/src/settings.ts +69 -15
  128. package/packages/kanboard/src/shapes.ts +5 -0
  129. package/packages/long-horizon/index.ts +190 -13
  130. package/packages/long-horizon/package.json +3 -3
  131. package/packages/long-horizon/src/commands.ts +103 -7
  132. package/packages/long-horizon/src/compaction-brief.ts +35 -0
  133. package/packages/long-horizon/src/engine/continuation.ts +84 -15
  134. package/packages/long-horizon/src/engine/goal-state.ts +64 -13
  135. package/packages/long-horizon/src/engine/nudge-stash.ts +71 -0
  136. package/packages/long-horizon/src/engine/ralph.ts +3 -2
  137. package/packages/long-horizon/src/engine/runaway.ts +68 -11
  138. package/packages/long-horizon/src/engine/verifier.ts +19 -0
  139. package/packages/long-horizon/src/gate.ts +37 -12
  140. package/packages/long-horizon/src/judge/resolve.ts +1 -0
  141. package/packages/long-horizon/src/owner.ts +35 -2
  142. package/packages/long-horizon/src/progress.ts +87 -0
  143. package/packages/long-horizon/src/prompts/goal.ts +1 -1
  144. package/packages/long-horizon/src/runtime.ts +172 -18
  145. package/packages/long-horizon/src/settings.ts +54 -39
  146. package/packages/long-horizon/src/tools/goal.ts +6 -0
  147. package/packages/long-horizon/src/tools/graph.ts +1 -1
  148. package/packages/long-horizon/src/tools/swarm.ts +3 -3
  149. package/packages/mcp/package.json +2 -2
  150. package/packages/memory/commands.ts +7 -2
  151. package/packages/memory/index.ts +210 -32
  152. package/packages/memory/package.json +3 -3
  153. package/packages/memory/save-session.ts +264 -0
  154. package/packages/memory/settings.ts +17 -0
  155. package/packages/memory/tools.ts +253 -203
  156. package/packages/notify/package.json +2 -2
  157. package/packages/skill-registry/README.md +53 -16
  158. package/packages/skill-registry/index.ts +230 -0
  159. package/packages/skill-registry/package.json +19 -8
  160. package/packages/skill-registry/src/editor.ts +206 -0
  161. package/packages/skill-registry/src/judge.ts +289 -0
  162. package/packages/skill-registry/src/registry.ts +87 -0
  163. package/packages/skill-registry/src/settings.ts +259 -0
  164. package/packages/skill-registry/src/vault.ts +80 -0
  165. package/packages/subagents/README.md +39 -119
  166. package/packages/subagents/package.json +6 -13
  167. package/packages/subagents/skills/subagents/SKILL.md +18 -42
  168. package/packages/subagents/src/agents.ts +213 -0
  169. package/packages/subagents/src/cards.ts +182 -0
  170. package/packages/subagents/src/index.ts +609 -1084
  171. package/packages/subagents/src/manager.ts +429 -0
  172. package/packages/subagents/src/profiles.ts +130 -0
  173. package/packages/subagents/src/transcript.ts +154 -0
  174. package/packages/subagents/src/ui.ts +389 -0
  175. package/packages/unipi/bundled.js +39756 -45569
  176. package/packages/unipi/index.ts +55 -10
  177. package/packages/updater/package.json +2 -2
  178. package/packages/utility/README.md +76 -69
  179. package/packages/utility/package.json +2 -2
  180. package/packages/utility/skills/image/SKILL.md +37 -0
  181. package/packages/utility/skills/utility/SKILL.md +17 -60
  182. package/packages/utility/src/answer/extract.ts +128 -0
  183. package/packages/utility/src/answer/index.ts +213 -0
  184. package/packages/utility/src/answer/reply.ts +133 -0
  185. package/packages/utility/src/answer/web.ts +167 -0
  186. package/packages/utility/src/attach/index.ts +205 -0
  187. package/packages/utility/src/commands.ts +38 -142
  188. package/packages/utility/src/diagnostics/engine.ts +50 -5
  189. package/packages/utility/src/image/index.ts +33 -0
  190. package/packages/utility/src/image/models.ts +221 -0
  191. package/packages/{image/src → utility/src/image}/recognize.ts +2 -2
  192. package/packages/utility/src/image/settings.ts +178 -0
  193. package/packages/{image/src/image-source.ts → utility/src/image/source.ts} +1 -1
  194. package/packages/utility/src/image/tools.ts +168 -0
  195. package/packages/utility/src/image/transports.ts +186 -0
  196. package/packages/utility/src/index.ts +68 -389
  197. package/packages/utility/src/lifecycle/cleanup.ts +116 -311
  198. package/packages/utility/src/rename/gate.ts +102 -0
  199. package/packages/utility/src/rename/index.ts +191 -0
  200. package/packages/utility/src/rename/session.ts +170 -0
  201. package/packages/utility/src/render/delegated.ts +285 -0
  202. package/packages/utility/src/render/harness.ts +683 -0
  203. package/packages/utility/src/render/parse.ts +156 -0
  204. package/packages/utility/src/render/pi-settings.ts +38 -0
  205. package/packages/utility/src/render/reply-bg.ts +307 -0
  206. package/packages/utility/src/render/simple.ts +724 -0
  207. package/packages/utility/src/render/spacing.ts +235 -0
  208. package/packages/utility/src/render/styled.ts +251 -0
  209. package/packages/utility/src/render/tools.ts +353 -0
  210. package/packages/utility/src/settings.ts +166 -233
  211. package/packages/utility/src/types.ts +1 -222
  212. package/packages/watchdog/index.ts +17 -6
  213. package/packages/watchdog/package.json +3 -3
  214. package/packages/watchdog/src/config.ts +3 -2
  215. package/packages/web-api/package.json +2 -2
  216. package/packages/workflow/README.md +3 -0
  217. package/packages/workflow/index.ts +0 -2
  218. package/packages/workflow/package.json +2 -2
  219. package/packages/workflow/src/permission/decide.ts +6 -4
  220. package/packages/workflow/src/permission/index.ts +17 -7
  221. package/packages/workflow/src/permission/settings.ts +39 -4
  222. package/packages/workflow/src/plan/index.ts +19 -4
  223. package/packages/background-tasks/extensions/delegate-child.ts +0 -1
  224. package/packages/background-tasks/src/context-parent-snapshot.ts +0 -142
  225. package/packages/background-tasks/src/context-token-budget.ts +0 -903
  226. package/packages/background-tasks/src/context-visible-conversation-v2.ts +0 -551
  227. package/packages/background-tasks/src/delegate/artifacts.ts +0 -487
  228. package/packages/background-tasks/src/delegate/budget.ts +0 -415
  229. package/packages/background-tasks/src/delegate/hook-contract-evidence.json +0 -18
  230. package/packages/background-tasks/src/delegate/hook-contract.ts +0 -154
  231. package/packages/background-tasks/src/delegate/launch.ts +0 -484
  232. package/packages/background-tasks/src/delegate/result-package.ts +0 -459
  233. package/packages/background-tasks/src/delegate/runner.ts +0 -430
  234. package/packages/background-tasks/src/delegate/seed.ts +0 -423
  235. package/packages/background-tasks/src/delegate/types.ts +0 -323
  236. package/packages/background-tasks/src/delegate-child-extension.ts +0 -978
  237. package/packages/background-tasks/src/delegate-extension.ts +0 -654
  238. package/packages/background-tasks/src/fixtures/delegate-context-incident.json +0 -17
  239. package/packages/compactor/skills/compactor-detail/SKILL.md +0 -116
  240. package/packages/compactor/skills/compactor-doctor/SKILL.md +0 -71
  241. package/packages/compactor/skills/compactor-stats/SKILL.md +0 -51
  242. package/packages/compactor/src/compaction/build-sections.ts +0 -76
  243. package/packages/compactor/src/compaction/extract/goals.ts +0 -36
  244. package/packages/compactor/src/compaction/extract/preferences.ts +0 -40
  245. package/packages/compactor/src/compaction/format.ts +0 -53
  246. package/packages/compactor/src/compaction/merge.ts +0 -143
  247. package/packages/compactor/src/config/presets.ts +0 -160
  248. package/packages/compactor/src/executor/executor.ts +0 -233
  249. package/packages/compactor/src/executor/runtime.ts +0 -115
  250. package/packages/compactor/src/security/evaluator.ts +0 -89
  251. package/packages/compactor/src/security/policy.ts +0 -96
  252. package/packages/compactor/src/security/scanner.ts +0 -65
  253. package/packages/compactor/src/session/auto-inject.ts +0 -60
  254. package/packages/compactor/src/session/db.ts +0 -325
  255. package/packages/compactor/src/session/extract.ts +0 -144
  256. package/packages/compactor/src/session/resume-inject.ts +0 -64
  257. package/packages/compactor/src/session/snapshot.ts +0 -327
  258. package/packages/compactor/src/tools/ctx-batch-execute.ts +0 -41
  259. package/packages/compactor/src/tools/ctx-execute-file.ts +0 -23
  260. package/packages/compactor/src/tools/ctx-execute.ts +0 -23
  261. package/packages/compactor/src/tools/ctx-stats.ts +0 -96
  262. package/packages/image/README.md +0 -99
  263. package/packages/image/package.json +0 -61
  264. package/packages/image/skills/image/SKILL.md +0 -76
  265. package/packages/image/src/generate.ts +0 -256
  266. package/packages/image/src/index.ts +0 -135
  267. package/packages/image/src/models.ts +0 -519
  268. package/packages/image/src/openai-images-api.ts +0 -282
  269. package/packages/image/src/register-providers.ts +0 -209
  270. package/packages/image/src/settings.ts +0 -173
  271. package/packages/image/src/tools.ts +0 -326
  272. package/packages/input-shortcuts/src/clipboard.ts +0 -119
  273. package/packages/kanboard/src/runner.ts +0 -817
  274. package/packages/skill-registry/skills/auto/SKILL.md +0 -465
  275. package/packages/skill-registry/skills/brainstorm/SKILL.md +0 -219
  276. package/packages/skill-registry/skills/chore-create/SKILL.md +0 -315
  277. package/packages/skill-registry/skills/chore-execute/SKILL.md +0 -314
  278. package/packages/skill-registry/skills/consolidate/SKILL.md +0 -142
  279. package/packages/skill-registry/skills/consultant/SKILL.md +0 -97
  280. package/packages/skill-registry/skills/debug/SKILL.md +0 -228
  281. package/packages/skill-registry/skills/document/SKILL.md +0 -120
  282. package/packages/skill-registry/skills/fix/SKILL.md +0 -212
  283. package/packages/skill-registry/skills/gather-context/SKILL.md +0 -145
  284. package/packages/skill-registry/skills/plan/SKILL.md +0 -231
  285. package/packages/skill-registry/skills/quick-fix/SKILL.md +0 -135
  286. package/packages/skill-registry/skills/quick-work/SKILL.md +0 -110
  287. package/packages/skill-registry/skills/research/SKILL.md +0 -251
  288. package/packages/skill-registry/skills/review-work/SKILL.md +0 -187
  289. package/packages/skill-registry/skills/scan-issues/SKILL.md +0 -195
  290. package/packages/skill-registry/skills/work/SKILL.md +0 -218
  291. package/packages/skill-registry/skills/worktree-create/SKILL.md +0 -69
  292. package/packages/skill-registry/skills/worktree-list/SKILL.md +0 -78
  293. package/packages/skill-registry/skills/worktree-merge/SKILL.md +0 -89
  294. package/packages/subagents/agents/delegate.md +0 -14
  295. package/packages/subagents/agents/oracle.md +0 -78
  296. package/packages/subagents/agents/researcher.md +0 -52
  297. package/packages/subagents/agents/reviewer.md +0 -80
  298. package/packages/subagents/agents/scout.md +0 -50
  299. package/packages/subagents/agents/worker.md +0 -59
  300. package/packages/subagents/prompts/council.md +0 -48
  301. package/packages/subagents/prompts/gather-context-and-clarify.md +0 -13
  302. package/packages/subagents/prompts/parallel-cleanup.md +0 -59
  303. package/packages/subagents/prompts/parallel-research.md +0 -50
  304. package/packages/subagents/prompts/parallel-review.md +0 -54
  305. package/packages/subagents/prompts/review-loop.md +0 -43
  306. package/packages/subagents/skills/council-mode/SKILL.md +0 -230
  307. package/packages/subagents/skills/subagents/references/constraints-and-recipes.md +0 -259
  308. package/packages/subagents/skills/subagents/references/execution-controls.md +0 -454
  309. package/packages/subagents/skills/subagents/references/management-authoring-rpc.md +0 -161
  310. package/packages/subagents/skills/subagents/references/multi-lane-orchestration.md +0 -39
  311. package/packages/subagents/skills/subagents/references/prompting-and-roles.md +0 -267
  312. package/packages/subagents/src/acceptance.ts +0 -331
  313. package/packages/subagents/src/agent-manager.ts +0 -405
  314. package/packages/subagents/src/agent-memory.ts +0 -300
  315. package/packages/subagents/src/agent-overrides.ts +0 -183
  316. package/packages/subagents/src/agent-runner.ts +0 -271
  317. package/packages/subagents/src/async-runner.ts +0 -422
  318. package/packages/subagents/src/authority-policy.ts +0 -47
  319. package/packages/subagents/src/budgets.ts +0 -285
  320. package/packages/subagents/src/child-safety.ts +0 -140
  321. package/packages/subagents/src/config.ts +0 -249
  322. package/packages/subagents/src/conversation-viewer.ts +0 -281
  323. package/packages/subagents/src/core-compat.ts +0 -94
  324. package/packages/subagents/src/custom-agents.ts +0 -343
  325. package/packages/subagents/src/file-system-retry.ts +0 -50
  326. package/packages/subagents/src/fleet-data.ts +0 -105
  327. package/packages/subagents/src/fleet-view.ts +0 -322
  328. package/packages/subagents/src/foreground-detach.ts +0 -59
  329. package/packages/subagents/src/fork-context.ts +0 -285
  330. package/packages/subagents/src/global.d.ts +0 -7
  331. package/packages/subagents/src/guide.ts +0 -129
  332. package/packages/subagents/src/mission-state.ts +0 -133
  333. package/packages/subagents/src/mission-store.ts +0 -436
  334. package/packages/subagents/src/output-limits.ts +0 -142
  335. package/packages/subagents/src/parity-types.ts +0 -315
  336. package/packages/subagents/src/pi-args.ts +0 -167
  337. package/packages/subagents/src/result-files.ts +0 -232
  338. package/packages/subagents/src/result-watcher.ts +0 -221
  339. package/packages/subagents/src/retained-children.ts +0 -176
  340. package/packages/subagents/src/run-fanout-budget.ts +0 -356
  341. package/packages/subagents/src/scheduled-runs.ts +0 -349
  342. package/packages/subagents/src/schemas.ts +0 -263
  343. package/packages/subagents/src/slash-commands.ts +0 -80
  344. package/packages/subagents/src/supervisor-channel.ts +0 -249
  345. package/packages/subagents/src/tool-handler.ts +0 -1144
  346. package/packages/subagents/src/types.ts +0 -238
  347. package/packages/subagents/src/widget.ts +0 -457
  348. package/packages/subagents/src/workflow-script.ts +0 -737
  349. package/packages/subagents/src/workflow-worker.ts +0 -384
  350. package/packages/subagents/src/worktree.ts +0 -614
  351. package/packages/utility/src/analytics/collector.ts +0 -293
  352. package/packages/utility/src/info-screen.ts +0 -80
  353. package/packages/utility/src/lifecycle/process.ts +0 -162
  354. package/packages/utility/src/prefix-cache.ts +0 -263
  355. package/packages/utility/src/skill-discovery.ts +0 -542
  356. package/packages/utility/src/tools/env.ts +0 -113
  357. package/packages/utility/src/tui/name-badge-state.ts +0 -315
  358. package/packages/utility/src/tui/name-badge.ts +0 -109
  359. /package/packages/{subagents/src → core/src/child-agent}/pi-spawn.ts +0 -0
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Typing-burst tracker for the undo history.
3
+ *
4
+ * The terminal-input handler must stay O(1): NO editor read per key except
5
+ * at burst start (which captures the pre-burst state, including programmatic
6
+ * changes like submit clearing the editor). Every input only stamps
7
+ * `lastInputAt`. One timer rides along: when it fires, an active burst that
8
+ * went quiet for BURST_IDLE_MS is flushed (post-burst state recorded) and
9
+ * closed; a burst that keeps going longer than BURST_MAX_MS is split so a
10
+ * long typing session still checkpoints. So a burst costs exactly two editor
11
+ * reads — one at open, one at close.
12
+ *
13
+ * Clock, timer and text access are injectable so tests can fake all of them.
14
+ */
15
+
16
+ export const BURST_IDLE_MS = 600;
17
+ export const BURST_MAX_MS = 2000;
18
+
19
+ export interface BurstDeps {
20
+ /** Read the editor text (called only at burst open and close). */
21
+ getText(): string;
22
+ /** Where the captured states go (EditHistory.record). */
23
+ record(text: string): void;
24
+ now(): number;
25
+ setTimeout(handler: () => void, ms: number): unknown;
26
+ clearTimeout(handle: unknown): void;
27
+ }
28
+
29
+ export class BurstTracker {
30
+ private open = false;
31
+ private burstStart = 0;
32
+ private lastInputAt = 0;
33
+ private timer: unknown = null;
34
+
35
+ constructor(private readonly deps: BurstDeps) {}
36
+
37
+ /** A terminal input arrived — O(1), no editor read once a burst is open. */
38
+ onInput(): void {
39
+ const now = this.deps.now();
40
+ if (!this.open) {
41
+ this.open = true;
42
+ this.burstStart = now;
43
+ this.lastInputAt = now;
44
+ this.deps.record(this.deps.getText());
45
+ this.arm(now);
46
+ return;
47
+ }
48
+ this.lastInputAt = now;
49
+ }
50
+
51
+ /**
52
+ * Flush and close the burst if one is open: the post-burst text is
53
+ * recorded (a no-op when nothing changed). Undo/redo call this first so
54
+ * un-flushed typing is captured before stepping.
55
+ */
56
+ close(): void {
57
+ const wasOpen = this.open;
58
+ this.cancel();
59
+ if (wasOpen) {
60
+ this.deps.record(this.deps.getText());
61
+ }
62
+ }
63
+
64
+ /** Drop the timer and forget the burst WITHOUT recording anything. */
65
+ cancel(): void {
66
+ if (this.timer !== null) {
67
+ this.deps.clearTimeout(this.timer);
68
+ this.timer = null;
69
+ }
70
+ this.open = false;
71
+ }
72
+
73
+ private arm(now: number): void {
74
+ const idleRemainder = BURST_IDLE_MS - (now - this.lastInputAt);
75
+ const burstRemainder = BURST_MAX_MS - (now - this.burstStart);
76
+ const wait = Math.max(0, Math.min(idleRemainder, burstRemainder));
77
+ this.timer = this.deps.setTimeout(() => this.onTimer(), wait);
78
+ }
79
+
80
+ private onTimer(): void {
81
+ const now = this.deps.now();
82
+ if (this.open && now - this.lastInputAt < BURST_IDLE_MS && now - this.burstStart < BURST_MAX_MS) {
83
+ this.arm(now);
84
+ return;
85
+ }
86
+ this.close();
87
+ }
88
+ }
@@ -1,19 +1,19 @@
1
1
  /**
2
- * TUI overlay component for ALT+S chord mode.
2
+ * TUI overlay component for the ALT+S chord.
3
3
  *
4
- * Two states: root chord (action menu) and register sub-chord (register list).
5
- * Uses ctx.ui.custom() pattern from btw/compactor.
4
+ * One state: the root action menu. Uses the ctx.ui.custom() pattern from
5
+ * btw/compactor.
6
6
  *
7
7
  * IMPORTANT: The overlay ONLY captures the user's action selection.
8
8
  * Actions are NOT executed inside the overlay — they are deferred to the
9
- * caller via callbacks (onStash, onUndo, etc.). The caller closes the
9
+ * caller via callbacks (onStash, onUndo, …). The caller closes the
10
10
  * overlay via done(), then executes the action outside the overlay context
11
11
  * where ctx.ui.getEditorText() / setEditorText() actually work.
12
12
  *
13
- * Closes on ESC or after selecting an action. No timeout.
13
+ * Closes on ESC or after selecting an action; an unknown key closes silently.
14
+ * No timeout.
14
15
  */
15
16
 
16
- import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
17
17
  import {
18
18
  Container,
19
19
  Key,
@@ -23,8 +23,6 @@ import {
23
23
  type TUI,
24
24
  type KeybindingsManager,
25
25
  } from "@earendil-works/pi-tui";
26
- import type { ChordState } from "./types.ts";
27
- import { THINKING_CYCLE } from "./types.ts";
28
26
 
29
27
  /** Theme-like interface matching pi-coding-agent's Theme */
30
28
  interface ThemeLike {
@@ -39,11 +37,9 @@ export interface ChordCallbacks {
39
37
  onStash: () => void;
40
38
  onUndo: () => void;
41
39
  onRedo: () => void;
42
- onAppendRegister: (index: number) => void;
43
40
  onAppendStash: () => void;
44
- onCopy: () => void;
45
- onCut: () => void;
46
- onToggleThinking: () => void;
41
+ onCopyLastResponse: () => void | Promise<void>;
42
+ onKanboard: () => void | Promise<void>;
47
43
  }
48
44
 
49
45
  // ─── Action menu lines ──────────────────────────────────────────────────────
@@ -52,26 +48,15 @@ const ROOT_ACTIONS: Array<{ key: string; label: string }> = [
52
48
  { key: "S", label: "Stash / Restore" },
53
49
  { key: "U", label: "Undo" },
54
50
  { key: "R", label: "Redo" },
55
- { key: "A", label: "Append from register" },
56
- { key: "Y", label: "Copy to clipboard" },
57
- { key: "D", label: "Cut to clipboard" },
58
- { key: "T", label: "Toggle thinking" },
51
+ { key: "A", label: "Append stash" },
52
+ { key: "Y", label: "Copy last response" },
53
+ { key: "K", label: "Add to kanboard backlog" },
59
54
  ];
60
55
 
61
- function buildRegisterActions(): Array<{ key: string; label: string }> {
62
- const actions: Array<{ key: string; label: string }> = [];
63
- for (let i = 0; i <= 9; i++) {
64
- actions.push({ key: String(i), label: `Register ${i}` });
65
- }
66
- actions.push({ key: "S", label: "Stash register" });
67
- return actions;
68
- }
69
-
70
- // ─── ChordOverlay Component ─────────────────────────────────────────────────
56
+ // ─── ChordOverlay Component ─────────────────────────────────────────────────────────
71
57
 
72
58
  export class ChordOverlay extends Container implements Focusable {
73
59
  private _focused = true;
74
- private state: ChordState = "chord_root";
75
60
  private actionLines: Text[] = [];
76
61
  private tui: TUI;
77
62
  private theme: ThemeLike;
@@ -103,22 +88,12 @@ export class ChordOverlay extends Container implements Focusable {
103
88
  }
104
89
 
105
90
  private renderRootMenu(): void {
106
- this.state = "chord_root";
107
91
  this.actionLines = ROOT_ACTIONS.map(
108
92
  (a) => new Text(` ${this.theme.fg("accent", `[${a.key}]`)} ${a.label}`, 1, 0),
109
93
  );
110
94
  this.requestRender();
111
95
  }
112
96
 
113
- private renderRegisterMenu(): void {
114
- this.state = "chord_reg";
115
- const regActions = buildRegisterActions();
116
- this.actionLines = regActions.map(
117
- (a) => new Text(` ${this.theme.fg("accent", `[${a.key}]`)} ${a.label}`, 1, 0),
118
- );
119
- this.requestRender();
120
- }
121
-
122
97
  private requestRender(): void {
123
98
  this.tui.requestRender();
124
99
  }
@@ -129,13 +104,7 @@ export class ChordOverlay extends Container implements Focusable {
129
104
  return;
130
105
  }
131
106
 
132
- const key = data.toLowerCase();
133
-
134
- if (this.state === "chord_root") {
135
- this.handleRootKey(key);
136
- } else if (this.state === "chord_reg") {
137
- this.handleRegKey(key);
138
- }
107
+ this.handleRootKey(data.toLowerCase());
139
108
  }
140
109
 
141
110
  private handleRootKey(key: string): void {
@@ -150,16 +119,13 @@ export class ChordOverlay extends Container implements Focusable {
150
119
  this.closeThenExecute(() => this.callbacks.onRedo());
151
120
  break;
152
121
  case "a":
153
- this.enterRegChord();
154
- return; // don't close — show register sub-menu
155
- case "y":
156
- this.closeThenExecute(() => this.callbacks.onCopy());
122
+ this.closeThenExecute(() => this.callbacks.onAppendStash());
157
123
  break;
158
- case "d":
159
- this.closeThenExecute(() => this.callbacks.onCut());
124
+ case "y":
125
+ this.closeThenExecute(() => this.callbacks.onCopyLastResponse());
160
126
  break;
161
- case "t":
162
- this.closeThenExecute(() => this.callbacks.onToggleThinking());
127
+ case "k":
128
+ this.closeThenExecute(() => this.callbacks.onKanboard());
163
129
  break;
164
130
  default:
165
131
  // Unknown key — silent close
@@ -168,28 +134,12 @@ export class ChordOverlay extends Container implements Focusable {
168
134
  }
169
135
  }
170
136
 
171
- private handleRegKey(key: string): void {
172
- if (key === "s") {
173
- this.closeThenExecute(() => this.callbacks.onAppendStash());
174
- } else if (/^[0-9]$/.test(key)) {
175
- const index = parseInt(key, 10);
176
- this.closeThenExecute(() => this.callbacks.onAppendRegister(index));
177
- } else {
178
- // Unknown key — silent close
179
- this.close();
180
- }
181
- }
182
-
183
- private enterRegChord(): void {
184
- this.renderRegisterMenu();
185
- }
186
-
187
137
  /**
188
138
  * Close the overlay, then execute the action.
189
139
  * The action runs AFTER the overlay is dismissed, so ctx.ui.getEditorText()
190
140
  * and setEditorText() work correctly (they don't work while overlay is open).
191
141
  */
192
- private closeThenExecute(action: () => void): void {
142
+ private closeThenExecute(action: () => void | Promise<void>): void {
193
143
  this.done(); // close the overlay
194
144
  // Use setTimeout(0) to defer action to next tick — overlay will be dismissed by then
195
145
  setTimeout(action, 0);
@@ -213,7 +163,7 @@ export class ChordOverlay extends Container implements Focusable {
213
163
  lines.push(this.theme.fg("borderMuted", `┌${"─".repeat(innerWidth)}┐`));
214
164
 
215
165
  // Title
216
- const title = this.state === "chord_root" ? "Input Shortcuts" : "Append from register";
166
+ const title = "Input Shortcuts";
217
167
  const titlePadded = title.padEnd(innerWidth);
218
168
  lines.push(`${this.theme.fg("borderMuted", "│")}${this.theme.fg("accent", titlePadded)}${this.theme.fg("borderMuted", "│")}`);
219
169
 
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Ctrl+C keeps what it cleared (Devin-style):
3
+ * - the text stays in the transcript, struck through (UI-only entry — custom
4
+ * entries never reach the model, so no tokens and no prefix-cache churn);
5
+ * - it is pushed onto the editor's ↑ history, so ↑ brings it back.
6
+ *
7
+ * pi still does the clearing (and double Ctrl+C still exits). We only look at
8
+ * the key first via onTerminalInput and never consume it.
9
+ */
10
+
11
+ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
12
+ import { matchesKey, truncateToWidth, type Component, type TUI } from "@earendil-works/pi-tui";
13
+ import type { KitTheme } from "@pi-unipi/core";
14
+
15
+ export const CLEARED_ENTRY = "unipi-cleared-input";
16
+ const PROBE_WIDGET = "unipi-cleared-input-probe";
17
+ const MAX_LINES = 3;
18
+
19
+ interface EditorLike {
20
+ getText(): string;
21
+ addToHistory(text: string): void;
22
+ }
23
+
24
+ function isEditor(c: unknown): c is EditorLike {
25
+ const e = c as Partial<EditorLike> | null | undefined;
26
+ return typeof e?.getText === "function" && typeof e.addToHistory === "function";
27
+ }
28
+
29
+ const strike = (s: string) => `\x1b[9m${s}\x1b[29m`;
30
+
31
+ /** `⌫ ~~fix the flaky test~~ ↑ restores` (+ up to two more struck lines). */
32
+ export function clearedLines(t: KitTheme, text: string, width: number): string[] {
33
+ const all = text.replace(/\s+$/u, "").split("\n");
34
+ const shown = all.slice(0, MAX_LINES);
35
+ const out = shown.map((l, i) => truncateToWidth(`${i === 0 ? t.fg("dim", "⌫ ") : " "}${t.fg("dim", strike(l))}`, width));
36
+ if (all.length > shown.length) out.push(t.fg("dim", ` … ${String(all.length - shown.length)} more line${all.length - shown.length === 1 ? "" : "s"}`));
37
+ out[0] = truncateToWidth(`${out[0]!}${t.fg("dim", " ↑ restores")}`, width);
38
+ return out;
39
+ }
40
+
41
+ /**
42
+ * Decide what to record for a key press. Returns the text to keep, or
43
+ * undefined when the key isn't Ctrl+C / the focus isn't a non-empty editor.
44
+ */
45
+ export function clearedText(data: string, focused: unknown): string | undefined {
46
+ if (!matchesKey(data, "ctrl+c") || !isEditor(focused)) return undefined;
47
+ const text = focused.getText();
48
+ return text.trim() ? text : undefined;
49
+ }
50
+
51
+ export function installClearedInput(pi: ExtensionAPI): void {
52
+ let tui: TUI | undefined;
53
+ let unsub: (() => void) | undefined;
54
+
55
+ try {
56
+ pi.registerEntryRenderer<{ text: string }>(CLEARED_ENTRY, (entry, _opts, theme): Component | undefined => {
57
+ const text = entry.data?.text;
58
+ if (!text) return undefined;
59
+ return { invalidate() {}, render: (w: number) => clearedLines(theme as KitTheme, text, w) };
60
+ });
61
+ } catch {
62
+ /* UI-dependent */
63
+ }
64
+
65
+ pi.on("session_start", (_e, ctx: ExtensionContext) => {
66
+ unsub?.();
67
+ unsub = undefined;
68
+ if (!ctx.hasUI) return;
69
+ try {
70
+ // An empty widget, only to get hold of the TUI (for the focused editor).
71
+ ctx.ui.setWidget(PROBE_WIDGET, (t) => {
72
+ tui = t;
73
+ return { invalidate() {}, render: () => [] };
74
+ }, { placement: "belowEditor" });
75
+ unsub = ctx.ui.onTerminalInput((data) => {
76
+ try {
77
+ const focused = (tui as { getFocusedComponent?: () => unknown } | undefined)?.getFocusedComponent?.();
78
+ const text = clearedText(data, focused);
79
+ if (text === undefined) return undefined;
80
+ (focused as EditorLike).addToHistory(text);
81
+ pi.appendEntry(CLEARED_ENTRY, { text });
82
+ } catch {
83
+ /* never block the key */
84
+ }
85
+ return undefined;
86
+ });
87
+ } catch {
88
+ /* UI-dependent */
89
+ }
90
+ });
91
+
92
+ pi.on("session_shutdown", () => {
93
+ unsub?.();
94
+ unsub = undefined;
95
+ tui = undefined;
96
+ });
97
+ }