@deepseek-harness-tui/dsh-tui 0.11.2 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +60 -8
- package/assets/deepy/README.md +60 -0
- package/assets/deepy/frames.json +1 -0
- package/assets/whale-girl/whale-girl-happy.png +0 -0
- package/assets/whaleGirl/README.md +7 -0
- package/assets/whaleGirl/frames.json +1 -0
- package/assets/whaleGirl/img/building/00.png +0 -0
- package/assets/whaleGirl/img/building/01.png +0 -0
- package/assets/whaleGirl/img/building/02.png +0 -0
- package/assets/whaleGirl/img/building/03.png +0 -0
- package/assets/whaleGirl/img/building/04.png +0 -0
- package/assets/whaleGirl/img/building/05.png +0 -0
- package/assets/whaleGirl/img/building/06.png +0 -0
- package/assets/whaleGirl/img/building/07.png +0 -0
- package/assets/whaleGirl/img/building/08.png +0 -0
- package/assets/whaleGirl/img/building/09.png +0 -0
- package/assets/whaleGirl/img/building/10.png +0 -0
- package/assets/whaleGirl/img/building/11.png +0 -0
- package/assets/whaleGirl/img/building/12.png +0 -0
- package/assets/whaleGirl/img/building/13.png +0 -0
- package/assets/whaleGirl/img/building/14.png +0 -0
- package/assets/whaleGirl/img/building/15.png +0 -0
- package/assets/whaleGirl/img/building/16.png +0 -0
- package/assets/whaleGirl/img/building/17.png +0 -0
- package/assets/whaleGirl/img/building/18.png +0 -0
- package/assets/whaleGirl/img/building/19.png +0 -0
- package/assets/whaleGirl/img/building/20.png +0 -0
- package/assets/whaleGirl/img/building/21.png +0 -0
- package/assets/whaleGirl/img/building/22.png +0 -0
- package/assets/whaleGirl/img/building/23.png +0 -0
- package/assets/whaleGirl/img/carrying/00.png +0 -0
- package/assets/whaleGirl/img/carrying/01.png +0 -0
- package/assets/whaleGirl/img/carrying/02.png +0 -0
- package/assets/whaleGirl/img/carrying/03.png +0 -0
- package/assets/whaleGirl/img/carrying/04.png +0 -0
- package/assets/whaleGirl/img/carrying/05.png +0 -0
- package/assets/whaleGirl/img/carrying/06.png +0 -0
- package/assets/whaleGirl/img/carrying/07.png +0 -0
- package/assets/whaleGirl/img/compacting/00.png +0 -0
- package/assets/whaleGirl/img/compacting/01.png +0 -0
- package/assets/whaleGirl/img/compacting/02.png +0 -0
- package/assets/whaleGirl/img/compacting/03.png +0 -0
- package/assets/whaleGirl/img/compacting/04.png +0 -0
- package/assets/whaleGirl/img/compacting/05.png +0 -0
- package/assets/whaleGirl/img/compacting/06.png +0 -0
- package/assets/whaleGirl/img/compacting/07.png +0 -0
- package/assets/whaleGirl/img/compacting/08.png +0 -0
- package/assets/whaleGirl/img/compacting/09.png +0 -0
- package/assets/whaleGirl/img/conducting/00.png +0 -0
- package/assets/whaleGirl/img/conducting/01.png +0 -0
- package/assets/whaleGirl/img/conducting/02.png +0 -0
- package/assets/whaleGirl/img/conducting/03.png +0 -0
- package/assets/whaleGirl/img/conducting/04.png +0 -0
- package/assets/whaleGirl/img/conducting/05.png +0 -0
- package/assets/whaleGirl/img/conducting/06.png +0 -0
- package/assets/whaleGirl/img/conducting/07.png +0 -0
- package/assets/whaleGirl/img/conducting/08.png +0 -0
- package/assets/whaleGirl/img/conducting/09.png +0 -0
- package/assets/whaleGirl/img/conducting/10.png +0 -0
- package/assets/whaleGirl/img/conducting/11.png +0 -0
- package/assets/whaleGirl/img/drag/00.png +0 -0
- package/assets/whaleGirl/img/drag/01.png +0 -0
- package/assets/whaleGirl/img/drag/02.png +0 -0
- package/assets/whaleGirl/img/drag/03.png +0 -0
- package/assets/whaleGirl/img/drag/04.png +0 -0
- package/assets/whaleGirl/img/drag/05.png +0 -0
- package/assets/whaleGirl/img/drag/06.png +0 -0
- package/assets/whaleGirl/img/drag/07.png +0 -0
- package/assets/whaleGirl/img/drag/08.png +0 -0
- package/assets/whaleGirl/img/drag/09.png +0 -0
- package/assets/whaleGirl/img/error/00.png +0 -0
- package/assets/whaleGirl/img/error/01.png +0 -0
- package/assets/whaleGirl/img/error/02.png +0 -0
- package/assets/whaleGirl/img/error/03.png +0 -0
- package/assets/whaleGirl/img/error/04.png +0 -0
- package/assets/whaleGirl/img/error/05.png +0 -0
- package/assets/whaleGirl/img/error/06.png +0 -0
- package/assets/whaleGirl/img/error/07.png +0 -0
- package/assets/whaleGirl/img/error/08.png +0 -0
- package/assets/whaleGirl/img/error/09.png +0 -0
- package/assets/whaleGirl/img/happy/00.png +0 -0
- package/assets/whaleGirl/img/happy/01.png +0 -0
- package/assets/whaleGirl/img/happy/02.png +0 -0
- package/assets/whaleGirl/img/happy/03.png +0 -0
- package/assets/whaleGirl/img/happy/04.png +0 -0
- package/assets/whaleGirl/img/happy/05.png +0 -0
- package/assets/whaleGirl/img/happy/06.png +0 -0
- package/assets/whaleGirl/img/happy/07.png +0 -0
- package/assets/whaleGirl/img/happy/08.png +0 -0
- package/assets/whaleGirl/img/happy/09.png +0 -0
- package/assets/whaleGirl/img/happy/10.png +0 -0
- package/assets/whaleGirl/img/idle/00.png +0 -0
- package/assets/whaleGirl/img/idle/01.png +0 -0
- package/assets/whaleGirl/img/idle/02.png +0 -0
- package/assets/whaleGirl/img/idle/03.png +0 -0
- package/assets/whaleGirl/img/idle/04.png +0 -0
- package/assets/whaleGirl/img/idle/05.png +0 -0
- package/assets/whaleGirl/img/idle/06.png +0 -0
- package/assets/whaleGirl/img/idle/07.png +0 -0
- package/assets/whaleGirl/img/idle/08.png +0 -0
- package/assets/whaleGirl/img/idle/09.png +0 -0
- package/assets/whaleGirl/img/idle/10.png +0 -0
- package/assets/whaleGirl/img/idle/11.png +0 -0
- package/assets/whaleGirl/img/idle/12.png +0 -0
- package/assets/whaleGirl/img/idle/13.png +0 -0
- package/assets/whaleGirl/img/idle/14.png +0 -0
- package/assets/whaleGirl/img/idle/15.png +0 -0
- package/assets/whaleGirl/img/idle/16.png +0 -0
- package/assets/whaleGirl/img/idle/17.png +0 -0
- package/assets/whaleGirl/img/idle/18.png +0 -0
- package/assets/whaleGirl/img/idle/19.png +0 -0
- package/assets/whaleGirl/img/idle/20.png +0 -0
- package/assets/whaleGirl/img/idle-look/00.png +0 -0
- package/assets/whaleGirl/img/idle-look/01.png +0 -0
- package/assets/whaleGirl/img/idle-look/02.png +0 -0
- package/assets/whaleGirl/img/idle-look/03.png +0 -0
- package/assets/whaleGirl/img/idle-look/04.png +0 -0
- package/assets/whaleGirl/img/idle-look/05.png +0 -0
- package/assets/whaleGirl/img/idle-look/06.png +0 -0
- package/assets/whaleGirl/img/idle-look/07.png +0 -0
- package/assets/whaleGirl/img/idle-look/08.png +0 -0
- package/assets/whaleGirl/img/idle-look/09.png +0 -0
- package/assets/whaleGirl/img/idle-look/10.png +0 -0
- package/assets/whaleGirl/img/idle-look/11.png +0 -0
- package/assets/whaleGirl/img/idle-look/12.png +0 -0
- package/assets/whaleGirl/img/idle-spout/00.png +0 -0
- package/assets/whaleGirl/img/idle-spout/01.png +0 -0
- package/assets/whaleGirl/img/idle-spout/02.png +0 -0
- package/assets/whaleGirl/img/idle-spout/03.png +0 -0
- package/assets/whaleGirl/img/idle-spout/04.png +0 -0
- package/assets/whaleGirl/img/idle-spout/05.png +0 -0
- package/assets/whaleGirl/img/idle-spout/06.png +0 -0
- package/assets/whaleGirl/img/idle-spout/07.png +0 -0
- package/assets/whaleGirl/img/idle-spout/08.png +0 -0
- package/assets/whaleGirl/img/idle-spout/09.png +0 -0
- package/assets/whaleGirl/img/idle-spout/10.png +0 -0
- package/assets/whaleGirl/img/music/00.png +0 -0
- package/assets/whaleGirl/img/music/01.png +0 -0
- package/assets/whaleGirl/img/music/02.png +0 -0
- package/assets/whaleGirl/img/music/03.png +0 -0
- package/assets/whaleGirl/img/music/04.png +0 -0
- package/assets/whaleGirl/img/music/05.png +0 -0
- package/assets/whaleGirl/img/music/06.png +0 -0
- package/assets/whaleGirl/img/music/07.png +0 -0
- package/assets/whaleGirl/img/notification/00.png +0 -0
- package/assets/whaleGirl/img/notification/01.png +0 -0
- package/assets/whaleGirl/img/notification/02.png +0 -0
- package/assets/whaleGirl/img/notification/03.png +0 -0
- package/assets/whaleGirl/img/notification/04.png +0 -0
- package/assets/whaleGirl/img/notification/05.png +0 -0
- package/assets/whaleGirl/img/notification/06.png +0 -0
- package/assets/whaleGirl/img/notification/07.png +0 -0
- package/assets/whaleGirl/img/poke-left/00.png +0 -0
- package/assets/whaleGirl/img/poke-left/01.png +0 -0
- package/assets/whaleGirl/img/poke-left/02.png +0 -0
- package/assets/whaleGirl/img/poke-left/03.png +0 -0
- package/assets/whaleGirl/img/poke-left/04.png +0 -0
- package/assets/whaleGirl/img/poke-left/05.png +0 -0
- package/assets/whaleGirl/img/poke-left/06.png +0 -0
- package/assets/whaleGirl/img/poke-left/07.png +0 -0
- package/assets/whaleGirl/img/poke-left/08.png +0 -0
- package/assets/whaleGirl/img/poke-left/09.png +0 -0
- package/assets/whaleGirl/img/poke-left/10.png +0 -0
- package/assets/whaleGirl/img/poke-right/00.png +0 -0
- package/assets/whaleGirl/img/poke-right/01.png +0 -0
- package/assets/whaleGirl/img/poke-right/02.png +0 -0
- package/assets/whaleGirl/img/poke-right/03.png +0 -0
- package/assets/whaleGirl/img/poke-right/04.png +0 -0
- package/assets/whaleGirl/img/poke-right/05.png +0 -0
- package/assets/whaleGirl/img/poke-right/06.png +0 -0
- package/assets/whaleGirl/img/poke-right/07.png +0 -0
- package/assets/whaleGirl/img/poke-right/08.png +0 -0
- package/assets/whaleGirl/img/poke-right/09.png +0 -0
- package/assets/whaleGirl/img/poke-right/10.png +0 -0
- package/assets/whaleGirl/img/sleeping/00.png +0 -0
- package/assets/whaleGirl/img/sleeping/01.png +0 -0
- package/assets/whaleGirl/img/sleeping/02.png +0 -0
- package/assets/whaleGirl/img/sleeping/03.png +0 -0
- package/assets/whaleGirl/img/sleeping/04.png +0 -0
- package/assets/whaleGirl/img/sleeping/05.png +0 -0
- package/assets/whaleGirl/img/smile-hearts/00.png +0 -0
- package/assets/whaleGirl/img/smile-hearts/01.png +0 -0
- package/assets/whaleGirl/img/smile-hearts/02.png +0 -0
- package/assets/whaleGirl/img/smile-hearts/03.png +0 -0
- package/assets/whaleGirl/img/smile-hearts/04.png +0 -0
- package/assets/whaleGirl/img/smile-hearts/05.png +0 -0
- package/assets/whaleGirl/img/smile-hearts/06.png +0 -0
- package/assets/whaleGirl/img/smile-hearts/07.png +0 -0
- package/assets/whaleGirl/img/smile-hearts/08.png +0 -0
- package/assets/whaleGirl/img/smile-hearts/09.png +0 -0
- package/assets/whaleGirl/img/smile-hearts/10.png +0 -0
- package/assets/whaleGirl/img/smile-hearts/11.png +0 -0
- package/assets/whaleGirl/img/smile-hearts/12.png +0 -0
- package/assets/whaleGirl/img/smile-hearts/13.png +0 -0
- package/assets/whaleGirl/img/smile-hearts/14.png +0 -0
- package/assets/whaleGirl/img/smile-hearts/15.png +0 -0
- package/assets/whaleGirl/img/swim/00.png +0 -0
- package/assets/whaleGirl/img/swim/01.png +0 -0
- package/assets/whaleGirl/img/swim/02.png +0 -0
- package/assets/whaleGirl/img/swim/03.png +0 -0
- package/assets/whaleGirl/img/swim/04.png +0 -0
- package/assets/whaleGirl/img/swim/05.png +0 -0
- package/assets/whaleGirl/img/swim/06.png +0 -0
- package/assets/whaleGirl/img/swim/07.png +0 -0
- package/assets/whaleGirl/img/thinking/00.png +0 -0
- package/assets/whaleGirl/img/thinking/01.png +0 -0
- package/assets/whaleGirl/img/thinking/02.png +0 -0
- package/assets/whaleGirl/img/thinking/03.png +0 -0
- package/assets/whaleGirl/img/thinking/04.png +0 -0
- package/assets/whaleGirl/img/thinking/05.png +0 -0
- package/assets/whaleGirl/img/thinking/06.png +0 -0
- package/assets/whaleGirl/img/thinking/07.png +0 -0
- package/assets/whaleGirl/img/thinking/08.png +0 -0
- package/assets/whaleGirl/img/thinking/09.png +0 -0
- package/assets/whaleGirl/img/thinking/10.png +0 -0
- package/assets/whaleGirl/img/thinking/11.png +0 -0
- package/assets/whaleGirl/img/thinking/12.png +0 -0
- package/assets/whaleGirl/img/thinking/13.png +0 -0
- package/assets/whaleGirl/img/thinking/14.png +0 -0
- package/assets/whaleGirl/img/thinking/15.png +0 -0
- package/assets/whaleGirl/img/thinking/16.png +0 -0
- package/assets/whaleGirl/img/thumbs-up/00.png +0 -0
- package/assets/whaleGirl/img/thumbs-up/01.png +0 -0
- package/assets/whaleGirl/img/thumbs-up/02.png +0 -0
- package/assets/whaleGirl/img/thumbs-up/03.png +0 -0
- package/assets/whaleGirl/img/thumbs-up/04.png +0 -0
- package/assets/whaleGirl/img/thumbs-up/05.png +0 -0
- package/assets/whaleGirl/img/thumbs-up/06.png +0 -0
- package/assets/whaleGirl/img/thumbs-up/07.png +0 -0
- package/assets/whaleGirl/img/thumbs-up/08.png +0 -0
- package/assets/whaleGirl/img/thumbs-up/09.png +0 -0
- package/assets/whaleGirl/img/thumbs-up/10.png +0 -0
- package/assets/whaleGirl/img/thumbs-up/11.png +0 -0
- package/assets/whaleGirl/img/thumbs-up/12.png +0 -0
- package/assets/whaleGirl/img/tickle/00.png +0 -0
- package/assets/whaleGirl/img/tickle/01.png +0 -0
- package/assets/whaleGirl/img/tickle/02.png +0 -0
- package/assets/whaleGirl/img/tickle/03.png +0 -0
- package/assets/whaleGirl/img/tickle/04.png +0 -0
- package/assets/whaleGirl/img/tickle/05.png +0 -0
- package/assets/whaleGirl/img/tickle/06.png +0 -0
- package/assets/whaleGirl/img/tickle/07.png +0 -0
- package/assets/whaleGirl/img/tickle/08.png +0 -0
- package/assets/whaleGirl/img/tickle/09.png +0 -0
- package/assets/whaleGirl/img/tickle/10.png +0 -0
- package/assets/whaleGirl/img/tickle/11.png +0 -0
- package/assets/whaleGirl/img/tickle/12.png +0 -0
- package/assets/whaleGirl/img/tickle/13.png +0 -0
- package/assets/whaleGirl/img/timings.json +1 -0
- package/assets/whaleGirl/img/typing/00.png +0 -0
- package/assets/whaleGirl/img/typing/01.png +0 -0
- package/assets/whaleGirl/img/typing/02.png +0 -0
- package/assets/whaleGirl/img/typing/03.png +0 -0
- package/assets/whaleGirl/img/typing/04.png +0 -0
- package/assets/whaleGirl/img/typing/05.png +0 -0
- package/assets/whaleGirl/img/typing/06.png +0 -0
- package/assets/whaleGirl/img/typing/07.png +0 -0
- package/assets/whaleGirl/img/typing/08.png +0 -0
- package/assets/whaleGirl/img/typing/09.png +0 -0
- package/assets/whaleGirl/img/typing/10.png +0 -0
- package/assets/whaleGirl/img/typing/11.png +0 -0
- package/assets/whaleGirl/img/typing/12.png +0 -0
- package/assets/whaleGirl/img/typing/13.png +0 -0
- package/assets/whaleGirl/img/waking/00.png +0 -0
- package/assets/whaleGirl/img/waking/01.png +0 -0
- package/assets/whaleGirl/img/waking/02.png +0 -0
- package/assets/whaleGirl/img/waking/03.png +0 -0
- package/assets/whaleGirl/img/waking/04.png +0 -0
- package/assets/whaleGirl/img/waking/05.png +0 -0
- package/assets/whaleGirl/img/waking/06.png +0 -0
- package/assets/whaleGirl/img/waking/07.png +0 -0
- package/assets/whaleGirl/img/waking/08.png +0 -0
- package/assets/whaleGirl/img/waking/09.png +0 -0
- package/assets/whaleGirl/img/waking/10.png +0 -0
- package/bin/dsh-tui.js +38 -6
- package/cordis.patch.yml +31 -6
- package/guide/dsh-tui-guide/SKILL.md +37 -0
- package/guide/dsh-tui-guide/configuration.en.md +415 -0
- package/guide/dsh-tui-guide/configuration.md +354 -0
- package/guide/dsh-tui-guide/getting-started.en.md +401 -0
- package/guide/dsh-tui-guide/getting-started.md +399 -0
- package/guide/dsh-tui-guide/interaction.en.md +738 -0
- package/guide/dsh-tui-guide/interaction.md +793 -0
- package/guide/dsh-tui-guide/migrate.en.md +166 -0
- package/guide/dsh-tui-guide/migrate.md +132 -0
- package/guide/dsh-tui-guide/plugins.en.md +78 -0
- package/guide/dsh-tui-guide/plugins.md +64 -0
- package/guide/dsh-tui-guide/themes.en.md +197 -0
- package/guide/dsh-tui-guide/themes.md +188 -0
- package/guide/dsh-tui-guide/user-guide.en.md +711 -0
- package/guide/dsh-tui-guide/user-guide.md +666 -0
- package/guide/dsh-tui-guide/vscode.en.md +301 -0
- package/guide/dsh-tui-guide/vscode.md +272 -0
- package/lib/settings.json +219 -5
- package/lib/types/adapter/channel/ui-policy.d.ts +7 -2
- package/lib/types/adapter/channel/ui-policy.d.ts.map +1 -1
- package/lib/types/adapter/channel/ui-policy.js +18 -1
- package/lib/types/adapter/index.d.ts +1 -1
- package/lib/types/adapter/index.js +1 -1
- package/lib/types/adapter/kernel/host-facade.d.ts +4 -1
- package/lib/types/adapter/kernel/host-facade.d.ts.map +1 -1
- package/lib/types/adapter/kernel/host-facade.js +8 -1
- package/lib/types/adapter/kernel/runtime.d.ts.map +1 -1
- package/lib/types/adapter/kernel/runtime.js +13 -0
- package/lib/types/adapter/kernel/slices/index.d.ts +1 -0
- package/lib/types/adapter/kernel/slices/index.d.ts.map +1 -1
- package/lib/types/adapter/kernel/slices/index.js +3 -0
- package/lib/types/adapter/kernel/slices/panels.d.ts +3 -0
- package/lib/types/adapter/kernel/slices/panels.d.ts.map +1 -0
- package/lib/types/adapter/kernel/slices/panels.js +14 -0
- package/lib/types/adapter/ports/channel-capabilities.d.ts +48 -0
- package/lib/types/adapter/ports/channel-capabilities.d.ts.map +1 -0
- package/lib/types/adapter/ports/channel-capabilities.js +2 -0
- package/lib/types/adapter/ports/channel-catalog.d.ts +7 -0
- package/lib/types/adapter/ports/channel-catalog.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-display.d.ts +10 -0
- package/lib/types/adapter/ports/channel-display.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-settings.d.ts +2 -1
- package/lib/types/adapter/ports/channel-settings.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-ui.d.ts +91 -4
- package/lib/types/adapter/ports/channel-ui.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-view.d.ts +137 -9
- package/lib/types/adapter/ports/channel-view.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel.d.ts +1 -1
- package/lib/types/adapter/ports/channel.js +1 -1
- package/lib/types/adapter/ports/descriptor.d.ts +1 -1
- package/lib/types/adapter/ports/descriptor.js +1 -1
- package/lib/types/adapter/ports/index.d.ts +1 -1
- package/lib/types/adapter/ports/index.js +1 -1
- package/lib/types/adapter/ports/panels.d.ts +28 -0
- package/lib/types/adapter/ports/panels.d.ts.map +1 -0
- package/lib/types/adapter/ports/panels.js +8 -0
- package/lib/types/adapter/ports/workspace.d.ts +1 -1
- package/lib/types/adapter/ports/workspace.js +1 -1
- package/lib/types/adapter/spec/index.d.ts +2 -2
- package/lib/types/adapter/spec/index.js +2 -2
- package/lib/types/adapter/spec/profile.d.ts +6 -6
- package/lib/types/adapter/spec/profile.d.ts.map +1 -1
- package/lib/types/adapter/spec/profile.js +6 -6
- package/lib/types/adapter/spec/protocol-constants.d.ts +3 -3
- package/lib/types/adapter/spec/protocol-constants.d.ts.map +1 -1
- package/lib/types/adapter/spec/protocol-constants.js +5 -5
- package/lib/types/adapter/spec/tui-contributions.d.ts +4 -4
- package/lib/types/adapter/spec/tui-contributions.d.ts.map +1 -1
- package/lib/types/adapter/spec/tui-contributions.js +5 -5
- package/lib/types/adapter/standard/descriptor.js +1 -1
- package/lib/types/adapter/standard/index.d.ts +3 -3
- package/lib/types/adapter/standard/index.js +3 -3
- package/lib/types/adapter/standard/registry.d.ts +3 -2
- package/lib/types/adapter/standard/registry.d.ts.map +1 -1
- package/lib/types/adapter/standard/registry.js +6 -5
- package/lib/types/adapter/standard/tui-extension.d.ts +1 -1
- package/lib/types/adapter/standard/tui-extension.js +1 -1
- package/lib/types/adapter/upstream/index.d.ts +1 -0
- package/lib/types/adapter/upstream/index.d.ts.map +1 -1
- package/lib/types/adapter/upstream/index.js +1 -0
- package/lib/types/adapter/upstream/panels-driver.d.ts +18 -0
- package/lib/types/adapter/upstream/panels-driver.d.ts.map +1 -0
- package/lib/types/adapter/upstream/panels-driver.js +159 -0
- package/lib/types/api.d.ts +2 -0
- package/lib/types/api.d.ts.map +1 -1
- package/lib/types/api.js +3 -1
- package/lib/types/commands.d.ts.map +1 -1
- package/lib/types/commands.js +12 -4
- package/lib/types/components/ActivityLine.d.ts +6 -9
- package/lib/types/components/ActivityLine.d.ts.map +1 -1
- package/lib/types/components/ActivityLine.js +7 -8
- package/lib/types/components/Chat/JobCard.d.ts +27 -1
- package/lib/types/components/Chat/JobCard.d.ts.map +1 -1
- package/lib/types/components/Chat/JobCard.js +128 -33
- package/lib/types/components/Chat/JobGroupHeader.d.ts +27 -0
- package/lib/types/components/Chat/JobGroupHeader.d.ts.map +1 -0
- package/lib/types/components/Chat/JobGroupHeader.js +62 -0
- package/lib/types/components/Chat/SubagentMessage.js +6 -6
- package/lib/types/components/GoalTodoPanel.d.ts +13 -1
- package/lib/types/components/GoalTodoPanel.d.ts.map +1 -1
- package/lib/types/components/GoalTodoPanel.js +55 -14
- package/lib/types/components/JobsPanel.d.ts +42 -2
- package/lib/types/components/JobsPanel.d.ts.map +1 -1
- package/lib/types/components/JobsPanel.js +220 -40
- package/lib/types/components/LogoV2.d.ts +43 -3
- package/lib/types/components/LogoV2.d.ts.map +1 -1
- package/lib/types/components/LogoV2.js +42 -15
- package/lib/types/components/MessageList.d.ts +8 -2
- package/lib/types/components/MessageList.d.ts.map +1 -1
- package/lib/types/components/MessageList.js +215 -21
- package/lib/types/components/OverlayAbove.d.ts +11 -1
- package/lib/types/components/OverlayAbove.d.ts.map +1 -1
- package/lib/types/components/OverlayAbove.js +2 -12
- package/lib/types/components/PageMargin.d.ts.map +1 -1
- package/lib/types/components/PageMargin.js +3 -1
- package/lib/types/components/PluginSceneBoundary.d.ts +1 -1
- package/lib/types/components/PluginSceneBoundary.js +1 -1
- package/lib/types/components/PresetPicker.d.ts +4 -0
- package/lib/types/components/PresetPicker.d.ts.map +1 -1
- package/lib/types/components/PresetPicker.js +5 -1
- package/lib/types/components/PromptInput.d.ts +20 -22
- package/lib/types/components/PromptInput.d.ts.map +1 -1
- package/lib/types/components/PromptInput.js +425 -157
- package/lib/types/components/SearchBox.d.ts +22 -5
- package/lib/types/components/SearchBox.d.ts.map +1 -1
- package/lib/types/components/SearchBox.js +17 -13
- package/lib/types/components/StarPrompt.d.ts +6 -0
- package/lib/types/components/StarPrompt.d.ts.map +1 -1
- package/lib/types/components/StarPrompt.js +45 -0
- package/lib/types/components/SubagentCard.d.ts.map +1 -1
- package/lib/types/components/SubagentCard.js +24 -9
- package/lib/types/components/SubagentDashboard.d.ts +18 -3
- package/lib/types/components/SubagentDashboard.d.ts.map +1 -1
- package/lib/types/components/SubagentDashboard.js +53 -5
- package/lib/types/components/SubagentDetailScene.d.ts +7 -1
- package/lib/types/components/SubagentDetailScene.d.ts.map +1 -1
- package/lib/types/components/SubagentDetailScene.js +160 -13
- package/lib/types/components/SurfaceEdges.d.ts +21 -0
- package/lib/types/components/SurfaceEdges.d.ts.map +1 -0
- package/lib/types/components/SurfaceEdges.js +7 -0
- package/lib/types/components/ThemePicker.d.ts +9 -0
- package/lib/types/components/ThemePicker.d.ts.map +1 -1
- package/lib/types/components/ThemePicker.js +74 -10
- package/lib/types/components/ThemePreviewPane.d.ts +26 -0
- package/lib/types/components/ThemePreviewPane.d.ts.map +1 -0
- package/lib/types/components/ThemePreviewPane.js +99 -0
- package/lib/types/components/WhaleGirl.d.ts +6 -0
- package/lib/types/components/WhaleGirl.d.ts.map +1 -1
- package/lib/types/components/WhaleGirl.js +18 -0
- package/lib/types/components/design-system/Divider.d.ts.map +1 -1
- package/lib/types/components/design-system/Divider.js +14 -9
- package/lib/types/components/launchpadActions.d.ts +73 -0
- package/lib/types/components/launchpadActions.d.ts.map +1 -0
- package/lib/types/components/launchpadActions.js +111 -0
- package/lib/types/components/launchpadLayout.d.ts +62 -0
- package/lib/types/components/launchpadLayout.d.ts.map +1 -0
- package/lib/types/components/launchpadLayout.js +176 -0
- package/lib/types/components/messages/AssistantThinkingMessage.js +4 -4
- package/lib/types/components/onboardingModel.d.ts +83 -0
- package/lib/types/components/onboardingModel.d.ts.map +1 -0
- package/lib/types/components/onboardingModel.js +128 -0
- package/lib/types/components/sidePanel/InfoPanel.d.ts +17 -0
- package/lib/types/components/sidePanel/InfoPanel.d.ts.map +1 -0
- package/lib/types/components/sidePanel/InfoPanel.js +124 -0
- package/lib/types/components/sidePanel/PanelBar.d.ts +45 -0
- package/lib/types/components/sidePanel/PanelBar.d.ts.map +1 -0
- package/lib/types/components/sidePanel/PanelBar.js +104 -0
- package/lib/types/components/sidePanel/PanelErrorBoundary.d.ts +21 -0
- package/lib/types/components/sidePanel/PanelErrorBoundary.d.ts.map +1 -0
- package/lib/types/components/sidePanel/PanelErrorBoundary.js +30 -0
- package/lib/types/components/sidePanel/PanelHost.d.ts +36 -0
- package/lib/types/components/sidePanel/PanelHost.d.ts.map +1 -0
- package/lib/types/components/sidePanel/PanelHost.js +81 -0
- package/lib/types/components/sidePanel/PanelPicker.d.ts +24 -0
- package/lib/types/components/sidePanel/PanelPicker.d.ts.map +1 -0
- package/lib/types/components/sidePanel/PanelPicker.js +45 -0
- package/lib/types/components/sidePanel/PanelStore.d.ts +55 -0
- package/lib/types/components/sidePanel/PanelStore.d.ts.map +1 -0
- package/lib/types/components/sidePanel/PanelStore.js +109 -0
- package/lib/types/components/sidePanel/SidePanelColumn.d.ts +31 -0
- package/lib/types/components/sidePanel/SidePanelColumn.d.ts.map +1 -0
- package/lib/types/components/sidePanel/SidePanelColumn.js +70 -0
- package/lib/types/components/sidePanel/SidePanelLayout.d.ts +54 -0
- package/lib/types/components/sidePanel/SidePanelLayout.d.ts.map +1 -0
- package/lib/types/components/sidePanel/SidePanelLayout.js +81 -0
- package/lib/types/components/sidePanel/SidePanelRuntimeContext.d.ts +43 -0
- package/lib/types/components/sidePanel/SidePanelRuntimeContext.d.ts.map +1 -0
- package/lib/types/components/sidePanel/SidePanelRuntimeContext.js +26 -0
- package/lib/types/components/sidePanel/TrajectoryPanel.d.ts +7 -0
- package/lib/types/components/sidePanel/TrajectoryPanel.d.ts.map +1 -0
- package/lib/types/components/sidePanel/TrajectoryPanel.js +263 -0
- package/lib/types/components/sidePanel/WorkspacePanel.d.ts +4 -0
- package/lib/types/components/sidePanel/WorkspacePanel.d.ts.map +1 -0
- package/lib/types/components/sidePanel/WorkspacePanel.js +171 -0
- package/lib/types/components/sidePanel/builtinPanels.d.ts +3 -0
- package/lib/types/components/sidePanel/builtinPanels.d.ts.map +1 -0
- package/lib/types/components/sidePanel/builtinPanels.js +229 -0
- package/lib/types/components/sidePanel/companion/CompanionPanel.d.ts +53 -0
- package/lib/types/components/sidePanel/companion/CompanionPanel.d.ts.map +1 -0
- package/lib/types/components/sidePanel/companion/CompanionPanel.js +528 -0
- package/lib/types/components/sidePanel/companion/SplashMascot.d.ts +32 -0
- package/lib/types/components/sidePanel/companion/SplashMascot.d.ts.map +1 -0
- package/lib/types/components/sidePanel/companion/SplashMascot.js +103 -0
- package/lib/types/components/sidePanel/companion/deepy.d.ts +75 -0
- package/lib/types/components/sidePanel/companion/deepy.d.ts.map +1 -0
- package/lib/types/components/sidePanel/companion/deepy.js +222 -0
- package/lib/types/components/sidePanel/companion/mood.d.ts +176 -0
- package/lib/types/components/sidePanel/companion/mood.d.ts.map +1 -0
- package/lib/types/components/sidePanel/companion/mood.js +212 -0
- package/lib/types/components/sidePanel/companion/pose.d.ts +43 -0
- package/lib/types/components/sidePanel/companion/pose.d.ts.map +1 -0
- package/lib/types/components/sidePanel/companion/pose.js +34 -0
- package/lib/types/components/sidePanel/companion/skins.d.ts +102 -0
- package/lib/types/components/sidePanel/companion/skins.d.ts.map +1 -0
- package/lib/types/components/sidePanel/companion/skins.js +408 -0
- package/lib/types/components/sidePanel/dimensions.d.ts +60 -0
- package/lib/types/components/sidePanel/dimensions.d.ts.map +1 -0
- package/lib/types/components/sidePanel/dimensions.js +75 -0
- package/lib/types/components/sidePanel/jobsFocusStore.d.ts +21 -0
- package/lib/types/components/sidePanel/jobsFocusStore.d.ts.map +1 -0
- package/lib/types/components/sidePanel/jobsFocusStore.js +30 -0
- package/lib/types/components/sidePanel/panelBridge.d.ts +44 -0
- package/lib/types/components/sidePanel/panelBridge.d.ts.map +1 -0
- package/lib/types/components/sidePanel/panelBridge.js +55 -0
- package/lib/types/components/sidePanel/pluginPanelAdapter.d.ts +22 -0
- package/lib/types/components/sidePanel/pluginPanelAdapter.d.ts.map +1 -0
- package/lib/types/components/sidePanel/pluginPanelAdapter.js +148 -0
- package/lib/types/components/sidePanel/types.d.ts +110 -0
- package/lib/types/components/sidePanel/types.d.ts.map +1 -0
- package/lib/types/components/sidePanel/types.js +1 -0
- package/lib/types/components/sidePanel/usePanelInput.d.ts +5 -0
- package/lib/types/components/sidePanel/usePanelInput.d.ts.map +1 -0
- package/lib/types/components/sidePanel/usePanelInput.js +44 -0
- package/lib/types/components/sidePanel/useSidePanel.d.ts +47 -0
- package/lib/types/components/sidePanel/useSidePanel.d.ts.map +1 -0
- package/lib/types/components/sidePanel/useSidePanel.js +284 -0
- package/lib/types/components/trajectory/MiniWake.d.ts +11 -1
- package/lib/types/components/trajectory/MiniWake.d.ts.map +1 -1
- package/lib/types/components/trajectory/MiniWake.js +9 -3
- package/lib/types/components/workspaces/HomeWorkspaceRow.d.ts +3 -1
- package/lib/types/components/workspaces/HomeWorkspaceRow.d.ts.map +1 -1
- package/lib/types/components/workspaces/HomeWorkspaceRow.js +3 -2
- package/lib/types/deepseekPricing.d.ts +10 -9
- package/lib/types/deepseekPricing.d.ts.map +1 -1
- package/lib/types/deepseekPricing.js +18 -11
- package/lib/types/dsh-adapter/channel/attached-context.d.ts +58 -0
- package/lib/types/dsh-adapter/channel/attached-context.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/attached-context.js +109 -0
- package/lib/types/dsh-adapter/channel/binding-events.d.ts +6 -0
- package/lib/types/dsh-adapter/channel/binding-events.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/binding-events.js +43 -0
- package/lib/types/dsh-adapter/channel/capabilities.d.ts +82 -0
- package/lib/types/dsh-adapter/channel/capabilities.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/capabilities.js +165 -0
- package/lib/types/dsh-adapter/channel/command-completions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/command-completions.js +8 -0
- package/lib/types/dsh-adapter/channel/context-bookkeeping.d.ts +4 -12
- package/lib/types/dsh-adapter/channel/context-bookkeeping.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/context-bookkeeping.js +9 -4
- package/lib/types/dsh-adapter/channel/external-commands.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/external-commands.js +8 -2
- package/lib/types/dsh-adapter/channel/input-delivery.d.ts +13 -2
- package/lib/types/dsh-adapter/channel/input-delivery.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/input-delivery.js +18 -1
- package/lib/types/dsh-adapter/channel/job-projection.d.ts +1 -0
- package/lib/types/dsh-adapter/channel/job-projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/job-projection.js +88 -3
- package/lib/types/dsh-adapter/channel/mode-actions.d.ts +13 -3
- package/lib/types/dsh-adapter/channel/mode-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/mode-actions.js +55 -9
- package/lib/types/dsh-adapter/channel/mode-permission-actions.d.ts +8 -1
- package/lib/types/dsh-adapter/channel/mode-permission-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/mode-permission-actions.js +25 -10
- package/lib/types/dsh-adapter/channel/preferences.d.ts +1 -1
- package/lib/types/dsh-adapter/channel/preferences.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/preferences.js +26 -8
- package/lib/types/dsh-adapter/channel/projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/projection.js +42 -37
- package/lib/types/dsh-adapter/channel/reports.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/reports.js +13 -4
- package/lib/types/dsh-adapter/channel/session-reset.d.ts +5 -1
- package/lib/types/dsh-adapter/channel/session-reset.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-reset.js +1 -0
- package/lib/types/dsh-adapter/channel/state.d.ts +21 -3
- package/lib/types/dsh-adapter/channel/state.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/state.js +3 -2
- package/lib/types/dsh-adapter/channel/subagent-projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/subagent-projection.js +5 -0
- package/lib/types/dsh-adapter/channel/types.d.ts +1 -1
- package/lib/types/dsh-adapter/channel/types.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/usage.d.ts +18 -1
- package/lib/types/dsh-adapter/channel/usage.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/usage.js +97 -2
- package/lib/types/dsh-adapter/channel.d.ts +1 -1
- package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel.js +72 -4
- package/lib/types/dsh-adapter/context-occupancy.d.ts +204 -0
- package/lib/types/dsh-adapter/context-occupancy.d.ts.map +1 -0
- package/lib/types/dsh-adapter/context-occupancy.js +299 -0
- package/lib/types/dsh-adapter/contract.d.ts +19 -4
- package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
- package/lib/types/dsh-adapter/contract.js +33 -3
- package/lib/types/dsh-adapter/index.d.ts +32 -0
- package/lib/types/dsh-adapter/index.d.ts.map +1 -1
- package/lib/types/dsh-adapter/index.js +20 -1
- package/lib/types/dsh-adapter/jobs.d.ts +82 -16
- package/lib/types/dsh-adapter/jobs.d.ts.map +1 -1
- package/lib/types/dsh-adapter/jobs.js +104 -9
- package/lib/types/dsh-adapter/migrate/sessionize.d.ts.map +1 -1
- package/lib/types/dsh-adapter/migrate/sessionize.js +11 -12
- package/lib/types/dsh-adapter/oauth/bonus.d.ts +27 -0
- package/lib/types/dsh-adapter/oauth/bonus.d.ts.map +1 -0
- package/lib/types/dsh-adapter/oauth/bonus.js +69 -0
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/command.d.ts +2 -1
- package/lib/types/dsh-adapter/oauth/command.d.ts.map +1 -0
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/command.js +7 -4
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/credentials.d.ts +13 -10
- package/lib/types/dsh-adapter/oauth/credentials.d.ts.map +1 -0
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/credentials.js +61 -23
- package/lib/types/dsh-adapter/oauth/deepseek.d.ts +39 -0
- package/lib/types/dsh-adapter/oauth/deepseek.d.ts.map +1 -0
- package/lib/types/dsh-adapter/oauth/deepseek.js +189 -0
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/index.d.ts +24 -16
- package/lib/types/dsh-adapter/oauth/index.d.ts.map +1 -0
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/index.js +34 -20
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/interaction.d.ts +14 -12
- package/lib/types/dsh-adapter/oauth/interaction.d.ts.map +1 -0
- package/lib/types/dsh-adapter/oauth/interaction.js +283 -0
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/opener.d.ts +2 -1
- package/lib/types/dsh-adapter/oauth/opener.d.ts.map +1 -0
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/opener.js +1 -1
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/pi-ai.d.ts +10 -3
- package/lib/types/dsh-adapter/oauth/pi-ai.d.ts.map +1 -0
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/pi-ai.js +8 -3
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/profiles.d.ts +6 -3
- package/lib/types/dsh-adapter/oauth/profiles.d.ts.map +1 -0
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/profiles.js +11 -3
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/service.d.ts +14 -7
- package/lib/types/dsh-adapter/oauth/service.d.ts.map +1 -0
- package/{node_modules/@deepseek-harness-tui/dsh-auth/lib → lib/types/dsh-adapter/oauth}/service.js +82 -17
- package/lib/types/dsh-adapter/panel-runtime-registry.d.ts +39 -0
- package/lib/types/dsh-adapter/panel-runtime-registry.d.ts.map +1 -0
- package/lib/types/dsh-adapter/panel-runtime-registry.js +84 -0
- package/lib/types/dsh-adapter/panels.d.ts +251 -0
- package/lib/types/dsh-adapter/panels.d.ts.map +1 -0
- package/lib/types/dsh-adapter/panels.js +407 -0
- package/lib/types/dsh-adapter/plugin-host.js +1 -1
- package/lib/types/dsh-adapter/plugin.d.ts +25 -2
- package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin.js +241 -44
- package/lib/types/dsh-adapter/presets.d.ts +26 -4
- package/lib/types/dsh-adapter/presets.d.ts.map +1 -1
- package/lib/types/dsh-adapter/presets.js +29 -5
- package/lib/types/dsh-adapter/providerWizard.d.ts.map +1 -1
- package/lib/types/dsh-adapter/providerWizard.js +6 -2
- package/lib/types/dsh-adapter/startup-args.d.ts +8 -0
- package/lib/types/dsh-adapter/startup-args.d.ts.map +1 -0
- package/lib/types/dsh-adapter/startup-args.js +34 -0
- package/lib/types/dsh-adapter/subagents.d.ts +1 -0
- package/lib/types/dsh-adapter/subagents.d.ts.map +1 -1
- package/lib/types/dsh-adapter/subagents.js +10 -1
- package/lib/types/history.d.ts +24 -7
- package/lib/types/history.d.ts.map +1 -1
- package/lib/types/history.js +77 -18
- package/lib/types/i18n.d.ts +908 -33
- package/lib/types/i18n.d.ts.map +1 -1
- package/lib/types/i18n.js +355 -17
- package/lib/types/ink/components/App.d.ts +14 -1
- package/lib/types/ink/components/App.d.ts.map +1 -1
- package/lib/types/ink/components/App.js +71 -61
- package/lib/types/ink/components/TerminalSizeContext.d.ts +7 -0
- package/lib/types/ink/components/TerminalSizeContext.d.ts.map +1 -1
- package/lib/types/ink/hooks/use-input.d.ts +11 -0
- package/lib/types/ink/hooks/use-input.d.ts.map +1 -1
- package/lib/types/ink/hooks/use-input.js +8 -2
- package/lib/types/ink/hooks/use-terminal-viewport.d.ts.map +1 -1
- package/lib/types/ink/hooks/use-terminal-viewport.js +3 -1
- package/lib/types/ink/ink.d.ts +18 -0
- package/lib/types/ink/ink.d.ts.map +1 -1
- package/lib/types/ink/ink.js +51 -8
- package/lib/types/ink/output.d.ts +10 -1
- package/lib/types/ink/output.d.ts.map +1 -1
- package/lib/types/ink/output.js +3 -3
- package/lib/types/ink/parse-keypress.d.ts +71 -3
- package/lib/types/ink/parse-keypress.d.ts.map +1 -1
- package/lib/types/ink/parse-keypress.js +815 -133
- package/lib/types/ink/render-node-to-output.d.ts +1 -1
- package/lib/types/ink/render-node-to-output.d.ts.map +1 -1
- package/lib/types/ink/render-node-to-output.js +37 -5
- package/lib/types/ink/screen.d.ts +26 -1
- package/lib/types/ink/screen.d.ts.map +1 -1
- package/lib/types/ink/screen.js +96 -1
- package/lib/types/ink/selection.d.ts +23 -1
- package/lib/types/ink/selection.d.ts.map +1 -1
- package/lib/types/ink/selection.js +102 -26
- package/lib/types/ink/sixel-codec.d.ts +11 -0
- package/lib/types/ink/sixel-codec.d.ts.map +1 -1
- package/lib/types/ink/sixel-codec.js +42 -8
- package/lib/types/ink/terminal-querier.d.ts +25 -0
- package/lib/types/ink/terminal-querier.d.ts.map +1 -1
- package/lib/types/ink/terminal-querier.js +42 -0
- package/lib/types/ink/update-overflow-guard.d.ts +24 -0
- package/lib/types/ink/update-overflow-guard.d.ts.map +1 -1
- package/lib/types/ink/update-overflow-guard.js +25 -3
- package/lib/types/math/renderer.d.ts +2 -0
- package/lib/types/math/renderer.d.ts.map +1 -1
- package/lib/types/math/renderer.js +4 -0
- package/lib/types/minimalUiMode.d.ts +19 -0
- package/lib/types/minimalUiMode.d.ts.map +1 -0
- package/lib/types/minimalUiMode.js +23 -0
- package/lib/types/oauth.d.ts +5 -10
- package/lib/types/oauth.d.ts.map +1 -1
- package/lib/types/oauth.js +5 -10
- package/lib/types/onboardingPrefs.d.ts +52 -0
- package/lib/types/onboardingPrefs.d.ts.map +1 -0
- package/lib/types/onboardingPrefs.js +107 -0
- package/lib/types/panels.d.ts +4 -0
- package/lib/types/panels.d.ts.map +1 -0
- package/lib/types/panels.js +4 -0
- package/lib/types/screens/Chat.d.ts +25 -1
- package/lib/types/screens/Chat.d.ts.map +1 -1
- package/lib/types/screens/Chat.js +1149 -302
- package/lib/types/screens/Launchpad.d.ts +194 -0
- package/lib/types/screens/Launchpad.d.ts.map +1 -0
- package/lib/types/screens/Launchpad.js +607 -0
- package/lib/types/screens/Onboarding.d.ts +37 -0
- package/lib/types/screens/Onboarding.d.ts.map +1 -0
- package/lib/types/screens/Onboarding.js +492 -0
- package/lib/types/screens/SessionSupervisor.d.ts.map +1 -1
- package/lib/types/screens/SessionSupervisor.js +18 -12
- package/lib/types/screens/StatusLine.d.ts +4 -0
- package/lib/types/screens/StatusLine.d.ts.map +1 -1
- package/lib/types/screens/StatusLine.js +43 -25
- package/lib/types/screens/StatusMetrics.d.ts +22 -0
- package/lib/types/screens/StatusMetrics.d.ts.map +1 -1
- package/lib/types/screens/StatusMetrics.js +20 -0
- package/lib/types/screens/chatOverlay.d.ts +18 -1
- package/lib/types/screens/chatOverlay.d.ts.map +1 -1
- package/lib/types/screens/chatOverlay.js +3 -0
- package/lib/types/screens/sessionSupervisor/model.d.ts +1 -2
- package/lib/types/screens/sessionSupervisor/model.d.ts.map +1 -1
- package/lib/types/screens/sessionSupervisor/model.js +4 -2
- package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts.map +1 -1
- package/lib/types/screens/sessionSupervisor/useSessionSupervisor.js +7 -3
- package/lib/types/settings/definitions.d.ts +93 -0
- package/lib/types/settings/definitions.d.ts.map +1 -1
- package/lib/types/settings/definitions.js +87 -4
- package/lib/types/tips.d.ts.map +1 -1
- package/lib/types/tips.js +13 -7
- package/lib/types/tuiDisplayPrefs.d.ts +42 -2
- package/lib/types/tuiDisplayPrefs.d.ts.map +1 -1
- package/lib/types/tuiDisplayPrefs.js +74 -0
- package/lib/types/update.d.ts +53 -9
- package/lib/types/update.d.ts.map +1 -1
- package/lib/types/update.js +103 -46
- package/lib/types/utils/bmp.d.ts.map +1 -1
- package/lib/types/utils/bmp.js +8 -1
- package/lib/types/utils/clipboard.d.ts.map +1 -1
- package/lib/types/utils/clipboard.js +25 -6
- package/lib/types/utils/credentials.d.ts.map +1 -1
- package/lib/types/utils/credentials.js +5 -1
- package/lib/types/utils/draftWordBoundary.d.ts +23 -0
- package/lib/types/utils/draftWordBoundary.d.ts.map +1 -0
- package/lib/types/utils/draftWordBoundary.js +161 -0
- package/lib/types/utils/fileTarget.d.ts.map +1 -1
- package/lib/types/utils/fileTarget.js +7 -9
- package/lib/types/utils/inputPaste.d.ts +62 -0
- package/lib/types/utils/inputPaste.d.ts.map +1 -0
- package/lib/types/utils/inputPaste.js +111 -0
- package/lib/types/utils/intl.d.ts +8 -0
- package/lib/types/utils/intl.d.ts.map +1 -1
- package/lib/types/utils/intl.js +11 -0
- package/lib/types/utils/keymap.d.ts +13 -3
- package/lib/types/utils/keymap.d.ts.map +1 -1
- package/lib/types/utils/keymap.js +27 -5
- package/lib/types/utils/pastedImagePath.d.ts +8 -0
- package/lib/types/utils/pastedImagePath.d.ts.map +1 -1
- package/lib/types/utils/pastedImagePath.js +29 -5
- package/package.json +128 -106
- package/presets/liangshen/agent.cordis.yml +4 -1
- package/presets/liangshen/preset.yml +1 -1
- package/{dsh-ecosystem-spec → tui-profile}/registry/README.md +1 -1
- package/{dsh-ecosystem-spec → tui-profile}/registry/registry-0.15.json +1 -1
- package/lib/types/minimalMode.d.ts +0 -13
- package/lib/types/minimalMode.d.ts.map +0 -1
- package/lib/types/minimalMode.js +0 -17
- package/node_modules/@deepseek-harness-tui/dsh-auth/LICENSE +0 -21
- package/node_modules/@deepseek-harness-tui/dsh-auth/README.md +0 -143
- package/node_modules/@deepseek-harness-tui/dsh-auth/cordis.patch.yml +0 -11
- package/node_modules/@deepseek-harness-tui/dsh-auth/dsh-plugin.json +0 -44
- package/node_modules/@deepseek-harness-tui/dsh-auth/lib/interaction.js +0 -193
- package/node_modules/@deepseek-harness-tui/dsh-auth/package.json +0 -69
- /package/{dsh-ecosystem-spec → tui-profile}/protocols/profile-definitions.d.ts +0 -0
- /package/{dsh-ecosystem-spec → tui-profile}/protocols/profile-definitions.js +0 -0
- /package/{dsh-ecosystem-spec → tui-profile}/protocols/tui-channel-http.d.ts +0 -0
- /package/{dsh-ecosystem-spec → tui-profile}/protocols/tui-channel-http.js +0 -0
- /package/{dsh-ecosystem-spec → tui-profile}/protocols/tui-channel.d.ts +0 -0
- /package/{dsh-ecosystem-spec → tui-profile}/protocols/tui-channel.js +0 -0
- /package/{dsh-ecosystem-spec → tui-profile}/protocols/tui-contributions.d.ts +0 -0
- /package/{dsh-ecosystem-spec → tui-profile}/protocols/tui-contributions.js +0 -0
- /package/{dsh-ecosystem-spec → tui-profile}/registry/contracts/decision-events-v1alpha1.json +0 -0
- /package/{dsh-ecosystem-spec → tui-profile}/registry/contracts/scene-v1alpha1.json +0 -0
- /package/{dsh-ecosystem-spec → tui-profile}/registry/contracts/settings-section-v1alpha1.json +0 -0
- /package/{dsh-ecosystem-spec → tui-profile}/registry/contracts/tui-channel-v1alpha1.json +0 -0
- /package/{dsh-ecosystem-spec → tui-profile}/registry/contracts/workspace-provider-v1alpha1.json +0 -0
- /package/{dsh-ecosystem-spec → tui-profile}/registry/host-descriptor.tui.example.json +0 -0
- /package/{dsh-ecosystem-spec → tui-profile}/registry/permissions-0.1.json +0 -0
- /package/{dsh-ecosystem-spec → tui-profile}/schemas/conformance-claim.schema.json +0 -0
- /package/{dsh-ecosystem-spec → tui-profile}/schemas/effect-ledger-record.schema.json +0 -0
- /package/{dsh-ecosystem-spec → tui-profile}/schemas/host-descriptor.schema.json +0 -0
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import React from 'react';
|
|
3
|
-
|
|
3
|
+
// 粘贴/清洗语义已抽到 utils/inputPaste.ts(方案 B:PromptInput 与 Launchpad 共享;
|
|
4
|
+
// 行为逐字节不变,只是搬了家)。
|
|
5
|
+
import { sanitizeEditableText, sanitizePastedText } from '../utils/inputPaste.js';
|
|
4
6
|
import { constants as fsConstants } from 'node:fs';
|
|
5
7
|
import { open, unlink } from 'node:fs/promises';
|
|
6
8
|
import { basename, resolve } from 'node:path';
|
|
@@ -19,12 +21,13 @@ import instances from '../ink/instances.js';
|
|
|
19
21
|
import { stringWidth } from '../ink/stringWidth.js';
|
|
20
22
|
import { truncateToWidth } from '../ink/truncateToWidth.js';
|
|
21
23
|
import { getGraphemeSegmenter } from '../utils/intl.js';
|
|
24
|
+
import { draftWordRangeAt, isDraftWordBoundary } from '../utils/draftWordBoundary.js';
|
|
22
25
|
import { formatClipboardInsert, readClipboard } from '../utils/clipboard.js';
|
|
23
26
|
import { imagePathMediaType, parsePastedImagePath, stageClipboardFilePaths } from '../utils/pastedImagePath.js';
|
|
24
27
|
import { editInExternalEditor } from '../utils/externalEditor.js';
|
|
25
28
|
import { setPromptEditorNode, EditorButton } from './PromptEditor.js';
|
|
26
29
|
import { isHiddenCommandName, parseCommandName } from '../commands.js';
|
|
27
|
-
import { appendHistory, HISTORY_LIMIT, loadHistoryOldestFirst } from '../history.js';
|
|
30
|
+
import { appendHistory, HISTORY_LIMIT, historyProjectKey, loadHistoryOldestFirst } from '../history.js';
|
|
28
31
|
import { mentionAtCaret } from '../utils/mentions.js';
|
|
29
32
|
import { preserveSelection } from '../utils/fileSuggestions.js';
|
|
30
33
|
import { isMod } from '../utils/modifiers.js';
|
|
@@ -35,6 +38,7 @@ import { HelpMenu } from './HelpMenu.js';
|
|
|
35
38
|
import { OverlayAbove } from './OverlayAbove.js';
|
|
36
39
|
import { SuggestionCard, cardContentWidth } from './SuggestionCard.js';
|
|
37
40
|
import { filterLiveImageBindings, isUsableDraftSnapshot, resolveBindingGeneration, } from './promptDraftCache.js';
|
|
41
|
+
export { sanitizeEditableText, sanitizePastedText } from '../utils/inputPaste.js';
|
|
38
42
|
/**
|
|
39
43
|
* Visible text of the session-entry control at the head of the input row:
|
|
40
44
|
* U+2338 APL FUNCTIONAL SYMBOL QUAD COLON plus a separator space.
|
|
@@ -53,6 +57,67 @@ import { filterLiveImageBindings, isUsableDraftSnapshot, resolveBindingGeneratio
|
|
|
53
57
|
*/
|
|
54
58
|
const HOME_BUTTON_TEXT = '⌸ ';
|
|
55
59
|
const HOME_BUTTON_COLS = stringWidth(HOME_BUTTON_TEXT);
|
|
60
|
+
/** Undo depth for both stacks (draft `Ctrl+Z` and vim `u`). */
|
|
61
|
+
const UNDO_LIMIT = 100;
|
|
62
|
+
/** Total characters kept across all snapshots; the oldest are dropped first. */
|
|
63
|
+
const UNDO_MAX_CHARS = 1_000_000;
|
|
64
|
+
/** Layer-3 idle window: a pause longer than this starts a new step. */
|
|
65
|
+
const UNDO_IDLE_MS = 700;
|
|
66
|
+
/**
|
|
67
|
+
* Common prefix/suffix of `prev` and `next` — the single edited span. Undo
|
|
68
|
+
* grouping works on this span rather than on a stdin chunk: one chunk may
|
|
69
|
+
* carry several characters (or several keys), so the unit is one real text
|
|
70
|
+
* mutation however it arrived. The common prefix must not pass either caret:
|
|
71
|
+
* repeated characters otherwise make an edit at the head look like a tail edit.
|
|
72
|
+
*/
|
|
73
|
+
function diffSpan(prev, next, cursorBefore, cursorAfter) {
|
|
74
|
+
let start = 0;
|
|
75
|
+
const common = Math.min(prev.length, next.length, cursorBefore, cursorAfter);
|
|
76
|
+
while (start < common && prev.charCodeAt(start) === next.charCodeAt(start))
|
|
77
|
+
start++;
|
|
78
|
+
let prevEnd = prev.length;
|
|
79
|
+
let nextEnd = next.length;
|
|
80
|
+
while (prevEnd > start &&
|
|
81
|
+
nextEnd > start &&
|
|
82
|
+
prev.charCodeAt(prevEnd - 1) === next.charCodeAt(nextEnd - 1)) {
|
|
83
|
+
prevEnd--;
|
|
84
|
+
nextEnd--;
|
|
85
|
+
}
|
|
86
|
+
return { start, inserted: next.slice(start, nextEnd) };
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Open a deletion run at the first character it removed: remember the word that
|
|
90
|
+
* character belongs to, and how much has been consumed so far.
|
|
91
|
+
*/
|
|
92
|
+
function startDeleteRun(text, start, removed) {
|
|
93
|
+
const word = draftWordRangeAt(text, start);
|
|
94
|
+
return { wordStart: word.start, wordEnd: word.end, lo: start, hi: start + removed };
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Whether a same-direction deletion extends the run recorded on `last`. The
|
|
98
|
+
* run's word interval and consumed range live in `last.text` coordinates, so
|
|
99
|
+
* the comparison survives the draft shrinking under it; extending past the word
|
|
100
|
+
* (or off the text) starts a new step. Only called once the direction, caret
|
|
101
|
+
* continuity and idle window have already agreed, so the new text is always
|
|
102
|
+
* adjacent to the consumed range.
|
|
103
|
+
*/
|
|
104
|
+
function extendDeleteRun(last, backward, removed) {
|
|
105
|
+
const run = last.deleteRun;
|
|
106
|
+
if (run === null || removed <= 0)
|
|
107
|
+
return false;
|
|
108
|
+
if (backward) {
|
|
109
|
+
const lo = run.lo - removed;
|
|
110
|
+
if (lo < 0 || lo < run.wordStart)
|
|
111
|
+
return false;
|
|
112
|
+
run.lo = lo;
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
const hi = run.hi + removed;
|
|
116
|
+
if (hi > last.text.length || hi > run.wordEnd)
|
|
117
|
+
return false;
|
|
118
|
+
run.hi = hi;
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
56
121
|
/**
|
|
57
122
|
* Paste fold with a visible preview and no black box:
|
|
58
123
|
* a paste that leaves the input this big folds into a one-line chip
|
|
@@ -65,66 +130,6 @@ const HOME_BUTTON_COLS = stringWidth(HOME_BUTTON_TEXT);
|
|
|
65
130
|
const FOLD_MIN_LINES = 6;
|
|
66
131
|
const FOLD_MIN_CHARS = 600;
|
|
67
132
|
const isBigInput = (text) => text.split('\n').length >= FOLD_MIN_LINES || text.length >= FOLD_MIN_CHARS;
|
|
68
|
-
/**
|
|
69
|
-
* Editable prompt text must have one stable source-to-screen geometry. The
|
|
70
|
-
* renderer interprets ANSI as zero-width styling and expands tabs relative to
|
|
71
|
-
* global tab stops; keeping either in `value` would let wrapping/click mapping
|
|
72
|
-
* count different cells and could split an escape sequence during selection.
|
|
73
|
-
* Strip terminal controls and expand tabs at ingress while preserving newlines.
|
|
74
|
-
*/
|
|
75
|
-
const EDITABLE_CONTROL = /[\u0000-\u0009\u000b-\u001f\u007f]/u;
|
|
76
|
-
/**
|
|
77
|
-
* Raw win32-input-mode records (`CSI Vk;Sc;Uc;Kd;Cs;Rc _`) that reached the
|
|
78
|
-
* editable buffer as text instead of being translated. `stripAnsi` consumes
|
|
79
|
-
* the record head and leaves its terminating `_` in the draft — the stray
|
|
80
|
-
* underscore users see after a multi-line paste (issue #1090). Only the full
|
|
81
|
-
* record grammar (exactly five `;` separators) matches, so a real `_` and
|
|
82
|
-
* ordinary bracket text survive untouched.
|
|
83
|
-
*/
|
|
84
|
-
const WIN32_RECORD_RESIDUE = /\u001b\[\d*(?:;\d*){5}_/gu;
|
|
85
|
-
/**
|
|
86
|
-
* The same record with its ESC byte missing: what a record split across
|
|
87
|
-
* reads leaves behind when the escape timer flushed the prefix before the
|
|
88
|
-
* tail arrived. Printable, so it is stripped only from paste payloads
|
|
89
|
-
* ({@link sanitizePastedText}) — and only when the same payload also carries
|
|
90
|
-
* a full ESC-bearing record as in-payload evidence of that split; typed text
|
|
91
|
-
* and literal clipboard/bracketed-paste bytes are left untouched.
|
|
92
|
-
*/
|
|
93
|
-
const WIN32_RECORD_RESIDUE_TAIL = /\[\d*(?:;\d*){5}_/gu;
|
|
94
|
-
/**
|
|
95
|
-
* Normalize editable text so no terminal control characters remain in state.
|
|
96
|
-
*/
|
|
97
|
-
export function sanitizeEditableText(text) {
|
|
98
|
-
// Fast path for ordinary and multi-line drafts: newline is intentionally
|
|
99
|
-
// absent from the probe, so large clean text returns without the
|
|
100
|
-
// stripAnsi/control-normalization passes.
|
|
101
|
-
if (!EDITABLE_CONTROL.test(text))
|
|
102
|
-
return text;
|
|
103
|
-
// Record residue goes first: `stripAnsi` would consume the CSI head and
|
|
104
|
-
// leave only the terminating `_` behind.
|
|
105
|
-
return stripAnsi(text.replace(WIN32_RECORD_RESIDUE, ''))
|
|
106
|
-
.replace(/\r\n?/gu, '\n')
|
|
107
|
-
.replace(/\t/gu, ' ')
|
|
108
|
-
.replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/gu, '');
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Paste-payload ingress: strip the ESC-less tail of a split record before
|
|
112
|
-
* normalizing. The tail is printable, so it survives `sanitizeEditableText`'s
|
|
113
|
-
* control probe untouched; typed text keeps it because only a paste payload
|
|
114
|
-
* can carry a partial record.
|
|
115
|
-
*
|
|
116
|
-
* The five separators only prove the *shape*, not that a record was split:
|
|
117
|
-
* a user can legitimately paste the literal `[13;28;13;1;0;1_`. Strip the
|
|
118
|
-
* ESC-less form only when the same payload also carries a full ESC-bearing
|
|
119
|
-
* record — only then is there in-payload evidence of a split stream.
|
|
120
|
-
* Otherwise the bytes are ordinary text and must survive verbatim.
|
|
121
|
-
*/
|
|
122
|
-
export function sanitizePastedText(text) {
|
|
123
|
-
// Probe with String#match: the /g detection regex carries lastIndex state
|
|
124
|
-
// across `.test` calls, so a previous success could skip a later match.
|
|
125
|
-
const hasRecordStream = text.match(WIN32_RECORD_RESIDUE) !== null;
|
|
126
|
-
return sanitizeEditableText(hasRecordStream ? text.replace(WIN32_RECORD_RESIDUE_TAIL, '') : text);
|
|
127
|
-
}
|
|
128
133
|
const COMPOSER_IMAGE_TOKEN = /\[Image #\d+\]/gu;
|
|
129
134
|
/** Format label for one image media type, matching the image preview card's
|
|
130
135
|
* title (`JPEG`, `PNG`, `WEBP`, `GIF`). */
|
|
@@ -414,7 +419,7 @@ const DOUBLE_CLICK_MS = 500;
|
|
|
414
419
|
* working) interrupts the turn and delivers them right away; Ctrl+Enter
|
|
415
420
|
* aborts the turn and sends the current input immediately.
|
|
416
421
|
*/
|
|
417
|
-
export function PromptInput({ channel, suspended = false, draftCache, helpOpen, onToggleHelp, onRunCommand, selectionActive, fillText, onFillConsumed, onRewindRequest, onBackgroundRequest, onOpenSessions, backgroundAgentsNeedingInput, controllerRef, onCaretImage, caretPreviewOpen = false, onDismissCaretPreview, }) {
|
|
422
|
+
export function PromptInput({ channel, toastSuppressed, suspended = false, draftCache, helpOpen, onToggleHelp, onRunCommand, selectionActive, fillText, onFillConsumed, onRewindRequest, onBackgroundRequest, onOpenSessions, backgroundAgentsNeedingInput, controllerRef, onCaretImage, caretPreviewOpen = false, onDismissCaretPreview, now = Date.now, }) {
|
|
418
423
|
const [themeName] = useTheme();
|
|
419
424
|
// Raw stdout writer for OSC 52 clipboard writes (selection copy) — must
|
|
420
425
|
// bypass the frame pipeline; null outside a mounted Ink App.
|
|
@@ -507,7 +512,20 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
507
512
|
const vimInsertRef = React.useRef(true);
|
|
508
513
|
vimEnabledRef.current = vimEnabled;
|
|
509
514
|
vimInsertRef.current = vimInsert;
|
|
510
|
-
/**
|
|
515
|
+
/**
|
|
516
|
+
* Draft-scoped undo stack (word-level `Ctrl+Z`). This is the DRAFT's own
|
|
517
|
+
* history: a submit, a recall or a session switch ends it. Entries hold image
|
|
518
|
+
* bindings exactly like the draft does, so dropping one must release the
|
|
519
|
+
* capabilities only it kept alive.
|
|
520
|
+
*/
|
|
521
|
+
const draftUndoRef = React.useRef([]);
|
|
522
|
+
/**
|
|
523
|
+
* Vim NORMAL-mode undo stack (vim `u`), deliberately separate from
|
|
524
|
+
* `draftUndoRef`: unifying the two transaction models is a user-visible vim
|
|
525
|
+
* behavior change and is out of this change's scope. `/vim` toggling clears
|
|
526
|
+
* THIS stack — a later re-enable must never `u` back past edits made while
|
|
527
|
+
* vim was off.
|
|
528
|
+
*/
|
|
511
529
|
const vimUndoRef = React.useRef([]);
|
|
512
530
|
/** Pending vim operator: `d` pressed, awaiting its second key. */
|
|
513
531
|
const vimPendingRef = React.useRef('');
|
|
@@ -575,8 +593,11 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
575
593
|
const history = React.useRef([]);
|
|
576
594
|
const historyIndex = React.useRef(-1);
|
|
577
595
|
const historyDraft = React.useRef({ text: '', images: [] });
|
|
578
|
-
/** The persisted history is read lazily, once per mount
|
|
579
|
-
|
|
596
|
+
/** The persisted history is read lazily, once per mount and project: the
|
|
597
|
+
* normalized project key it was seeded for, so a workspace switch re-seeds
|
|
598
|
+
* (see seedHistory) while a respelled path to the same directory does not.
|
|
599
|
+
* `null` = never seeded; `''` = seeded without a workspace. */
|
|
600
|
+
const historySeededProject = React.useRef(null);
|
|
580
601
|
/** Visible `[Image #N]` labels are presentation only; this sidecar carries
|
|
581
602
|
* the non-reusable capability for the current draft. History/rewind text
|
|
582
603
|
* restored without this map can never bind to a later image by accident. */
|
|
@@ -606,6 +627,7 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
606
627
|
const detachDraftImages = () => {
|
|
607
628
|
advanceDraftRevision();
|
|
608
629
|
draftImagesRef.current.clear();
|
|
630
|
+
clearDraftUndo();
|
|
609
631
|
clearVimUndo();
|
|
610
632
|
};
|
|
611
633
|
const stageIdIsRetained = (stageId) => {
|
|
@@ -613,7 +635,8 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
613
635
|
if (current === stageId)
|
|
614
636
|
return true;
|
|
615
637
|
}
|
|
616
|
-
return
|
|
638
|
+
return draftUndoRef.current.some(entry => entry.images.some(image => image.stageId === stageId))
|
|
639
|
+
|| vimUndoRef.current.some(entry => entry.images.some(image => image.stageId === stageId))
|
|
617
640
|
|| history.current.some(entry => entry.images.some(image => image.stageId === stageId))
|
|
618
641
|
|| historyDraft.current.images.some(image => image.stageId === stageId)
|
|
619
642
|
|| channel.pending.some(item => item.images?.some(image => image.stageId === stageId) === true);
|
|
@@ -624,14 +647,109 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
624
647
|
channel.discardStagedImage(stageId);
|
|
625
648
|
}
|
|
626
649
|
};
|
|
650
|
+
const clearDraftUndo = () => {
|
|
651
|
+
const previous = draftUndoRef.current;
|
|
652
|
+
draftUndoRef.current = [];
|
|
653
|
+
discardUnretainedImages(previous.flatMap(entry => entry.images.map(image => image.stageId)));
|
|
654
|
+
};
|
|
627
655
|
const clearVimUndo = () => {
|
|
628
656
|
const previous = vimUndoRef.current;
|
|
629
657
|
vimUndoRef.current = [];
|
|
630
658
|
discardUnretainedImages(previous.flatMap(entry => entry.images.map(image => image.stageId)));
|
|
631
659
|
};
|
|
632
|
-
|
|
660
|
+
/** Push one step and enforce the depth/character guards. */
|
|
661
|
+
const pushDraftUndo = (snapshot, kind, caretAfter, deleteRun = null) => {
|
|
662
|
+
draftUndoRef.current.push({ ...snapshot, atMs: now(), caretAfter, kind, deleteRun });
|
|
663
|
+
const dropped = [];
|
|
664
|
+
while (draftUndoRef.current.length > UNDO_LIMIT)
|
|
665
|
+
dropped.push(draftUndoRef.current.shift());
|
|
666
|
+
let chars = draftUndoRef.current.reduce((total, entry) => total + entry.text.length, 0);
|
|
667
|
+
while (chars > UNDO_MAX_CHARS && draftUndoRef.current.length > 1) {
|
|
668
|
+
const oldest = draftUndoRef.current.shift();
|
|
669
|
+
chars -= oldest.text.length;
|
|
670
|
+
dropped.push(oldest);
|
|
671
|
+
}
|
|
672
|
+
if (dropped.length > 0) {
|
|
673
|
+
discardUnretainedImages(dropped.flatMap(entry => entry.images.map(image => image.stageId)));
|
|
674
|
+
}
|
|
675
|
+
};
|
|
676
|
+
/**
|
|
677
|
+
* Record one real text mutation. `group` folds it into the current step when
|
|
678
|
+
* the direction, caret continuity, idle window and word rule all agree;
|
|
679
|
+
* `step` always starts a sealed step. A chunk carrying several characters is
|
|
680
|
+
* judged per mutation, never per stdin read.
|
|
681
|
+
*/
|
|
682
|
+
const recordDraftEdit = (prev, prevCursor, block, next, nextCursor, mode) => {
|
|
683
|
+
const span = diffSpan(prev, next, prevCursor, nextCursor);
|
|
684
|
+
// Backspace consumes the character BEFORE the caret; Delete consumes the
|
|
685
|
+
// one AT it. The two directions anchor differently, so their runs must
|
|
686
|
+
// never fold into one another.
|
|
687
|
+
const backward = span.start < prevCursor;
|
|
688
|
+
const kind = span.inserted.length > 0 ? 'insert' : backward ? 'deleteBackward' : 'deleteForward';
|
|
689
|
+
const removed = prev.length - next.length;
|
|
690
|
+
const caretAfter = nextCursor;
|
|
691
|
+
if (mode === 'group') {
|
|
692
|
+
const last = draftUndoRef.current[draftUndoRef.current.length - 1];
|
|
693
|
+
// Continuity: this edit must begin where the last one ended. An insertion
|
|
694
|
+
// begins at the caret; a Backspace consumes the character BEFORE it, so
|
|
695
|
+
// the pre-edit caret is its start — comparing `span.start` there would
|
|
696
|
+
// make every repeated Backspace a step of its own.
|
|
697
|
+
const editStart = kind === 'insert' ? span.start : prevCursor;
|
|
698
|
+
if (last !== undefined &&
|
|
699
|
+
last.caretAfter !== null &&
|
|
700
|
+
last.kind === kind &&
|
|
701
|
+
last.caretAfter === editStart &&
|
|
702
|
+
now() - last.atMs <= UNDO_IDLE_MS &&
|
|
703
|
+
// An insertion extends a word when its seam is not a boundary; a
|
|
704
|
+
// deletion continues while it stays inside the word its run began in.
|
|
705
|
+
// The boundary question is deliberately NOT asked of a deletion: at the
|
|
706
|
+
// seam, `isDraftWordBoundary(prev, span.start)` reads the removed
|
|
707
|
+
// character's LEFT neighbour, which stops the run one keystroke early
|
|
708
|
+
// at a word's left edge and at the text head (and mis-splits a
|
|
709
|
+
// re-segmented CJK suffix).
|
|
710
|
+
(kind === 'insert'
|
|
711
|
+
? !isDraftWordBoundary(next, span.start)
|
|
712
|
+
: extendDeleteRun(last, backward, removed))) {
|
|
713
|
+
last.atMs = now();
|
|
714
|
+
last.caretAfter = caretAfter;
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
pushDraftUndo({ text: prev, cursor: prevCursor, images: imageRefsFor(prev), block }, kind, mode === 'group' ? caretAfter : null,
|
|
719
|
+
// A sealed step never groups, so only a groupable deletion needs (and
|
|
720
|
+
// pays for) the word interval.
|
|
721
|
+
mode === 'group' && kind !== 'insert' ? startDeleteRun(prev, span.start, removed) : null);
|
|
722
|
+
};
|
|
723
|
+
/**
|
|
724
|
+
* Clear the draft while keeping ONE undo step, so `Ctrl+Z` can bring the
|
|
725
|
+
* whole draft back (text, caret, images and fold block). The snapshot is
|
|
726
|
+
* taken before the images are released: afterwards the capabilities would
|
|
727
|
+
* already be gone and the restored `[Image #N]` tokens would be inert.
|
|
728
|
+
*/
|
|
729
|
+
const clearDraftUndoably = () => {
|
|
730
|
+
syncImageGeneration();
|
|
731
|
+
// Nothing to come back to on an already-empty draft: pushing a snapshot
|
|
732
|
+
// there would waste the next Ctrl+Z (and hide an older real step).
|
|
733
|
+
if (valueRef.current !== '') {
|
|
734
|
+
pushDraftUndo({
|
|
735
|
+
text: valueRef.current,
|
|
736
|
+
cursor: cursorRef.current,
|
|
737
|
+
images: imageRefsFor(valueRef.current),
|
|
738
|
+
block: foldBlockRef.current,
|
|
739
|
+
}, 'clear', null);
|
|
740
|
+
}
|
|
741
|
+
discardDraftImages({ keepUndo: true });
|
|
742
|
+
setInput('', 0, 'silent');
|
|
743
|
+
setSelectedCommand(0);
|
|
744
|
+
setFileSelected(0);
|
|
745
|
+
};
|
|
746
|
+
const discardDraftImages = (options) => {
|
|
633
747
|
advanceDraftRevision();
|
|
634
748
|
const stageIds = [...draftImagesRef.current.values()];
|
|
749
|
+
// The draft stack may be kept so Ctrl+Z can undo the clear; the vim stack
|
|
750
|
+
// is never restored by `u` across a whole-draft replacement.
|
|
751
|
+
if (options?.keepUndo !== true)
|
|
752
|
+
clearDraftUndo();
|
|
635
753
|
clearVimUndo();
|
|
636
754
|
draftImagesRef.current.clear();
|
|
637
755
|
discardUnretainedImages(stageIds);
|
|
@@ -651,6 +769,7 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
651
769
|
if (draftImagesGenerationRef.current !== generation) {
|
|
652
770
|
// The channel has already cleared every old-generation capability.
|
|
653
771
|
// Only detach the UI sidecar; calling discard would be redundant.
|
|
772
|
+
draftUndoRef.current = [];
|
|
654
773
|
vimUndoRef.current = [];
|
|
655
774
|
detachDraftImages();
|
|
656
775
|
draftImagesGenerationRef.current = generation;
|
|
@@ -721,6 +840,12 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
721
840
|
const next = sanitizeEditableText(previous + text);
|
|
722
841
|
if (next !== previous)
|
|
723
842
|
inputEditSequenceRef.current += 1;
|
|
843
|
+
// An external injection is a NEW draft baseline. It bypasses setInput,
|
|
844
|
+
// so the stack would still describe the pre-injection text: one Ctrl+Z
|
|
845
|
+
// would then erase the injected text together with the typing it
|
|
846
|
+
// joined (the injection is not an edit of the draft the user made).
|
|
847
|
+
if (next !== previous)
|
|
848
|
+
clearDraftUndo();
|
|
724
849
|
valueRef.current = next;
|
|
725
850
|
cursorRef.current = next.length;
|
|
726
851
|
setValue(next);
|
|
@@ -739,14 +864,16 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
739
864
|
// The selection stays: copy never clears it (Esc/typing/delete do).
|
|
740
865
|
return true;
|
|
741
866
|
},
|
|
867
|
+
consumeEscape: consumeEditingEscape,
|
|
742
868
|
toggleVim: () => {
|
|
743
869
|
const next = !vimEnabledRef.current;
|
|
744
870
|
vimEnabledRef.current = next;
|
|
745
871
|
setVimEnabled(next);
|
|
746
872
|
// Every toggle lands in INSERT: a fresh vim user keeps typing
|
|
747
873
|
// normally until they press Esc for the first time. Turning the
|
|
748
|
-
// mode off also clears the undo stack — a later re-enable must
|
|
749
|
-
// never `u` its way back past edits made while vim was off.
|
|
874
|
+
// mode off also clears the VIM undo stack — a later re-enable must
|
|
875
|
+
// never `u` its way back past edits made while vim was off. The
|
|
876
|
+
// draft stack (Ctrl+Z) is a different history and is left alone.
|
|
750
877
|
vimInsertRef.current = true;
|
|
751
878
|
setVimInsert(true);
|
|
752
879
|
vimPendingRef.current = '';
|
|
@@ -769,7 +896,9 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
769
896
|
syncImageGeneration();
|
|
770
897
|
discardDraftImages();
|
|
771
898
|
updateFoldBlock(null);
|
|
772
|
-
|
|
899
|
+
// A recall is not undoable (D4): the stack was just cleared above, so
|
|
900
|
+
// the fill must not push a snapshot of the draft it replaced.
|
|
901
|
+
setInput(fillText, fillText.length, 'silent');
|
|
773
902
|
onFillConsumed?.();
|
|
774
903
|
}
|
|
775
904
|
}, [fillText, onFillConsumed]);
|
|
@@ -797,9 +926,10 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
797
926
|
*
|
|
798
927
|
* `advanceDraftRevision` invalidates any image read/stage still in
|
|
799
928
|
* flight, so a late continuation cannot bind a capability into a composer
|
|
800
|
-
* that no longer exists. `clearVimUndo`
|
|
801
|
-
* only
|
|
802
|
-
* nothing will ever restore them once this composer is
|
|
929
|
+
* that no longer exists. `clearDraftUndo`/`clearVimUndo` release the
|
|
930
|
+
* capabilities that only an undo stack was holding: they are not part of
|
|
931
|
+
* the draft, and nothing will ever restore them once this composer is
|
|
932
|
+
* gone.
|
|
803
933
|
*
|
|
804
934
|
* The stageIds the DRAFT holds are deliberately NOT revoked — they are
|
|
805
935
|
* part of the snapshot the slot now keeps, and the restore filters out
|
|
@@ -807,6 +937,7 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
807
937
|
* an image draft used to come back as inert text.
|
|
808
938
|
*/
|
|
809
939
|
advanceDraftRevision();
|
|
940
|
+
clearDraftUndo();
|
|
810
941
|
clearVimUndo();
|
|
811
942
|
const images = [...draftImagesRef.current.entries()]
|
|
812
943
|
.map(([token, stageId]) => [token, stageId]);
|
|
@@ -980,7 +1111,13 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
980
1111
|
}
|
|
981
1112
|
}
|
|
982
1113
|
};
|
|
983
|
-
|
|
1114
|
+
/**
|
|
1115
|
+
* Apply `next` at `cursorOffset` and record the edit on the undo stack.
|
|
1116
|
+
* `snapshotBlock` overrides the block the step snapshots: a caller that must
|
|
1117
|
+
* clear the fold block BEFORE writing (the external-editor refill) still
|
|
1118
|
+
* wants the block that was live at edit time.
|
|
1119
|
+
*/
|
|
1120
|
+
const setInput = (next, cursorOffset = next.length, undo = 'group', snapshotBlock) => {
|
|
984
1121
|
// Apply the same ingress normalization to fills/history/editor results as
|
|
985
1122
|
// to paste. Map the requested caret through the sanitized prefix so an
|
|
986
1123
|
// ANSI sequence removed before it cannot leave the caret past the text.
|
|
@@ -1022,6 +1159,16 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
1022
1159
|
// one continues in its direction of travel (←/word-left/↑ → the token's
|
|
1023
1160
|
// start, →/word-right/↓ → its end); with no travel, the nearer edge.
|
|
1024
1161
|
offset = snapOffImageToken(boundImageSpans(next), offset, offset < prevCursor ? 'start' : offset > prevCursor ? 'end' : 'nearest');
|
|
1162
|
+
// Undo bookkeeping runs before the mirrors move: it snapshots the state
|
|
1163
|
+
// this edit replaces, and `diffSpan` needs both texts. `reset` ends the
|
|
1164
|
+
// draft's history, `silent` (undo itself, a recall) leaves it untouched.
|
|
1165
|
+
if (next !== prev) {
|
|
1166
|
+
if (undo === 'reset')
|
|
1167
|
+
clearDraftUndo();
|
|
1168
|
+
else if (undo !== 'silent') {
|
|
1169
|
+
recordDraftEdit(prev, prevCursor, snapshotBlock === undefined ? block : snapshotBlock, next, offset, undo);
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1025
1172
|
// The synchronous mirrors are what batch-dispatched events (one stdin
|
|
1026
1173
|
// read → several keys, no render in between) read on their next turn.
|
|
1027
1174
|
if (next !== prev)
|
|
@@ -1044,12 +1191,12 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
1044
1191
|
setValue(next);
|
|
1045
1192
|
setCursor(offset);
|
|
1046
1193
|
};
|
|
1047
|
-
const deleteInputRange = (start, end) => {
|
|
1194
|
+
const deleteInputRange = (start, end, undo = 'group') => {
|
|
1048
1195
|
if (start >= end)
|
|
1049
1196
|
return;
|
|
1050
1197
|
const text = valueRef.current;
|
|
1051
1198
|
const range = expandImageTokenRange(boundImageSpans(text), start, end);
|
|
1052
|
-
setInput(text.slice(0, range.start) + text.slice(range.end), range.start);
|
|
1199
|
+
setInput(text.slice(0, range.start) + text.slice(range.end), range.start, undo);
|
|
1053
1200
|
};
|
|
1054
1201
|
/**
|
|
1055
1202
|
* Write the selection [start, end) (snapped to grapheme boundaries,
|
|
@@ -1112,7 +1259,7 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
1112
1259
|
const suffix = mention.pathEnd === undefined ? '' : value.slice(mention.pathEnd, mention.end);
|
|
1113
1260
|
const insert = candidate.kind === 'directory' ? `${body}${suffix}` : `${body}${suffix} `;
|
|
1114
1261
|
const next = value.slice(0, mention.start) + insert + value.slice(mention.end);
|
|
1115
|
-
setInput(next, mention.start + insert.length);
|
|
1262
|
+
setInput(next, mention.start + insert.length, 'step');
|
|
1116
1263
|
setFileSelected(0);
|
|
1117
1264
|
};
|
|
1118
1265
|
const imageRefsFor = (text) => {
|
|
@@ -1145,14 +1292,35 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
1145
1292
|
* persisted entries first, this run's submits behind them — instead of two
|
|
1146
1293
|
* lists to merge at recall time. Restored text carries no image capability
|
|
1147
1294
|
* (the file stores text only), which is also what keeps a recalled entry
|
|
1148
|
-
* from binding to a later staged image by accident.
|
|
1295
|
+
* from binding to a later staged image by accident. The walk is scoped to
|
|
1296
|
+
* the channel's workspace, keyed the same way the store keys it
|
|
1297
|
+
* (historyProjectKey), so a workspace switch re-seeds it with that
|
|
1298
|
+
* project's history instead of carrying the previous one over — and a
|
|
1299
|
+
* respelled path to the same directory is not a switch.
|
|
1300
|
+
* @returns Whether the re-seed cut short a walk in progress: the composer
|
|
1301
|
+
* then shows a recalled entry of the previous project while the draft that
|
|
1302
|
+
* walk started from is still held in `historyDraft`.
|
|
1149
1303
|
*/
|
|
1150
1304
|
const seedHistory = () => {
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1305
|
+
// The store's own key, not the raw cwd: `/repo` and `/repo/` are one
|
|
1306
|
+
// project, so respelling the path must not look like a workspace switch.
|
|
1307
|
+
const project = historyProjectKey(channel.cwd) ?? '';
|
|
1308
|
+
if (historySeededProject.current === project)
|
|
1309
|
+
return false;
|
|
1310
|
+
const interrupted = historyIndex.current >= 0;
|
|
1311
|
+
historySeededProject.current = project;
|
|
1312
|
+
history.current = loadHistoryOldestFirst(channel.cwd).map(entry => ({ text: entry.text, images: [] }));
|
|
1313
|
+
historyIndex.current = -1;
|
|
1314
|
+
return interrupted;
|
|
1315
|
+
};
|
|
1316
|
+
/** End the walk and put back the draft it started from. */
|
|
1317
|
+
const restoreHistoryDraft = () => {
|
|
1155
1318
|
historyIndex.current = -1;
|
|
1319
|
+
updateFoldBlock(null);
|
|
1320
|
+
restoreDraftImages(historyDraft.current);
|
|
1321
|
+
// A recall is not undoable (D4): `restoreDraftImages` just ended the
|
|
1322
|
+
// history, so the restore must not push a step of its own.
|
|
1323
|
+
setInput(historyDraft.current.text, historyDraft.current.text.length, 'silent');
|
|
1156
1324
|
};
|
|
1157
1325
|
const rememberHistory = (text, images) => {
|
|
1158
1326
|
// Both entries into the walk (a submit and ↑) must see the persisted
|
|
@@ -1165,14 +1333,15 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
1165
1333
|
if (history.current.length > HISTORY_LIMIT)
|
|
1166
1334
|
history.current.shift();
|
|
1167
1335
|
historyIndex.current = -1;
|
|
1168
|
-
void appendHistory(text);
|
|
1336
|
+
void appendHistory(text, channel.cwd);
|
|
1169
1337
|
};
|
|
1170
1338
|
const clearDeliveredDraft = () => {
|
|
1171
1339
|
syncImageGeneration();
|
|
1172
1340
|
// Delivery captured the opaque refs and history retains them; only the
|
|
1173
|
-
// editable-draft binding is ending here.
|
|
1341
|
+
// editable-draft binding is ending here. `reset` ends the draft's undo
|
|
1342
|
+
// history: a submitted message must not come back with Ctrl+Z.
|
|
1174
1343
|
detachDraftImages();
|
|
1175
|
-
setInput('', 0);
|
|
1344
|
+
setInput('', 0, 'reset');
|
|
1176
1345
|
setSelectedCommand(0);
|
|
1177
1346
|
setFileSelected(0);
|
|
1178
1347
|
};
|
|
@@ -1189,8 +1358,40 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
1189
1358
|
syncImageGeneration();
|
|
1190
1359
|
advanceDraftRevision();
|
|
1191
1360
|
replaceDraftImages(entry.images);
|
|
1361
|
+
// A recall is not undoable (D4): both stacks end with the draft it replaced.
|
|
1362
|
+
clearDraftUndo();
|
|
1192
1363
|
clearVimUndo();
|
|
1193
1364
|
};
|
|
1365
|
+
/**
|
|
1366
|
+
* `Ctrl+Z`: pop back to the state before the current undo step — text,
|
|
1367
|
+
* caret, images and fold block together. An empty stack is a no-op (never
|
|
1368
|
+
* the rewind picker, never a clear). The restore is `silent`, so repeated
|
|
1369
|
+
* Ctrl+Z walks further back instead of pushing what it just left. Vim `u`
|
|
1370
|
+
* uses its own stack (see {@link vimUndoRef}).
|
|
1371
|
+
*/
|
|
1372
|
+
const undoDraft = () => {
|
|
1373
|
+
// A session replacement invalidates the whole stack. Check that BEFORE
|
|
1374
|
+
// popping: restoring first and discarding afterwards would put the old
|
|
1375
|
+
// session's text (and its image tokens) back into the new composer.
|
|
1376
|
+
syncImageGeneration();
|
|
1377
|
+
const entry = draftUndoRef.current.pop();
|
|
1378
|
+
if (entry === undefined)
|
|
1379
|
+
return;
|
|
1380
|
+
advanceDraftRevision();
|
|
1381
|
+
replaceDraftImages(entry.images);
|
|
1382
|
+
// Drop the live block first: setInput's atomicity rules describe the block
|
|
1383
|
+
// that was live at edit time, and re-shifting it here would corrupt the
|
|
1384
|
+
// snapshot's. The snapshot's own block goes back afterwards, and only if
|
|
1385
|
+
// its range still fits the text it was captured from.
|
|
1386
|
+
updateFoldBlock(null);
|
|
1387
|
+
setInput(entry.text, entry.cursor, 'silent');
|
|
1388
|
+
const block = entry.block !== null && entry.block.start < entry.block.end && entry.block.end <= entry.text.length
|
|
1389
|
+
? entry.block
|
|
1390
|
+
: null;
|
|
1391
|
+
updateFoldBlock(block);
|
|
1392
|
+
setSelectedCommand(0);
|
|
1393
|
+
setFileSelected(0);
|
|
1394
|
+
};
|
|
1194
1395
|
const submitText = (text, notice) => {
|
|
1195
1396
|
const trimmed = text.trim();
|
|
1196
1397
|
if (!trimmed)
|
|
@@ -1258,7 +1459,7 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
1258
1459
|
text: item.text,
|
|
1259
1460
|
images: item.images ?? [],
|
|
1260
1461
|
});
|
|
1261
|
-
setInput(item.text);
|
|
1462
|
+
setInput(item.text, item.text.length, 'silent');
|
|
1262
1463
|
updateFoldBlock(null);
|
|
1263
1464
|
setSelectedCommand(0);
|
|
1264
1465
|
setFileSelected(0);
|
|
@@ -1480,6 +1681,19 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
1480
1681
|
lastClickColRef.current = -1;
|
|
1481
1682
|
lastClickRowRef.current = -1;
|
|
1482
1683
|
};
|
|
1684
|
+
/** Local Esc layers, shared by the prompt listener and Chat's delegation.
|
|
1685
|
+
* Refs preserve this order even when expansion and Esc share a stdin batch. */
|
|
1686
|
+
const consumeEditingEscape = () => {
|
|
1687
|
+
if (selectionRef.current && !helpOpen && !overlayOpen && !fileOverlayOpen) {
|
|
1688
|
+
clearSelection();
|
|
1689
|
+
return true;
|
|
1690
|
+
}
|
|
1691
|
+
if (expandedRef.current) {
|
|
1692
|
+
collapseEditor();
|
|
1693
|
+
return true;
|
|
1694
|
+
}
|
|
1695
|
+
return false;
|
|
1696
|
+
};
|
|
1483
1697
|
/** The editor's explicit send (Ctrl+Enter / Send button): the Enter main
|
|
1484
1698
|
* path, then collapse — an empty draft just collapses. */
|
|
1485
1699
|
const submitFromEditor = () => {
|
|
@@ -1498,7 +1712,8 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
1498
1712
|
const next = sel
|
|
1499
1713
|
? current.slice(0, sel.start) + text + current.slice(sel.end)
|
|
1500
1714
|
: current.slice(0, position) + text + current.slice(position);
|
|
1501
|
-
|
|
1715
|
+
// A paste is ONE undo step however many characters it carries.
|
|
1716
|
+
setInput(next, position + text.length, 'step');
|
|
1502
1717
|
setSelectedCommand(0);
|
|
1503
1718
|
setFileSelected(0);
|
|
1504
1719
|
return { next, at: position };
|
|
@@ -1650,27 +1865,18 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
1650
1865
|
// ONLY drops the highlight (text untouched), and Backspace/Delete
|
|
1651
1866
|
// delete the selected span. Arrows/typing handle the selection at their
|
|
1652
1867
|
// own arms below.
|
|
1653
|
-
if (key.escape &&
|
|
1868
|
+
if (key.escape && consumeEditingEscape()) {
|
|
1654
1869
|
event.stopImmediatePropagation();
|
|
1655
|
-
clearSelection();
|
|
1656
1870
|
return;
|
|
1657
1871
|
}
|
|
1658
1872
|
if ((key.backspace || key.delete) && selection) {
|
|
1659
|
-
|
|
1873
|
+
// Removing a selection is atomic: it must undo in one step, not fold
|
|
1874
|
+
// into whatever the caret-continuity rule would otherwise see.
|
|
1875
|
+
deleteInputRange(selection.start, selection.end, 'step');
|
|
1660
1876
|
setSelectedCommand(0);
|
|
1661
1877
|
setFileSelected(0);
|
|
1662
1878
|
return;
|
|
1663
1879
|
}
|
|
1664
|
-
// ── 全屏草稿编辑(expandEditor,默认 Ctrl+Shift+E / 输入行 ✎)─────
|
|
1665
|
-
// 展开态拥有屏幕;Esc 收起(有选区时上面的 selection 分支已先行只清
|
|
1666
|
-
// 选区)。滚轮不经此——编辑区的 onWheel 位置路由直接驱动滚动窗口。
|
|
1667
|
-
if (key.escape && expandedRef.current) {
|
|
1668
|
-
// Collapse runs AHEAD of the fold-block/vim Esc meanings: the
|
|
1669
|
-
// fullscreen cover is the outermost modal layer.
|
|
1670
|
-
event?.stopImmediatePropagation();
|
|
1671
|
-
collapseEditor();
|
|
1672
|
-
return;
|
|
1673
|
-
}
|
|
1674
1880
|
// Fold block: Esc expands it — it must NEVER clear text
|
|
1675
1881
|
// that LOOKS like one line; Backspace at the block's tail / Delete at
|
|
1676
1882
|
// its head deletes the WHOLE block in one key; ←/→ jump over the
|
|
@@ -1690,7 +1896,7 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
1690
1896
|
if ((key.backspace && cursor === block.end) || (key.delete && cursor === block.start)) {
|
|
1691
1897
|
const next = value.slice(0, block.start) + value.slice(block.end);
|
|
1692
1898
|
updateFoldBlock(null);
|
|
1693
|
-
setInput(next, block.start);
|
|
1899
|
+
setInput(next, block.start, 'step', block);
|
|
1694
1900
|
setSelectedCommand(0);
|
|
1695
1901
|
setFileSelected(0);
|
|
1696
1902
|
return;
|
|
@@ -1711,7 +1917,7 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
1711
1917
|
* active selection is REPLACED by the insert (standard editor
|
|
1712
1918
|
* semantics). Returns the insertion offset so callers can derive the
|
|
1713
1919
|
* inserted span (paste fold). */
|
|
1714
|
-
const insertAtCaret = (text) => {
|
|
1920
|
+
const insertAtCaret = (text, undo = 'group') => {
|
|
1715
1921
|
if (helpOpen)
|
|
1716
1922
|
onToggleHelp();
|
|
1717
1923
|
const sel = selectionRef.current;
|
|
@@ -1719,7 +1925,9 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
1719
1925
|
const next = sel
|
|
1720
1926
|
? value.slice(0, sel.start) + text + value.slice(sel.end)
|
|
1721
1927
|
: value.slice(0, cursor) + text + value.slice(cursor);
|
|
1722
|
-
|
|
1928
|
+
// Replacing a selection is atomic (like deleting one): the replaced span
|
|
1929
|
+
// must not fold into the surrounding typed run.
|
|
1930
|
+
setInput(next, at + text.length, sel ? 'step' : undo);
|
|
1723
1931
|
setSelectedCommand(0);
|
|
1724
1932
|
setFileSelected(0);
|
|
1725
1933
|
return at;
|
|
@@ -1758,7 +1966,8 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
1758
1966
|
});
|
|
1759
1967
|
return;
|
|
1760
1968
|
}
|
|
1761
|
-
|
|
1969
|
+
// One paste is ONE undo step however many characters it carries.
|
|
1970
|
+
const at = insertAtCaret(text, 'step');
|
|
1762
1971
|
// A big paste becomes a fold block right away (hover peeks
|
|
1763
1972
|
// at it); an existing block is replaced by the new paste's span.
|
|
1764
1973
|
// The EXPANDED editor never folds — pasting there is plain text
|
|
@@ -1950,8 +2159,12 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
1950
2159
|
if (!draftImageLeaseIsCurrent(editorLease))
|
|
1951
2160
|
return;
|
|
1952
2161
|
if (outcome.kind === 'edited') {
|
|
2162
|
+
// Snapshot the block BEFORE clearing it: the refill is one undo
|
|
2163
|
+
// step (D4), and Ctrl+Z must bring back the fold chip the draft
|
|
2164
|
+
// had, not the already-cleared null.
|
|
2165
|
+
const beforeBlock = foldBlockRef.current;
|
|
1953
2166
|
updateFoldBlock(null);
|
|
1954
|
-
setInput(outcome.text);
|
|
2167
|
+
setInput(outcome.text, outcome.text.length, 'step', beforeBlock);
|
|
1955
2168
|
setSelectedCommand(0);
|
|
1956
2169
|
setFileSelected(0);
|
|
1957
2170
|
}
|
|
@@ -2063,7 +2276,18 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
2063
2276
|
// indentation arm so the expanded editor participates in the cycle too —
|
|
2064
2277
|
// the parser reports backtab as key.tab + key.shift.
|
|
2065
2278
|
if (key.tab && key.shift) {
|
|
2066
|
-
|
|
2279
|
+
// The key is consumed either way. `cycleMode` is best-effort inside the
|
|
2280
|
+
// channel, but a dropped rejection here would be an unhandledRejection
|
|
2281
|
+
// (the process guard rethrows everything that is not React #185), and
|
|
2282
|
+
// an unhandled rejection kills the TUI with the session still open —
|
|
2283
|
+
// so the caller keeps a catch of its own rather than `void`ing the
|
|
2284
|
+
// promise (the sibling `/permission` entry point does the same).
|
|
2285
|
+
void channel.cycleMode().catch((error) => {
|
|
2286
|
+
channel.notify(t('mode-switch-failed', { err: error instanceof Error ? error.message : String(error) }), {
|
|
2287
|
+
color: 'error',
|
|
2288
|
+
timeoutMs: 8000,
|
|
2289
|
+
});
|
|
2290
|
+
});
|
|
2067
2291
|
return;
|
|
2068
2292
|
}
|
|
2069
2293
|
// Expanded editor: plain Tab inserts indentation; Shift+Tab was handled
|
|
@@ -2083,7 +2307,7 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
2083
2307
|
const command = suggestions[selectedCommand];
|
|
2084
2308
|
if (command) {
|
|
2085
2309
|
updateFoldBlock(null);
|
|
2086
|
-
setInput(command.replacement);
|
|
2310
|
+
setInput(command.replacement, command.replacement.length, 'step');
|
|
2087
2311
|
}
|
|
2088
2312
|
return;
|
|
2089
2313
|
}
|
|
@@ -2171,10 +2395,18 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
2171
2395
|
setSelectedCommand(index => index <= 0 ? suggestions.length - 1 : index - 1);
|
|
2172
2396
|
return;
|
|
2173
2397
|
}
|
|
2174
|
-
|
|
2175
|
-
|
|
2398
|
+
// A workspace switch mid-walk keeps the draft that walk started from:
|
|
2399
|
+
// the composer shows the previous project's entry, not a new draft.
|
|
2400
|
+
const interrupted = seedHistory();
|
|
2401
|
+
if (history.current.length === 0) {
|
|
2402
|
+
if (interrupted)
|
|
2403
|
+
restoreHistoryDraft();
|
|
2176
2404
|
return;
|
|
2177
|
-
|
|
2405
|
+
}
|
|
2406
|
+
if (interrupted) {
|
|
2407
|
+
historyIndex.current = history.current.length - 1;
|
|
2408
|
+
}
|
|
2409
|
+
else if (historyIndex.current < 0) {
|
|
2178
2410
|
historyDraft.current = {
|
|
2179
2411
|
text: value,
|
|
2180
2412
|
images: imageRefsFor(value),
|
|
@@ -2190,7 +2422,7 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
2190
2422
|
retractRecalledCopy(entry.text);
|
|
2191
2423
|
updateFoldBlock(null);
|
|
2192
2424
|
restoreDraftImages(entry);
|
|
2193
|
-
setInput(entry.text);
|
|
2425
|
+
setInput(entry.text, entry.text.length, 'silent');
|
|
2194
2426
|
return;
|
|
2195
2427
|
}
|
|
2196
2428
|
if (key.downArrow) {
|
|
@@ -2242,20 +2474,23 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
2242
2474
|
setSelectedCommand(index => index >= suggestions.length - 1 ? 0 : index + 1);
|
|
2243
2475
|
return;
|
|
2244
2476
|
}
|
|
2477
|
+
// A walk cut short by a workspace switch has no position in the new
|
|
2478
|
+
// project's list; ↓ just ends it and returns the draft.
|
|
2479
|
+
if (seedHistory()) {
|
|
2480
|
+
restoreHistoryDraft();
|
|
2481
|
+
return;
|
|
2482
|
+
}
|
|
2245
2483
|
if (historyIndex.current < 0)
|
|
2246
2484
|
return;
|
|
2247
2485
|
if (historyIndex.current >= history.current.length - 1) {
|
|
2248
|
-
|
|
2249
|
-
updateFoldBlock(null);
|
|
2250
|
-
restoreDraftImages(historyDraft.current);
|
|
2251
|
-
setInput(historyDraft.current.text);
|
|
2486
|
+
restoreHistoryDraft();
|
|
2252
2487
|
}
|
|
2253
2488
|
else {
|
|
2254
2489
|
historyIndex.current += 1;
|
|
2255
2490
|
const entry = history.current[historyIndex.current];
|
|
2256
2491
|
if (entry !== undefined) {
|
|
2257
2492
|
restoreDraftImages(entry);
|
|
2258
|
-
setInput(entry.text);
|
|
2493
|
+
setInput(entry.text, entry.text.length, 'silent');
|
|
2259
2494
|
}
|
|
2260
2495
|
}
|
|
2261
2496
|
return;
|
|
@@ -2344,10 +2579,19 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
2344
2579
|
deleteInputRange(cursor, end);
|
|
2345
2580
|
return;
|
|
2346
2581
|
}
|
|
2582
|
+
if (actionMatches('undo', input, key)) {
|
|
2583
|
+
// Word-level draft undo (remappable via /settings). Only the prompt
|
|
2584
|
+
// draft has an undo space: with the keyboard owned by a panel or a
|
|
2585
|
+
// dialog this handler is inactive (useInput isActive), and an empty
|
|
2586
|
+
// stack is a no-op rather than the rewind picker.
|
|
2587
|
+
undoDraft();
|
|
2588
|
+
return;
|
|
2589
|
+
}
|
|
2347
2590
|
if (isMod(key) && input === 'w') {
|
|
2348
|
-
// Delete the word before the cursor:
|
|
2349
|
-
// trailing whitespace, then the
|
|
2350
|
-
//
|
|
2591
|
+
// Delete the word before the cursor: readline's whitespace-delimited
|
|
2592
|
+
// rule (skip trailing whitespace, then the word). The ICU/CJK
|
|
2593
|
+
// alternative is a separate editor-UX change, not part of draft undo.
|
|
2594
|
+
// The deletion start never crosses into the block.
|
|
2351
2595
|
const before = value.slice(0, cursor);
|
|
2352
2596
|
let end = before.length;
|
|
2353
2597
|
while (end > 0 && /\s/.test(before[end - 1]))
|
|
@@ -2364,25 +2608,30 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
2364
2608
|
// NORMAL submode: bare characters and Esc are vim keys; help/command/
|
|
2365
2609
|
// file overlays, modified combos, Tab, Enter, arrows and other
|
|
2366
2610
|
// structured keys keep their existing handlers.
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
setFileSelected(0);
|
|
2372
|
-
};
|
|
2611
|
+
/**
|
|
2612
|
+
* Push one vim NORMAL-mode step. Vim edits never touch the draft stack:
|
|
2613
|
+
* `u` and `Ctrl+Z` are two independent histories (see {@link vimUndoRef}).
|
|
2614
|
+
*/
|
|
2373
2615
|
const vimPushUndo = () => {
|
|
2374
2616
|
const images = imageRefsFor(valueRef.current);
|
|
2375
|
-
const evicted = vimUndoRef.current.length >=
|
|
2617
|
+
const evicted = vimUndoRef.current.length >= UNDO_LIMIT ? vimUndoRef.current.shift() : undefined;
|
|
2376
2618
|
vimUndoRef.current.push({ text: valueRef.current, cursor: cursorRef.current, images });
|
|
2377
|
-
if (evicted !== undefined)
|
|
2619
|
+
if (evicted !== undefined) {
|
|
2378
2620
|
discardUnretainedImages(evicted.images.map(image => image.stageId));
|
|
2621
|
+
}
|
|
2622
|
+
};
|
|
2623
|
+
const vimNormalEdit = (next, cursorOffset) => {
|
|
2624
|
+
updateFoldBlock(null);
|
|
2625
|
+
setInput(next, cursorOffset, 'silent');
|
|
2626
|
+
setSelectedCommand(0);
|
|
2627
|
+
setFileSelected(0);
|
|
2379
2628
|
};
|
|
2380
2629
|
const vimDeleteRange = (start, end) => {
|
|
2381
2630
|
if (start >= end)
|
|
2382
2631
|
return;
|
|
2383
2632
|
vimPushUndo();
|
|
2384
2633
|
updateFoldBlock(null);
|
|
2385
|
-
deleteInputRange(start, end);
|
|
2634
|
+
deleteInputRange(start, end, 'silent');
|
|
2386
2635
|
setSelectedCommand(0);
|
|
2387
2636
|
setFileSelected(0);
|
|
2388
2637
|
};
|
|
@@ -2499,7 +2748,7 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
2499
2748
|
case 'd':
|
|
2500
2749
|
vimPendingRef.current = 'd';
|
|
2501
2750
|
return;
|
|
2502
|
-
case 'u': { // undo the last vim edit
|
|
2751
|
+
case 'u': { // undo the last vim edit (its own stack, not Ctrl+Z's)
|
|
2503
2752
|
syncImageGeneration();
|
|
2504
2753
|
const prev = vimUndoRef.current.pop();
|
|
2505
2754
|
if (prev === undefined)
|
|
@@ -2507,7 +2756,7 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
2507
2756
|
advanceDraftRevision();
|
|
2508
2757
|
replaceDraftImages(prev.images);
|
|
2509
2758
|
updateFoldBlock(null);
|
|
2510
|
-
setInput(prev.text, prev.cursor);
|
|
2759
|
+
setInput(prev.text, prev.cursor, 'silent');
|
|
2511
2760
|
setSelectedCommand(0);
|
|
2512
2761
|
setFileSelected(0);
|
|
2513
2762
|
return;
|
|
@@ -2580,12 +2829,17 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
2580
2829
|
return;
|
|
2581
2830
|
// `/` opens the slash-command menu even in NORMAL: insert it and
|
|
2582
2831
|
// switch to INSERT so the rest of the command types normally
|
|
2583
|
-
// (the menu then owns the keys while it is open).
|
|
2832
|
+
// (the menu then owns the keys while it is open). The insertion is
|
|
2833
|
+
// a NORMAL command, so it lands on the vim undo stack (`u` reverts
|
|
2834
|
+
// it); anything typed afterwards is a draft edit whose first
|
|
2835
|
+
// snapshot already contains the `/`, so `Ctrl+Z` never peels the
|
|
2836
|
+
// `/` off on its own.
|
|
2584
2837
|
if (input === '/') {
|
|
2585
2838
|
const text = valueRef.current;
|
|
2586
2839
|
const pos = cursorRef.current;
|
|
2587
2840
|
const next = text.slice(0, pos) + '/' + text.slice(pos);
|
|
2588
|
-
|
|
2841
|
+
vimPushUndo(); // NORMAL command: one vim-undo step, not a draft edit
|
|
2842
|
+
setInput(next, pos + 1, 'silent');
|
|
2589
2843
|
setSelectedCommand(0);
|
|
2590
2844
|
setFileSelected(0);
|
|
2591
2845
|
vimInsertRef.current = true;
|
|
@@ -2623,11 +2877,7 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
2623
2877
|
// A single Esc closes the open command menu first;
|
|
2624
2878
|
// the double-tap-clear semantics only apply to ordinary input.
|
|
2625
2879
|
if (overlayOpen) {
|
|
2626
|
-
|
|
2627
|
-
discardDraftImages();
|
|
2628
|
-
setInput('', 0);
|
|
2629
|
-
setSelectedCommand(0);
|
|
2630
|
-
setFileSelected(0);
|
|
2880
|
+
clearDraftUndoably();
|
|
2631
2881
|
return;
|
|
2632
2882
|
}
|
|
2633
2883
|
// File overlay: Esc dismisses the menu for THIS token only — clearing
|
|
@@ -2649,6 +2899,18 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
2649
2899
|
});
|
|
2650
2900
|
return;
|
|
2651
2901
|
}
|
|
2902
|
+
// "Send to Chat" chips peel before the draft: the first Esc drops the
|
|
2903
|
+
// contexts panels staged and leaves the typed text untouched, so a second
|
|
2904
|
+
// Esc then clears the input as usual. The press is CONSUMED — this rung
|
|
2905
|
+
// has exactly one meaning, and a running turn must not be interrupted by
|
|
2906
|
+
// the same key that only dropped a chip.
|
|
2907
|
+
const stagedContexts = channel.attachedContexts ?? [];
|
|
2908
|
+
if (stagedContexts.length > 0) {
|
|
2909
|
+
event?.stopImmediatePropagation();
|
|
2910
|
+
for (const staged of [...stagedContexts])
|
|
2911
|
+
channel.detachContext(staged.id);
|
|
2912
|
+
return;
|
|
2913
|
+
}
|
|
2652
2914
|
// A single Esc clears the current input (if any); the double-tap
|
|
2653
2915
|
// path below handles rewind/clear on an already-empty input. A BIG
|
|
2654
2916
|
// input folds into a block instead (Esc = the fold toggle; the
|
|
@@ -2661,28 +2923,19 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
2661
2923
|
setFileSelected(0);
|
|
2662
2924
|
return;
|
|
2663
2925
|
}
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
setSelectedCommand(0);
|
|
2668
|
-
setFileSelected(0);
|
|
2926
|
+
// Esc clearing the draft is undoable (D4): Ctrl+Z brings the whole
|
|
2927
|
+
// draft back, images and fold block included.
|
|
2928
|
+
clearDraftUndoably();
|
|
2669
2929
|
return;
|
|
2670
2930
|
}
|
|
2671
|
-
// Double-tap Esc
|
|
2672
|
-
//
|
|
2673
|
-
//
|
|
2931
|
+
// Double-tap Esc opens the rewind picker. Reaching here means the draft
|
|
2932
|
+
// is empty: every non-empty branch above returns after clearing, so the
|
|
2933
|
+
// second tap can only be the rewind gesture.
|
|
2674
2934
|
if (escPendingRef.current) {
|
|
2675
2935
|
escPendingRef.current = false;
|
|
2676
2936
|
if (escTimerRef.current)
|
|
2677
2937
|
clearTimeout(escTimerRef.current);
|
|
2678
|
-
|
|
2679
|
-
onRewindRequest?.();
|
|
2680
|
-
}
|
|
2681
|
-
else {
|
|
2682
|
-
syncImageGeneration();
|
|
2683
|
-
discardDraftImages();
|
|
2684
|
-
setInput('', 0);
|
|
2685
|
-
}
|
|
2938
|
+
onRewindRequest?.();
|
|
2686
2939
|
return;
|
|
2687
2940
|
}
|
|
2688
2941
|
escPendingRef.current = true;
|
|
@@ -2706,7 +2959,9 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
2706
2959
|
const next = sel
|
|
2707
2960
|
? value.slice(0, sel.start) + input + value.slice(sel.end)
|
|
2708
2961
|
: value.slice(0, cursor) + input + value.slice(cursor);
|
|
2709
|
-
|
|
2962
|
+
// Replacing a selection is atomic, exactly like `insertAtCaret`: the
|
|
2963
|
+
// replaced span must not fold into the surrounding typed run.
|
|
2964
|
+
setInput(next, at + input.length, sel ? 'step' : 'group');
|
|
2710
2965
|
setSelectedCommand(0);
|
|
2711
2966
|
setFileSelected(0);
|
|
2712
2967
|
}
|
|
@@ -2999,6 +3254,11 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
2999
3254
|
prevContentRowsRef.current = contentRows;
|
|
3000
3255
|
}, [contentRows]);
|
|
3001
3256
|
const lastNotification = channel.notifications[channel.notifications.length - 1];
|
|
3257
|
+
// The pet panel can "say" a notice with its speech bubble instead: while
|
|
3258
|
+
// that panel is the ACTIVE one the host suppresses the duplicate toast
|
|
3259
|
+
// here (errors always toast — they may need action). Same render, same
|
|
3260
|
+
// commit, so the swap cannot flash one frame of toast first.
|
|
3261
|
+
const toastVisible = lastNotification !== undefined && (toastSuppressed?.(lastNotification) ?? false) !== true;
|
|
3002
3262
|
// Park the native terminal cursor at the input caret (via the renderer's
|
|
3003
3263
|
// cursor-declaration mechanism). Terminal emulators render IME preedit
|
|
3004
3264
|
// text and screen-reader focus at the physical cursor, so parking it at
|
|
@@ -3235,6 +3495,13 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
3235
3495
|
// 顶边框右侧的会话名标签 chip:色随强调色;超宽截断,宽度
|
|
3236
3496
|
// 随终端列数伸缩但不超过 28 显示单元。默认关闭——`/settings` 的
|
|
3237
3497
|
// 「会话名标签」开关(dsh-tui.promptSessionLabel)开启后显示。
|
|
3498
|
+
// "Send to Chat" chips (side-panel §6.7): the contexts panels staged for the
|
|
3499
|
+
// next submission, rendered as one strip directly above the prompt border.
|
|
3500
|
+
// Read defensively — hosts and older fixtures mount this composer with a
|
|
3501
|
+
// partial channel stub (Chat guards `agentViewRows` for the same reason),
|
|
3502
|
+
// and a missing projection means "nothing attached". A render-time TypeError
|
|
3503
|
+
// here would be swallowed by ink and silently freeze the screen.
|
|
3504
|
+
const attachedContexts = channel.attachedContexts ?? [];
|
|
3238
3505
|
const sessionTitle = channel.sessionTitle ?? '';
|
|
3239
3506
|
const topRightLabel = channel.promptSessionLabel === true && sessionTitle !== ''
|
|
3240
3507
|
? {
|
|
@@ -3327,7 +3594,8 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
3327
3594
|
return (_jsxs(Box, { flexDirection: "column", marginTop: 1, children: [floatersOpen && (_jsxs(OverlayAbove, { maxHeight: Math.max(terminalRows - 6, 1), children: [helpOpen && (_jsx(Box, { marginBottom: 1, children: _jsx(HelpMenu, { commands: channel.commandList, viewportHeight: helpViewportHeight, viewportWidth: columns, scrollRef: helpScrollRef, onCommandPick: (name) => {
|
|
3328
3595
|
// 点击命令行 = 填入 /name 并关闭帮助(Tab 补全的鼠标等价)
|
|
3329
3596
|
updateFoldBlock(null);
|
|
3330
|
-
|
|
3597
|
+
// `/${name} ` — the whole fill is one undo step.
|
|
3598
|
+
setInput(`/${name} `, name.length + 2, 'step');
|
|
3331
3599
|
onToggleHelp();
|
|
3332
3600
|
} }) })), !helpOpen && channel.pending.length > 0 && (_jsxs(Box, { flexDirection: "column", paddingLeft: 2, paddingBottom: 1, children: [channel.pending.some(item => item.placement === 'steer') && (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Text, { dimColor: true, children: ["\u26A1 ", t('input-pending-steer-label')] }), channel.pending
|
|
3333
3601
|
.filter(item => item.placement === 'steer')
|
|
@@ -3358,7 +3626,7 @@ export function PromptInput({ channel, suspended = false, draftCache, helpOpen,
|
|
|
3358
3626
|
: undefined, rows: peekVisualLines.map((row, index) => (_jsx(Text, { wrap: "truncate-end", children: row }, index))), onRowPick: () => {
|
|
3359
3627
|
updateFoldBlock(null);
|
|
3360
3628
|
setHovered(false);
|
|
3361
|
-
} }) }))] })), lastNotification && (_jsx(Box, { position: "absolute", marginTop: -1, height: 1, width: "100%", paddingLeft: 2, paddingRight: 1, flexDirection: "column", justifyContent: "flex-end", overflow: "hidden", children: _jsx(Box, { justifyContent: "flex-end", children: _jsx(Text, { color: lastNotification.color, dimColor: !lastNotification.color, wrap: "truncate", children: lastNotification.text }) }) })), _jsx(EffortInputBorder, { effort: channel.reasoningEffort, levels: channel.effortLevels, columns: columns, onLight: isLightThemeActive(themeName), idleColor: promptAccent, topRightLabel: topRightLabel, children: _jsxs(Box, { flexDirection: "row", alignItems: "flex-start", width: "100%", children: [onOpenSessions !== undefined && (_jsx(Box, { flexShrink: 0, onClick: (event) => {
|
|
3629
|
+
} }) }))] })), attachedContexts.length > 0 && (_jsx(Box, { flexDirection: "row", width: "100%", height: 1, overflow: "hidden", paddingLeft: 2, columnGap: 2, children: attachedContexts.map(item => (_jsx(Box, { overflow: "hidden", children: _jsx(Text, { color: promptAccent, wrap: "truncate-end", children: t('prompt-attached-context-chip', { title: item.title }) }) }, item.id))) })), lastNotification && toastVisible && (_jsx(Box, { position: "absolute", marginTop: -1, height: 1, width: "100%", paddingLeft: 2, paddingRight: 1, flexDirection: "column", justifyContent: "flex-end", overflow: "hidden", children: _jsx(Box, { justifyContent: "flex-end", children: _jsx(Text, { color: lastNotification.color, dimColor: !lastNotification.color, wrap: "truncate", children: lastNotification.text }) }) })), _jsx(EffortInputBorder, { effort: channel.reasoningEffort, levels: channel.effortLevels, columns: columns, onLight: isLightThemeActive(themeName), idleColor: promptAccent, topRightLabel: topRightLabel, children: _jsxs(Box, { flexDirection: "row", alignItems: "flex-start", width: "100%", children: [onOpenSessions !== undefined && (_jsx(Box, { flexShrink: 0, onClick: (event) => {
|
|
3362
3630
|
event.stopImmediatePropagation();
|
|
3363
3631
|
onOpenSessions?.();
|
|
3364
3632
|
}, onMouseEnter: () => {
|