@deepseek-harness-tui/dsh-tui 0.12.0 → 0.14.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 +124 -8
- package/assets/claude-girl/claude-girl-happy.png +0 -0
- package/assets/claude-girl/claude-girl.png +0 -0
- package/assets/codex-girl/codex-girl-happy.png +0 -0
- package/assets/codex-girl/codex-girl.png +0 -0
- 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 +112 -21
- package/cordis.patch.yml +9 -1
- package/cordis.yml +2 -0
- package/guide/dsh-tui-guide/SKILL.md +4 -2
- package/guide/dsh-tui-guide/claude-backend.en.md +203 -0
- package/guide/dsh-tui-guide/claude-backend.md +161 -0
- package/guide/dsh-tui-guide/codex-backend.en.md +297 -0
- package/guide/dsh-tui-guide/codex-backend.md +257 -0
- package/guide/dsh-tui-guide/configuration.en.md +13 -1
- package/guide/dsh-tui-guide/configuration.md +13 -1
- package/guide/dsh-tui-guide/getting-started.en.md +6 -3
- package/guide/dsh-tui-guide/getting-started.md +4 -2
- package/guide/dsh-tui-guide/interaction.en.md +221 -15
- package/guide/dsh-tui-guide/interaction.md +153 -9
- package/guide/dsh-tui-guide/plugins.en.md +16 -6
- package/guide/dsh-tui-guide/plugins.md +14 -6
- package/guide/dsh-tui-guide/themes.en.md +31 -4
- package/guide/dsh-tui-guide/themes.md +26 -4
- package/guide/dsh-tui-guide/user-guide.en.md +145 -27
- package/guide/dsh-tui-guide/user-guide.md +113 -22
- package/guide/dsh-tui-guide/vscode.en.md +1 -0
- package/guide/dsh-tui-guide/vscode.md +1 -0
- package/lib/settings.json +348 -1
- package/lib/types/adapter/channel/state.d.ts.map +1 -1
- package/lib/types/adapter/channel/state.js +1 -0
- package/lib/types/adapter/channel/ui-policy.d.ts +21 -2
- package/lib/types/adapter/channel/ui-policy.d.ts.map +1 -1
- package/lib/types/adapter/channel/ui-policy.js +43 -1
- package/lib/types/adapter/channel/ui.d.ts.map +1 -1
- package/lib/types/adapter/channel/ui.js +45 -5
- 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 +14 -0
- package/lib/types/adapter/ports/channel-catalog.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-display.d.ts +17 -1
- package/lib/types/adapter/ports/channel-display.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-session.d.ts +5 -0
- package/lib/types/adapter/ports/channel-session.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-settings.d.ts +20 -0
- package/lib/types/adapter/ports/channel-settings.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-ui.d.ts +243 -6
- package/lib/types/adapter/ports/channel-ui.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-view.d.ts +566 -8
- 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/agent/backend.d.ts +168 -0
- package/lib/types/agent/backend.d.ts.map +1 -0
- package/lib/types/agent/backend.js +1 -0
- package/lib/types/agent/capabilities.d.ts +461 -0
- package/lib/types/agent/capabilities.d.ts.map +1 -0
- package/lib/types/agent/capabilities.js +1 -0
- package/lib/types/agent/events.d.ts +733 -0
- package/lib/types/agent/events.d.ts.map +1 -0
- package/lib/types/agent/events.js +2 -0
- package/lib/types/agent/index.d.ts +8 -0
- package/lib/types/agent/index.d.ts.map +1 -0
- package/lib/types/agent/index.js +7 -0
- package/lib/types/agent/messages.d.ts +52 -0
- package/lib/types/agent/messages.d.ts.map +1 -0
- package/lib/types/agent/messages.js +91 -0
- package/lib/types/agent/presentation.d.ts +29 -0
- package/lib/types/agent/presentation.d.ts.map +1 -0
- package/lib/types/agent/presentation.js +4 -0
- package/lib/types/agent/refs.d.ts +30 -0
- package/lib/types/agent/refs.d.ts.map +1 -0
- package/lib/types/agent/refs.js +39 -0
- package/lib/types/agent/session.d.ts +78 -0
- package/lib/types/agent/session.d.ts.map +1 -0
- package/lib/types/agent/session.js +1 -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/backends/claude/activity.d.ts +53 -0
- package/lib/types/backends/claude/activity.d.ts.map +1 -0
- package/lib/types/backends/claude/activity.js +103 -0
- package/lib/types/backends/claude/auth.d.ts +245 -0
- package/lib/types/backends/claude/auth.d.ts.map +1 -0
- package/lib/types/backends/claude/auth.js +503 -0
- package/lib/types/backends/claude/backend.d.ts +32 -0
- package/lib/types/backends/claude/backend.d.ts.map +1 -0
- package/lib/types/backends/claude/backend.js +296 -0
- package/lib/types/backends/claude/catalog.d.ts +17 -0
- package/lib/types/backends/claude/catalog.d.ts.map +1 -0
- package/lib/types/backends/claude/catalog.js +94 -0
- package/lib/types/backends/claude/channels.d.ts +63 -0
- package/lib/types/backends/claude/channels.d.ts.map +1 -0
- package/lib/types/backends/claude/channels.js +275 -0
- package/lib/types/backends/claude/contract.d.ts +37 -0
- package/lib/types/backends/claude/contract.d.ts.map +1 -0
- package/lib/types/backends/claude/contract.js +46 -0
- package/lib/types/backends/claude/controls.d.ts +134 -0
- package/lib/types/backends/claude/controls.d.ts.map +1 -0
- package/lib/types/backends/claude/controls.js +425 -0
- package/lib/types/backends/claude/dialogs.d.ts +62 -0
- package/lib/types/backends/claude/dialogs.d.ts.map +1 -0
- package/lib/types/backends/claude/dialogs.js +253 -0
- package/lib/types/backends/claude/flag-settings.d.ts +12 -0
- package/lib/types/backends/claude/flag-settings.d.ts.map +1 -0
- package/lib/types/backends/claude/flag-settings.js +49 -0
- package/lib/types/backends/claude/images.d.ts +49 -0
- package/lib/types/backends/claude/images.d.ts.map +1 -0
- package/lib/types/backends/claude/images.js +94 -0
- package/lib/types/backends/claude/index.d.ts +5 -0
- package/lib/types/backends/claude/index.d.ts.map +1 -0
- package/lib/types/backends/claude/index.js +4 -0
- package/lib/types/backends/claude/install.d.ts +15 -0
- package/lib/types/backends/claude/install.d.ts.map +1 -0
- package/lib/types/backends/claude/install.js +91 -0
- package/lib/types/backends/claude/modelEnv.d.ts +64 -0
- package/lib/types/backends/claude/modelEnv.d.ts.map +1 -0
- package/lib/types/backends/claude/modelEnv.js +199 -0
- package/lib/types/backends/claude/narrow.d.ts +10 -0
- package/lib/types/backends/claude/narrow.d.ts.map +1 -0
- package/lib/types/backends/claude/narrow.js +8 -0
- package/lib/types/backends/claude/older-history.d.ts +16 -0
- package/lib/types/backends/claude/older-history.d.ts.map +1 -0
- package/lib/types/backends/claude/older-history.js +101 -0
- package/lib/types/backends/claude/options.d.ts +181 -0
- package/lib/types/backends/claude/options.d.ts.map +1 -0
- package/lib/types/backends/claude/options.js +208 -0
- package/lib/types/backends/claude/permissions.d.ts +83 -0
- package/lib/types/backends/claude/permissions.d.ts.map +1 -0
- package/lib/types/backends/claude/permissions.js +331 -0
- package/lib/types/backends/claude/prefs.d.ts +55 -0
- package/lib/types/backends/claude/prefs.d.ts.map +1 -0
- package/lib/types/backends/claude/prefs.js +150 -0
- package/lib/types/backends/claude/process.d.ts +19 -0
- package/lib/types/backends/claude/process.d.ts.map +1 -0
- package/lib/types/backends/claude/process.js +156 -0
- package/lib/types/backends/claude/replay.d.ts +129 -0
- package/lib/types/backends/claude/replay.d.ts.map +1 -0
- package/lib/types/backends/claude/replay.js +505 -0
- package/lib/types/backends/claude/sdk-warnings.d.ts +23 -0
- package/lib/types/backends/claude/sdk-warnings.d.ts.map +1 -0
- package/lib/types/backends/claude/sdk-warnings.js +55 -0
- package/lib/types/backends/claude/sdk.d.ts +12 -0
- package/lib/types/backends/claude/sdk.d.ts.map +1 -0
- package/lib/types/backends/claude/sdk.js +34 -0
- package/lib/types/backends/claude/send-message.d.ts +54 -0
- package/lib/types/backends/claude/send-message.d.ts.map +1 -0
- package/lib/types/backends/claude/send-message.js +65 -0
- package/lib/types/backends/claude/session/auth.d.ts +47 -0
- package/lib/types/backends/claude/session/auth.d.ts.map +1 -0
- package/lib/types/backends/claude/session/auth.js +226 -0
- package/lib/types/backends/claude/session/channels.d.ts +82 -0
- package/lib/types/backends/claude/session/channels.d.ts.map +1 -0
- package/lib/types/backends/claude/session/channels.js +45 -0
- package/lib/types/backends/claude/session/input.d.ts +16 -0
- package/lib/types/backends/claude/session/input.d.ts.map +1 -0
- package/lib/types/backends/claude/session/input.js +64 -0
- package/lib/types/backends/claude/session/lifecycle.d.ts +6 -0
- package/lib/types/backends/claude/session/lifecycle.d.ts.map +1 -0
- package/lib/types/backends/claude/session/lifecycle.js +852 -0
- package/lib/types/backends/claude/session/store.d.ts +17 -0
- package/lib/types/backends/claude/session/store.d.ts.map +1 -0
- package/lib/types/backends/claude/session/store.js +122 -0
- package/lib/types/backends/claude/session/subagents.d.ts +13 -0
- package/lib/types/backends/claude/session/subagents.d.ts.map +1 -0
- package/lib/types/backends/claude/session/subagents.js +77 -0
- package/lib/types/backends/claude/session/types.d.ts +89 -0
- package/lib/types/backends/claude/session/types.d.ts.map +1 -0
- package/lib/types/backends/claude/session/types.js +1 -0
- package/lib/types/backends/claude/session.d.ts +4 -0
- package/lib/types/backends/claude/session.d.ts.map +1 -0
- package/lib/types/backends/claude/session.js +2 -0
- package/lib/types/backends/claude/side-query.d.ts +34 -0
- package/lib/types/backends/claude/side-query.d.ts.map +1 -0
- package/lib/types/backends/claude/side-query.js +116 -0
- package/lib/types/backends/claude/task-output.d.ts +13 -0
- package/lib/types/backends/claude/task-output.d.ts.map +1 -0
- package/lib/types/backends/claude/task-output.js +101 -0
- package/lib/types/backends/claude/tools.d.ts +45 -0
- package/lib/types/backends/claude/tools.d.ts.map +1 -0
- package/lib/types/backends/claude/tools.js +231 -0
- package/lib/types/backends/claude/transcript-file.d.ts +41 -0
- package/lib/types/backends/claude/transcript-file.d.ts.map +1 -0
- package/lib/types/backends/claude/transcript-file.js +195 -0
- package/lib/types/backends/claude/translate/attempts.d.ts +33 -0
- package/lib/types/backends/claude/translate/attempts.d.ts.map +1 -0
- package/lib/types/backends/claude/translate/attempts.js +243 -0
- package/lib/types/backends/claude/translate/content.d.ts +33 -0
- package/lib/types/backends/claude/translate/content.d.ts.map +1 -0
- package/lib/types/backends/claude/translate/content.js +91 -0
- package/lib/types/backends/claude/translate/core.d.ts +76 -0
- package/lib/types/backends/claude/translate/core.d.ts.map +1 -0
- package/lib/types/backends/claude/translate/core.js +447 -0
- package/lib/types/backends/claude/translate/events.d.ts +9 -0
- package/lib/types/backends/claude/translate/events.d.ts.map +1 -0
- package/lib/types/backends/claude/translate/events.js +77 -0
- package/lib/types/backends/claude/translate/lanes.d.ts +31 -0
- package/lib/types/backends/claude/translate/lanes.d.ts.map +1 -0
- package/lib/types/backends/claude/translate/lanes.js +177 -0
- package/lib/types/backends/claude/translate/messages.d.ts +36 -0
- package/lib/types/backends/claude/translate/messages.d.ts.map +1 -0
- package/lib/types/backends/claude/translate/messages.js +202 -0
- package/lib/types/backends/claude/translate/system.d.ts +40 -0
- package/lib/types/backends/claude/translate/system.d.ts.map +1 -0
- package/lib/types/backends/claude/translate/system.js +399 -0
- package/lib/types/backends/claude/translate/tasks.d.ts +19 -0
- package/lib/types/backends/claude/translate/tasks.d.ts.map +1 -0
- package/lib/types/backends/claude/translate/tasks.js +159 -0
- package/lib/types/backends/claude/translate/types.d.ts +114 -0
- package/lib/types/backends/claude/translate/types.d.ts.map +1 -0
- package/lib/types/backends/claude/translate/types.js +1 -0
- package/lib/types/backends/claude/translate.d.ts +9 -0
- package/lib/types/backends/claude/translate.d.ts.map +1 -0
- package/lib/types/backends/claude/translate.js +6 -0
- package/lib/types/backends/codex/auth/external-tokens.d.ts +66 -0
- package/lib/types/backends/codex/auth/external-tokens.d.ts.map +1 -0
- package/lib/types/backends/codex/auth/external-tokens.js +325 -0
- package/lib/types/backends/codex/auth/route.d.ts +14 -0
- package/lib/types/backends/codex/auth/route.d.ts.map +1 -0
- package/lib/types/backends/codex/auth/route.js +52 -0
- package/lib/types/backends/codex/auth/status.d.ts +16 -0
- package/lib/types/backends/codex/auth/status.d.ts.map +1 -0
- package/lib/types/backends/codex/auth/status.js +115 -0
- package/lib/types/backends/codex/backend.d.ts +58 -0
- package/lib/types/backends/codex/backend.d.ts.map +1 -0
- package/lib/types/backends/codex/backend.js +201 -0
- package/lib/types/backends/codex/catalog.d.ts +17 -0
- package/lib/types/backends/codex/catalog.d.ts.map +1 -0
- package/lib/types/backends/codex/catalog.js +128 -0
- package/lib/types/backends/codex/channels.d.ts +59 -0
- package/lib/types/backends/codex/channels.d.ts.map +1 -0
- package/lib/types/backends/codex/channels.js +274 -0
- package/lib/types/backends/codex/contract.d.ts +46 -0
- package/lib/types/backends/codex/contract.d.ts.map +1 -0
- package/lib/types/backends/codex/contract.js +80 -0
- package/lib/types/backends/codex/detect.d.ts +14 -0
- package/lib/types/backends/codex/detect.d.ts.map +1 -0
- package/lib/types/backends/codex/detect.js +90 -0
- package/lib/types/backends/codex/index.d.ts +6 -0
- package/lib/types/backends/codex/index.d.ts.map +1 -0
- package/lib/types/backends/codex/index.js +5 -0
- package/lib/types/backends/codex/modes.d.ts +16 -0
- package/lib/types/backends/codex/modes.d.ts.map +1 -0
- package/lib/types/backends/codex/modes.js +49 -0
- package/lib/types/backends/codex/narrow.d.ts +20 -0
- package/lib/types/backends/codex/narrow.d.ts.map +1 -0
- package/lib/types/backends/codex/narrow.js +18 -0
- package/lib/types/backends/codex/prefs.d.ts +42 -0
- package/lib/types/backends/codex/prefs.d.ts.map +1 -0
- package/lib/types/backends/codex/prefs.js +124 -0
- package/lib/types/backends/codex/protocol/index.d.ts +149 -0
- package/lib/types/backends/codex/protocol/index.d.ts.map +1 -0
- package/lib/types/backends/codex/protocol/index.js +130 -0
- package/lib/types/backends/codex/rpc/binary.d.ts +35 -0
- package/lib/types/backends/codex/rpc/binary.d.ts.map +1 -0
- package/lib/types/backends/codex/rpc/binary.js +174 -0
- package/lib/types/backends/codex/rpc/client.d.ts +72 -0
- package/lib/types/backends/codex/rpc/client.d.ts.map +1 -0
- package/lib/types/backends/codex/rpc/client.js +214 -0
- package/lib/types/backends/codex/rpc/hub.d.ts +105 -0
- package/lib/types/backends/codex/rpc/hub.d.ts.map +1 -0
- package/lib/types/backends/codex/rpc/hub.js +532 -0
- package/lib/types/backends/codex/rpc/transport.d.ts +39 -0
- package/lib/types/backends/codex/rpc/transport.d.ts.map +1 -0
- package/lib/types/backends/codex/rpc/transport.js +212 -0
- package/lib/types/backends/codex/session/activity.d.ts +18 -0
- package/lib/types/backends/codex/session/activity.d.ts.map +1 -0
- package/lib/types/backends/codex/session/activity.js +108 -0
- package/lib/types/backends/codex/session/approvals.d.ts +39 -0
- package/lib/types/backends/codex/session/approvals.d.ts.map +1 -0
- package/lib/types/backends/codex/session/approvals.js +477 -0
- package/lib/types/backends/codex/session/commands.d.ts +37 -0
- package/lib/types/backends/codex/session/commands.d.ts.map +1 -0
- package/lib/types/backends/codex/session/commands.js +141 -0
- package/lib/types/backends/codex/session/controls.d.ts +37 -0
- package/lib/types/backends/codex/session/controls.d.ts.map +1 -0
- package/lib/types/backends/codex/session/controls.js +303 -0
- package/lib/types/backends/codex/session/goals.d.ts +25 -0
- package/lib/types/backends/codex/session/goals.d.ts.map +1 -0
- package/lib/types/backends/codex/session/goals.js +97 -0
- package/lib/types/backends/codex/session/history.d.ts +52 -0
- package/lib/types/backends/codex/session/history.d.ts.map +1 -0
- package/lib/types/backends/codex/session/history.js +196 -0
- package/lib/types/backends/codex/session/images.d.ts +17 -0
- package/lib/types/backends/codex/session/images.d.ts.map +1 -0
- package/lib/types/backends/codex/session/images.js +138 -0
- package/lib/types/backends/codex/session/input.d.ts +75 -0
- package/lib/types/backends/codex/session/input.d.ts.map +1 -0
- package/lib/types/backends/codex/session/input.js +294 -0
- package/lib/types/backends/codex/session/plan-review.d.ts +19 -0
- package/lib/types/backends/codex/session/plan-review.d.ts.map +1 -0
- package/lib/types/backends/codex/session/plan-review.js +48 -0
- package/lib/types/backends/codex/session/prompts.d.ts +7 -0
- package/lib/types/backends/codex/session/prompts.d.ts.map +1 -0
- package/lib/types/backends/codex/session/prompts.js +47 -0
- package/lib/types/backends/codex/session/session.d.ts +12 -0
- package/lib/types/backends/codex/session/session.d.ts.map +1 -0
- package/lib/types/backends/codex/session/session.js +871 -0
- package/lib/types/backends/codex/session/side-query.d.ts +25 -0
- package/lib/types/backends/codex/session/side-query.d.ts.map +1 -0
- package/lib/types/backends/codex/session/side-query.js +121 -0
- package/lib/types/backends/codex/session/state.d.ts +57 -0
- package/lib/types/backends/codex/session/state.d.ts.map +1 -0
- package/lib/types/backends/codex/session/state.js +1 -0
- package/lib/types/backends/codex/session/subagents.d.ts +28 -0
- package/lib/types/backends/codex/session/subagents.d.ts.map +1 -0
- package/lib/types/backends/codex/session/subagents.js +286 -0
- package/lib/types/backends/codex/session/tasks.d.ts +25 -0
- package/lib/types/backends/codex/session/tasks.d.ts.map +1 -0
- package/lib/types/backends/codex/session/tasks.js +207 -0
- package/lib/types/backends/codex/session/tool-output.d.ts +9 -0
- package/lib/types/backends/codex/session/tool-output.d.ts.map +1 -0
- package/lib/types/backends/codex/session/tool-output.js +29 -0
- package/lib/types/backends/codex/translate/commands.d.ts +30 -0
- package/lib/types/backends/codex/translate/commands.d.ts.map +1 -0
- package/lib/types/backends/codex/translate/commands.js +103 -0
- package/lib/types/backends/codex/translate/events.d.ts +9 -0
- package/lib/types/backends/codex/translate/events.d.ts.map +1 -0
- package/lib/types/backends/codex/translate/events.js +71 -0
- package/lib/types/backends/codex/translate/items.d.ts +112 -0
- package/lib/types/backends/codex/translate/items.d.ts.map +1 -0
- package/lib/types/backends/codex/translate/items.js +375 -0
- package/lib/types/backends/codex/translate/live.d.ts +39 -0
- package/lib/types/backends/codex/translate/live.d.ts.map +1 -0
- package/lib/types/backends/codex/translate/live.js +315 -0
- package/lib/types/backends/codex/translate/notices.d.ts +27 -0
- package/lib/types/backends/codex/translate/notices.d.ts.map +1 -0
- package/lib/types/backends/codex/translate/notices.js +99 -0
- package/lib/types/backends/codex/translate/presentation.d.ts +49 -0
- package/lib/types/backends/codex/translate/presentation.d.ts.map +1 -0
- package/lib/types/backends/codex/translate/presentation.js +237 -0
- package/lib/types/backends/codex/translate/replay.d.ts +18 -0
- package/lib/types/backends/codex/translate/replay.d.ts.map +1 -0
- package/lib/types/backends/codex/translate/replay.js +33 -0
- package/lib/types/backends/codex/translate/usage.d.ts +29 -0
- package/lib/types/backends/codex/translate/usage.d.ts.map +1 -0
- package/lib/types/backends/codex/translate/usage.js +65 -0
- package/lib/types/backends/shared/atomic-file.d.ts +4 -0
- package/lib/types/backends/shared/atomic-file.d.ts.map +1 -0
- package/lib/types/backends/shared/atomic-file.js +52 -0
- package/lib/types/backends/shared/channel-tokens.d.ts +29 -0
- package/lib/types/backends/shared/channel-tokens.d.ts.map +1 -0
- package/lib/types/backends/shared/channel-tokens.js +161 -0
- package/lib/types/backends/shared/display-path.d.ts +3 -0
- package/lib/types/backends/shared/display-path.d.ts.map +1 -0
- package/lib/types/backends/shared/display-path.js +12 -0
- package/lib/types/branding.d.ts +92 -0
- package/lib/types/branding.d.ts.map +1 -0
- package/lib/types/branding.js +117 -0
- package/lib/types/channel/activity.d.ts +53 -0
- package/lib/types/channel/activity.d.ts.map +1 -0
- package/lib/types/channel/activity.js +955 -0
- package/lib/types/channel/capabilities.d.ts +24 -0
- package/lib/types/channel/capabilities.d.ts.map +1 -0
- package/lib/types/channel/capabilities.js +57 -0
- package/lib/types/channel/channel-slug.d.ts +9 -0
- package/lib/types/channel/channel-slug.d.ts.map +1 -0
- package/lib/types/channel/channel-slug.js +15 -0
- package/lib/types/channel/channel-wizard.d.ts +30 -0
- package/lib/types/channel/channel-wizard.d.ts.map +1 -0
- package/lib/types/channel/channel-wizard.js +226 -0
- package/lib/types/channel/elicitation.d.ts +135 -0
- package/lib/types/channel/elicitation.d.ts.map +1 -0
- package/lib/types/channel/elicitation.js +360 -0
- package/lib/types/channel/goal-command.d.ts +49 -0
- package/lib/types/channel/goal-command.d.ts.map +1 -0
- package/lib/types/channel/goal-command.js +72 -0
- package/lib/types/channel/history-restore.d.ts +16 -0
- package/lib/types/channel/history-restore.d.ts.map +1 -0
- package/lib/types/channel/history-restore.js +214 -0
- package/lib/types/channel/interaction.d.ts +38 -0
- package/lib/types/channel/interaction.d.ts.map +1 -0
- package/lib/types/channel/interaction.js +110 -0
- package/lib/types/channel/job-format.d.ts +6 -0
- package/lib/types/channel/job-format.d.ts.map +1 -0
- package/lib/types/channel/job-format.js +12 -0
- package/lib/types/channel/live-output.d.ts +35 -0
- package/lib/types/channel/live-output.d.ts.map +1 -0
- package/lib/types/channel/live-output.js +74 -0
- package/lib/types/channel/model-capabilities.d.ts +10 -0
- package/lib/types/channel/model-capabilities.d.ts.map +1 -0
- package/lib/types/channel/model-capabilities.js +51 -0
- package/lib/types/channel/permissions.d.ts +155 -0
- package/lib/types/channel/permissions.d.ts.map +1 -0
- package/lib/types/channel/permissions.js +188 -0
- package/lib/types/channel/projection.d.ts +110 -0
- package/lib/types/channel/projection.d.ts.map +1 -0
- package/lib/types/channel/projection.js +1521 -0
- package/lib/types/channel/question-record.d.ts +76 -0
- package/lib/types/channel/question-record.d.ts.map +1 -0
- package/lib/types/channel/question-record.js +109 -0
- package/lib/types/channel/questions.d.ts +204 -0
- package/lib/types/channel/questions.d.ts.map +1 -0
- package/lib/types/channel/questions.js +286 -0
- package/lib/types/channel/sanitize.d.ts +49 -0
- package/lib/types/channel/sanitize.d.ts.map +1 -0
- package/lib/types/channel/sanitize.js +88 -0
- package/lib/types/channel/selection-record.d.ts +18 -0
- package/lib/types/channel/selection-record.d.ts.map +1 -0
- package/lib/types/channel/selection-record.js +45 -0
- package/lib/types/channel/side-prompts.d.ts +59 -0
- package/lib/types/channel/side-prompts.d.ts.map +1 -0
- package/lib/types/channel/side-prompts.js +127 -0
- package/lib/types/channel/transcript.d.ts +17 -0
- package/lib/types/channel/transcript.d.ts.map +1 -0
- package/lib/types/channel/transcript.js +19 -0
- package/lib/types/channel/usage.d.ts +48 -0
- package/lib/types/channel/usage.d.ts.map +1 -0
- package/lib/types/channel/usage.js +143 -0
- package/lib/types/commands.d.ts +147 -0
- package/lib/types/commands.d.ts.map +1 -1
- package/lib/types/commands.js +208 -6
- 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/AgentMessageComposer.d.ts +50 -0
- package/lib/types/components/AgentMessageComposer.d.ts.map +1 -0
- package/lib/types/components/AgentMessageComposer.js +159 -0
- package/lib/types/components/BtwPanel.d.ts +13 -12
- package/lib/types/components/BtwPanel.d.ts.map +1 -1
- package/lib/types/components/BtwPanel.js +35 -24
- package/lib/types/components/ChannelPicker.d.ts +40 -0
- package/lib/types/components/ChannelPicker.d.ts.map +1 -0
- package/lib/types/components/ChannelPicker.js +26 -0
- package/lib/types/components/Chat/JobCard.d.ts +29 -14
- package/lib/types/components/Chat/JobCard.d.ts.map +1 -1
- package/lib/types/components/Chat/JobCard.js +51 -64
- 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.d.ts +4 -1
- package/lib/types/components/Chat/SubagentMessage.d.ts.map +1 -1
- package/lib/types/components/Chat/SubagentMessage.js +10 -3
- package/lib/types/components/ClaudeGirl.d.ts +27 -0
- package/lib/types/components/ClaudeGirl.d.ts.map +1 -0
- package/lib/types/components/ClaudeGirl.js +30 -0
- package/lib/types/components/CodeBlockFrame.d.ts +19 -0
- package/lib/types/components/CodeBlockFrame.d.ts.map +1 -0
- package/lib/types/components/CodeBlockFrame.js +138 -0
- package/lib/types/components/CommandSuggestions.d.ts +10 -1
- package/lib/types/components/CommandSuggestions.d.ts.map +1 -1
- package/lib/types/components/CommandSuggestions.js +20 -3
- package/lib/types/components/ContextBarView.d.ts +2 -2
- package/lib/types/components/ContextBarView.d.ts.map +1 -1
- package/lib/types/components/ContextBarView.js +18 -8
- package/lib/types/components/EffortChargeGlyph.d.ts +1 -1
- package/lib/types/components/EffortChargeGlyph.d.ts.map +1 -1
- package/lib/types/components/EffortChargeGlyph.js +3 -4
- package/lib/types/components/EffortInputBorder.d.ts +1 -2
- package/lib/types/components/EffortInputBorder.d.ts.map +1 -1
- package/lib/types/components/EffortInputBorder.js +7 -4
- package/lib/types/components/EffortSlider.d.ts +5 -1
- package/lib/types/components/EffortSlider.d.ts.map +1 -1
- package/lib/types/components/EffortSlider.js +2 -2
- package/lib/types/components/EffortTierBadge.d.ts +1 -2
- package/lib/types/components/EffortTierBadge.d.ts.map +1 -1
- package/lib/types/components/EffortTierBadge.js +8 -5
- package/lib/types/components/GoalTodoPanel.d.ts +15 -2
- package/lib/types/components/GoalTodoPanel.d.ts.map +1 -1
- package/lib/types/components/GoalTodoPanel.js +65 -18
- package/lib/types/components/InlineMathParagraph.js +1 -1
- package/lib/types/components/JobsPanel.d.ts +41 -2
- package/lib/types/components/JobsPanel.d.ts.map +1 -1
- package/lib/types/components/JobsPanel.js +208 -16
- package/lib/types/components/KernelPicker.d.ts +28 -0
- package/lib/types/components/KernelPicker.d.ts.map +1 -0
- package/lib/types/components/KernelPicker.js +37 -0
- package/lib/types/components/LogoV2.d.ts +49 -3
- package/lib/types/components/LogoV2.d.ts.map +1 -1
- package/lib/types/components/LogoV2.js +157 -34
- package/lib/types/components/Markdown.d.ts +2 -1
- package/lib/types/components/Markdown.d.ts.map +1 -1
- package/lib/types/components/Markdown.js +37 -8
- package/lib/types/components/MathBlock.d.ts.map +1 -1
- package/lib/types/components/MathBlock.js +3 -1
- package/lib/types/components/MermaidDiagram.d.ts.map +1 -1
- package/lib/types/components/MermaidDiagram.js +7 -5
- package/lib/types/components/MessageList.d.ts +28 -4
- package/lib/types/components/MessageList.d.ts.map +1 -1
- package/lib/types/components/MessageList.js +247 -33
- package/lib/types/components/ModePicker.d.ts +20 -0
- package/lib/types/components/ModePicker.d.ts.map +1 -0
- package/lib/types/components/ModePicker.js +17 -0
- 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/PromptInput.d.ts +22 -24
- package/lib/types/components/PromptInput.d.ts.map +1 -1
- package/lib/types/components/PromptInput.js +720 -210
- package/lib/types/components/SdkInstallWizard.d.ts +44 -0
- package/lib/types/components/SdkInstallWizard.d.ts.map +1 -0
- package/lib/types/components/SdkInstallWizard.js +18 -0
- package/lib/types/components/SearchBox.d.ts +22 -6
- package/lib/types/components/SearchBox.d.ts.map +1 -1
- package/lib/types/components/SearchBox.js +27 -14
- package/lib/types/components/SplitDiffView.d.ts.map +1 -1
- package/lib/types/components/SplitDiffView.js +113 -6
- package/lib/types/components/StarPrompt.d.ts.map +1 -1
- package/lib/types/components/StarPrompt.js +5 -3
- package/lib/types/components/StreamingMarkdown.d.ts.map +1 -1
- package/lib/types/components/StreamingMarkdown.js +6 -4
- package/lib/types/components/SubagentCard.d.ts +2 -1
- package/lib/types/components/SubagentCard.d.ts.map +1 -1
- package/lib/types/components/SubagentCard.js +32 -10
- package/lib/types/components/SubagentDashboard.d.ts +22 -3
- package/lib/types/components/SubagentDashboard.d.ts.map +1 -1
- package/lib/types/components/SubagentDashboard.js +69 -10
- package/lib/types/components/SubagentDetailScene.d.ts +22 -1
- package/lib/types/components/SubagentDetailScene.d.ts.map +1 -1
- package/lib/types/components/SubagentDetailScene.js +245 -45
- 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/SyntaxText.d.ts.map +1 -1
- package/lib/types/components/SyntaxText.js +4 -1
- 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/TurnInterruptedRow.d.ts +3 -1
- package/lib/types/components/TurnInterruptedRow.d.ts.map +1 -1
- package/lib/types/components/TurnInterruptedRow.js +6 -3
- package/lib/types/components/TurnUsageRow.d.ts +24 -0
- package/lib/types/components/TurnUsageRow.d.ts.map +1 -0
- package/lib/types/components/TurnUsageRow.js +46 -0
- package/lib/types/components/WorkingSpinner.d.ts +2 -1
- package/lib/types/components/WorkingSpinner.d.ts.map +1 -1
- package/lib/types/components/WorkingSpinner.js +21 -4
- package/lib/types/components/approvals/ApprovalPanel.d.ts +36 -13
- package/lib/types/components/approvals/ApprovalPanel.d.ts.map +1 -1
- package/lib/types/components/approvals/ApprovalPanel.js +173 -25
- package/lib/types/components/claudeGirlSprite.d.ts +18 -0
- package/lib/types/components/claudeGirlSprite.d.ts.map +1 -0
- package/lib/types/components/claudeGirlSprite.js +48 -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/design-system/ThemeProvider.d.ts.map +1 -1
- package/lib/types/components/design-system/ThemeProvider.js +46 -13
- package/lib/types/components/design-system/ThemedText.d.ts +3 -1
- package/lib/types/components/design-system/ThemedText.d.ts.map +1 -1
- package/lib/types/components/design-system/ThemedText.js +2 -2
- package/lib/types/components/diffPatch.d.ts +55 -0
- package/lib/types/components/diffPatch.d.ts.map +1 -0
- package/lib/types/components/diffPatch.js +142 -0
- package/lib/types/components/kernelCatalog.d.ts +48 -0
- package/lib/types/components/kernelCatalog.d.ts.map +1 -0
- package/lib/types/components/kernelCatalog.js +53 -0
- package/lib/types/components/launchpadActions.d.ts +80 -0
- package/lib/types/components/launchpadActions.d.ts.map +1 -0
- package/lib/types/components/launchpadActions.js +133 -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/launchpadParams.d.ts +101 -0
- package/lib/types/components/launchpadParams.d.ts.map +1 -0
- package/lib/types/components/launchpadParams.js +171 -0
- package/lib/types/components/maidPortrait.d.ts +37 -5
- package/lib/types/components/maidPortrait.d.ts.map +1 -1
- package/lib/types/components/maidPortrait.js +73 -54
- package/lib/types/components/messages/AgentMessageFlow.d.ts +20 -0
- package/lib/types/components/messages/AgentMessageFlow.d.ts.map +1 -0
- package/lib/types/components/messages/AgentMessageFlow.js +37 -0
- package/lib/types/components/messages/AssistantThinkingMessage.d.ts +6 -1
- package/lib/types/components/messages/AssistantThinkingMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantThinkingMessage.js +29 -5
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts +11 -2
- package/lib/types/components/messages/AssistantToolUseMessage.d.ts.map +1 -1
- package/lib/types/components/messages/AssistantToolUseMessage.js +289 -36
- package/lib/types/components/messages/TranscriptLeaves.d.ts +85 -0
- package/lib/types/components/messages/TranscriptLeaves.d.ts.map +1 -0
- package/lib/types/components/messages/TranscriptLeaves.js +74 -0
- package/lib/types/components/messages/agentTeam.d.ts +69 -0
- package/lib/types/components/messages/agentTeam.d.ts.map +1 -0
- package/lib/types/components/messages/agentTeam.js +53 -0
- package/lib/types/components/messages/liveOutputLines.d.ts +33 -0
- package/lib/types/components/messages/liveOutputLines.d.ts.map +1 -0
- package/lib/types/components/messages/liveOutputLines.js +100 -0
- package/lib/types/components/messages/subagentTranscript.d.ts +146 -0
- package/lib/types/components/messages/subagentTranscript.d.ts.map +1 -0
- package/lib/types/components/messages/subagentTranscript.js +304 -0
- 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/questions/AskUserQuestionPanel.d.ts +16 -1
- package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
- package/lib/types/components/questions/AskUserQuestionPanel.js +76 -6
- package/lib/types/components/questions/PlanReviewPanel.d.ts +8 -3
- package/lib/types/components/questions/PlanReviewPanel.d.ts.map +1 -1
- package/lib/types/components/questions/PlanReviewPanel.js +11 -6
- package/lib/types/components/questions/ProviderModelEditor.d.ts +12 -0
- package/lib/types/components/questions/ProviderModelEditor.d.ts.map +1 -0
- package/lib/types/components/questions/ProviderModelEditor.js +266 -0
- package/lib/types/components/shimmer.d.ts +26 -0
- package/lib/types/components/shimmer.d.ts.map +1 -1
- package/lib/types/components/shimmer.js +26 -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 +129 -0
- package/lib/types/components/sidePanel/PanelBar.d.ts +21 -0
- package/lib/types/components/sidePanel/PanelBar.d.ts.map +1 -0
- package/lib/types/components/sidePanel/PanelBar.js +82 -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 +57 -0
- package/lib/types/components/sidePanel/PanelStore.d.ts.map +1 -0
- package/lib/types/components/sidePanel/PanelStore.js +113 -0
- package/lib/types/components/sidePanel/SidePanelColumn.d.ts +24 -0
- package/lib/types/components/sidePanel/SidePanelColumn.d.ts.map +1 -0
- package/lib/types/components/sidePanel/SidePanelColumn.js +67 -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 +327 -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/agentViewStore.d.ts +20 -0
- package/lib/types/components/sidePanel/agentViewStore.d.ts.map +1 -0
- package/lib/types/components/sidePanel/agentViewStore.js +26 -0
- package/lib/types/components/sidePanel/btw/BtwComposer.d.ts +50 -0
- package/lib/types/components/sidePanel/btw/BtwComposer.d.ts.map +1 -0
- package/lib/types/components/sidePanel/btw/BtwComposer.js +45 -0
- package/lib/types/components/sidePanel/btw/BtwPanelAdapter.d.ts +13 -0
- package/lib/types/components/sidePanel/btw/BtwPanelAdapter.d.ts.map +1 -0
- package/lib/types/components/sidePanel/btw/BtwPanelAdapter.js +147 -0
- package/lib/types/components/sidePanel/btw/BtwThreadScene.d.ts +14 -0
- package/lib/types/components/sidePanel/btw/BtwThreadScene.d.ts.map +1 -0
- package/lib/types/components/sidePanel/btw/BtwThreadScene.js +131 -0
- package/lib/types/components/sidePanel/btw/BtwThreadView.d.ts +30 -0
- package/lib/types/components/sidePanel/btw/BtwThreadView.d.ts.map +1 -0
- package/lib/types/components/sidePanel/btw/BtwThreadView.js +87 -0
- package/lib/types/components/sidePanel/btw/threads.d.ts +111 -0
- package/lib/types/components/sidePanel/btw/threads.d.ts.map +1 -0
- package/lib/types/components/sidePanel/btw/threads.js +302 -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 +269 -0
- package/lib/types/components/sidePanel/companion/CompanionPanel.d.ts +11 -0
- package/lib/types/components/sidePanel/companion/CompanionPanel.d.ts.map +1 -0
- package/lib/types/components/sidePanel/companion/CompanionPanel.js +492 -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 +208 -0
- package/lib/types/components/sidePanel/companion/mood.d.ts.map +1 -0
- package/lib/types/components/sidePanel/companion/mood.js +256 -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 +136 -0
- package/lib/types/components/sidePanel/companion/skins.d.ts.map +1 -0
- package/lib/types/components/sidePanel/companion/skins.js +582 -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/splashFonts.d.ts +17 -9
- package/lib/types/components/splashFonts.d.ts.map +1 -1
- package/lib/types/components/splashFonts.js +119 -15
- package/lib/types/components/splashLayout.d.ts.map +1 -1
- package/lib/types/components/splashLayout.js +3 -1
- package/lib/types/components/subagentDetailMemory.d.ts +17 -0
- package/lib/types/components/subagentDetailMemory.d.ts.map +1 -0
- package/lib/types/components/subagentDetailMemory.js +28 -0
- package/lib/types/components/trajectory/Inspector.d.ts.map +1 -1
- package/lib/types/components/trajectory/Inspector.js +9 -0
- package/lib/types/components/trajectory/Ledger.d.ts.map +1 -1
- package/lib/types/components/trajectory/Ledger.js +7 -1
- package/lib/types/components/trajectory/scope.d.ts +64 -0
- package/lib/types/components/trajectory/scope.d.ts.map +1 -0
- package/lib/types/components/trajectory/scope.js +88 -0
- package/lib/types/components/trajectory/useTrajectoryScope.d.ts +42 -0
- package/lib/types/components/trajectory/useTrajectoryScope.d.ts.map +1 -0
- package/lib/types/components/trajectory/useTrajectoryScope.js +86 -0
- 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/customTheme.d.ts +4 -6
- package/lib/types/customTheme.d.ts.map +1 -1
- package/lib/types/customTheme.js +6 -8
- 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/approvals.d.ts +18 -5
- package/lib/types/dsh-adapter/approvals.d.ts.map +1 -1
- package/lib/types/dsh-adapter/approvals.js +17 -4
- package/lib/types/dsh-adapter/backend/session.d.ts +64 -0
- package/lib/types/dsh-adapter/backend/session.d.ts.map +1 -0
- package/lib/types/dsh-adapter/backend/session.js +291 -0
- package/lib/types/dsh-adapter/backend/translate.d.ts +58 -0
- package/lib/types/dsh-adapter/backend/translate.d.ts.map +1 -0
- package/lib/types/dsh-adapter/backend/translate.js +467 -0
- package/lib/types/dsh-adapter/backends.d.ts +49 -0
- package/lib/types/dsh-adapter/backends.d.ts.map +1 -0
- package/lib/types/dsh-adapter/backends.js +124 -0
- package/lib/types/dsh-adapter/channel/action-readiness.d.ts +16 -0
- package/lib/types/dsh-adapter/channel/action-readiness.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/action-readiness.js +109 -0
- package/lib/types/dsh-adapter/channel/agent-view-projection.d.ts +2 -2
- package/lib/types/dsh-adapter/channel/agent-view-projection.d.ts.map +1 -1
- 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/background-action.d.ts +2 -2
- package/lib/types/dsh-adapter/channel/background-action.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/background-action.js +7 -5
- package/lib/types/dsh-adapter/channel/binding-events.d.ts +25 -9
- package/lib/types/dsh-adapter/channel/binding-events.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/binding-events.js +101 -135
- package/lib/types/dsh-adapter/channel/binding.d.ts +61 -14
- package/lib/types/dsh-adapter/channel/binding.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/binding.js +102 -35
- 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 +3 -0
- package/lib/types/dsh-adapter/channel/command-completions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/command-completions.js +41 -4
- package/lib/types/dsh-adapter/channel/compaction.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/compaction.js +3 -2
- package/lib/types/dsh-adapter/channel/composer-images.d.ts +5 -0
- package/lib/types/dsh-adapter/channel/composer-images.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/composer-images.js +4 -3
- 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/core/actions.d.ts +39 -0
- package/lib/types/dsh-adapter/channel/core/actions.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/core/actions.js +152 -0
- package/lib/types/dsh-adapter/channel/core/binding-feed.d.ts +145 -0
- package/lib/types/dsh-adapter/channel/core/binding-feed.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/core/binding-feed.js +289 -0
- package/lib/types/dsh-adapter/channel/core/compose.d.ts +217 -0
- package/lib/types/dsh-adapter/channel/core/compose.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/core/compose.js +938 -0
- package/lib/types/dsh-adapter/channel/core/files.d.ts +57 -0
- package/lib/types/dsh-adapter/channel/core/files.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/core/files.js +45 -0
- package/lib/types/dsh-adapter/channel/core/host.d.ts +55 -0
- package/lib/types/dsh-adapter/channel/core/host.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/core/host.js +116 -0
- package/lib/types/dsh-adapter/channel/core/local-actions.d.ts +46 -0
- package/lib/types/dsh-adapter/channel/core/local-actions.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/core/local-actions.js +117 -0
- package/lib/types/dsh-adapter/channel/core/local-images.d.ts +20 -0
- package/lib/types/dsh-adapter/channel/core/local-images.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/core/local-images.js +147 -0
- package/lib/types/dsh-adapter/channel/core/reports.d.ts +12 -0
- package/lib/types/dsh-adapter/channel/core/reports.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/core/reports.js +77 -0
- package/lib/types/dsh-adapter/channel/core/session-controls.d.ts +39 -0
- package/lib/types/dsh-adapter/channel/core/session-controls.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/core/session-controls.js +219 -0
- package/lib/types/dsh-adapter/channel/core/session-switch.d.ts +174 -0
- package/lib/types/dsh-adapter/channel/core/session-switch.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/core/session-switch.js +390 -0
- package/lib/types/dsh-adapter/channel/core/sessions.d.ts +40 -0
- package/lib/types/dsh-adapter/channel/core/sessions.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/core/sessions.js +268 -0
- package/lib/types/dsh-adapter/channel/decisions.d.ts +4 -3
- package/lib/types/dsh-adapter/channel/decisions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/decisions.js +4 -4
- package/lib/types/dsh-adapter/channel/emitter.d.ts +15 -2
- package/lib/types/dsh-adapter/channel/emitter.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/emitter.js +5 -3
- package/lib/types/dsh-adapter/channel/extensions.d.ts +36 -0
- package/lib/types/dsh-adapter/channel/extensions.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/extensions.js +714 -0
- package/lib/types/dsh-adapter/channel/ide-selection.d.ts +1 -10
- package/lib/types/dsh-adapter/channel/ide-selection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/ide-selection.js +4 -46
- package/lib/types/dsh-adapter/channel/input-actions.d.ts +27 -4
- package/lib/types/dsh-adapter/channel/input-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/input-actions.js +240 -21
- package/lib/types/dsh-adapter/channel/input-delivery.d.ts +34 -7
- package/lib/types/dsh-adapter/channel/input-delivery.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/input-delivery.js +79 -24
- package/lib/types/dsh-adapter/channel/local-actions.d.ts +10 -32
- package/lib/types/dsh-adapter/channel/local-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/local-actions.js +10 -78
- package/lib/types/dsh-adapter/channel/local-fs.d.ts +3 -0
- package/lib/types/dsh-adapter/channel/local-fs.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/local-fs.js +46 -0
- package/lib/types/dsh-adapter/channel/mode-actions.d.ts +3 -6
- package/lib/types/dsh-adapter/channel/mode-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/mode-actions.js +7 -2
- package/lib/types/dsh-adapter/channel/mode-permission-actions.d.ts +10 -3
- package/lib/types/dsh-adapter/channel/mode-permission-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/mode-permission-actions.js +0 -1
- package/lib/types/dsh-adapter/channel/model-actions.d.ts +3 -3
- package/lib/types/dsh-adapter/channel/model-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/model-actions.js +38 -5
- package/lib/types/dsh-adapter/channel/model-switch.d.ts +2 -2
- package/lib/types/dsh-adapter/channel/model-switch.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/model-switch.js +9 -6
- 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 +25 -1
- package/lib/types/dsh-adapter/channel/projection.d.ts +16 -13
- package/lib/types/dsh-adapter/channel/projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/projection.js +38 -1138
- package/lib/types/dsh-adapter/channel/question-record.d.ts +3 -75
- package/lib/types/dsh-adapter/channel/question-record.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/question-record.js +3 -107
- 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-activity.d.ts +9 -0
- package/lib/types/dsh-adapter/channel/session-activity.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/session-activity.js +42 -0
- package/lib/types/dsh-adapter/channel/session-adoption.d.ts +4 -4
- package/lib/types/dsh-adapter/channel/session-adoption.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-adoption.js +3 -1
- package/lib/types/dsh-adapter/channel/session-fork.d.ts +1 -1
- package/lib/types/dsh-adapter/channel/session-fork.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-fork.js +2 -1
- package/lib/types/dsh-adapter/channel/session-live-adoption.d.ts +7 -3
- package/lib/types/dsh-adapter/channel/session-live-adoption.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-live-adoption.js +1 -1
- package/lib/types/dsh-adapter/channel/session-metadata.d.ts +2 -9
- package/lib/types/dsh-adapter/channel/session-metadata.d.ts.map +1 -1
- 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 +5 -0
- package/lib/types/dsh-adapter/channel/session-resume.d.ts +5 -10
- package/lib/types/dsh-adapter/channel/session-resume.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-resume.js +74 -113
- package/lib/types/dsh-adapter/channel/session-rewind.d.ts +4 -4
- package/lib/types/dsh-adapter/channel/session-rewind.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-rewind.js +7 -6
- package/lib/types/dsh-adapter/channel/session-tree-actions.d.ts +4 -4
- package/lib/types/dsh-adapter/channel/session-tree-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-tree-actions.js +8 -7
- package/lib/types/dsh-adapter/channel/settings-host.d.ts +1 -1
- package/lib/types/dsh-adapter/channel/settings-host.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/settings-host.js +8 -0
- package/lib/types/dsh-adapter/channel/skill-catalog.d.ts +5 -1
- package/lib/types/dsh-adapter/channel/skill-catalog.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/skill-catalog.js +2 -2
- package/lib/types/dsh-adapter/channel/state.d.ts +89 -2
- package/lib/types/dsh-adapter/channel/state.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/state.js +9 -4
- package/lib/types/dsh-adapter/channel/subagent-projection.d.ts +58 -3
- package/lib/types/dsh-adapter/channel/subagent-projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/subagent-projection.js +153 -9
- package/lib/types/dsh-adapter/channel/subagent-transcript.d.ts +114 -0
- package/lib/types/dsh-adapter/channel/subagent-transcript.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/subagent-transcript.js +279 -0
- package/lib/types/dsh-adapter/channel/transcript.d.ts +7 -15
- package/lib/types/dsh-adapter/channel/transcript.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/transcript.js +17 -21
- package/lib/types/dsh-adapter/channel/types.d.ts +16 -7
- package/lib/types/dsh-adapter/channel/types.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/usage.d.ts +3 -6
- package/lib/types/dsh-adapter/channel/usage.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/usage.js +5 -16
- package/lib/types/dsh-adapter/channel/workspace-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/workspace-actions.js +2 -1
- package/lib/types/dsh-adapter/channel.d.ts +17 -8
- package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel.js +24 -1006
- package/lib/types/dsh-adapter/context-occupancy.d.ts +209 -0
- package/lib/types/dsh-adapter/context-occupancy.d.ts.map +1 -0
- package/lib/types/dsh-adapter/context-occupancy.js +304 -0
- package/lib/types/dsh-adapter/contract.d.ts +14 -0
- package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
- package/lib/types/dsh-adapter/contract.js +24 -0
- package/lib/types/dsh-adapter/decision-guard.d.ts +24 -0
- package/lib/types/dsh-adapter/decision-guard.d.ts.map +1 -1
- package/lib/types/dsh-adapter/decision-guard.js +44 -0
- package/lib/types/dsh-adapter/extension-events.d.ts +4 -1
- package/lib/types/dsh-adapter/extension-events.d.ts.map +1 -1
- package/lib/types/dsh-adapter/extension-events.js +22 -10
- package/lib/types/dsh-adapter/index.d.ts +71 -1
- package/lib/types/dsh-adapter/index.d.ts.map +1 -1
- package/lib/types/dsh-adapter/index.js +47 -1
- package/lib/types/dsh-adapter/jobs.d.ts +5 -3
- package/lib/types/dsh-adapter/jobs.d.ts.map +1 -1
- package/lib/types/dsh-adapter/jobs.js +53 -14
- package/lib/types/dsh-adapter/migrate/parse/jsonl.d.ts +1 -16
- package/lib/types/dsh-adapter/migrate/parse/jsonl.d.ts.map +1 -1
- package/lib/types/dsh-adapter/migrate/parse/jsonl.js +3 -29
- 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-credential-source.d.ts +34 -0
- package/lib/types/dsh-adapter/oauth-credential-source.d.ts.map +1 -0
- package/lib/types/dsh-adapter/oauth-credential-source.js +66 -0
- 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 +55 -3
- package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin.js +708 -135
- package/lib/types/dsh-adapter/presets.d.ts +26 -6
- package/lib/types/dsh-adapter/presets.d.ts.map +1 -1
- package/lib/types/dsh-adapter/presets.js +29 -7
- package/lib/types/dsh-adapter/provider-model-capabilities.d.ts +10 -0
- package/lib/types/dsh-adapter/provider-model-capabilities.d.ts.map +1 -0
- package/lib/types/dsh-adapter/provider-model-capabilities.js +80 -0
- package/lib/types/dsh-adapter/providerWizard.d.ts +8 -2
- package/lib/types/dsh-adapter/providerWizard.d.ts.map +1 -1
- package/lib/types/dsh-adapter/providerWizard.js +118 -52
- package/lib/types/dsh-adapter/questions.d.ts +29 -124
- package/lib/types/dsh-adapter/questions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/questions.js +33 -267
- package/lib/types/dsh-adapter/recap.d.ts +3 -15
- package/lib/types/dsh-adapter/recap.d.ts.map +1 -1
- package/lib/types/dsh-adapter/recap.js +3 -46
- package/lib/types/dsh-adapter/sanitize.d.ts +4 -44
- package/lib/types/dsh-adapter/sanitize.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sanitize.js +4 -84
- package/lib/types/dsh-adapter/session-mount-heartbeat.d.ts +3 -1
- package/lib/types/dsh-adapter/session-mount-heartbeat.d.ts.map +1 -1
- package/lib/types/dsh-adapter/session-mount-heartbeat.js +4 -2
- package/lib/types/dsh-adapter/sessions/digest.d.ts +18 -3
- package/lib/types/dsh-adapter/sessions/digest.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sessions/digest.js +60 -27
- package/lib/types/dsh-adapter/sessions/list.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sessions/list.js +6 -4
- package/lib/types/dsh-adapter/sessions/recovery.d.ts +2 -2
- package/lib/types/dsh-adapter/sessions/recovery.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sessions/recovery.js +23 -14
- package/lib/types/dsh-adapter/sessions/store.d.ts +2 -0
- package/lib/types/dsh-adapter/sessions/store.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sessions/store.js +1 -0
- package/lib/types/dsh-adapter/sessions/types.d.ts +2 -0
- package/lib/types/dsh-adapter/sessions/types.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sideQuestion.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sideQuestion.js +3 -13
- 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.map +1 -1
- package/lib/types/dsh-adapter/subagents.js +7 -0
- package/lib/types/dsh-adapter/themes.d.ts +1 -1
- package/lib/types/dsh-adapter/themes.d.ts.map +1 -1
- package/lib/types/dsh-adapter/trajectory/agent-source.d.ts +84 -0
- package/lib/types/dsh-adapter/trajectory/agent-source.d.ts.map +1 -0
- package/lib/types/dsh-adapter/trajectory/agent-source.js +601 -0
- package/lib/types/dsh-adapter/trajectory/guards.d.ts +31 -1
- package/lib/types/dsh-adapter/trajectory/guards.d.ts.map +1 -1
- package/lib/types/dsh-adapter/trajectory/guards.js +28 -0
- package/lib/types/dsh-adapter/trajectory/index.d.ts +3 -1
- package/lib/types/dsh-adapter/trajectory/index.d.ts.map +1 -1
- package/lib/types/dsh-adapter/trajectory/index.js +1 -0
- package/lib/types/dsh-adapter/trajectory/inspect.d.ts +7 -0
- package/lib/types/dsh-adapter/trajectory/inspect.d.ts.map +1 -1
- package/lib/types/dsh-adapter/trajectory/inspect.js +70 -2
- package/lib/types/dsh-adapter/trajectory/projection.d.ts +4 -0
- package/lib/types/dsh-adapter/trajectory/projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/trajectory/projection.js +36 -0
- package/lib/types/dsh-adapter/trajectory/types.d.ts +13 -0
- package/lib/types/dsh-adapter/trajectory/types.d.ts.map +1 -1
- package/lib/types/effortPrefs.d.ts +7 -0
- package/lib/types/effortPrefs.d.ts.map +1 -1
- package/lib/types/effortPrefs.js +11 -2
- package/lib/types/handoffAck.d.ts +57 -0
- package/lib/types/handoffAck.d.ts.map +1 -0
- package/lib/types/handoffAck.js +154 -0
- package/lib/types/handoffEvents.d.ts +52 -0
- package/lib/types/handoffEvents.d.ts.map +1 -0
- package/lib/types/handoffEvents.js +128 -0
- 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 +3937 -97
- package/lib/types/i18n.d.ts.map +1 -1
- package/lib/types/i18n.js +1154 -12
- package/lib/types/ink/colorize.d.ts.map +1 -1
- package/lib/types/ink/colorize.js +8 -2
- package/lib/types/ink/components/AlternateScreen.d.ts +12 -1
- package/lib/types/ink/components/AlternateScreen.d.ts.map +1 -1
- package/lib/types/ink/components/AlternateScreen.js +25 -4
- package/lib/types/ink/components/App.d.ts +19 -2
- package/lib/types/ink/components/App.d.ts.map +1 -1
- package/lib/types/ink/components/App.js +114 -66
- package/lib/types/ink/components/Image.d.ts +8 -1
- package/lib/types/ink/components/Image.d.ts.map +1 -1
- package/lib/types/ink/components/Image.js +2 -2
- 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/components/Text.d.ts +8 -1
- package/lib/types/ink/components/Text.d.ts.map +1 -1
- package/lib/types/ink/components/Text.js +11 -1
- package/lib/types/ink/dom.d.ts.map +1 -1
- package/lib/types/ink/dom.js +75 -3
- 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 +17 -6
- 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 +59 -10
- package/lib/types/ink/kitty-graphics.d.ts +7 -2
- package/lib/types/ink/kitty-graphics.d.ts.map +1 -1
- package/lib/types/ink/kitty-graphics.js +15 -7
- package/lib/types/ink/node-cache.d.ts +15 -1
- package/lib/types/ink/node-cache.d.ts.map +1 -1
- package/lib/types/ink/node-cache.js +4 -1
- 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 +5 -3
- package/lib/types/ink/parse-keypress.d.ts +49 -3
- package/lib/types/ink/parse-keypress.d.ts.map +1 -1
- package/lib/types/ink/parse-keypress.js +700 -127
- package/lib/types/ink/reconciler.d.ts.map +1 -1
- package/lib/types/ink/reconciler.js +9 -0
- 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 +237 -9
- package/lib/types/ink/render-stats.d.ts +35 -0
- package/lib/types/ink/render-stats.d.ts.map +1 -0
- package/lib/types/ink/render-stats.js +53 -0
- 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 +21 -0
- package/lib/types/ink/sixel-codec.d.ts.map +1 -1
- package/lib/types/ink/sixel-codec.js +49 -8
- package/lib/types/ink/sixel-graphics.js +2 -2
- package/lib/types/ink/styles.d.ts +46 -0
- package/lib/types/ink/styles.d.ts.map +1 -1
- package/lib/types/ink/terminal-image.d.ts +7 -0
- package/lib/types/ink/terminal-image.d.ts.map +1 -1
- package/lib/types/ink/terminal-querier.d.ts +1 -1
- package/lib/types/ink/terminal-querier.js +4 -4
- package/lib/types/ink/text-decoration.d.ts +49 -0
- package/lib/types/ink/text-decoration.d.ts.map +1 -0
- package/lib/types/ink/text-decoration.js +235 -0
- package/lib/types/ink/update-overflow-guard.d.ts +9 -0
- package/lib/types/ink/update-overflow-guard.d.ts.map +1 -1
- package/lib/types/ink/update-overflow-guard.js +41 -0
- package/lib/types/ink/wrap-text.d.ts.map +1 -1
- package/lib/types/ink/wrap-text.js +5 -1
- package/lib/types/kernelPrefs.d.ts +51 -0
- package/lib/types/kernelPrefs.d.ts.map +1 -0
- package/lib/types/kernelPrefs.js +126 -0
- 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/modelRecents.d.ts +10 -2
- package/lib/types/modelRecents.d.ts.map +1 -1
- package/lib/types/modelRecents.js +20 -7
- 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/AgentTranscriptScene.d.ts +42 -0
- package/lib/types/screens/AgentTranscriptScene.d.ts.map +1 -0
- package/lib/types/screens/AgentTranscriptScene.js +269 -0
- package/lib/types/screens/Chat.d.ts +66 -7
- package/lib/types/screens/Chat.d.ts.map +1 -1
- package/lib/types/screens/Chat.js +1720 -381
- package/lib/types/screens/Launchpad.d.ts +211 -0
- package/lib/types/screens/Launchpad.d.ts.map +1 -0
- package/lib/types/screens/Launchpad.js +726 -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 +3 -3
- package/lib/types/screens/SessionSupervisor.d.ts.map +1 -1
- package/lib/types/screens/SessionSupervisor.js +87 -17
- package/lib/types/screens/Settings.d.ts.map +1 -1
- package/lib/types/screens/Settings.js +211 -7
- package/lib/types/screens/StatusLine.d.ts +40 -1
- package/lib/types/screens/StatusLine.d.ts.map +1 -1
- package/lib/types/screens/StatusLine.js +160 -30
- package/lib/types/screens/StatusMetrics.d.ts +75 -17
- package/lib/types/screens/StatusMetrics.d.ts.map +1 -1
- package/lib/types/screens/StatusMetrics.js +161 -30
- package/lib/types/screens/TrajectoryScene.d.ts.map +1 -1
- package/lib/types/screens/TrajectoryScene.js +74 -12
- package/lib/types/screens/chat/backendCommands.d.ts +37 -0
- package/lib/types/screens/chat/backendCommands.d.ts.map +1 -0
- package/lib/types/screens/chat/backendCommands.js +51 -0
- package/lib/types/screens/chat/useBackendChannels.d.ts +20 -0
- package/lib/types/screens/chat/useBackendChannels.d.ts.map +1 -0
- package/lib/types/screens/chat/useBackendChannels.js +117 -0
- package/lib/types/screens/chat/useKernelPicker.d.ts +23 -0
- package/lib/types/screens/chat/useKernelPicker.d.ts.map +1 -0
- package/lib/types/screens/chat/useKernelPicker.js +72 -0
- package/lib/types/screens/chatOverlay.d.ts +49 -2
- package/lib/types/screens/chatOverlay.d.ts.map +1 -1
- package/lib/types/screens/chatOverlay.js +12 -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/useForeignSessions.d.ts.map +1 -1
- package/lib/types/screens/sessionSupervisor/useForeignSessions.js +5 -1
- package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts +14 -0
- package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts.map +1 -1
- package/lib/types/screens/sessionSupervisor/useSessionSupervisor.js +104 -25
- package/lib/types/sessionHistory.d.ts +18 -1
- package/lib/types/sessionHistory.d.ts.map +1 -1
- package/lib/types/sessionHistory.js +46 -4
- package/lib/types/sessionPins.d.ts +7 -0
- package/lib/types/sessionPins.d.ts.map +1 -1
- package/lib/types/sessionPins.js +9 -0
- package/lib/types/sessions/resumeFailure.d.ts.map +1 -1
- package/lib/types/sessions/resumeFailure.js +2 -1
- package/lib/types/settings/definitions.d.ts +167 -0
- package/lib/types/settings/definitions.d.ts.map +1 -1
- package/lib/types/settings/definitions.js +129 -0
- package/lib/types/terminal-utils/hyperlink.d.ts +2 -2
- package/lib/types/terminal-utils/hyperlink.d.ts.map +1 -1
- package/lib/types/terminal-utils/hyperlink.js +21 -4
- package/lib/types/terminal-utils/markdown.d.ts +34 -6
- package/lib/types/terminal-utils/markdown.d.ts.map +1 -1
- package/lib/types/terminal-utils/markdown.js +257 -66
- package/lib/types/theme.d.ts +49 -8
- package/lib/types/theme.d.ts.map +1 -1
- package/lib/types/theme.js +514 -18
- package/lib/types/tips.js +7 -7
- package/lib/types/trajectory/effortIgnition.d.ts +25 -7
- package/lib/types/trajectory/effortIgnition.d.ts.map +1 -1
- package/lib/types/trajectory/effortIgnition.js +106 -34
- package/lib/types/trajectory/window.d.ts +26 -0
- package/lib/types/trajectory/window.d.ts.map +1 -0
- package/lib/types/trajectory/window.js +27 -0
- package/lib/types/tuiDisplayPrefs.d.ts +79 -2
- package/lib/types/tuiDisplayPrefs.d.ts.map +1 -1
- package/lib/types/tuiDisplayPrefs.js +118 -0
- package/lib/types/update.d.ts +141 -12
- package/lib/types/update.d.ts.map +1 -1
- package/lib/types/update.js +386 -62
- 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/crashDetail.d.ts +56 -0
- package/lib/types/utils/crashDetail.d.ts.map +1 -0
- package/lib/types/utils/crashDetail.js +175 -0
- 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/imageResize.d.ts +9 -23
- package/lib/types/utils/imageResize.d.ts.map +1 -1
- package/lib/types/utils/imageResize.js +24 -20
- package/lib/types/utils/inputPaste.d.ts +63 -0
- package/lib/types/utils/inputPaste.d.ts.map +1 -0
- package/lib/types/utils/inputPaste.js +148 -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/jsonl.d.ts +24 -0
- package/lib/types/utils/jsonl.d.ts.map +1 -0
- package/lib/types/utils/jsonl.js +36 -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/package.json +36 -9
- 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/{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,11 +1,14 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { t, getLang, setLang, isLang, writeLangPref, readLangPref, subscribeLang, LANGS } from '../i18n.js';
|
|
4
|
+
import { checkForTuiUpdate, installedTuiVersion } from '../update.js';
|
|
5
|
+
import { installedKernelVersion } from '../dsh-adapter/contract.js';
|
|
4
6
|
import { readThemePref } from '../themePrefs.js';
|
|
5
7
|
import { readPresetPref } from '../presetPrefs.js';
|
|
6
8
|
import { readModelPref } from '../modelPrefs.js';
|
|
7
9
|
import { readActivityFrames } from '../activityPrefs.js';
|
|
8
10
|
import { envThemeOverride } from '../components/design-system/ThemeProvider.js';
|
|
11
|
+
import { resolveBrand, setActiveBrand } from '../branding.js';
|
|
9
12
|
import { hasPath } from '../dsh-adapter/settingsEditor.js';
|
|
10
13
|
import { planReload } from '../reload.js';
|
|
11
14
|
import { AlternateScreen, Box, Image, Text, useInput, ScrollBox, useTheme, useTerminalSize } from '../ui.js';
|
|
@@ -14,11 +17,13 @@ import { POINTER } from '../terminal-utils/figures.js';
|
|
|
14
17
|
import { isPlainReturnInput } from '../utils/modifiers.js';
|
|
15
18
|
import { actionMatches, effectiveComboDisplay, primaryComboString } from '../utils/keymap.js';
|
|
16
19
|
import { formatTokens } from '../terminal-utils/format.js';
|
|
20
|
+
import { formatClock } from '../trajectory/format.js';
|
|
17
21
|
import { homeDir } from '../utils/paths.js';
|
|
18
22
|
import { execFileNoThrow } from '../utils/execFileNoThrow.js';
|
|
19
23
|
import { cleanRenderText, cleanScalarText } from '../dsh-adapter/sanitize.js';
|
|
20
24
|
import { deriveModelGroups, modelPickerLanding, recentCatalogModels, RECENTS_GROUP_PROVIDER, } from '../modelGroups.js';
|
|
21
25
|
import { readModelRecents, recordModelUse } from '../modelRecents.js';
|
|
26
|
+
import { WORKING_GATE_NOTICES } from '../commands.js';
|
|
22
27
|
import { TuiDialogStore } from '../dsh-adapter/dialogs.js';
|
|
23
28
|
import { TuiStatusStore } from '../dsh-adapter/status.js';
|
|
24
29
|
import { ActivityStore, useActivity } from '../dsh-adapter/activity-store.js';
|
|
@@ -30,11 +35,16 @@ import { renderMathRaster } from '../math/renderer.js';
|
|
|
30
35
|
const MATH_PREVIEW_SCALE = 2;
|
|
31
36
|
const MATH_PREVIEW_MAX_COLUMNS = 480;
|
|
32
37
|
const MATH_PREVIEW_MAX_ROWS = 64;
|
|
33
|
-
import { runProviderWizard } from '../dsh-adapter/providerWizard.js';
|
|
34
|
-
import {
|
|
38
|
+
import { runOAuthLogin, runProviderWizard } from '../dsh-adapter/providerWizard.js';
|
|
39
|
+
import { useKernelPicker } from './chat/useKernelPicker.js';
|
|
40
|
+
import { useBackendChannels } from './chat/useBackendChannels.js';
|
|
41
|
+
import { backendModeStatus as modeStatus, backendPermissionCommand, parseMcpCommand } from './chat/backendCommands.js';
|
|
42
|
+
import { PermissionStore } from '../channel/permissions.js';
|
|
43
|
+
import { goalStatusLines, parseGoalCommand } from '../channel/goal-command.js';
|
|
35
44
|
import { AskUserQuestionPanel } from '../components/questions/AskUserQuestionPanel.js';
|
|
36
45
|
import { ApprovalPanel } from '../components/approvals/ApprovalPanel.js';
|
|
37
46
|
import { ExtensionDialog } from '../components/ExtensionDialog.js';
|
|
47
|
+
import { consumeBoundaryRecoveryRemount } from '../ink/update-overflow-guard.js';
|
|
38
48
|
import { useSearchHighlight } from '../ink/hooks/use-search-highlight.js';
|
|
39
49
|
import { useTerminalTitle } from '../ink/hooks/use-terminal-title.js';
|
|
40
50
|
import { useTerminalFocus } from '../ink/hooks/use-terminal-focus.js';
|
|
@@ -44,24 +54,35 @@ import { NoSelect } from '../ink/components/NoSelect.js';
|
|
|
44
54
|
import { LogoHeader, MessageList } from '../components/MessageList.js';
|
|
45
55
|
import { splashFontIdOf } from '../components/splashFonts.js';
|
|
46
56
|
import { StarPrompt, WhaleCouponPrompt } from '../components/StarPrompt.js';
|
|
47
|
-
import { dueStarModal, markStarAsked, STAR_MILESTONES } from '../usageStats.js';
|
|
57
|
+
import { dueStarModal, markStarAsked, pendingStarMilestone, readUsage, STAR_MILESTONES } from '../usageStats.js';
|
|
48
58
|
import { TimelineRail } from '../components/TimelineRail.js';
|
|
49
59
|
import { ScrollbarGutter } from '../components/ScrollbarGutter.js';
|
|
50
60
|
import { normalizeScrollGutter } from '../tuiDisplayPrefs.js';
|
|
51
61
|
import { OverlayAbove } from '../components/OverlayAbove.js';
|
|
52
62
|
import { TooltipLayer } from '../components/Tooltip.js';
|
|
53
63
|
import { PromptInput } from '../components/PromptInput.js';
|
|
64
|
+
import { turnUsageParts } from '../components/TurnUsageRow.js';
|
|
65
|
+
import { AgentTranscriptScene } from './AgentTranscriptScene.js';
|
|
66
|
+
import { agentViewStore } from '../components/sidePanel/agentViewStore.js';
|
|
67
|
+
import { agentComposeTargetOf } from '../components/messages/agentTeam.js';
|
|
54
68
|
import { PromptEditorLayer, usePromptEditorOpen } from '../components/PromptEditor.js';
|
|
55
69
|
import { GoalTodoPanel } from '../components/GoalTodoPanel.js';
|
|
70
|
+
import { useSidePanel } from '../components/sidePanel/useSidePanel.js';
|
|
71
|
+
import { jobsFocusStore } from '../components/sidePanel/jobsFocusStore.js';
|
|
72
|
+
import { SidePanelLayout } from '../components/sidePanel/SidePanelLayout.js';
|
|
73
|
+
import { SidePanelColumn } from '../components/sidePanel/SidePanelColumn.js';
|
|
74
|
+
import { PanelPicker, usePanelPickerRows } from '../components/sidePanel/PanelPicker.js';
|
|
56
75
|
import { AutoRecapRow } from '../components/AutoRecapRow.js';
|
|
57
76
|
import { CompactionStatusRow } from '../components/CompactionStatusRow.js';
|
|
58
77
|
import { BalanceReportRow } from '../components/BalanceReportRow.js';
|
|
59
78
|
import { estimateSessionCostSnapshotCny } from '../deepseekPricing.js';
|
|
60
79
|
import { LoadedContextPanel } from '../components/LoadedContextPanel.js';
|
|
61
|
-
import { StatusLine } from './StatusLine.js';
|
|
80
|
+
import { formatCostReport, StatusLine } from './StatusLine.js';
|
|
81
|
+
import { channelContextOccupancy } from './StatusMetrics.js';
|
|
62
82
|
import { WorkingSpinner, useThinkingStatus } from '../components/WorkingSpinner.js';
|
|
63
83
|
import { ActivityLine, contextPressurePct } from '../components/ActivityLine.js';
|
|
64
84
|
import { ModelPicker } from '../components/ModelPicker.js';
|
|
85
|
+
import { HelpMenu } from '../components/HelpMenu.js';
|
|
65
86
|
import { PluginSceneBoundary } from '../components/PluginSceneBoundary.js';
|
|
66
87
|
import { PluginStatusViewBoundary } from '../components/PluginStatusViewBoundary.js';
|
|
67
88
|
import { ImagePreviewOverlay } from '../components/ImagePreviewOverlay.js';
|
|
@@ -81,6 +102,11 @@ import { ColorPicker } from '../components/ColorPicker.js';
|
|
|
81
102
|
import { EffortSlider } from '../components/EffortSlider.js';
|
|
82
103
|
import { PresetPicker } from '../components/PresetPicker.js';
|
|
83
104
|
import { PermissionsPicker } from '../components/PermissionsPicker.js';
|
|
105
|
+
import { ModePicker } from '../components/ModePicker.js';
|
|
106
|
+
import { KernelPicker } from '../components/KernelPicker.js';
|
|
107
|
+
import { SdkInstallWizard } from '../components/SdkInstallWizard.js';
|
|
108
|
+
import { ChannelPicker } from '../components/ChannelPicker.js';
|
|
109
|
+
import { modeDisplayName } from '../sessionModes.js';
|
|
84
110
|
import { PlanPicker } from '../components/PlanPicker.js';
|
|
85
111
|
import { LangPicker } from '../components/LangPicker.js';
|
|
86
112
|
import { ThemePicker, getThemeOptions } from '../components/ThemePicker.js';
|
|
@@ -89,7 +115,10 @@ import { FRAME_PRESETS, PRESET_NAMES } from '../components/activityFrames.js';
|
|
|
89
115
|
import { ThinkingToggle } from '../components/ThinkingToggle.js';
|
|
90
116
|
import { HistorySearchDialog } from '../components/HistorySearchDialog.js';
|
|
91
117
|
import { RewindPicker } from '../components/RewindPicker.js';
|
|
92
|
-
import {
|
|
118
|
+
import { BtwPanelFallback } from '../components/BtwPanel.js';
|
|
119
|
+
import { btwThreads } from '../components/sidePanel/btw/threads.js';
|
|
120
|
+
import { getBtwContextBudget, getBtwContextTurns } from '../tuiDisplayPrefs.js';
|
|
121
|
+
import { BtwThreadScene } from '../components/sidePanel/btw/BtwThreadScene.js';
|
|
93
122
|
import { RecapPanel } from '../components/RecapPanel.js';
|
|
94
123
|
import { isValidSessionColor, SESSION_COLOR_NAMES } from '../terminal-utils/sessionColors.js';
|
|
95
124
|
import { TipsPanel } from '../components/TipsPanel.js';
|
|
@@ -108,6 +137,12 @@ import { useAnimationFrame } from '../ink/hooks/use-animation-frame.js';
|
|
|
108
137
|
import { useExternalVersion } from '../hooks/useExternalVersion.js';
|
|
109
138
|
import { TrajectoryScene } from './TrajectoryScene.js';
|
|
110
139
|
import { markHomeSeen } from '../homePrefs.js';
|
|
140
|
+
import { markOnboardingDone } from '../onboardingPrefs.js';
|
|
141
|
+
import { Launchpad, launchpadVisible } from './Launchpad.js';
|
|
142
|
+
import { resolveLaunchpadActions } from '../components/launchpadActions.js';
|
|
143
|
+
import { Onboarding } from './Onboarding.js';
|
|
144
|
+
import { appendHistory } from '../history.js';
|
|
145
|
+
import { isHiddenCommandName, isLocalCommandName, parseCommandName } from '../commands.js';
|
|
111
146
|
import { extendTrajectory, projectWave } from '../dsh-adapter/trajectory/index.js';
|
|
112
147
|
import { miniWakeWidth } from '../components/trajectory/MiniWake.js';
|
|
113
148
|
import { readTrajectorySeen, writeTrajectorySeen } from '../trajectoryPrefs.js';
|
|
@@ -140,6 +175,27 @@ const COMMAND_RESULT_CELLS = 200;
|
|
|
140
175
|
* file, but a healthy import of thousands of conversations finishes well
|
|
141
176
|
* inside this; without a cap a wedged child would hang the loop forever. */
|
|
142
177
|
const MIGRATE_CHILD_TIMEOUT_MS = 30 * 60 * 1000;
|
|
178
|
+
/**
|
|
179
|
+
* 落地页参数行四段能点开的既有选择器(第五版):模型 → /model、思考深度 →
|
|
180
|
+
* /effort、模式 → /plan、权限预设 → /permission。盖在落地页之上时键盘归
|
|
181
|
+
* 选择器(见 useInput 的 launchpad 分支注释);其余 overlay 类型不在此列,
|
|
182
|
+
* 落地页期间照旧整块让位。
|
|
183
|
+
*/
|
|
184
|
+
const LAUNCHPAD_OVERLAY_KINDS = new Set([
|
|
185
|
+
'model', 'effort', 'plan', 'preset', 'permission', 'mode',
|
|
186
|
+
// 第七版:左下角工作目录铭牌点开的工作区菜单(及其二级选择器/流程层)
|
|
187
|
+
// 也是「盖在落地页之上」的姿态——同一套 pickerPanels 挂载,Esc 回落地页。
|
|
188
|
+
'workspace-menu', 'workspace-picker', 'workspace-flow',
|
|
189
|
+
// 第八版:帮助入口也走「盖在落地页之上」的浮层姿态(overlay kind 'help',
|
|
190
|
+
// HelpMenu 经 pickerPanels 挂进 OverlayAbove)——不再收掉落地页进对话页。
|
|
191
|
+
'help',
|
|
192
|
+
// 内核选择器(/kernel 与启动页「内核」入口):同一姿态盖在落地页之上,
|
|
193
|
+
// 点选即切换内核并重启(组合根的 onSwitchBackend)。
|
|
194
|
+
'kernel',
|
|
195
|
+
// SDK 安装向导(内核选择器「未安装」行 Enter 进入):同一姿态,Esc 层级
|
|
196
|
+
// 一样——向导收回,露出落地页。
|
|
197
|
+
'sdk-install',
|
|
198
|
+
]);
|
|
143
199
|
function cleanCommandError(error) {
|
|
144
200
|
try {
|
|
145
201
|
if (error instanceof Error) {
|
|
@@ -178,6 +234,27 @@ const NO_ROWS = [];
|
|
|
178
234
|
function capitalize(text) {
|
|
179
235
|
return text.length === 0 ? text : text[0].toUpperCase() + text.slice(1);
|
|
180
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* The occupancy line `/tokens` and `/status` print.
|
|
239
|
+
*
|
|
240
|
+
* Occupancy has ONE source (see `dsh-adapter/context-occupancy.ts`): this is
|
|
241
|
+
* the same reading the footer's ctx field, the segmented bar and the
|
|
242
|
+
* context-low warning use — never the session's cumulative uncached input,
|
|
243
|
+
* which is a different quantity by orders of magnitude.
|
|
244
|
+
* @param channel - Live channel surface.
|
|
245
|
+
* @returns The localized line, or `undefined` when no window is known.
|
|
246
|
+
*/
|
|
247
|
+
function contextOccupancyLine(channel) {
|
|
248
|
+
const occupancy = channelContextOccupancy(channel);
|
|
249
|
+
if (occupancy === undefined || occupancy.contextWindow === undefined || occupancy.contextWindow <= 0)
|
|
250
|
+
return undefined;
|
|
251
|
+
const percent = Math.max(0, Math.min(100, Math.round((occupancy.usedTokens / occupancy.contextWindow) * 100)));
|
|
252
|
+
return t('context-occupancy', {
|
|
253
|
+
percent,
|
|
254
|
+
used: formatTokens(occupancy.usedTokens),
|
|
255
|
+
window: formatTokens(occupancy.contextWindow),
|
|
256
|
+
});
|
|
257
|
+
}
|
|
181
258
|
/** Terminal-title spinner frames. */
|
|
182
259
|
const TITLE_SPINNER_FRAMES = ['⠂', '⠐'];
|
|
183
260
|
/** Searchable transcript text for one row (`/` incsearch):
|
|
@@ -230,7 +307,7 @@ const noCouponSnapshot = () => null;
|
|
|
230
307
|
function peekKey(image, title) {
|
|
231
308
|
return `${title ?? ''} ${image.id}`;
|
|
232
309
|
}
|
|
233
|
-
export function Chat({ channel, questionStore, approvalStore, extensionDialogs, bonusNotices, extensionStatus, activityStore, extensionShortcuts, themeHost, onExit, onUpdate, onRestart, fullscreen = false, trajectorySeen: trajectorySeenProp, injectControllerRef, promptControllerRef: promptControllerRefProp, renderScene, openHomeOnBoot, starPrompt, }) {
|
|
310
|
+
export function Chat({ channel, questionStore, approvalStore, extensionDialogs, bonusNotices, extensionStatus, activityStore, extensionShortcuts, themeHost, onExit, onUpdate, onRestart, onSwitchBackend, onRestartFreshSession, onProbeKernels, onResolveSdkInstallTarget, onStartSdkInstall, onCheckPnpm, sdkInstallPinned, kernelPinned, fullscreen = false, trajectorySeen: trajectorySeenProp, injectControllerRef, promptControllerRef: promptControllerRefProp, renderScene, openHomeOnBoot, launchpadOnBoot, onboardingOnBoot, starPrompt, }) {
|
|
234
311
|
const writeRaw = React.useContext(TerminalWriteContext);
|
|
235
312
|
// Re-render whenever the channel mutates; rows/status are read fresh below.
|
|
236
313
|
// DEFAULT lane on purpose (useExternalVersion): the channel version bumps
|
|
@@ -251,7 +328,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
251
328
|
// parks here until the panel decides; shown with priority over a pending
|
|
252
329
|
// questionnaire since it gates a tool about to run. Hosts that pass no
|
|
253
330
|
// approvalStore share one inert instance that never holds an ask.
|
|
254
|
-
const approvals = approvalStore ?? (fallbackApprovalStore ??= new
|
|
331
|
+
const approvals = approvalStore ?? (fallbackApprovalStore ??= new PermissionStore());
|
|
255
332
|
const approvalSnapshot = React.useSyncExternalStore(listener => approvals.subscribe(listener), () => approvals.getSnapshot());
|
|
256
333
|
// The pending managed plugin dialog (tuiDialogs seam): a plugin's
|
|
257
334
|
// select/confirm/input request parks here until the panel settles it.
|
|
@@ -350,7 +427,9 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
350
427
|
/** Provider display identities for the /model group level; refreshed alongside `models`. */
|
|
351
428
|
const [providerInfos, setProviderInfos] = React.useState([]);
|
|
352
429
|
/** /model 最近使用分组:成功切换即记录(去重置顶,上限 10),重启保留。 */
|
|
353
|
-
|
|
430
|
+
// Recents are per backend: a Claude session's picks never evict the DSH list.
|
|
431
|
+
const recentsBackend = channel.backendCapabilities?.backendId;
|
|
432
|
+
const [modelRecents, setModelRecents] = React.useState(() => readModelRecents(undefined, recentsBackend));
|
|
354
433
|
/** Two-level /model: the drilled-in provider route; undefined = group level.
|
|
355
434
|
* Reset on open; stale ids resolve back to the group level via `activeModelGroup`. */
|
|
356
435
|
const [modelGroup, setModelGroup] = React.useState(undefined);
|
|
@@ -384,7 +463,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
384
463
|
return ok;
|
|
385
464
|
if (name !== undefined)
|
|
386
465
|
channel.notify(t('model-switched', { name }));
|
|
387
|
-
setModelRecents(recordModelUse({ provider, id }));
|
|
466
|
+
setModelRecents(recordModelUse({ provider, id }, undefined, recentsBackend));
|
|
388
467
|
return ok;
|
|
389
468
|
});
|
|
390
469
|
};
|
|
@@ -408,7 +487,202 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
408
487
|
* on" has not been answered yet. Every later launch starts on the chat
|
|
409
488
|
* screen, and the screen stays reachable.
|
|
410
489
|
*/
|
|
411
|
-
|
|
490
|
+
// 根错误边界恢复后的重挂不是一次启动:启动页、首启引导与会话管理屏都
|
|
491
|
+
// 不再打开,直接回到对话页(一次性标记由错误边界的恢复路径写入,见
|
|
492
|
+
// update-overflow-guard)。首次渲染即消费;若这次渲染被丢弃,最坏只是
|
|
493
|
+
// 多显示一次启动入口。
|
|
494
|
+
const recoveryRemountOnBoot = consumeBoundaryRecoveryRemount();
|
|
495
|
+
// 第七版:启动页在开时**不再**预开会话浏览器。旧姿态是「先收落地页再开
|
|
496
|
+
// 整屏」,浏览器必须提前藏在下面;现在整屏(会话/设置/任务面板)盖在
|
|
497
|
+
// 落地页**之上**、Esc 退回落地页,按需打开即可——boot 时同时为真反而会
|
|
498
|
+
// 让浏览器盖住落地页(渲染顺序见各 early-return)。恢复重挂同样不开它。
|
|
499
|
+
const [supervisorOpen, setSupervisorOpen] = React.useState(openHomeOnBoot === true && launchpadOnBoot !== true && !recoveryRemountOnBoot);
|
|
500
|
+
/**
|
|
501
|
+
* The launchpad: the landing page every ordinary launch starts on.
|
|
502
|
+
*
|
|
503
|
+
* Seeded from `launchpadOnBoot`, and the screen that closes it is the one
|
|
504
|
+
* that decides what comes next — a submitted line hands over to the chat
|
|
505
|
+
* screen, an action hands over to whatever surface that action opens.
|
|
506
|
+
*/
|
|
507
|
+
const [launchpadOpen, setLaunchpadOpen] = React.useState(launchpadOnBoot === true && !recoveryRemountOnBoot);
|
|
508
|
+
/**
|
|
509
|
+
* The launchpad's draft. It lives HERE, not inside the screen, because the
|
|
510
|
+
* screen unmounts the moment the user submits: a draft owned by an
|
|
511
|
+
* unmounting component would be lost in exactly the transition it exists
|
|
512
|
+
* to carry.
|
|
513
|
+
*/
|
|
514
|
+
const [launchpadDraft, setLaunchpadDraft] = React.useState('');
|
|
515
|
+
const [launchpadCaret, setLaunchpadCaret] = React.useState(0);
|
|
516
|
+
const [launchpadFocus, setLaunchpadFocus] = React.useState(-1);
|
|
517
|
+
/**
|
|
518
|
+
* 「整屏盖启动页」的显式授权(第七版防御位,用户实测回归:启动页一闪而过
|
|
519
|
+
* 被顶掉)。整屏分支排在落地页**之前**,任何一处状态在开机后被异步置真
|
|
520
|
+
* (杂散输入/宿主事件/未来新代码)都会把落地页挤掉。授权位只有**从落地页
|
|
521
|
+
* 出发的交互**(入口行/空输入 Esc/目录铭牌/命令面板里的整屏命令、Continue
|
|
522
|
+
* 的兜底浏览器)才置真;覆盖屏全部收起时自动落 false。开机后即便某个整屏
|
|
523
|
+
* 状态被误置真,落地页仍在最上层——「浮层可以盖、整屏必须经授权」。
|
|
524
|
+
*/
|
|
525
|
+
const launchpadCoverRef = React.useRef(false);
|
|
526
|
+
/**
|
|
527
|
+
* 这一帧到底出不出落地页:状态开着还不够,minimal 模式(`dsh-tui.minimal`)
|
|
528
|
+
* 下它整块不存在——`minimalMode.ts` 的标志由 channel 在设置落地后写入,
|
|
529
|
+
* 建 state 时读不到,所以判定必须放在**渲染期**读(与其它 minimal 门同一口径)。
|
|
530
|
+
* 键盘守卫、渲染分支与"有没有整屏界面"的判定都认这一个值,三者不会分叉。
|
|
531
|
+
*/
|
|
532
|
+
/**
|
|
533
|
+
* 右下角铭牌的版本号:`installedTuiVersion()` 每次都要读一遍 package.json,
|
|
534
|
+
* 而它在一个进程里不会变——mount 时读一次就够。
|
|
535
|
+
*/
|
|
536
|
+
const tuiVersion = React.useMemo(() => installedTuiVersion(), []);
|
|
537
|
+
/**
|
|
538
|
+
* 内核(dsh)版本(第七版:落地页右下角双版本铭牌)。真实来源见
|
|
539
|
+
* `contract.installedKernelVersion`(宿主 CLI 的 manifest,回落内核线包);
|
|
540
|
+
* 两级都读不到 = undefined → 铭牌只画 TUI 段,绝不编造。
|
|
541
|
+
*/
|
|
542
|
+
const kernelVersion = React.useMemo(() => installedKernelVersion(), []);
|
|
543
|
+
const launchpadShown = launchpadOpen && launchpadVisible();
|
|
544
|
+
/**
|
|
545
|
+
* 落地页之上是否盖着一个参数选择器(第五版:参数行四段各自可点,点开的
|
|
546
|
+
* 是聊天页同一套 /model · /effort · /plan · /permission overlay)。这时
|
|
547
|
+
* 键盘归选择器(Esc 关它回到落地页),渲染也要把 pickerPanels 带进
|
|
548
|
+
* 落地页分支——不然整屏 early-return 把 overlay 吞了,"点了没反应"。
|
|
549
|
+
*/
|
|
550
|
+
const launchpadOverlayUp = launchpadShown && LAUNCHPAD_OVERLAY_KINDS.has(overlay.kind);
|
|
551
|
+
/**
|
|
552
|
+
* 渲染在**覆盖层**(而不是整屏 early-return)的那几个命令。
|
|
553
|
+
*
|
|
554
|
+
* 落地页的快捷入口与向导招式卡的「试一下」都走 `runCommand`,而 supervisor /
|
|
555
|
+
* settings / help 的 early-return 排在两个界面**之后**:不收掉当前界面就是
|
|
556
|
+
* "点了没反应",状态还滞留着、等界面关掉才突然弹出来。默认收,白名单只留给覆盖层。
|
|
557
|
+
*/
|
|
558
|
+
const overlayCommandNames = React.useMemo(() => new Set(['model', 'effort', 'plan', 'preset', 'permission', 'kernel']), []);
|
|
559
|
+
/**
|
|
560
|
+
* 打开**整屏界面**的命令(第七版):从落地页触发这些命令时**不收掉落地页**
|
|
561
|
+
* ——整屏盖在落地页之上渲染(它们的 early-return 排在落地页分支之前),
|
|
562
|
+
* Esc 退出整屏回到落地页(草稿/参数/焦点原样保留)。这是「从启动页进入
|
|
563
|
+
* 对话页的唯一路径 = Enter 提交一条非命令消息」的落地:任何返回键都不再
|
|
564
|
+
* 把人甩到对话页。其余命令(star / update / help / 转录输出类)的反馈在
|
|
565
|
+
* 对话页,仍按旧约收掉落地页再执行。
|
|
566
|
+
*/
|
|
567
|
+
const launchpadScreenCommands = React.useMemo(() => new Set(['home', 'resume', 'agentview', 'settings', 'jobs', 'tree', 'agents', 'setup', 'bg', 'background']), []);
|
|
568
|
+
/**
|
|
569
|
+
* 落地页条件位②(有新版本):`checkForTuiUpdate()`(与 /update 同一条
|
|
570
|
+
* 判定,src/update.ts)在启动页第一次挂起时后台探一次——registry 延迟
|
|
571
|
+
* 不许拖慢第一帧;失败/离线静默为 false(绝不放假按钮)。
|
|
572
|
+
*/
|
|
573
|
+
const [launchpadUpdateAvailable, setLaunchpadUpdateAvailable] = React.useState(false);
|
|
574
|
+
const launchpadUpdateProbedRef = React.useRef(false);
|
|
575
|
+
React.useEffect(() => {
|
|
576
|
+
if (!launchpadShown || launchpadUpdateProbedRef.current)
|
|
577
|
+
return;
|
|
578
|
+
launchpadUpdateProbedRef.current = true;
|
|
579
|
+
void checkForTuiUpdate().then(update => {
|
|
580
|
+
setLaunchpadUpdateAvailable(update !== undefined);
|
|
581
|
+
}).catch(() => undefined);
|
|
582
|
+
}, [launchpadShown]);
|
|
583
|
+
const canInstallSdk = onResolveSdkInstallTarget !== undefined && onStartSdkInstall !== undefined
|
|
584
|
+
&& onCheckPnpm !== undefined && sdkInstallPinned !== undefined;
|
|
585
|
+
const { currentId: kernelCurrentId, options: kernelOptions, open: openKernelPicker, pick: pickKernel, reprobe: reprobeKernels } = useKernelPicker({
|
|
586
|
+
channel, kernelVersion, launchpadShown, onProbeKernels, onSwitchBackend, canInstallSdk, dispatchOverlay,
|
|
587
|
+
});
|
|
588
|
+
/**
|
|
589
|
+
* SDK 安装向导的步骤态(异步进程状态,按 chatOverlay 的分工留在 Chat,
|
|
590
|
+
* 不进 overlay union)。生命周期约定:向导打开时从 idle 初始化,安装
|
|
591
|
+
* (checking/running)期间面板保持打开——所有异步落地都发生在面板还在
|
|
592
|
+
* 的窗口内;关闭路径(Esc/Enter 离开)一律重置回 idle,下一次打开重新
|
|
593
|
+
* 解析安装目标。
|
|
594
|
+
*/
|
|
595
|
+
const [sdkPhase, setSdkPhase] = React.useState({ kind: 'idle' });
|
|
596
|
+
const sdkInstallerRef = React.useRef(undefined);
|
|
597
|
+
// 打开即解析安装目标(同步、只读 argv + 文件系统):profile → 确认面板;
|
|
598
|
+
// standalone / 无 profile → 直接给手动指引面板。
|
|
599
|
+
React.useEffect(() => {
|
|
600
|
+
if (overlay.kind !== 'sdk-install' || sdkPhase.kind !== 'idle' || onResolveSdkInstallTarget === undefined)
|
|
601
|
+
return;
|
|
602
|
+
const target = onResolveSdkInstallTarget();
|
|
603
|
+
if (target.kind === 'profile' && sdkInstallPinned !== undefined) {
|
|
604
|
+
setSdkPhase({ kind: 'confirm', dir: target.dir, version: sdkInstallPinned.version, specifier: sdkInstallPinned.specifier });
|
|
605
|
+
}
|
|
606
|
+
else {
|
|
607
|
+
setSdkPhase({ kind: 'no-target', reason: target.kind === 'standalone' ? 'standalone' : 'no-profile' });
|
|
608
|
+
}
|
|
609
|
+
}, [overlay.kind, sdkPhase.kind, onResolveSdkInstallTarget, sdkInstallPinned]);
|
|
610
|
+
const closeSdkInstallToKernelPicker = () => {
|
|
611
|
+
setSdkPhase({ kind: 'idle' });
|
|
612
|
+
dispatchOverlay({ type: 'close' });
|
|
613
|
+
openKernelPicker();
|
|
614
|
+
};
|
|
615
|
+
const closeSdkInstall = () => {
|
|
616
|
+
setSdkPhase({ kind: 'idle' });
|
|
617
|
+
dispatchOverlay({ type: 'close' });
|
|
618
|
+
};
|
|
619
|
+
const runSdkInstall = (dir) => {
|
|
620
|
+
if (onStartSdkInstall === undefined || sdkInstallPinned === undefined)
|
|
621
|
+
return;
|
|
622
|
+
const installer = onStartSdkInstall(dir);
|
|
623
|
+
sdkInstallerRef.current = installer;
|
|
624
|
+
setSdkPhase({ kind: 'running' });
|
|
625
|
+
void installer.result.then(result => {
|
|
626
|
+
if (result.kind === 'ok') {
|
|
627
|
+
// 装好了:重探内核(灰行变亮,无需重启进程),停在完成面板。
|
|
628
|
+
reprobeKernels();
|
|
629
|
+
setSdkPhase({ kind: 'done' });
|
|
630
|
+
}
|
|
631
|
+
else if (result.kind === 'failed') {
|
|
632
|
+
setSdkPhase({ kind: 'failed', exitCode: result.exitCode, tail: result.tail, dir, version: sdkInstallPinned.version, specifier: sdkInstallPinned.specifier });
|
|
633
|
+
}
|
|
634
|
+
else if (result.kind === 'pnpm-missing') {
|
|
635
|
+
setSdkPhase({ kind: 'pnpm-missing', dir, version: sdkInstallPinned.version, specifier: sdkInstallPinned.specifier });
|
|
636
|
+
}
|
|
637
|
+
else {
|
|
638
|
+
setSdkPhase({ kind: 'cancelled' });
|
|
639
|
+
}
|
|
640
|
+
});
|
|
641
|
+
};
|
|
642
|
+
const confirmSdkInstall = (dir) => {
|
|
643
|
+
if (onCheckPnpm === undefined)
|
|
644
|
+
return;
|
|
645
|
+
setSdkPhase({ kind: 'checking' });
|
|
646
|
+
void onCheckPnpm().then(ok => {
|
|
647
|
+
if (!ok && sdkInstallPinned !== undefined) {
|
|
648
|
+
setSdkPhase({ kind: 'pnpm-missing', dir, version: sdkInstallPinned.version, specifier: sdkInstallPinned.specifier });
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
runSdkInstall(dir);
|
|
652
|
+
});
|
|
653
|
+
};
|
|
654
|
+
const host = channel.backendChannels?.();
|
|
655
|
+
const { rows: channelRows, open: openChannelPicker, pick: pickChannel, setMode: runBackendModeCommand, login: runBackendLogin } = useBackendChannels({
|
|
656
|
+
channel, host, questionStore, dispatchOverlay, onRestartFreshSession, runOAuthLogin,
|
|
657
|
+
});
|
|
658
|
+
/**
|
|
659
|
+
* 落地页条件位③(投喂一颗 Star):与开屏求 star 弹窗**同一口径**——
|
|
660
|
+
* `usageStats`(~/.dsh-tui/usage.json)里有未报过的已达档里程碑
|
|
661
|
+
* (`pendingStarMilestone`,首档 24h)且本进程尚未 star 成功。star 成功
|
|
662
|
+
* 后(`starred` 翻真)按钮立即消失;记账过的档不再纠缠。
|
|
663
|
+
*/
|
|
664
|
+
/**
|
|
665
|
+
* The first-run guide. Renders above the launchpad (see the prop docs): a
|
|
666
|
+
* launch that needs setup has not answered the launchpad's question yet.
|
|
667
|
+
*/
|
|
668
|
+
const [onboardingOpen, setOnboardingOpen] = React.useState(onboardingOnBoot === true && !recoveryRemountOnBoot);
|
|
669
|
+
/**
|
|
670
|
+
* 落地页那条"第一次用?跑一遍引导"的横幅认的是**还欠一次引导**,而不是启动快照:
|
|
671
|
+
* 完成(写进 onboarding.json)之后立刻收掉;跳过刻意保留——没记账,下次启动还会问,
|
|
672
|
+
* 横幅说的正是这件事。
|
|
673
|
+
*/
|
|
674
|
+
const [onboardingPending, setOnboardingPending] = React.useState(onboardingOnBoot === true && !recoveryRemountOnBoot);
|
|
675
|
+
/**
|
|
676
|
+
* 品牌档(`branding.ts`):设置项 `dsh-tui.brand`(`auto` = 跟后端)与当前
|
|
677
|
+
* 后端 id(`backendCapabilities.backendId`,boot 时即定)的合成。开屏词、
|
|
678
|
+
* 立绘、大字配色读 prop;主题默认档经 `setActiveBrand` 镜像给
|
|
679
|
+
* ThemeProvider(它挂在 Chat 外层,拿不到 channel)——plugin 已在首帧前
|
|
680
|
+
* 铺过初值,这里负责 `/settings` 切品牌时的实时跟动。
|
|
681
|
+
*/
|
|
682
|
+
const brand = resolveBrand(channel.brand, channel.backendCapabilities?.backendId);
|
|
683
|
+
React.useEffect(() => {
|
|
684
|
+
setActiveBrand(brand);
|
|
685
|
+
}, [brand]);
|
|
412
686
|
/** `/tree` opens the session family tree (pi's Session Tree): every rewind
|
|
413
687
|
* fork stitched back onto the message it diverged from, hover previews,
|
|
414
688
|
* and per-node rewind/fork/adopt actions. Like the supervisor, a screen. */
|
|
@@ -425,11 +699,19 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
425
699
|
const EMPTY_AGENT_VIEW_ROWS = [];
|
|
426
700
|
const agentViewRows = React.useSyncExternalStore(listener => channel.subscribeAgentView?.(listener) ?? (() => { }), () => channel.agentViewRows?.() ?? EMPTY_AGENT_VIEW_ROWS);
|
|
427
701
|
const backgroundAgentsNeedingInput = agentViewRows.filter(row => row.status === 'needs-input' && !row.current).length;
|
|
428
|
-
/**
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
* attaches back to it). */
|
|
702
|
+
/** Open the supervisor from `/bg`, `/background`, or an empty-prompt ←.
|
|
703
|
+
* DSH backgrounds the attached session first and uses it as the Esc
|
|
704
|
+
* return target; other backends keep the current session attached. */
|
|
432
705
|
const backgroundToAgentView = React.useCallback(() => {
|
|
706
|
+
// The non-DSH backends have a session catalog, but no live background
|
|
707
|
+
// handoff. Open the shared session manager without pretending to park the
|
|
708
|
+
// current turn. DSH keeps its existing handoff and Esc return target.
|
|
709
|
+
const backendId = channel.backendCapabilities?.backendId;
|
|
710
|
+
if (backendId !== undefined && backendId !== 'dsh') {
|
|
711
|
+
agentViewOpenSessionRef.current = channel.agentId;
|
|
712
|
+
setSupervisorOpen(true);
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
433
715
|
void channel.backgroundCurrent().then((result) => {
|
|
434
716
|
if (result.ok) {
|
|
435
717
|
setAgentViewReturnId(result.backgroundedSessionId);
|
|
@@ -448,6 +730,16 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
448
730
|
* `null` 显式关闭,传 actions 覆写两个按钮(不跑真 gh、不开真浏览器)。 */
|
|
449
731
|
/** 本次会话是否已经 star 成功(开屏彩蛋标题切「捡到小星星啦」)。 */
|
|
450
732
|
const [starred, setStarred] = React.useState(false);
|
|
733
|
+
/**
|
|
734
|
+
* 落地页条件位③(投喂一颗 Star):与开屏求 star 弹窗**同一口径**——
|
|
735
|
+
* `usageStats`(~/.dsh-tui/usage.json)里有未报过的已达档里程碑
|
|
736
|
+
* (`pendingStarMilestone`,首档 24h)且本进程尚未 star 成功。star 成功
|
|
737
|
+
* 后(`starred` 翻真)按钮立即消失;记账过的档不再纠缠。readUsage 是
|
|
738
|
+
* 文件读,只在 starred 翻真或测试缝变化时重算,不逐帧读盘。
|
|
739
|
+
*/
|
|
740
|
+
const launchpadStarDue = React.useMemo(() => !starred && pendingStarMilestone(readUsage(starPrompt?.dir)) !== null,
|
|
741
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps -- dir 经测试缝注入
|
|
742
|
+
[starred, starPrompt]);
|
|
451
743
|
const [starModal, setStarModal] = React.useState(null);
|
|
452
744
|
// 单发闩:只在第一个"安静的开屏视口"上武装定时器。700ms 窗口内整屏
|
|
453
745
|
// 界面打开 → cleanup 掐掉定时器且**不再重臂**(记账只发生在回调里,
|
|
@@ -462,7 +754,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
462
754
|
return;
|
|
463
755
|
if (starPrompt === null)
|
|
464
756
|
return;
|
|
465
|
-
if (supervisorOpen || treeOpen || settingsOpen || channel.working)
|
|
757
|
+
if (supervisorOpen || treeOpen || settingsOpen || launchpadShown || onboardingOpen || channel.working)
|
|
466
758
|
return;
|
|
467
759
|
starModalArmedRef.current = true;
|
|
468
760
|
// 让开屏先画半秒:弹窗压在介绍动画之上,而不是同抢第一帧。
|
|
@@ -484,7 +776,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
484
776
|
}, 700);
|
|
485
777
|
return () => { clearTimeout(timer); };
|
|
486
778
|
// eslint-disable-next-line react-hooks/exhaustive-deps -- 只在整屏界面开合时重判;闩保证只武装一次
|
|
487
|
-
}, [supervisorOpen, treeOpen, settingsOpen]);
|
|
779
|
+
}, [supervisorOpen, treeOpen, settingsOpen, launchpadShown, onboardingOpen]);
|
|
488
780
|
/** `/star` 命令、开屏标语的点击/`Alt+S` 共用的一键动作:异步跑 gh,界面
|
|
489
781
|
* 全程不阻塞,结果回来按四类各报一句(成功 / 没装 gh / 没登录 / 失败)。
|
|
490
782
|
* `starPrompt.onStar` 存在时走同一条测试缝(夹具因此不会真的去 star)。 */
|
|
@@ -593,10 +885,35 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
593
885
|
const workspaceFlowAbortRef = React.useRef(null);
|
|
594
886
|
/** `/preset` agent-preset roster (issue #8): loads async, persists. */
|
|
595
887
|
const [presetOptions, setPresetOptions] = React.useState([]);
|
|
888
|
+
/**
|
|
889
|
+
* 落地页参数行的模式段(第六版设计 1)显示 preset 的**显示名**
|
|
890
|
+
* (Standard/PTC/极简…),名册是异步的——落地页出来时顺手预热一次
|
|
891
|
+
* (空名册不写;失败静默,段缺省不画)。/preset 自己的加载路径不动。
|
|
892
|
+
*/
|
|
893
|
+
React.useEffect(() => {
|
|
894
|
+
if (!launchpadShown || presetOptions.length > 0)
|
|
895
|
+
return;
|
|
896
|
+
let cancelled = false;
|
|
897
|
+
channel.listPresets()
|
|
898
|
+
.then(list => { if (!cancelled && list.length > 0)
|
|
899
|
+
setPresetOptions(list); })
|
|
900
|
+
.catch(() => { });
|
|
901
|
+
return () => { cancelled = true; };
|
|
902
|
+
}, [launchpadShown, presetOptions.length, channel]);
|
|
596
903
|
/** `/effort` adapter levels: load async before the slider opens. */
|
|
597
904
|
const [effortOptions, setEffortOptions] = React.useState([]);
|
|
905
|
+
/** True when those levels are the CLI-standard compatibility ladder (the
|
|
906
|
+
* model row declares no tiers of its own) — the slider says so. */
|
|
907
|
+
const [effortLevelsFallback, setEffortLevelsFallback] = React.useState(false);
|
|
598
908
|
const [themeName, setTheme] = useTheme();
|
|
599
909
|
const { rows: terminalRows } = useTerminalSize();
|
|
910
|
+
/**
|
|
911
|
+
* 帮助盖屏(第八版,overlay kind 'help')的滚动视口:HelpMenu 自带
|
|
912
|
+
* ScrollBox,键盘(↑/↓/PgUp/PgDn/Home/End)由 Chat 的 overlay 分支驱动。
|
|
913
|
+
* 视口预算与 PromptInput 的 helpViewportHeight 同式(PR #446 的口径)。
|
|
914
|
+
*/
|
|
915
|
+
const helpCoverScrollRef = React.useRef(null);
|
|
916
|
+
const helpCoverViewportHeight = Math.max(3, Math.min(terminalRows - 7, 15));
|
|
600
917
|
const [showAllMessages, setShowAllMessages] = React.useState(false);
|
|
601
918
|
/** Scope the fold to this question: an aborted ask can promote its queued
|
|
602
919
|
* successor without ever publishing an idle (null) snapshot. */
|
|
@@ -612,15 +929,31 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
612
929
|
* plugin answering after the user moved on must not open a confirm for
|
|
613
930
|
* a row they are no longer looking at). */
|
|
614
931
|
const rewindRequestRef = React.useRef(0);
|
|
615
|
-
/** /btw side-question
|
|
616
|
-
*
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
932
|
+
/** /btw side-question thread: pure UI state in btwThreads — the answers
|
|
933
|
+
* never enter the transcript or the session log. The floating overlay is
|
|
934
|
+
* only the FALLBACK surface (btw panel not enabled); with the panel
|
|
935
|
+
* enabled the same thread routes to the sidebar instead — one answer,
|
|
936
|
+
* exactly one surface. */
|
|
937
|
+
const [btwOverlayOpen, setBtwOverlayOpen] = React.useState(false);
|
|
938
|
+
/** ⤢ fullscreen thread scene (openPanelFullscreen 'btw' route). */
|
|
939
|
+
const [btwSceneOpen, setBtwSceneOpen] = React.useState(false);
|
|
940
|
+
// Only the fallback overlay reads the thread here. With the overlay closed
|
|
941
|
+
// the snapshot stays undefined, so an answer streaming into the sidebar
|
|
942
|
+
// panel does not re-render the whole Chat on every delta.
|
|
943
|
+
const btwOverlayThread = React.useSyncExternalStore(btwThreads.subscribe, () => (btwOverlayOpen ? btwThreads.get(String(channel.agentId)) : undefined));
|
|
944
|
+
const closeBtwOverlay = () => {
|
|
945
|
+
// Fallback parity with the pre-thread overlay: closing cancels the
|
|
946
|
+
// in-flight ask (completed turns stay in the thread).
|
|
947
|
+
btwThreads.abortActive(String(channel.agentId));
|
|
948
|
+
setBtwOverlayOpen(false);
|
|
623
949
|
};
|
|
950
|
+
/** 有模态或整屏界面时,/btw 的回答不抢着打开面板,只标未读。 */
|
|
951
|
+
const btwSurfaceFree = () => approvalSnapshot === null && dialogSnapshot === null && questionSnapshot === null
|
|
952
|
+
&& overlay.kind === 'none' && !helpOpen && !starModal && !couponVisible
|
|
953
|
+
&& !supervisorOpen && !treeOpen && !settingsOpen && !jobsPanelOpen
|
|
954
|
+
&& !sceneOpen && channel.pluginScene === undefined
|
|
955
|
+
&& !subagentDashboardOpen && subagentDetailId === null
|
|
956
|
+
&& !onboardingOpen && !launchpadShown && !btwSceneOpen && !promptEditorOpen;
|
|
624
957
|
/** /recap overlay (pi-recap semantics): pure UI state like /btw — the
|
|
625
958
|
* summary never enters the transcript or session log; applying the
|
|
626
959
|
* proposed title goes through the normal /rename path. `auto` marks the
|
|
@@ -657,14 +990,11 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
657
990
|
balanceSeqRef.current += 1;
|
|
658
991
|
setBalance(null);
|
|
659
992
|
}, [balanceSessionId]);
|
|
660
|
-
// A side question belongs to its captured session just like a recap.
|
|
661
|
-
//
|
|
662
|
-
// the
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
btwAbortRef.current = null;
|
|
666
|
-
setBtw(null);
|
|
667
|
-
}, [channel.agentId]);
|
|
993
|
+
// A side question belongs to its captured session just like a recap. The
|
|
994
|
+
// THREAD stays in memory under its own session id (an archived thread may
|
|
995
|
+
// keep streaming); only the FALLBACK overlay is retired on a binding change
|
|
996
|
+
// (see the btwSessionIdRef effect above) so an old conversation never leaks
|
|
997
|
+
// onto the new one's screen.
|
|
668
998
|
// Auto-recap (`dsh-tui.recapOnOpen`): every time the session switches
|
|
669
999
|
// (mount = open/resume, rewind/fork included), summarize its tail into
|
|
670
1000
|
// the dim AutoRecapRow. Failures stay silent in auto mode — `/recap`
|
|
@@ -755,7 +1085,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
755
1085
|
setSearchCursor(0);
|
|
756
1086
|
setSearchCount(0);
|
|
757
1087
|
setSearchCurrent(0);
|
|
758
|
-
|
|
1088
|
+
setBtwOverlayOpen(false);
|
|
759
1089
|
repaintTranscript();
|
|
760
1090
|
}, [channel.agentId]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
761
1091
|
/** The session attached when the agent view opened; a close on a
|
|
@@ -772,17 +1102,102 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
772
1102
|
/** Subagent dashboard (Ctrl+A): displays active/completed subagents. */
|
|
773
1103
|
const [subagentDashboardOpen, setSubagentDashboardOpen] = React.useState(false);
|
|
774
1104
|
const [jobsPanelOpen, setJobsPanelOpen] = React.useState(false);
|
|
1105
|
+
/** Job id the panel should focus on open: set by a transcript card click
|
|
1106
|
+
* (open the panel AT that job), cleared on close so the keyboard/command
|
|
1107
|
+
* path reopens at the top. */
|
|
1108
|
+
const [jobsPanelFocusId, setJobsPanelFocusId] = React.useState(null);
|
|
1109
|
+
// Side-panel routing needs the controller, which is created further down;
|
|
1110
|
+
// a ref keeps this identity-stable callback fresh anyway.
|
|
1111
|
+
const sidePanelRef = React.useRef(null);
|
|
775
1112
|
// MessageList forwards these open handlers to every memoized row. Their
|
|
776
1113
|
// identities must survive token/metrics updates, including for tool rows.
|
|
777
|
-
const openJobsPanel = React.useCallback(() =>
|
|
1114
|
+
const openJobsPanel = React.useCallback((focusId) => {
|
|
1115
|
+
const sidePanel = sidePanelRef.current;
|
|
1116
|
+
// Split mode: open the jobs side panel at the requested job (the focus
|
|
1117
|
+
// lane carries the id; a fresh nonce refocuses even for the same id).
|
|
1118
|
+
if (sidePanel !== null && sidePanel.split && sidePanel.enabledPanelIds.includes('jobs')) {
|
|
1119
|
+
if (typeof focusId === 'string' && focusId !== '')
|
|
1120
|
+
jobsFocusStore.request(focusId);
|
|
1121
|
+
sidePanel.openPanel('jobs', { focus: true });
|
|
1122
|
+
return;
|
|
1123
|
+
}
|
|
1124
|
+
// Narrow / inline fallback: the full-screen overlay (unchanged).
|
|
1125
|
+
if (typeof focusId === 'string' && focusId !== '')
|
|
1126
|
+
setJobsPanelFocusId(focusId);
|
|
1127
|
+
setJobsPanelOpen(true);
|
|
1128
|
+
}, []);
|
|
1129
|
+
// A job card / the panel keeps its output tail fresh while on screen, when
|
|
1130
|
+
// the backend reads output on demand. The control is re-projected on every
|
|
1131
|
+
// read; this handler keeps one identity per channel capability so the
|
|
1132
|
+
// memoized rows are not re-rendered by it.
|
|
1133
|
+
const jobControlRef = React.useRef(channel.jobControl);
|
|
1134
|
+
jobControlRef.current = channel.jobControl;
|
|
1135
|
+
const jobOutputWatchable = typeof channel.jobControl?.watchOutput === 'function';
|
|
1136
|
+
const watchJobOutput = React.useMemo(() => jobOutputWatchable ? (id) => jobControlRef.current?.watchOutput?.(id) ?? (() => undefined) : undefined, [jobOutputWatchable]);
|
|
1137
|
+
/** Ctrl+A / detail 回退:侧栏分栏且 agents 已启用时打开右栏 Panel(内部
|
|
1138
|
+
* dashboard ↔ detail 二级路由自己管);窄屏 / inline 保留整屏形态。 */
|
|
1139
|
+
const openSubagentDashboard = React.useCallback(() => {
|
|
1140
|
+
const sidePanel = sidePanelRef.current;
|
|
1141
|
+
if (sidePanel !== null && sidePanel.split && sidePanel.enabledPanelIds.includes('agents')) {
|
|
1142
|
+
sidePanel.openPanel('agents', { focus: true });
|
|
1143
|
+
return;
|
|
1144
|
+
}
|
|
1145
|
+
setSubagentDashboardOpen(true);
|
|
1146
|
+
}, []);
|
|
778
1147
|
/** Detail view for a specific subagent (opened from dashboard). */
|
|
779
1148
|
const [subagentDetailId, setSubagentDetailId] = React.useState(null);
|
|
1149
|
+
/**
|
|
1150
|
+
* 主屏只读 Agent View:Chat 自己的场景层。父 Chat、Channel 与 PromptInput
|
|
1151
|
+
* 保持挂载(草稿经 draftCache 往返),场景只借用屏幕与键盘;Esc 回到打开它
|
|
1152
|
+
* 的地方(对话 / 代理面板 / 详情 / 转录卡)。不建第二个 Channel。
|
|
1153
|
+
*/
|
|
1154
|
+
const [agentView, setAgentView] = React.useState(null);
|
|
1155
|
+
const openAgentView = React.useCallback((agentId, source) => {
|
|
1156
|
+
setAgentView({ agentId, source });
|
|
1157
|
+
}, []);
|
|
1158
|
+
/** 工作台里切到同级或父代理:原地换被查看的代理,Esc 仍回最初的入口。 */
|
|
1159
|
+
const switchViewedAgent = React.useCallback((agentId) => {
|
|
1160
|
+
setAgentView(prev => prev === null ? prev : { ...prev, agentId });
|
|
1161
|
+
}, []);
|
|
1162
|
+
/** 转录卡入口的稳定句柄:MessageList 的 memo 行按 props 身份比较,内联
|
|
1163
|
+
* 箭头会让每个流式 tick 重渲染全部落定行(verify-tool-history-window)。 */
|
|
1164
|
+
const openSubagentViewFromCard = React.useCallback((agentId, rowId) => {
|
|
1165
|
+
openAgentView(agentId, { kind: 'transcript-card', rowId });
|
|
1166
|
+
}, [openAgentView]);
|
|
1167
|
+
// 侧栏 agents 面板 / 其 Detail 的主屏查看请求(面板没有 Chat 的场景 state)。
|
|
1168
|
+
React.useEffect(() => agentViewStore.subscribe(() => {
|
|
1169
|
+
const request = agentViewStore.get();
|
|
1170
|
+
if (request === null)
|
|
1171
|
+
return;
|
|
1172
|
+
const source = request.source === 'agents-dashboard'
|
|
1173
|
+
? { kind: 'agents-dashboard', ...(request.panel ? { panel: true } : {}) }
|
|
1174
|
+
: { kind: 'agent-detail', agentId: request.agentId, ...(request.panel ? { panel: true } : {}) };
|
|
1175
|
+
setAgentView({ agentId: request.agentId, source });
|
|
1176
|
+
}), []);
|
|
1177
|
+
/** Esc 的返回路由:面板来源回面板(路由经模块记忆保真),整屏来源回整屏。 */
|
|
1178
|
+
const exitAgentView = React.useCallback((source) => {
|
|
1179
|
+
setAgentView(null);
|
|
1180
|
+
const sidePanel = sidePanelRef.current;
|
|
1181
|
+
const panelReturn = (sidePanel !== null && sidePanel.split && sidePanel.enabledPanelIds.includes('agents'));
|
|
1182
|
+
if (source.kind === 'agents-dashboard') {
|
|
1183
|
+
if (source.panel === true && panelReturn)
|
|
1184
|
+
sidePanel.openPanel('agents', { focus: true });
|
|
1185
|
+
else
|
|
1186
|
+
setSubagentDashboardOpen(true);
|
|
1187
|
+
return;
|
|
1188
|
+
}
|
|
1189
|
+
if (source.kind === 'agent-detail') {
|
|
1190
|
+
if (source.panel === true && panelReturn)
|
|
1191
|
+
sidePanel.openPanel('agents', { focus: true });
|
|
1192
|
+
else
|
|
1193
|
+
setSubagentDetailId(source.agentId);
|
|
1194
|
+
}
|
|
1195
|
+
}, []);
|
|
780
1196
|
/**
|
|
781
1197
|
* Hidden `/deepseek` easter egg: each invocation bumps this key so the
|
|
782
1198
|
* logo header remounts and replays the whale spout + text shimmer.
|
|
783
1199
|
*/
|
|
784
1200
|
const [logoNonce, setLogoNonce] = React.useState(0);
|
|
785
|
-
React.useEffect(() => () => btwAbortRef.current?.abort(), []);
|
|
786
1201
|
React.useEffect(() => () => recapAbortRef.current?.abort(), []);
|
|
787
1202
|
/**
|
|
788
1203
|
* The trajectory scene (issue #80 evolution). Unlike every other overlay
|
|
@@ -802,16 +1217,64 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
802
1217
|
const closeScene = React.useCallback(() => {
|
|
803
1218
|
setSceneOpen(false);
|
|
804
1219
|
}, []);
|
|
805
|
-
/**
|
|
806
|
-
|
|
1220
|
+
/**
|
|
1221
|
+
* 整屏分支的「盖启动页」闸门(第七版防御位,用户实测回归:启动页一闪
|
|
1222
|
+
* 而过被顶掉)。落地页在屏上时,只有**经 `launchpadCoverRef` 授权**
|
|
1223
|
+
* (= 从落地页出发的交互打开)的整屏才盖它;否则该整屏状态被无视
|
|
1224
|
+
* (渲染落到落地页),启动页永远不被开机期的杂散状态挤掉。落地页不在
|
|
1225
|
+
* 屏上时闸门恒开(普通姿态与从前逐字节一致)。
|
|
1226
|
+
*
|
|
1227
|
+
* ⚠ 这一段必须排在组件**所有** early-return 之前(hooks 规则):曾放在
|
|
1228
|
+
* onboarding/interrupt 分支之后,向导一开就少跑这个 effect,React 直接
|
|
1229
|
+
* 报 hooks 乱序(verify-launchpad-onboarding-chat A2/E5/H2 全红)。
|
|
1230
|
+
*/
|
|
1231
|
+
const launchpadGate = () => !launchpadShown || launchpadCoverRef.current;
|
|
1232
|
+
// 覆盖屏全部收起时收回授权:下一次打开必须再经过落地页自己的交互。
|
|
1233
|
+
const launchpadCoverScreenUp = supervisorOpen || treeOpen || settingsOpen
|
|
1234
|
+
|| jobsPanelOpen || subagentDashboardOpen || subagentDetailId !== null || sceneOpen
|
|
1235
|
+
|| agentView !== null
|
|
1236
|
+
|| btwSceneOpen;
|
|
1237
|
+
React.useEffect(() => {
|
|
1238
|
+
if (!launchpadCoverScreenUp)
|
|
1239
|
+
launchpadCoverRef.current = false;
|
|
1240
|
+
}, [launchpadCoverScreenUp]);
|
|
1241
|
+
/**
|
|
1242
|
+
* 从落地页出发的交互要开整屏前先授权(配合 `launchpadGate`):调用点只在
|
|
1243
|
+
* 落地页自己的回调里(onAction / onCommandPick / onEscape 的会话浏览路)。
|
|
1244
|
+
* 异步误置真的整屏状态没有这道授权 → 闸门挡下,落地页留在最上层。
|
|
1245
|
+
*/
|
|
1246
|
+
const authorizeLaunchpadCover = () => { launchpadCoverRef.current = true; };
|
|
1247
|
+
/**
|
|
1248
|
+
* Open the trajectory, mark failures seen, and retire the key hint for good.
|
|
1249
|
+
*
|
|
1250
|
+
* Ctrl+T and `/trace` share this one entry point, and it is SPLIT-AWARE the
|
|
1251
|
+
* same way `/jobs` and `/agents` already are: while the sidebar is
|
|
1252
|
+
* rendering, the trajectory opens as the `trajectory` panel inside it
|
|
1253
|
+
* instead of taking the whole screen. `options.fullscreen` is the escape
|
|
1254
|
+
* hatch the panel's own ⤢ button uses — without it that button would route
|
|
1255
|
+
* straight back into the panel it is trying to leave.
|
|
1256
|
+
*/
|
|
1257
|
+
const openScene = React.useCallback((options) => {
|
|
1258
|
+
// /trace, Ctrl+T, the sidebar tab and ⤢ all open the trajectory. A
|
|
1259
|
+
// kernel without a trajectory source reports 'unsupported' and the
|
|
1260
|
+
// scene/panel say so; no entry point refuses on its own, so they can
|
|
1261
|
+
// never disagree about the capability.
|
|
807
1262
|
seenFailuresRef.current = trajectoryRef.current?.counts.errors ?? 0;
|
|
808
1263
|
setTrajectorySeen(previous => {
|
|
809
1264
|
if (!previous)
|
|
810
1265
|
writeTrajectorySeen();
|
|
811
1266
|
return true;
|
|
812
1267
|
});
|
|
1268
|
+
const controller = sidePanelRef.current;
|
|
1269
|
+
if (options?.fullscreen !== true
|
|
1270
|
+
&& controller !== null
|
|
1271
|
+
&& controller.split
|
|
1272
|
+
&& controller.enabledPanelIds.includes('trajectory')) {
|
|
1273
|
+
controller.openPanel('trajectory', { focus: true });
|
|
1274
|
+
return;
|
|
1275
|
+
}
|
|
813
1276
|
setSceneOpen(true);
|
|
814
|
-
}, []);
|
|
1277
|
+
}, [channel]);
|
|
815
1278
|
/**
|
|
816
1279
|
* Leave the session supervisor for the conversation.
|
|
817
1280
|
*
|
|
@@ -840,6 +1303,32 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
840
1303
|
}).catch(() => undefined);
|
|
841
1304
|
}
|
|
842
1305
|
}, [agentViewReturnId, channel, repaintTranscript]);
|
|
1306
|
+
/**
|
|
1307
|
+
* Leave the first-run guide.
|
|
1308
|
+
*
|
|
1309
|
+
* `done` writes the one-shot marker; `skipped` deliberately does NOT — the
|
|
1310
|
+
* user has not answered, and a later launch is exactly when they might.
|
|
1311
|
+
* Both cases land on the launchpad rather than the transcript: the wizard
|
|
1312
|
+
* interrupted a launch, so the launch resumes where it left off.
|
|
1313
|
+
*
|
|
1314
|
+
* The write is best-effort by design (`markOnboardingDone` returns false
|
|
1315
|
+
* when the data directory is unwritable); a read-only install gets one more
|
|
1316
|
+
* offer next launch, which is the recoverable end of the trade.
|
|
1317
|
+
*/
|
|
1318
|
+
const closeOnboarding = React.useCallback((outcome) => {
|
|
1319
|
+
setOnboardingOpen(false);
|
|
1320
|
+
if (outcome === 'done') {
|
|
1321
|
+
const written = markOnboardingDone();
|
|
1322
|
+
setOnboardingPending(false);
|
|
1323
|
+
channel.notify(t(written ? 'onboarding-finished' : 'onboarding-write-failed'), {
|
|
1324
|
+
color: written ? 'success' : 'warning',
|
|
1325
|
+
timeoutMs: written ? 3000 : 6000,
|
|
1326
|
+
});
|
|
1327
|
+
}
|
|
1328
|
+
else {
|
|
1329
|
+
channel.notify(t('onboarding-skipped'), { timeoutMs: 4000 });
|
|
1330
|
+
}
|
|
1331
|
+
}, [channel]);
|
|
843
1332
|
/** The startup summary gives way to transcript rows after the first local command or message. */
|
|
844
1333
|
const loadedContextVisible = channel.rows.length === 0 && channel.loadedContext !== undefined;
|
|
845
1334
|
/** Startup context panel: collapsed by default, toggled with Ctrl+P. */
|
|
@@ -1634,6 +2123,69 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
1634
2123
|
: t('migrate-failed', { n: failures }), failures === 0 ? { timeoutMs: 6000 } : { color: 'error', timeoutMs: 10000 });
|
|
1635
2124
|
})();
|
|
1636
2125
|
};
|
|
2126
|
+
/**
|
|
2127
|
+
* Close the launchpad and hand the draft to the chat screen.
|
|
2128
|
+
*
|
|
2129
|
+
* THREE cases, and they are genuinely different:
|
|
2130
|
+
*
|
|
2131
|
+
* - a slash command → `runCommand`, the same dispatch a typed command
|
|
2132
|
+
* takes in the composer. The line is NOT submitted to the model.
|
|
2133
|
+
* Recognition is the composer's OWN rule (第六版 BUG 1 修复): the merged
|
|
2134
|
+
* command list (locals + plugin/registry commands via channel.commandList)
|
|
2135
|
+
* decides whether the line is a command — isLocalCommandName alone missed
|
|
2136
|
+
* registry-only names (e.g. /plan, /goal), which then fell through to
|
|
2137
|
+
* channel.submit and went to the model as a user message.
|
|
2138
|
+
* - ordinary text → SENT DIRECTLY (fifth revision, user-reported bug:
|
|
2139
|
+
* "按了回车就直接进入流式输出"). The line rides the composer's own
|
|
2140
|
+
* submit path (`channel.submit`, which queues through the DSH inbox
|
|
2141
|
+
* while a turn is running) — no draft is parked anywhere, the composer
|
|
2142
|
+
* mounts EMPTY because the content is already gone as the first turn.
|
|
2143
|
+
* - empty → nothing to send; just show the conversation.
|
|
2144
|
+
*
|
|
2145
|
+
* History is appended for the two non-empty cases (matching what PromptInput
|
|
2146
|
+
* does on submit) so the launchpad's first line is reachable with ↑ later.
|
|
2147
|
+
*/
|
|
2148
|
+
const closeLaunchpad = React.useCallback((submit) => {
|
|
2149
|
+
const text = submit.trim();
|
|
2150
|
+
setLaunchpadOpen(false);
|
|
2151
|
+
// 首启时 openHomeOnBoot 与落地页同时为真:会话浏览器已经开着、只是被落地页盖住。
|
|
2152
|
+
// 提交首句后必须把它收掉,否则用户落到浏览器而不是"草稿就在眼前的对话",
|
|
2153
|
+
// 与本函数 doc 承诺的落点直接矛盾。
|
|
2154
|
+
setSupervisorOpen(false);
|
|
2155
|
+
setLaunchpadFocus(-1);
|
|
2156
|
+
setLaunchpadDraft('');
|
|
2157
|
+
setLaunchpadCaret(0);
|
|
2158
|
+
if (text === '')
|
|
2159
|
+
return;
|
|
2160
|
+
void appendHistory(text);
|
|
2161
|
+
const parsed = text.startsWith('/') ? parseCommandName(text) : undefined;
|
|
2162
|
+
// 第八版:/help 在落地页上也是盖屏浮层(补全面板被 Esc 收掉后直接
|
|
2163
|
+
// Enter 的那条路)——不收落地页、不进对话页。聊天页里 /help 的行为
|
|
2164
|
+
// 不变(那边不走这个回调)。
|
|
2165
|
+
if (parsed !== undefined && parsed.name === 'help' && launchpadOpen) {
|
|
2166
|
+
dispatchOverlay({ type: 'open', overlay: { kind: 'help' } });
|
|
2167
|
+
return;
|
|
2168
|
+
}
|
|
2169
|
+
// 与 composer 的 tryRunCommand 同一条判定:合并命令表(LOCAL_COMMANDS +
|
|
2170
|
+
// channel.commandList 的插件/registry 命令)里有名字才是命令;hidden
|
|
2171
|
+
// 命令照旧认。判定之外的 / 开头行才走 submit(与聊天页 Enter 行为一致)。
|
|
2172
|
+
if (parsed !== undefined && (isLocalCommandName(parsed.name)
|
|
2173
|
+
|| isHiddenCommandName(parsed.name)
|
|
2174
|
+
|| channel.commandList.some(entry => entry.name === parsed.name))) {
|
|
2175
|
+
void runCommand(parsed.name, parsed.rawInput);
|
|
2176
|
+
return;
|
|
2177
|
+
}
|
|
2178
|
+
// 直接发送:与 composer 回车同一条提交路径。发出去之后输入框是空的
|
|
2179
|
+
// (内容已作为首轮发出,绝不"既发了又留在框里"),也没有交接提示——
|
|
2180
|
+
// 没有草稿要交,一句"已放进输入框"的 toast 反而是假的。
|
|
2181
|
+
channel.submit(text);
|
|
2182
|
+
}, [channel, launchpadOpen]);
|
|
2183
|
+
/**
|
|
2184
|
+
* The screen's command dispatcher. Every entry point reaches this one
|
|
2185
|
+
* closure — PromptInput's `onRunCommand`, the completion menu, this screen's
|
|
2186
|
+
* own `/` cases, and the launchpad handoff above. There is deliberately no
|
|
2187
|
+
* second dispatcher for the landing page.
|
|
2188
|
+
*/
|
|
1637
2189
|
const runCommand = (name, rawInput = '', images = []) => {
|
|
1638
2190
|
switch (name) {
|
|
1639
2191
|
case 'activity': {
|
|
@@ -1746,11 +2298,12 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
1746
2298
|
return true;
|
|
1747
2299
|
}
|
|
1748
2300
|
setHelpOpen(false);
|
|
1749
|
-
void channel.listEfforts().then(({ efforts, defaultEffort }) => {
|
|
2301
|
+
void channel.listEfforts().then(({ efforts, defaultEffort, levelsFallback }) => {
|
|
1750
2302
|
// 0/1-tier routes were already notified by listEfforts.
|
|
1751
2303
|
if (efforts.length <= 1)
|
|
1752
2304
|
return;
|
|
1753
2305
|
setEffortOptions(efforts);
|
|
2306
|
+
setEffortLevelsFallback(levelsFallback === true);
|
|
1754
2307
|
const current = channel.reasoningEffort ?? defaultEffort;
|
|
1755
2308
|
const index = efforts.findIndex(effort => effort.id === current);
|
|
1756
2309
|
// open-if: a picker the user opened during the round trip wins
|
|
@@ -1916,9 +2469,24 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
1916
2469
|
setSelectedId(null);
|
|
1917
2470
|
setSelectionActive(false);
|
|
1918
2471
|
return true;
|
|
1919
|
-
case 'compact':
|
|
1920
|
-
|
|
2472
|
+
case 'compact': {
|
|
2473
|
+
// The TUI's own transaction is the primary path: it owns the
|
|
2474
|
+
// `tui/compact` decision event, the progress row with live token
|
|
2475
|
+
// count, Esc cancellation, and the settle before a session switch
|
|
2476
|
+
// (issue #1092) — the official `dsh-command-compact` command has none
|
|
2477
|
+
// of that. A composition that mounts no compaction service falls back
|
|
2478
|
+
// to the registry command; one with neither says WHY up front instead
|
|
2479
|
+
// of looking usable and failing on use (channel/capabilities.ts).
|
|
2480
|
+
const compact = channel.capabilities().compact;
|
|
2481
|
+
if (compact.route === 'local') {
|
|
2482
|
+
channel.compact();
|
|
2483
|
+
return true;
|
|
2484
|
+
}
|
|
2485
|
+
if (compact.route === 'registry')
|
|
2486
|
+
return runExternalCommand('compact', rawInput, images);
|
|
2487
|
+
channel.notify(t('capability-unavailable', { name: 'compact', reason: t(compact.reasonKey) }), { color: 'warning', timeoutMs: 8000 });
|
|
1921
2488
|
return true;
|
|
2489
|
+
}
|
|
1922
2490
|
case 'trace':
|
|
1923
2491
|
// `/trace` is kept as the discoverable spelling of Ctrl+T: the
|
|
1924
2492
|
// command menu is where a user finds out the trajectory exists.
|
|
@@ -1946,7 +2514,9 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
1946
2514
|
setHelpOpen(false);
|
|
1947
2515
|
const spec = parts[0];
|
|
1948
2516
|
const slash = spec.indexOf('/');
|
|
1949
|
-
|
|
2517
|
+
// Backend model routes accept an unqualified model id.
|
|
2518
|
+
const singleProvider = channel.backendCapabilities?.modelRoutes === 'backend';
|
|
2519
|
+
const provider = slash >= 0 ? spec.slice(0, slash) : singleProvider ? channel.provider : undefined;
|
|
1950
2520
|
const id = slash >= 0 ? spec.slice(slash + 1) : spec;
|
|
1951
2521
|
if (provider === undefined || id.length === 0 || provider.length === 0) {
|
|
1952
2522
|
channel.notify(t('model-usage'), { color: 'warning' });
|
|
@@ -1973,7 +2543,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
1973
2543
|
let recentsNow = modelRecents;
|
|
1974
2544
|
if (channel.provider !== '' && channel.model !== ''
|
|
1975
2545
|
&& !recentsNow.some(ref => ref.provider === channel.provider && ref.id === channel.model)) {
|
|
1976
|
-
recentsNow = recordModelUse({ provider: channel.provider, id: channel.model });
|
|
2546
|
+
recentsNow = recordModelUse({ provider: channel.provider, id: channel.model }, undefined, recentsBackend);
|
|
1977
2547
|
setModelRecents(recentsNow);
|
|
1978
2548
|
}
|
|
1979
2549
|
// Two-level landing: recents (when catalogued) focus their pinned
|
|
@@ -2078,14 +2648,39 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2078
2648
|
});
|
|
2079
2649
|
return true;
|
|
2080
2650
|
case 'tokens': {
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2651
|
+
// Four separately-labelled facts, never two measures side by side:
|
|
2652
|
+
// what THIS request uploaded (the provider's mutually-exclusive prompt
|
|
2653
|
+
// buckets, with when it was sampled), what the last turn used (its
|
|
2654
|
+
// own ledger, never added into the session counters), what the
|
|
2655
|
+
// session has accumulated, and how full the window is (the channel's
|
|
2656
|
+
// single occupancy reading — the same number the footer and the
|
|
2657
|
+
// context-low warning show).
|
|
2658
|
+
const usage = channel.lastUsage;
|
|
2659
|
+
const lines = [];
|
|
2660
|
+
if (usage !== undefined) {
|
|
2661
|
+
const upload = usage.input + usage.cacheRead + usage.cacheWrite;
|
|
2662
|
+
const rate = upload > 0 ? ((usage.cacheRead / upload) * 100).toFixed(1) : '0.0';
|
|
2663
|
+
lines.push(`${t('tokens-request-upload', {
|
|
2664
|
+
upload: formatTokens(upload),
|
|
2665
|
+
input: formatTokens(usage.input),
|
|
2666
|
+
read: formatTokens(usage.cacheRead),
|
|
2667
|
+
write: formatTokens(usage.cacheWrite),
|
|
2668
|
+
rate,
|
|
2669
|
+
})} · ${t('usage-sampled-at', { time: formatClock(usage.at) })}`);
|
|
2088
2670
|
}
|
|
2671
|
+
const turn = channel.turnUsage;
|
|
2672
|
+
if (turn !== undefined)
|
|
2673
|
+
lines.push(`${t('usage-turn-summary')} ${turnUsageParts(turn).join(' · ')}`);
|
|
2674
|
+
lines.push(t('tokens-session-breakdown', {
|
|
2675
|
+
input: formatTokens(channel.tokens.input),
|
|
2676
|
+
output: formatTokens(channel.tokens.output),
|
|
2677
|
+
read: formatTokens(channel.tokens.cacheRead),
|
|
2678
|
+
write: formatTokens(channel.tokens.cacheWrite),
|
|
2679
|
+
}));
|
|
2680
|
+
const occupancyLine = contextOccupancyLine(channel);
|
|
2681
|
+
if (occupancyLine !== undefined)
|
|
2682
|
+
lines.push(occupancyLine);
|
|
2683
|
+
channel.notify(lines.join('\n'));
|
|
2089
2684
|
return true;
|
|
2090
2685
|
}
|
|
2091
2686
|
case 'resume':
|
|
@@ -2098,7 +2693,26 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2098
2693
|
* commands is about muscle memory, not about three surfaces — every one
|
|
2099
2694
|
* of them lands here, on the same runtime.
|
|
2100
2695
|
*/
|
|
2101
|
-
case 'home':
|
|
2696
|
+
case 'home': {
|
|
2697
|
+
setHelpOpen(false);
|
|
2698
|
+
// Split-aware, like /trace and /jobs: while the sidebar is rendering
|
|
2699
|
+
// and the workspace panel is enabled, the workspace view opens THERE.
|
|
2700
|
+
// The panel's own ⤢ goes back to the full-screen home. The panel reads
|
|
2701
|
+
// the DSH workspace ledger, though: a backend without that capability
|
|
2702
|
+
// (capability snapshots absent on test stubs = DSH) would have its
|
|
2703
|
+
// /resume swallowed by an unsupported panel and no history anywhere —
|
|
2704
|
+
// those keep the full-screen session supervisor.
|
|
2705
|
+
const capabilities = channel.backendCapabilities;
|
|
2706
|
+
const controller = sidePanelRef.current;
|
|
2707
|
+
if ((capabilities === undefined || capabilities.commands.includes('workspace'))
|
|
2708
|
+
&& controller !== null && controller.split && controller.enabledPanelIds.includes('workspace')) {
|
|
2709
|
+
controller.openPanel('workspace', { focus: true });
|
|
2710
|
+
return true;
|
|
2711
|
+
}
|
|
2712
|
+
agentViewOpenSessionRef.current = channel.agentId;
|
|
2713
|
+
setSupervisorOpen(true);
|
|
2714
|
+
return true;
|
|
2715
|
+
}
|
|
2102
2716
|
case 'agentview': {
|
|
2103
2717
|
setHelpOpen(false);
|
|
2104
2718
|
// The screen opens immediately and loads its own list. Waiting for the
|
|
@@ -2110,9 +2724,8 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2110
2724
|
}
|
|
2111
2725
|
case 'bg':
|
|
2112
2726
|
case 'background': {
|
|
2113
|
-
//
|
|
2114
|
-
//
|
|
2115
|
-
// session, and the supervisor opens on top.
|
|
2727
|
+
// DSH parks the attached session before opening the supervisor;
|
|
2728
|
+
// other backends open it over their still-attached session.
|
|
2116
2729
|
setHelpOpen(false);
|
|
2117
2730
|
backgroundToAgentView();
|
|
2118
2731
|
return true;
|
|
@@ -2199,23 +2812,29 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2199
2812
|
return true;
|
|
2200
2813
|
case 'status': {
|
|
2201
2814
|
const usage = channel.lastUsage;
|
|
2202
|
-
const pct = channel.contextWindow === undefined
|
|
2203
|
-
? undefined
|
|
2204
|
-
: Math.max(0, Math.min(100, Math.round((channel.tokens.input / channel.contextWindow) * 100)));
|
|
2205
2815
|
const lines = [
|
|
2206
2816
|
`${t('status-model', { model: channel.model })}${channel.reasoningEffort ? ` · ${capitalize(channel.reasoningEffort)} effort` : ''}`,
|
|
2207
2817
|
`${t('status-state', { state: channel.working ? t('status-working') : t('status-idle') })}`,
|
|
2208
2818
|
`${t('status-session', { id: channel.agentId })}`,
|
|
2209
2819
|
`${t('status-dir', { cwd: channel.displayCwd })}${channel.gitBranch ? ` · ${channel.gitBranch}` : ''}`,
|
|
2210
|
-
|
|
2820
|
+
t('tokens-session-total', {
|
|
2821
|
+
input: formatTokens(channel.tokens.input),
|
|
2822
|
+
output: formatTokens(channel.tokens.output),
|
|
2823
|
+
}),
|
|
2211
2824
|
];
|
|
2212
2825
|
if (usage !== undefined) {
|
|
2213
2826
|
const total = usage.input + usage.cacheRead + usage.cacheWrite;
|
|
2214
2827
|
const rate = total > 0 ? ((usage.cacheRead / total) * 100).toFixed(1) : '0.0';
|
|
2215
|
-
lines.push(t('cost-cache-rate', { rate, read: formatTokens(usage.cacheRead), write: formatTokens(usage.cacheWrite) }));
|
|
2828
|
+
lines.push(`${t('cost-cache-rate', { rate, read: formatTokens(usage.cacheRead), write: formatTokens(usage.cacheWrite) })} · ${t('usage-sampled-at', { time: formatClock(usage.at) })}`);
|
|
2216
2829
|
}
|
|
2217
|
-
|
|
2218
|
-
|
|
2830
|
+
// The last turn gets its own labelled line so it never reads as part
|
|
2831
|
+
// of the session totals.
|
|
2832
|
+
const turn = channel.turnUsage;
|
|
2833
|
+
if (turn !== undefined)
|
|
2834
|
+
lines.push(`${t('usage-turn-summary')} ${turnUsageParts(turn).join(' · ')}`);
|
|
2835
|
+
const occupancyLine = contextOccupancyLine(channel);
|
|
2836
|
+
if (occupancyLine !== undefined)
|
|
2837
|
+
lines.push(occupancyLine);
|
|
2219
2838
|
if (channel.sessionTitle)
|
|
2220
2839
|
lines.push(t('status-title', { title: channel.sessionTitle }));
|
|
2221
2840
|
setHelpOpen(false);
|
|
@@ -2225,13 +2844,26 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2225
2844
|
case 'cost': {
|
|
2226
2845
|
const usage = channel.lastUsage;
|
|
2227
2846
|
const lines = [
|
|
2228
|
-
|
|
2847
|
+
t('tokens-session-total', {
|
|
2848
|
+
input: formatTokens(channel.tokens.input),
|
|
2849
|
+
output: formatTokens(channel.tokens.output),
|
|
2850
|
+
}),
|
|
2229
2851
|
];
|
|
2230
2852
|
if (usage !== undefined) {
|
|
2231
2853
|
const total = usage.input + usage.cacheRead + usage.cacheWrite;
|
|
2232
2854
|
const rate = total > 0 ? ((usage.cacheRead / total) * 100).toFixed(1) : '0.0';
|
|
2233
2855
|
lines.push(t('cost-cache-hit-rate', { rate, read: formatTokens(usage.cacheRead), write: formatTokens(usage.cacheWrite) }));
|
|
2234
2856
|
}
|
|
2857
|
+
// A backend that reports its own session cost (Claude) states the
|
|
2858
|
+
// bill itself; the DeepSeek estimate below would only be noise.
|
|
2859
|
+
// oxlint-disable-next-line typescript/no-unnecessary-condition -- partial embedder channels omit the report
|
|
2860
|
+
const report = channel.costReport;
|
|
2861
|
+
if (report !== undefined) {
|
|
2862
|
+
lines.push(`${formatCostReport(report)} · ${t(report.source === 'backend' ? 'cost-source-backend' : 'status-cost-note')}`);
|
|
2863
|
+
setHelpOpen(false);
|
|
2864
|
+
channel.pushLocal('/cost', lines);
|
|
2865
|
+
return true;
|
|
2866
|
+
}
|
|
2235
2867
|
// 金额与拆解:主会话按模型分桶 + 子代理按各自 (provider, model) 分桶;
|
|
2236
2868
|
// 全部未计价时只报 token 并标注未计价,不显示 ¥0.00 金额行(DESIGN D4/D6)。
|
|
2237
2869
|
const estimate = estimateSessionCostSnapshotCny({
|
|
@@ -2274,6 +2906,54 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2274
2906
|
setSettingsOpen(true);
|
|
2275
2907
|
return true;
|
|
2276
2908
|
}
|
|
2909
|
+
case 'continue': {
|
|
2910
|
+
// 落地页第四版的 Continue(最高频动作):继续**最近一条可继续会话**。
|
|
2911
|
+
// 数据是真的——`agentViewRows`(含持久化名册,listing 落地后含全部历史)
|
|
2912
|
+
// 里挑 updatedAt 最新的非当前行;没有可继续的就去会话名册挑,失败也不
|
|
2913
|
+
// 静默(notify + 打开 supervisor 让用户自己挑),绝不点了个没反应。
|
|
2914
|
+
setHelpOpen(false);
|
|
2915
|
+
const candidates = agentViewRows.filter(row => !row.current && row.id !== channel.agentId && row.title.trim() !== '');
|
|
2916
|
+
const latest = candidates.reduce((acc, row) => (acc === undefined || row.updatedAt > acc.updatedAt ? row : acc), undefined);
|
|
2917
|
+
if (latest === undefined) {
|
|
2918
|
+
channel.notify(t('launchpad-continue-none'), { color: 'error', timeoutMs: 6000 });
|
|
2919
|
+
agentViewOpenSessionRef.current = channel.agentId;
|
|
2920
|
+
// 第七版:无可继续会话时浏览器盖在落地页之上(不收落地页)——Esc
|
|
2921
|
+
// 回启动页,与合并入口「会话与工作区」同一条姿态。
|
|
2922
|
+
setSupervisorOpen(true);
|
|
2923
|
+
return true;
|
|
2924
|
+
}
|
|
2925
|
+
setLaunchpadOpen(false);
|
|
2926
|
+
void channel.resumeTo(latest.id)
|
|
2927
|
+
.then((result) => {
|
|
2928
|
+
if (!result.ok) {
|
|
2929
|
+
channel.notify(t('launchpad-continue-failed'), { color: 'error', timeoutMs: 8000 });
|
|
2930
|
+
agentViewOpenSessionRef.current = channel.agentId;
|
|
2931
|
+
setSupervisorOpen(true);
|
|
2932
|
+
return;
|
|
2933
|
+
}
|
|
2934
|
+
channel.notify(t('resume-resumed'));
|
|
2935
|
+
suppressLogoIntroRef.current = true;
|
|
2936
|
+
setAgentViewReturnId(undefined);
|
|
2937
|
+
repaintTranscript();
|
|
2938
|
+
})
|
|
2939
|
+
.catch(() => {
|
|
2940
|
+
channel.notify(t('launchpad-continue-failed'), { color: 'error', timeoutMs: 8000 });
|
|
2941
|
+
});
|
|
2942
|
+
return true;
|
|
2943
|
+
}
|
|
2944
|
+
case 'setup': {
|
|
2945
|
+
// `/setup` re-runs the first-run guide. Unlike the boot path this is
|
|
2946
|
+
// an EXPLICIT request, so it opens unconditionally — a user who typed
|
|
2947
|
+
// it has already decided the wizard is what they want. It reuses the
|
|
2948
|
+
// same screen and the same `onClose`, so completing it here also
|
|
2949
|
+
// (re)writes the one-shot marker.
|
|
2950
|
+
// 第七版:向导的 early-return 在落地页**之前**,天然盖在落地页之上;
|
|
2951
|
+
// 不再收掉落地页——Esc/跳过/完成都回到启动页(旧姿态收掉落地页后,
|
|
2952
|
+
// 向导关掉就落到对话页,正是用户报的 bug 形态之一)。
|
|
2953
|
+
setHelpOpen(false);
|
|
2954
|
+
setOnboardingOpen(true);
|
|
2955
|
+
return true;
|
|
2956
|
+
}
|
|
2277
2957
|
case 'star': {
|
|
2278
2958
|
// 一键 star:**只有用户主动敲 /star 才会跑**(绝不自动)。动作用
|
|
2279
2959
|
// runStarAction(与开屏弹窗共用),异步执行、结果用 notify 报。
|
|
@@ -2367,6 +3047,11 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2367
3047
|
return true;
|
|
2368
3048
|
}
|
|
2369
3049
|
case 'init': {
|
|
3050
|
+
const backend = channel.backendInit?.();
|
|
3051
|
+
if (backend !== undefined) {
|
|
3052
|
+
void backend.run();
|
|
3053
|
+
return true;
|
|
3054
|
+
}
|
|
2370
3055
|
const result = channel.initWorkspace();
|
|
2371
3056
|
if (result === null)
|
|
2372
3057
|
channel.notify(t('agentsmd-create-failed'), { color: 'error' });
|
|
@@ -2376,10 +3061,52 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2376
3061
|
channel.notify(t('agentsmd-created', { result }));
|
|
2377
3062
|
return true;
|
|
2378
3063
|
}
|
|
2379
|
-
case 'jobs':
|
|
3064
|
+
case 'jobs': {
|
|
2380
3065
|
setHelpOpen(false);
|
|
2381
|
-
|
|
3066
|
+
// Split mode routes to the side panel; narrow terminals keep the
|
|
3067
|
+
// full-screen overlay.
|
|
3068
|
+
if (sidePanel.split && sidePanel.enabledPanelIds.includes('jobs')) {
|
|
3069
|
+
sidePanel.openPanel('jobs', { focus: true });
|
|
3070
|
+
}
|
|
3071
|
+
else {
|
|
3072
|
+
setJobsPanelFocusId(null);
|
|
3073
|
+
setJobsPanelOpen(true);
|
|
3074
|
+
}
|
|
2382
3075
|
return true;
|
|
3076
|
+
}
|
|
3077
|
+
case 'panel': {
|
|
3078
|
+
setHelpOpen(false);
|
|
3079
|
+
// 无参 → 面板选择器(overlay 互斥结构内);有参 → 侧栏命令分发。
|
|
3080
|
+
if (rawInput.trim() === '' && sidePanel.splitAvailable && panelPickerRows.length > 0) {
|
|
3081
|
+
const current = panelPickerRows.findIndex(row => row.id === sidePanel.activePanelId);
|
|
3082
|
+
dispatchOverlay({ type: 'open', overlay: { kind: 'panel', index: Math.max(0, current) } });
|
|
3083
|
+
return true;
|
|
3084
|
+
}
|
|
3085
|
+
if (sidePanel.command(rawInput))
|
|
3086
|
+
return true;
|
|
3087
|
+
// 分栏不可用(窄屏 / inline / 编辑器展开 / splitEnabled=false)
|
|
3088
|
+
// 或参数未知时的整屏回退与兜底:已知面板走整屏形态,其余消费
|
|
3089
|
+
// 掉并提示——绝不原样返回 false,否则 PromptInput 会把
|
|
3090
|
+
// "/panel …" 当普通消息发给模型。
|
|
3091
|
+
const arg = rawInput.trim().toLowerCase();
|
|
3092
|
+
const target = arg === '' || arg === 'focus' || arg === 'toggle' || arg === 'zoom'
|
|
3093
|
+
? sidePanel.activePanelId
|
|
3094
|
+
: arg;
|
|
3095
|
+
if (target === 'jobs') {
|
|
3096
|
+
setJobsPanelFocusId(null);
|
|
3097
|
+
setJobsPanelOpen(true);
|
|
3098
|
+
return true;
|
|
3099
|
+
}
|
|
3100
|
+
if (target === 'agents') {
|
|
3101
|
+
setSubagentDashboardOpen(true);
|
|
3102
|
+
return true;
|
|
3103
|
+
}
|
|
3104
|
+
if (arg === 'toggle' || arg === 'focus' || arg === 'zoom' || arg === '' || target !== undefined) {
|
|
3105
|
+
channel.notify(t('panel-unavailable-hint'));
|
|
3106
|
+
return true;
|
|
3107
|
+
}
|
|
3108
|
+
return false;
|
|
3109
|
+
}
|
|
2383
3110
|
case 'agents':
|
|
2384
3111
|
setHelpOpen(false);
|
|
2385
3112
|
void channel.listSubagents().then((lines) => {
|
|
@@ -2388,6 +3115,8 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2388
3115
|
return true;
|
|
2389
3116
|
case 'login': {
|
|
2390
3117
|
setHelpOpen(false);
|
|
3118
|
+
if (runBackendLogin())
|
|
3119
|
+
return true;
|
|
2391
3120
|
void channel.describeCredential('DEEPSEEK_API_KEY')
|
|
2392
3121
|
.catch(() => undefined)
|
|
2393
3122
|
.then(async (status) => {
|
|
@@ -2431,9 +3160,14 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2431
3160
|
});
|
|
2432
3161
|
return true;
|
|
2433
3162
|
}
|
|
2434
|
-
case 'logout':
|
|
2435
|
-
channel.
|
|
3163
|
+
case 'logout': {
|
|
3164
|
+
const auth = channel.backendAuth();
|
|
3165
|
+
if (auth?.logout === undefined)
|
|
3166
|
+
channel.notify(t('login-logout-hint'));
|
|
3167
|
+
else
|
|
3168
|
+
void auth.logout();
|
|
2436
3169
|
return true;
|
|
3170
|
+
}
|
|
2437
3171
|
case 'permission': {
|
|
2438
3172
|
// The command itself is registered by the permission-presets row
|
|
2439
3173
|
// (dsh-base): bare `/permission` opens the preset picker and Enter
|
|
@@ -2498,15 +3232,32 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2498
3232
|
setHelpOpen(false);
|
|
2499
3233
|
return runPermissionCommand(rawInput, images);
|
|
2500
3234
|
}
|
|
2501
|
-
|
|
3235
|
+
const native = backendPermissionCommand(channel.backendModes?.()?.snapshot(), rawInput, modeDisplayName(channel.mode));
|
|
3236
|
+
if (native === undefined)
|
|
3237
|
+
return false;
|
|
3238
|
+
if (native.kind === 'unknown') {
|
|
3239
|
+
channel.notify(t('permission-mode-unknown', { id: native.id }), { color: 'error' });
|
|
3240
|
+
return true;
|
|
3241
|
+
}
|
|
3242
|
+
setHelpOpen(false);
|
|
3243
|
+
if (native.kind === 'status')
|
|
3244
|
+
channel.pushLocal('/permission', native.lines);
|
|
3245
|
+
else if (native.kind === 'picker')
|
|
3246
|
+
dispatchOverlay({ type: 'open', overlay: native.overlay });
|
|
3247
|
+
else
|
|
3248
|
+
void runBackendModeCommand(native.mode.id, native.mode.name);
|
|
3249
|
+
return true;
|
|
2502
3250
|
}
|
|
2503
3251
|
case 'plan': {
|
|
2504
3252
|
// Registered by dsh-plan-mode: bare `/plan` opens an on/off picker
|
|
2505
3253
|
// marked with the current state instead of toggling blindly; Enter
|
|
2506
3254
|
// dispatches `/plan` or `/plan off`. Arguments pass through verbatim
|
|
2507
|
-
// (`/plan off`)
|
|
2508
|
-
//
|
|
2509
|
-
|
|
3255
|
+
// (`/plan off`). Availability comes from the shared capability facts
|
|
3256
|
+
// (the same read Shift+Tab uses), not from a second command-list
|
|
3257
|
+
// scan; with no registry command the line falls through to the model,
|
|
3258
|
+
// exactly as before.
|
|
3259
|
+
const plan = channel.capabilities().plan;
|
|
3260
|
+
const mounted = plan.route !== 'none';
|
|
2510
3261
|
const parts = rawInput.trim().split(/\s+/).filter(Boolean);
|
|
2511
3262
|
if (mounted && parts.length === 0) {
|
|
2512
3263
|
setHelpOpen(false);
|
|
@@ -2536,17 +3287,29 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2536
3287
|
t('hooks-mount-hint'),
|
|
2537
3288
|
]);
|
|
2538
3289
|
return true;
|
|
2539
|
-
case 'mcp':
|
|
3290
|
+
case 'mcp': {
|
|
2540
3291
|
setHelpOpen(false);
|
|
3292
|
+
const control = channel.backendMcp?.();
|
|
3293
|
+
const request = parseMcpCommand(rawInput);
|
|
3294
|
+
if (control !== undefined && request.kind !== 'status') {
|
|
3295
|
+
if (request.kind === 'usage')
|
|
3296
|
+
channel.notify(t('mcp-control-usage'), { color: 'warning' });
|
|
3297
|
+
else if (request.kind === 'reconnect')
|
|
3298
|
+
void control.reconnect(request.name);
|
|
3299
|
+
else
|
|
3300
|
+
void control.toggle(request.name, request.enabled);
|
|
3301
|
+
return true;
|
|
3302
|
+
}
|
|
2541
3303
|
channel.pushLocal('/mcp', channel.mcpStatus());
|
|
2542
3304
|
return true;
|
|
3305
|
+
}
|
|
2543
3306
|
case 'update':
|
|
2544
3307
|
setHelpOpen(false);
|
|
2545
3308
|
if (onUpdate === undefined) {
|
|
2546
3309
|
channel.notify(t('update-unavailable'), { color: 'warning' });
|
|
2547
3310
|
}
|
|
2548
3311
|
else if (channel.working) {
|
|
2549
|
-
channel.notify(t(
|
|
3312
|
+
channel.notify(t(WORKING_GATE_NOTICES.update), { color: 'warning' });
|
|
2550
3313
|
}
|
|
2551
3314
|
else {
|
|
2552
3315
|
channel.notify(t('update-starting'));
|
|
@@ -2630,6 +3393,64 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2630
3393
|
channel.pushLocal('/reload', lines);
|
|
2631
3394
|
return true;
|
|
2632
3395
|
}
|
|
3396
|
+
case 'goal': {
|
|
3397
|
+
// DSH: the `dsh-command-goal` registry row owns /goal, exactly as the
|
|
3398
|
+
// default branch below would dispatch it.
|
|
3399
|
+
if (channel.commandList.some(command => command.external && command.name === 'goal')) {
|
|
3400
|
+
setHelpOpen(false);
|
|
3401
|
+
return runExternalCommand(name, rawInput, images);
|
|
3402
|
+
}
|
|
3403
|
+
// Another backend: the channel core's host over its typed `goals`
|
|
3404
|
+
// capability. None (DSH without the row, or a backend's own `goal`
|
|
3405
|
+
// command) keeps the previous route: the line goes on as text. A
|
|
3406
|
+
// backend with neither never gets here — PromptInput refuses /goal
|
|
3407
|
+
// as unavailable (isUnavailableLocalCommand).
|
|
3408
|
+
const goals = channel.backendGoals?.();
|
|
3409
|
+
if (goals === undefined)
|
|
3410
|
+
return false;
|
|
3411
|
+
setHelpOpen(false);
|
|
3412
|
+
// The capability calls settle like registry commands: the draft is
|
|
3413
|
+
// consumed only once the backend took the change (a failure is
|
|
3414
|
+
// reported by the host and leaves the line editable). An invalid
|
|
3415
|
+
// line is never sent anywhere: it stays in the composer.
|
|
3416
|
+
const command = parseGoalCommand(rawInput);
|
|
3417
|
+
switch (command.kind) {
|
|
3418
|
+
case 'status':
|
|
3419
|
+
channel.pushLocal('/goal', goalStatusLines(channel.goal));
|
|
3420
|
+
return true;
|
|
3421
|
+
case 'invalid':
|
|
3422
|
+
channel.notify(command.reason, { color: 'error' });
|
|
3423
|
+
return Promise.resolve(false);
|
|
3424
|
+
case 'set':
|
|
3425
|
+
return goals.set(command.objective, command.tokenBudget === undefined ? undefined : { tokenBudget: command.tokenBudget });
|
|
3426
|
+
case 'pause':
|
|
3427
|
+
return goals.pause();
|
|
3428
|
+
case 'resume':
|
|
3429
|
+
return goals.resume();
|
|
3430
|
+
case 'clear':
|
|
3431
|
+
return goals.clear();
|
|
3432
|
+
}
|
|
3433
|
+
}
|
|
3434
|
+
case 'channel': {
|
|
3435
|
+
// 渠道选择器。/channel 只在声明了 channels 能力的内核下进命令表,
|
|
3436
|
+
// 能走到这里就说明可用。与 /kernel 一样,再执行一次就收起。
|
|
3437
|
+
setHelpOpen(false);
|
|
3438
|
+
if (overlay.kind === 'channel')
|
|
3439
|
+
dispatchOverlay({ type: 'close' });
|
|
3440
|
+
else
|
|
3441
|
+
openChannelPicker();
|
|
3442
|
+
return true;
|
|
3443
|
+
}
|
|
3444
|
+
case 'kernel':
|
|
3445
|
+
// 内核选择器,每个内核下都可用(在对话页里切回 DSH 只有这一条路)。
|
|
3446
|
+
// 确认后由组合根的 onSwitchBackend 记住选择并以新内核重启。与 /help、
|
|
3447
|
+
// 参数行一致:选择器已开着就收起,没开才打开。
|
|
3448
|
+
setHelpOpen(false);
|
|
3449
|
+
if (overlay.kind === 'kernel')
|
|
3450
|
+
dispatchOverlay({ type: 'close' });
|
|
3451
|
+
else
|
|
3452
|
+
openKernelPicker();
|
|
3453
|
+
return true;
|
|
2633
3454
|
case 'restart':
|
|
2634
3455
|
// pi-style reload tail: /reload cannot re-read boot-time-only state
|
|
2635
3456
|
// (cordis.yml root config, frozen fullscreen layout, newly built
|
|
@@ -2640,7 +3461,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2640
3461
|
channel.notify(t('restart-unavailable'), { color: 'warning' });
|
|
2641
3462
|
}
|
|
2642
3463
|
else if (channel.working) {
|
|
2643
|
-
channel.notify(t(
|
|
3464
|
+
channel.notify(t(WORKING_GATE_NOTICES.restart), { color: 'warning' });
|
|
2644
3465
|
}
|
|
2645
3466
|
else {
|
|
2646
3467
|
channel.notify(t('restart-starting'));
|
|
@@ -2695,30 +3516,28 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2695
3516
|
return true;
|
|
2696
3517
|
}
|
|
2697
3518
|
case 'btw': {
|
|
2698
|
-
// `/btw
|
|
2699
|
-
//
|
|
3519
|
+
// `/btw`:单轮无工具侧问,线程只在内存里(btwThreads,按会话
|
|
3520
|
+
// 隔离),不打断主回合、不写会话历史。空参数只提示用法。启用了
|
|
3521
|
+
// btw 面板就进面板线程(有模态界面时不抢开,只标未读);没启用
|
|
3522
|
+
// 就用浮层。同一个问答只出现在一处。
|
|
2700
3523
|
setHelpOpen(false);
|
|
2701
3524
|
const question = rawInput.trim();
|
|
2702
3525
|
if (!question) {
|
|
2703
3526
|
channel.notify(t('btw-usage'), { timeoutMs: 3000 });
|
|
2704
3527
|
return true;
|
|
2705
3528
|
}
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
}
|
|
2718
|
-
if (controller.signal.aborted)
|
|
2719
|
-
return;
|
|
2720
|
-
setBtw(prev => prev ? { ...prev, error: error instanceof Error ? error.message : String(error), done: true } : prev);
|
|
2721
|
-
});
|
|
3529
|
+
const btwResult = btwThreads.submit(String(channel.agentId), question, (q, options) => channel.sideQuestion(q, options), { recentTurnsLimit: getBtwContextTurns(), contextBudget: getBtwContextBudget() });
|
|
3530
|
+
if (!btwResult.ok) {
|
|
3531
|
+
channel.notify(t('btw-thread-busy'), { color: 'warning', timeoutMs: 3000 });
|
|
3532
|
+
return true;
|
|
3533
|
+
}
|
|
3534
|
+
if (sidePanel.enabledPanelIds.includes('btw')) {
|
|
3535
|
+
if (btwSurfaceFree())
|
|
3536
|
+
sidePanel.openPanel('btw');
|
|
3537
|
+
}
|
|
3538
|
+
else {
|
|
3539
|
+
setBtwOverlayOpen(true);
|
|
3540
|
+
}
|
|
2722
3541
|
return true;
|
|
2723
3542
|
}
|
|
2724
3543
|
case 'deepseek': {
|
|
@@ -2785,6 +3604,10 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2785
3604
|
: NO_ROWS;
|
|
2786
3605
|
/** Open the rewind picker (from PromptInput's double-Esc on an empty input). */
|
|
2787
3606
|
const openRewind = () => {
|
|
3607
|
+
if (channel.backendCapabilities?.rewind === false) {
|
|
3608
|
+
channel.notify(t('capability-unavailable-backend', { name: 'rewind' }), { color: 'warning', timeoutMs: 4000 });
|
|
3609
|
+
return;
|
|
3610
|
+
}
|
|
2788
3611
|
// The overlay is not 'rewind' yet this render, so rewindRows is empty —
|
|
2789
3612
|
// scan directly instead of reading the gated list.
|
|
2790
3613
|
const candidates = channel.rows
|
|
@@ -2854,7 +3677,63 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
2854
3677
|
*/
|
|
2855
3678
|
const { columns: terminalColumns } = useTerminalSize();
|
|
2856
3679
|
const pageInsetX = usePageInset().x;
|
|
2857
|
-
|
|
3680
|
+
// 侧栏控制器:几何(chatColumns/panelColumns)、焦点与键盘分发都在
|
|
3681
|
+
// 这个 hook 里(设计文档 §16.5——Chat 只多一次调用、一处键盘让位、
|
|
3682
|
+
// 一条 runCommand case)。编辑器展开时几何强制 collapsed。
|
|
3683
|
+
const sidePanel = useSidePanel({
|
|
3684
|
+
columns: terminalColumns,
|
|
3685
|
+
fullscreen,
|
|
3686
|
+
editorOpen: promptEditorOpen,
|
|
3687
|
+
});
|
|
3688
|
+
/**
|
|
3689
|
+
* 「全屏」出口(PanelBar 的 ⤢):把侧栏里那个面板的内容切到它原本的整屏
|
|
3690
|
+
* 形态。只映射**真的有整屏对应物**的面板 id(能力位 capabilities.fullscreen
|
|
3691
|
+
* 决定按钮画不画,这里决定点了去哪);没映射到的 id 静默无操作——按钮与
|
|
3692
|
+
* 落地页、键盘入口共用同一个状态位,所以从整屏返回时侧栏还在原处。
|
|
3693
|
+
*/
|
|
3694
|
+
const openPanelFullscreen = React.useCallback((panelId) => {
|
|
3695
|
+
if (panelId === 'jobs') {
|
|
3696
|
+
sidePanelRef.current?.focusChat();
|
|
3697
|
+
setJobsPanelOpen(true);
|
|
3698
|
+
return;
|
|
3699
|
+
}
|
|
3700
|
+
if (panelId === 'agents') {
|
|
3701
|
+
sidePanelRef.current?.focusChat();
|
|
3702
|
+
setSubagentDashboardOpen(true);
|
|
3703
|
+
return;
|
|
3704
|
+
}
|
|
3705
|
+
if (panelId === 'trajectory') {
|
|
3706
|
+
sidePanelRef.current?.focusChat();
|
|
3707
|
+
// 强制整屏:默认的 openScene 在分屏下会路由回面板(见它的注释)。
|
|
3708
|
+
openScene({ fullscreen: true });
|
|
3709
|
+
return;
|
|
3710
|
+
}
|
|
3711
|
+
if (panelId === 'workspace') {
|
|
3712
|
+
sidePanelRef.current?.focusChat();
|
|
3713
|
+
setSupervisorOpen(true);
|
|
3714
|
+
return;
|
|
3715
|
+
}
|
|
3716
|
+
if (panelId === 'btw') {
|
|
3717
|
+
// ⤢ 进整屏线程场景:Esc 返回侧栏,不清 thread/draft(面板
|
|
3718
|
+
// mountPolicy=enabled 保挂载,路由/焦点/滚动原样恢复)。
|
|
3719
|
+
sidePanelRef.current?.focusChat();
|
|
3720
|
+
setBtwSceneOpen(true);
|
|
3721
|
+
}
|
|
3722
|
+
}, [openScene]);
|
|
3723
|
+
// openJobsPanel(在上方、identity 稳定)经 ref 读取最新控制器。
|
|
3724
|
+
sidePanelRef.current = sidePanel;
|
|
3725
|
+
/**
|
|
3726
|
+
* 宠物「代言」判定:分屏开着且 companion 是活动面板时,新通知由宠物头顶
|
|
3727
|
+
* 气泡说出,输入框上方的 toast 不再重复同一条。error 色恒不压制(可能
|
|
3728
|
+
* 要行动)。渲染期读控制器状态——与气泡同一提交,无先闪后消的竞态。
|
|
3729
|
+
*/
|
|
3730
|
+
const petSaysNotices = React.useCallback((item) => item.color !== 'error' && sidePanel.split && sidePanel.activePanelId === 'companion', [sidePanel.split, sidePanel.activePanelId]);
|
|
3731
|
+
// 聊天列宽:收起时 = 内容区全宽(与现状逐字节一致),分栏时 = 左栏宽。
|
|
3732
|
+
// 所有显式下传的宽度(gutter / 图片预览区 / wake 条)都改用它;转录
|
|
3733
|
+
// 子树则经 SidePanelLayout 的 TerminalSizeContext 覆盖自动拿到。
|
|
3734
|
+
const chatColumns = sidePanel.chatColumns;
|
|
3735
|
+
const wakeWidth = miniWakeWidth(chatColumns);
|
|
3736
|
+
const panelPickerRows = usePanelPickerRows(sidePanel);
|
|
2858
3737
|
const wakeBand = React.useMemo(() => wakeWidth === 0
|
|
2859
3738
|
? undefined
|
|
2860
3739
|
// `sequence`, not the scene's `compressed`: at sixteen columns an idle
|
|
@@ -3021,9 +3900,10 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
3021
3900
|
const lastModalEnterAtRef = React.useRef(0);
|
|
3022
3901
|
const couponVisible = coupon !== null && starModal === null
|
|
3023
3902
|
&& approvalSnapshot === null && dialogSnapshot === null && questionSnapshot === null
|
|
3024
|
-
&& overlay.kind === 'none' &&
|
|
3903
|
+
&& overlay.kind === 'none' && !btwOverlayOpen && recap === null
|
|
3025
3904
|
&& !supervisorOpen && !treeOpen && !settingsOpen && !jobsPanelOpen
|
|
3026
|
-
&& !sceneOpen && !subagentDashboardOpen && subagentDetailId === null
|
|
3905
|
+
&& !sceneOpen && !subagentDashboardOpen && subagentDetailId === null
|
|
3906
|
+
&& !btwSceneOpen;
|
|
3027
3907
|
const markCouponShown = React.useCallback((orderId) => {
|
|
3028
3908
|
bonusNotices?.shown(orderId);
|
|
3029
3909
|
}, [bonusNotices]);
|
|
@@ -3042,10 +3922,27 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
3042
3922
|
// still lets the panel receive them. PromptInput now stays mounted but
|
|
3043
3923
|
// suspended to preserve async command drafts, making this guard also
|
|
3044
3924
|
// essential for Ctrl+C: it must never clear the hidden composer.
|
|
3045
|
-
if (
|
|
3925
|
+
if (btwOverlayOpen
|
|
3046
3926
|
|| overlay.kind === 'tips'
|
|
3047
3927
|
|| (recap !== null && (!recap.auto || recap.expanded)))
|
|
3048
3928
|
return;
|
|
3929
|
+
// The first-run guide owns the whole terminal while it is up: it is a
|
|
3930
|
+
// wizard with its own step navigation, its own focus ring inside the
|
|
3931
|
+
// pickers it borrows, and no free-text input at all. Registered ABOVE the
|
|
3932
|
+
// launchpad because it renders above it.
|
|
3933
|
+
if (onboardingOpen)
|
|
3934
|
+
return;
|
|
3935
|
+
// The launchpad owns the whole terminal while it is up — including the
|
|
3936
|
+
// plain letters that would otherwise reach the composer, which is exactly
|
|
3937
|
+
// the point: it IS the composer on this screen, and its draft is submitted
|
|
3938
|
+
// directly (see closeLaunchpad). ONE exception (fifth revision): a picker
|
|
3939
|
+
// opened from the param row renders ABOVE the launchpad and therefore owns
|
|
3940
|
+
// the keyboard — fall through to the overlay branches below (Esc closes the
|
|
3941
|
+
// picker back onto the launchpad). The launchpad's own useInput is paused
|
|
3942
|
+
// via inputPaused for exactly this window, so keys the picker does not
|
|
3943
|
+
// consume cannot leak into the draft.
|
|
3944
|
+
if (launchpadShown && !launchpadOverlayUp)
|
|
3945
|
+
return;
|
|
3049
3946
|
// The session tree owns the whole terminal while it is up: plain letters
|
|
3050
3947
|
// drive its search, clicks and Enter drive its action menu.
|
|
3051
3948
|
if (treeOpen)
|
|
@@ -3063,12 +3960,20 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
3063
3960
|
// Subagent dashboard or detail scene: it owns the keyboard while open.
|
|
3064
3961
|
if (subagentDashboardOpen || subagentDetailId !== null)
|
|
3065
3962
|
return;
|
|
3963
|
+
// The main-screen Agent View owns the whole terminal while open (its
|
|
3964
|
+
// composer, scrolling and Esc layering live in the scene).
|
|
3965
|
+
if (agentView !== null)
|
|
3966
|
+
return;
|
|
3066
3967
|
// The `/jobs` panel replaces the conversation too, so it owns Esc (close)
|
|
3067
3968
|
// and k (kill) while open. Unguarded, Esc meant to CLOSE the panel also
|
|
3068
3969
|
// reached the chat:cancel branch below whenever a turn was in flight —
|
|
3069
3970
|
// dismissing the panel and killing the turn with one key.
|
|
3070
3971
|
if (jobsPanelOpen)
|
|
3071
3972
|
return;
|
|
3973
|
+
// The ⤢ btw thread scene owns the keyboard the same way: Esc there
|
|
3974
|
+
// returns to the sidebar (never the chat:cancel branch below).
|
|
3975
|
+
if (btwSceneOpen)
|
|
3976
|
+
return;
|
|
3072
3977
|
// A plugin scene (dsh-tui-scenes) or the trajectory scene owns the whole
|
|
3073
3978
|
// screen while open: every key belongs to it. Unguarded, an Esc meant to
|
|
3074
3979
|
// CLOSE the scene also reached the chat:cancel branch below whenever a
|
|
@@ -3093,7 +3998,10 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
3093
3998
|
// Events only arrive with mouse tracking on; inline mode never sees
|
|
3094
3999
|
// them, so this is a no-op there.
|
|
3095
4000
|
if (key.wheelUp || key.wheelDown) {
|
|
3096
|
-
|
|
4001
|
+
// 焦点在右栏时滚轮不回落到转录:落在面板矩形上的滚轮已由命中
|
|
4002
|
+
// 测试路由给面板自己的 ScrollBox,到达这里的兜底事件不应在
|
|
4003
|
+
// 用户操作右栏时误滚左栏。
|
|
4004
|
+
if (helpOpen || sidePanel.focus === 'panel')
|
|
3097
4005
|
return;
|
|
3098
4006
|
// Any open transient dialog is modal to the wheel; the one exception
|
|
3099
4007
|
// mirrors the render gate — a workspace picker whose target list has
|
|
@@ -3130,7 +4038,8 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
3130
4038
|
// pending. The panels bind ↑/↓/Space/Tab/Enter/Esc and never these keys,
|
|
3131
4039
|
// so paging cannot steal anything from them.
|
|
3132
4040
|
if ((key.pageUp || key.pageDown) && fullscreen) {
|
|
3133
|
-
|
|
4041
|
+
// 焦点在右栏时 PgUp/PgDn 属于活动面板(经侧栏键盘分发)。
|
|
4042
|
+
if (helpOpen || sidePanel.focus === 'panel')
|
|
3134
4043
|
return;
|
|
3135
4044
|
const overlayModal = overlay.kind !== 'none' &&
|
|
3136
4045
|
(overlay.kind !== 'workspace-picker' || workspaceTargets.length > 0);
|
|
@@ -3169,6 +4078,12 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
3169
4078
|
}
|
|
3170
4079
|
return;
|
|
3171
4080
|
}
|
|
4081
|
+
// 侧栏键盘分发(v2.1 优先级):上面的审批 / 问卷 / 对话框守卫仍然
|
|
4082
|
+
// 最先,其次是侧栏全局快捷键(Ctrl+B / Alt+Z,两种焦点都生效),
|
|
4083
|
+
// 然后焦点在右栏时一切按键归侧栏——活动面板的业务键优先,宿主
|
|
4084
|
+
// 回退键(←/→ 切面板、z、+/-、Esc 回聊天)兜底。
|
|
4085
|
+
if (sidePanel.handleKey(input, key, event))
|
|
4086
|
+
return;
|
|
3172
4087
|
const returnCandidate = isPlainReturnInput(input, key);
|
|
3173
4088
|
const returnNow = Date.now();
|
|
3174
4089
|
const plainReturn = returnCandidate && returnNow - lastModalEnterAtRef.current >= 80;
|
|
@@ -3263,6 +4178,32 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
3263
4178
|
event.stopImmediatePropagation();
|
|
3264
4179
|
return;
|
|
3265
4180
|
}
|
|
4181
|
+
if (overlay.kind === 'help') {
|
|
4182
|
+
// 帮助盖屏(第八版):Esc/Ctrl+C/Enter 收起回落地页;纵向导航归这个
|
|
4183
|
+
// 视口(与 PromptInput 的 helpOpen 分支同一套键位),其余按键模态吞掉
|
|
4184
|
+
// ——绝不漏进落地页草稿。
|
|
4185
|
+
const page = Math.max(1, helpCoverViewportHeight - 2);
|
|
4186
|
+
if (key.upArrow || key.wheelUp) {
|
|
4187
|
+
helpCoverScrollRef.current?.scrollBy(key.wheelUp ? -3 : -1);
|
|
4188
|
+
}
|
|
4189
|
+
else if (key.downArrow || key.wheelDown) {
|
|
4190
|
+
helpCoverScrollRef.current?.scrollBy(key.wheelDown ? 3 : 1);
|
|
4191
|
+
}
|
|
4192
|
+
else if (key.pageUp || key.pageDown) {
|
|
4193
|
+
helpCoverScrollRef.current?.scrollBy(key.pageUp ? -page : page);
|
|
4194
|
+
}
|
|
4195
|
+
else if (key.home) {
|
|
4196
|
+
helpCoverScrollRef.current?.scrollTo(0);
|
|
4197
|
+
}
|
|
4198
|
+
else if (key.end) {
|
|
4199
|
+
helpCoverScrollRef.current?.scrollTo(Number.MAX_SAFE_INTEGER);
|
|
4200
|
+
}
|
|
4201
|
+
else if (key.escape || (key.ctrl && (input === 'c' || input === 'd')) || plainReturn) {
|
|
4202
|
+
dispatchOverlay({ type: 'close' });
|
|
4203
|
+
}
|
|
4204
|
+
event.stopImmediatePropagation();
|
|
4205
|
+
return;
|
|
4206
|
+
}
|
|
3266
4207
|
if (overlay.kind === 'thinking') {
|
|
3267
4208
|
if (key.upArrow || key.downArrow) {
|
|
3268
4209
|
dispatchOverlay({ type: 'move', delta: key.upArrow ? -1 : 1, count: 2 });
|
|
@@ -3632,6 +4573,84 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
3632
4573
|
}
|
|
3633
4574
|
return;
|
|
3634
4575
|
}
|
|
4576
|
+
if (overlay.kind === 'mode') {
|
|
4577
|
+
if (key.upArrow || key.downArrow) {
|
|
4578
|
+
dispatchOverlay({ type: 'move', delta: key.upArrow ? -1 : 1, count: overlay.modes.length });
|
|
4579
|
+
}
|
|
4580
|
+
else if (plainReturn) {
|
|
4581
|
+
const option = overlay.modes[overlay.index];
|
|
4582
|
+
dispatchOverlay({ type: 'close' });
|
|
4583
|
+
if (option !== undefined)
|
|
4584
|
+
void runBackendModeCommand(option.id, option.name);
|
|
4585
|
+
}
|
|
4586
|
+
else if (key.escape) {
|
|
4587
|
+
dispatchOverlay({ type: 'close' });
|
|
4588
|
+
}
|
|
4589
|
+
return;
|
|
4590
|
+
}
|
|
4591
|
+
if (overlay.kind === 'kernel') {
|
|
4592
|
+
// 名册不冻在 overlay 里(kernelOptions 是渲染期派生值):探测落地后
|
|
4593
|
+
// 选择器自己就刷新成完整目录,不需要重开。
|
|
4594
|
+
if (key.upArrow || key.downArrow) {
|
|
4595
|
+
dispatchOverlay({ type: 'move', delta: key.upArrow ? -1 : 1, count: kernelOptions.length });
|
|
4596
|
+
}
|
|
4597
|
+
else if (plainReturn) {
|
|
4598
|
+
pickKernel(overlay.index);
|
|
4599
|
+
}
|
|
4600
|
+
else if (key.escape) {
|
|
4601
|
+
dispatchOverlay({ type: 'close' });
|
|
4602
|
+
}
|
|
4603
|
+
return;
|
|
4604
|
+
}
|
|
4605
|
+
if (overlay.kind === 'sdk-install') {
|
|
4606
|
+
// 向导按键按步骤态分派;checking/running 期间除 Esc(取消安装)外
|
|
4607
|
+
// 全部吞掉——异步落地只发生在面板还在的窗口内(见 sdkPhase 注释)。
|
|
4608
|
+
if (sdkPhase.kind === 'confirm') {
|
|
4609
|
+
if (plainReturn)
|
|
4610
|
+
confirmSdkInstall(sdkPhase.dir);
|
|
4611
|
+
else if (key.escape)
|
|
4612
|
+
closeSdkInstallToKernelPicker();
|
|
4613
|
+
}
|
|
4614
|
+
else if (sdkPhase.kind === 'checking') {
|
|
4615
|
+
// 亚秒级预检,无键可按。
|
|
4616
|
+
}
|
|
4617
|
+
else if (sdkPhase.kind === 'running') {
|
|
4618
|
+
if (key.escape)
|
|
4619
|
+
sdkInstallerRef.current?.cancel();
|
|
4620
|
+
}
|
|
4621
|
+
else if (sdkPhase.kind === 'done') {
|
|
4622
|
+
if (plainReturn)
|
|
4623
|
+
closeSdkInstallToKernelPicker();
|
|
4624
|
+
else if (key.escape)
|
|
4625
|
+
closeSdkInstall();
|
|
4626
|
+
}
|
|
4627
|
+
else if (sdkPhase.kind === 'failed') {
|
|
4628
|
+
if (input === 'r' && !key.ctrl && !key.meta)
|
|
4629
|
+
confirmSdkInstall(sdkPhase.dir);
|
|
4630
|
+
else if (key.escape)
|
|
4631
|
+
closeSdkInstallToKernelPicker();
|
|
4632
|
+
}
|
|
4633
|
+
else {
|
|
4634
|
+
// pnpm-missing / cancelled / no-target:Esc 回内核选择器。
|
|
4635
|
+
if (key.escape)
|
|
4636
|
+
closeSdkInstallToKernelPicker();
|
|
4637
|
+
}
|
|
4638
|
+
return;
|
|
4639
|
+
}
|
|
4640
|
+
if (overlay.kind === 'channel') {
|
|
4641
|
+
// 名册不冻在 overlay 里(channelRows 是渲染期派生值):切换/导入后
|
|
4642
|
+
// 选择器自己就刷新成新状态,不需要重开。
|
|
4643
|
+
if (key.upArrow || key.downArrow) {
|
|
4644
|
+
dispatchOverlay({ type: 'move', delta: key.upArrow ? -1 : 1, count: channelRows.length });
|
|
4645
|
+
}
|
|
4646
|
+
else if (plainReturn) {
|
|
4647
|
+
pickChannel(overlay.index);
|
|
4648
|
+
}
|
|
4649
|
+
else if (key.escape) {
|
|
4650
|
+
dispatchOverlay({ type: 'close' });
|
|
4651
|
+
}
|
|
4652
|
+
return;
|
|
4653
|
+
}
|
|
3635
4654
|
if (overlay.kind === 'plan') {
|
|
3636
4655
|
if (key.upArrow || key.downArrow) {
|
|
3637
4656
|
dispatchOverlay({ type: 'move', delta: key.upArrow ? -1 : 1, count: 2 });
|
|
@@ -3661,6 +4680,21 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
3661
4680
|
}
|
|
3662
4681
|
return;
|
|
3663
4682
|
}
|
|
4683
|
+
if (overlay.kind === 'panel') {
|
|
4684
|
+
if (key.upArrow || key.downArrow) {
|
|
4685
|
+
dispatchOverlay({ type: 'move', delta: key.upArrow ? -1 : 1, count: panelPickerRows.length });
|
|
4686
|
+
}
|
|
4687
|
+
else if (plainReturn) {
|
|
4688
|
+
const row = panelPickerRows[overlay.index];
|
|
4689
|
+
dispatchOverlay({ type: 'close' });
|
|
4690
|
+
if (row !== undefined)
|
|
4691
|
+
sidePanel.openPanel(row.id, { focus: true });
|
|
4692
|
+
}
|
|
4693
|
+
else if (key.escape) {
|
|
4694
|
+
dispatchOverlay({ type: 'close' });
|
|
4695
|
+
}
|
|
4696
|
+
return;
|
|
4697
|
+
}
|
|
3664
4698
|
if (overlay.kind === 'theme') {
|
|
3665
4699
|
const options = getThemeOptions(themeHost);
|
|
3666
4700
|
if (key.upArrow || key.downArrow) {
|
|
@@ -3832,11 +4866,12 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
3832
4866
|
return;
|
|
3833
4867
|
}
|
|
3834
4868
|
if (actionMatches('dashboard', input, key)) {
|
|
3835
|
-
// The subagent dashboard key (default Ctrl+A) opens the dashboard
|
|
3836
|
-
//
|
|
3837
|
-
//
|
|
3838
|
-
//
|
|
3839
|
-
|
|
4869
|
+
// The subagent dashboard key (default Ctrl+A) opens the dashboard —
|
|
4870
|
+
// split mode routes it to the agents side panel instead. Consume the
|
|
4871
|
+
// key: without the stop the prompt editor's readline binding ALSO
|
|
4872
|
+
// fires (Ctrl+A moves the caret to line start), so one press both
|
|
4873
|
+
// opens the view and jumps the cursor.
|
|
4874
|
+
openSubagentDashboard();
|
|
3840
4875
|
event.stopImmediatePropagation();
|
|
3841
4876
|
return;
|
|
3842
4877
|
}
|
|
@@ -3848,7 +4883,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
3848
4883
|
return;
|
|
3849
4884
|
}
|
|
3850
4885
|
if (actionMatches('history', input, key) && !helpOpen) {
|
|
3851
|
-
setHistoryEntries(loadHistory());
|
|
4886
|
+
setHistoryEntries(loadHistory(channel.cwd));
|
|
3852
4887
|
dispatchOverlay({
|
|
3853
4888
|
type: 'open',
|
|
3854
4889
|
overlay: { kind: 'history', query: '', cursor: 0, focus: 0 },
|
|
@@ -3873,22 +4908,25 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
3873
4908
|
setSelectedId(null);
|
|
3874
4909
|
}
|
|
3875
4910
|
}
|
|
4911
|
+
else if (key.escape && promptControllerRef.current?.consumeEscape()) {
|
|
4912
|
+
// Selection/editor Esc stays with the composer even though Chat's
|
|
4913
|
+
// global listener runs first. Consume it before interrupting the turn.
|
|
4914
|
+
event.stopImmediatePropagation();
|
|
4915
|
+
}
|
|
3876
4916
|
else if (key.escape && channel.working && !helpOpen && !promptControllerRef.current?.vimActive()) {
|
|
3877
4917
|
// Esc interrupts a running turn (the prompt input
|
|
3878
4918
|
// only sees esc when idle, where it has the double-tap-clear meaning).
|
|
3879
|
-
// With messages queued
|
|
3880
|
-
//
|
|
4919
|
+
// With messages queued, the queue DOCKS (Claude Code parity): the
|
|
4920
|
+
// abort drops the backend copies, the previews park channel-side and
|
|
4921
|
+
// the composer's dock hint offers ↑ to edit one / ⏎ to send them all
|
|
4922
|
+
// — nothing auto-sends. Already-docked rows dock nothing new; the
|
|
4923
|
+
// turn still needs its plain abort.
|
|
3881
4924
|
// vim mode (either submode) yields: there Esc is a MODE key (INSERT→
|
|
3882
4925
|
// NORMAL, NORMAL = no-op/cancel pending d) and the prompt owns it;
|
|
3883
4926
|
// interrupting still works via Ctrl+C / Ctrl+Enter.
|
|
3884
4927
|
if (channel.pending.length > 0) {
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
images: item.images ?? [],
|
|
3888
|
-
})));
|
|
3889
|
-
if (count > 0) {
|
|
3890
|
-
channel.notify(t('interrupt-delivered', { n: count }), { timeoutMs: 2500 });
|
|
3891
|
-
}
|
|
4928
|
+
if (channel.interruptAndDock() === 0)
|
|
4929
|
+
channel.cancel();
|
|
3892
4930
|
}
|
|
3893
4931
|
else {
|
|
3894
4932
|
channel.cancel();
|
|
@@ -4040,10 +5078,17 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
4040
5078
|
// (wired to the toast below).
|
|
4041
5079
|
event.stopImmediatePropagation();
|
|
4042
5080
|
}
|
|
5081
|
+
}, {
|
|
5082
|
+
// Chat's global layer must see every key before the composer and the
|
|
5083
|
+
// panels it hosts (the handler's yield guards and readline shadowing
|
|
5084
|
+
// both assume it), whether or not they mounted in the same
|
|
5085
|
+
// commit — child effects run first, so append order would put a
|
|
5086
|
+
// first-mount PromptInput ahead of Chat (#1155).
|
|
5087
|
+
prepend: true,
|
|
4043
5088
|
});
|
|
4044
5089
|
// Working-activity line (spinner slot): context-pressure prefix shares the
|
|
4045
|
-
// StatusLine thresholds (amber ≥ 80, red ≥ 95).
|
|
4046
|
-
const activityWarnPct = contextPressurePct(channel
|
|
5090
|
+
// StatusLine thresholds (amber ≥ 80, red ≥ 95) and its occupancy source.
|
|
5091
|
+
const activityWarnPct = contextPressurePct(channelContextOccupancy(channel));
|
|
4047
5092
|
// Who owns the spinner slot: with the working-activity line on, that slot
|
|
4048
5093
|
// draws the user's `/activity` preset, so the compaction row borrows the same
|
|
4049
5094
|
// indicator instead of answering with the classic dot.
|
|
@@ -4064,7 +5109,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
4064
5109
|
// covered screen is unmounted, exactly like the chat-state prompt slot.
|
|
4065
5110
|
// The panel elements are shared with the prompt-slot chain below so the
|
|
4066
5111
|
// two mount sites cannot drift.
|
|
4067
|
-
const approvalPanelNode = approvalSnapshot !== null ? (_jsx(ApprovalPanel, { approval: approvalSnapshot, background: approvalSnapshot.agentId !== channel.agentId, onDecide: outcome => approvals.decide(outcome) }, approvalSnapshot.key)) : null;
|
|
5112
|
+
const approvalPanelNode = approvalSnapshot !== null ? (_jsx(ApprovalPanel, { approval: approvalSnapshot, background: approvalSnapshot.agentId !== channel.agentId, onDecide: (outcome, decision) => approvals.decide(outcome, decision) }, approvalSnapshot.key)) : null;
|
|
4068
5113
|
const questionPanelNode = questionSnapshot !== null ? (_jsx(AskUserQuestionPanel, { question: questionSnapshot.question, position: questionSnapshot.position, total: questionSnapshot.total, answered: questionSnapshot.answered, initialDraft: questionSnapshot.draft, onAnswer: selection => {
|
|
4069
5114
|
if (!questionStore.stillCurrent(questionSnapshot.key))
|
|
4070
5115
|
return;
|
|
@@ -4099,8 +5144,201 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
4099
5144
|
}
|
|
4100
5145
|
: undefined, collapsed: questionMinimized, onExpand: () => setMinimizedQuestionKey(null), onToggleFold: () => setMinimizedQuestionKey(previous => previous === questionSnapshot.key ? null : questionSnapshot.key), fullscreen: fullscreen }, questionSnapshot.key)) : null;
|
|
4101
5146
|
const interruptPanel = approvalPanelNode ?? questionPanelNode;
|
|
5147
|
+
/**
|
|
5148
|
+
* Transient picker panels (pickers/dialogs) - this JSX feeds TWO mount
|
|
5149
|
+
* points since the fifth launchpad revision: the chat page OverlayAbove
|
|
5150
|
+
* (above the input cluster) and the launchpad itself (above its input
|
|
5151
|
+
* card, see the launchpad branch). Defined once so the two never drift.
|
|
5152
|
+
*/
|
|
5153
|
+
const backendModeStatus = modeStatus(channel.backendModes?.()?.snapshot(), () => { void runCommand('permission', ''); });
|
|
5154
|
+
/**
|
|
5155
|
+
* 底栏模型段/思考档位段的点击(与模式段同一契约):后端声明了模型目录或
|
|
5156
|
+
* effort 能力(backendCapabilities 位)才挂,点击 = 既有 /model · /effort
|
|
5157
|
+
* 命令(同一批选择器);无能力不挂点击,hover 也不承诺(StatusLine 的
|
|
5158
|
+
* effort hover id 与点击同乘,model hover 只是不追加操作行)。
|
|
5159
|
+
*/
|
|
5160
|
+
const backendCaps = channel.backendCapabilities;
|
|
5161
|
+
const modelPickerStatus = backendCaps?.models === false
|
|
5162
|
+
? undefined
|
|
5163
|
+
: { onOpen: () => { void runCommand('model', ''); } };
|
|
5164
|
+
const effortPickerStatus = backendCaps?.effort === false
|
|
5165
|
+
? undefined
|
|
5166
|
+
: { onOpen: () => { void runCommand('effort', ''); } };
|
|
5167
|
+
const pickerPanels = (_jsxs(_Fragment, { children: [overlay.kind === 'help' && (_jsx(Box, { flexDirection: "column", marginBottom: 1, children: _jsx(HelpMenu, { commands: channel.commandList, viewportHeight: helpCoverViewportHeight, viewportWidth: chatColumns, scrollRef: helpCoverScrollRef, onCommandPick: (name) => {
|
|
5168
|
+
// 点击命令行 = 把 /name 填进落地页草稿(聊天页 Tab 补全的
|
|
5169
|
+
// 鼠标等价),浮层收起、人还在启动页(第八版:不许进对话页)。
|
|
5170
|
+
dispatchOverlay({ type: 'close' });
|
|
5171
|
+
const filled = '/' + name + ' ';
|
|
5172
|
+
setLaunchpadDraft(filled);
|
|
5173
|
+
setLaunchpadCaret(filled.length);
|
|
5174
|
+
setLaunchpadFocus(-1);
|
|
5175
|
+
} }) })), overlay.kind === 'thinking' && (_jsx(ThinkingToggle, { currentValue: thinkingVisible, focusIndex: overlay.focus, onPick: (index) => {
|
|
5176
|
+
// 点击行 = 设焦点 + 应用(与 Enter 同一条路径)
|
|
5177
|
+
const visible = index === 0;
|
|
5178
|
+
setThinkingVisible(visible);
|
|
5179
|
+
dispatchOverlay({ type: 'close' });
|
|
5180
|
+
channel.notify(t('thinking-toggled', { state: visible ? t('thinking-on') : t('thinking-off') }));
|
|
5181
|
+
} })), overlay.kind === 'workspace-picker' && workspaceTargets.length > 0 && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(WorkspacePicker, { targets: workspaceTargets, focusIndex: overlay.index, currentCwd: channel.cwd, onPick: (index) => {
|
|
5182
|
+
// 点击行 = 切换该行目标(与 Enter 同一条路径)
|
|
5183
|
+
const target = workspaceTargets[index];
|
|
5184
|
+
dispatchOverlay({ type: 'close' });
|
|
5185
|
+
if (target !== undefined)
|
|
5186
|
+
void channel.switchWorkspace(target);
|
|
5187
|
+
} }) })), overlay.kind === 'workspace-menu' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(WorkspaceMenuPicker, { options: workspaceMenuOptions, focusIndex: overlay.index, onPick: (index) => {
|
|
5188
|
+
// 点击行 = 执行该行(与 Enter 同一条路径)
|
|
5189
|
+
runWorkspaceMenuOption(workspaceMenuOptions[index]);
|
|
5190
|
+
} }) })), overlay.kind === 'workspace-flow' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(WorkspaceFlowPicker, { title: overlay.flow.title, choices: overlay.flow.choices, focusIndex: overlay.index, busy: overlay.busy, input: overlay.input, onPick: (index) => {
|
|
5191
|
+
// 点击行 = 设焦点 + 执行分支(与 Enter 同一条路径);
|
|
5192
|
+
// busy/输入态在组件侧禁点
|
|
5193
|
+
const choice = overlay.flow.choices[index];
|
|
5194
|
+
if (choice === undefined)
|
|
5195
|
+
return;
|
|
5196
|
+
dispatchOverlay({ type: 'set-index', kind: 'workspace-flow', index });
|
|
5197
|
+
runWorkspaceFlowAction(signal => choice.choose(signal));
|
|
5198
|
+
} }) })), overlay.kind === 'model' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: models.length === 0 ? (_jsx(ModelPickerLoading, {})) : activeModelGroup === undefined ? (_jsx(ModelPicker, { groups: modelGroups, focusIndex: overlay.index, currentProvider: channel.provider, onPick: (index) => {
|
|
5199
|
+
// 点击分组行 = 进入该组(与 Enter 同一条路径)
|
|
5200
|
+
const group = modelGroups[index];
|
|
5201
|
+
if (!group)
|
|
5202
|
+
return;
|
|
5203
|
+
setModelGroup(group.provider);
|
|
5204
|
+
if (group.provider === RECENTS_GROUP_PROVIDER) {
|
|
5205
|
+
dispatchOverlay({ type: 'set-index', kind: 'model', index: 0 });
|
|
5206
|
+
return;
|
|
5207
|
+
}
|
|
5208
|
+
const landing = modelPickerLanding(models.filter(model => model.provider === group.provider), channel.provider, channel.model);
|
|
5209
|
+
dispatchOverlay({ type: 'set-index', kind: 'model', index: landing.index });
|
|
5210
|
+
} })) : (_jsx(ModelPicker, { models: groupModels, groupLabel: activeModelGroup === RECENTS_GROUP_PROVIDER
|
|
5211
|
+
? t('picker-group-recent')
|
|
5212
|
+
: modelGroups.find(group => group.provider === activeModelGroup)?.label, showBack: modelGroups.length > 1 && !modelPickerDirect, showProviderPrefix: activeModelGroup === RECENTS_GROUP_PROVIDER, focusIndex: overlay.index, currentModel: `${channel.provider}/${channel.model}`, onPick: (index) => {
|
|
5213
|
+
// 点击行 = 应用该行模型(与 Enter 同一条路径)
|
|
5214
|
+
const model = groupModels[index];
|
|
5215
|
+
if (!model)
|
|
5216
|
+
return;
|
|
5217
|
+
dispatchOverlay({ type: 'close' });
|
|
5218
|
+
void switchModelRecorded(model.provider, model.id, model.name);
|
|
5219
|
+
} })) })), overlay.kind === 'migrate' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(MigratePicker, { rows: migrateRows ?? [], focusIndex: overlay.index, checked: migrateChecked, loading: migrateRows === null, onPick: (index) => {
|
|
5220
|
+
const row = (migrateRows ?? [])[index];
|
|
5221
|
+
if (!row)
|
|
5222
|
+
return;
|
|
5223
|
+
setMigrateChecked(current => {
|
|
5224
|
+
const next = new Set(current);
|
|
5225
|
+
if (next.has(row.agentId))
|
|
5226
|
+
next.delete(row.agentId);
|
|
5227
|
+
else
|
|
5228
|
+
next.add(row.agentId);
|
|
5229
|
+
return next;
|
|
5230
|
+
});
|
|
5231
|
+
} }) })), overlay.kind === 'migrate-confirm' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(MigrateConfirm, { rows: migratePending }) })), overlay.kind === 'skills' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: skillsList === null ? (_jsx(SkillsPickerLoading, {})) : (_jsx(SkillsPicker, { skills: skillsList, focusIndex: overlay.index, onPick: (index) => {
|
|
5232
|
+
const skill = skillsList[index];
|
|
5233
|
+
if (!skill)
|
|
5234
|
+
return;
|
|
5235
|
+
dispatchOverlay({ type: 'close' });
|
|
5236
|
+
if (skill.userInvocable)
|
|
5237
|
+
setHistoryFill(`/${skill.name} `);
|
|
5238
|
+
} })) })), overlay.kind === 'activity' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(ActivityPicker, { focusIndex: overlay.index, currentPreset: channel.activityFrames, onPick: (index) => {
|
|
5239
|
+
dispatchOverlay({ type: 'close' });
|
|
5240
|
+
const name = PRESET_NAMES[index];
|
|
5241
|
+
if (name)
|
|
5242
|
+
channel.setActivityFrames(name);
|
|
5243
|
+
} }) })), overlay.kind === 'color' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(ColorPicker, { focusIndex: overlay.index, currentColor: channel.sessionColor, onPick: (index) => {
|
|
5244
|
+
dispatchOverlay({ type: 'close' });
|
|
5245
|
+
const name = SESSION_COLOR_NAMES[index];
|
|
5246
|
+
if (name) {
|
|
5247
|
+
channel.setSessionColor(name);
|
|
5248
|
+
channel.notify(t('color-set', { name }), { color: 'success' });
|
|
5249
|
+
}
|
|
5250
|
+
} }) })), overlay.kind === 'panel' && panelPickerRows.length > 0 && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(PanelPicker, { rows: panelPickerRows, focusIndex: overlay.index, activeId: sidePanel.activePanelId, onPick: (index) => {
|
|
5251
|
+
const row = panelPickerRows[index];
|
|
5252
|
+
dispatchOverlay({ type: 'close' });
|
|
5253
|
+
if (row !== undefined)
|
|
5254
|
+
sidePanel.openPanel(row.id, { focus: true });
|
|
5255
|
+
} }) })), overlay.kind === 'effort' && effortOptions.length > 1 && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(EffortSlider, { options: effortOptions, focusIndex: overlay.index, currentId: channel.reasoningEffort, levelsFallback: effortLevelsFallback,
|
|
5256
|
+
// 点击档位 = 移到该档并即时应用(与 ←/→ 同语义)
|
|
5257
|
+
onPick: (index) => {
|
|
5258
|
+
dispatchOverlay({ type: 'set-index', kind: 'effort', index });
|
|
5259
|
+
const option = effortOptions[index];
|
|
5260
|
+
if (option)
|
|
5261
|
+
void channel.setEffort(option.id);
|
|
5262
|
+
} }) })), overlay.kind === 'preset' && presetOptions.length > 0 && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(PresetPicker, { presets: presetOptions, focusIndex: overlay.index, currentPreset: channel.agentPreset, onPick: (index) => {
|
|
5263
|
+
dispatchOverlay({ type: 'close' });
|
|
5264
|
+
const option = presetOptions[index];
|
|
5265
|
+
if (option)
|
|
5266
|
+
void channel.switchPreset(option.id);
|
|
5267
|
+
} }) })), overlay.kind === 'permission' && overlay.snapshot.options.length > 0 && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(PermissionsPicker, { options: overlay.snapshot.options, focusIndex: overlay.index, currentValue: overlay.snapshot.current?.value, cwd: channel.cwd, onPick: (index) => {
|
|
5268
|
+
if (approvalSnapshot !== null || questionSnapshot !== null || dialogSnapshot !== null)
|
|
5269
|
+
return;
|
|
5270
|
+
const option = overlay.snapshot.options[index];
|
|
5271
|
+
dispatchOverlay({ type: 'close' });
|
|
5272
|
+
if (option !== undefined)
|
|
5273
|
+
void runPermissionCommand(` ${option.value}`);
|
|
5274
|
+
} }) })), overlay.kind === 'mode' && overlay.modes.length > 0 && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(ModePicker, { modes: overlay.modes, focusIndex: overlay.index, currentId: overlay.currentId, onPick: (index) => {
|
|
5275
|
+
if (approvalSnapshot !== null || questionSnapshot !== null || dialogSnapshot !== null)
|
|
5276
|
+
return;
|
|
5277
|
+
const option = overlay.modes[index];
|
|
5278
|
+
dispatchOverlay({ type: 'close' });
|
|
5279
|
+
if (option !== undefined)
|
|
5280
|
+
void runBackendModeCommand(option.id, option.name);
|
|
5281
|
+
} }) })), overlay.kind === 'kernel' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(KernelPicker, { options: kernelOptions, focusIndex: overlay.index, pinned: kernelPinned === true, onPick: (index) => {
|
|
5282
|
+
if (approvalSnapshot !== null || questionSnapshot !== null || dialogSnapshot !== null)
|
|
5283
|
+
return;
|
|
5284
|
+
pickKernel(index);
|
|
5285
|
+
} }) })), overlay.kind === 'sdk-install' && sdkPhase.kind !== 'idle' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(SdkInstallWizard, { phase: sdkPhase }) })), overlay.kind === 'channel' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(ChannelPicker, { rows: channelRows, focusIndex: overlay.index, onPick: (index) => {
|
|
5286
|
+
if (approvalSnapshot !== null || questionSnapshot !== null || dialogSnapshot !== null)
|
|
5287
|
+
return;
|
|
5288
|
+
pickChannel(index);
|
|
5289
|
+
} }) })), overlay.kind === 'plan' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(PlanPicker, { focusIndex: overlay.index, currentOn: channel.mode.plan === true, onPick: (index) => {
|
|
5290
|
+
dispatchOverlay({ type: 'close' });
|
|
5291
|
+
const on = index === 0;
|
|
5292
|
+
void runExternalCommand('plan', on ? '' : ' off');
|
|
5293
|
+
} }) })), overlay.kind === 'lang' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(LangPicker, { focusIndex: overlay.index, currentLang: getLang(), onPick: (index) => {
|
|
5294
|
+
const lang = LANGS[index];
|
|
5295
|
+
if (lang === undefined)
|
|
5296
|
+
return;
|
|
5297
|
+
dispatchOverlay({ type: 'close' });
|
|
5298
|
+
applyLang(lang);
|
|
5299
|
+
} }) })), overlay.kind === 'theme' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(ThemePicker, { focusIndex: overlay.index, currentTheme: themeName, themeHost: themeHost, onPick: (index) => {
|
|
5300
|
+
dispatchOverlay({ type: 'close' });
|
|
5301
|
+
const name = getThemeOptions(themeHost)[index]?.value;
|
|
5302
|
+
if (name !== undefined) {
|
|
5303
|
+
const ok = setTheme(name);
|
|
5304
|
+
channel.notify(ok ? t('theme-switched-saved', { name }) : t('theme-switch-failed', { name }), { color: ok ? 'success' : 'error' });
|
|
5305
|
+
}
|
|
5306
|
+
} }) })), overlay.kind === 'history' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(HistorySearchDialog, { query: overlay.query, cursorOffset: overlay.cursor, matches: historyMatches, focusIndex: overlay.focus, onPick: (index) => {
|
|
5307
|
+
// 点击行 = 填入该历史命令(与 Enter 同路径)
|
|
5308
|
+
const entry = historyMatches[index];
|
|
5309
|
+
if (entry) {
|
|
5310
|
+
setHistoryFill(entry.text);
|
|
5311
|
+
dispatchOverlay({ type: 'close' });
|
|
5312
|
+
}
|
|
5313
|
+
} }) })), overlay.kind === 'rewind' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(RewindPicker, { rows: rewindRows, focusIndex: overlay.index, confirmRow: overlay.confirm, modes: overlay.modes, modeIndex: overlay.modeIndex, busy: overlay.busy, onPickRow: (index) => {
|
|
5314
|
+
// 列表页点击只选中:进入确认态保留键盘 Enter 显式触发
|
|
5315
|
+
dispatchOverlay({ type: 'set-index', kind: 'rewind', index });
|
|
5316
|
+
}, onConfirm: () => {
|
|
5317
|
+
// 确认页即显式确认层,点击直接执行(与 Enter 同路径)
|
|
5318
|
+
const row = overlay.confirm;
|
|
5319
|
+
if (row === null)
|
|
5320
|
+
return;
|
|
5321
|
+
dispatchOverlay({ type: 'close' });
|
|
5322
|
+
void performRewind(row);
|
|
5323
|
+
}, onPickMode: (index) => {
|
|
5324
|
+
// 模式列表点击直接执行该模式(与 Enter 同路径)
|
|
5325
|
+
const row = overlay.confirm;
|
|
5326
|
+
if (row === null)
|
|
5327
|
+
return;
|
|
5328
|
+
// 模式页仅当 modes 非空才渲染,这里空安全取值
|
|
5329
|
+
const mode = index === 0 ? null : (overlay.modes?.[index - 1]?.id ?? null);
|
|
5330
|
+
dispatchOverlay({ type: 'close' });
|
|
5331
|
+
void performRewind(row, mode);
|
|
5332
|
+
} }) })), overlay.kind === 'file-actions' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(FileActionsPanel, { path: overlay.path, isDir: overlay.isDir, focusIndex: overlay.index, onPick: (index) => {
|
|
5333
|
+
// 点击行直接执行该动作(与 Enter 同路径)
|
|
5334
|
+
const path = overlay.path;
|
|
5335
|
+
dispatchOverlay({ type: 'close' });
|
|
5336
|
+
runFileAction(index, path);
|
|
5337
|
+
} }) })), overlay.kind === 'search' && _jsx(TranscriptSearch, { query: searchQuery, cursorOffset: searchCursor, count: searchCount, current: searchCurrent })] }));
|
|
4102
5338
|
const screenOpen = channel.pluginScene !== undefined || supervisorOpen || settingsOpen
|
|
4103
|
-
|| subagentDetailId !== null || subagentDashboardOpen || sceneOpen
|
|
5339
|
+
|| subagentDetailId !== null || subagentDashboardOpen || sceneOpen
|
|
5340
|
+
|| agentView !== null
|
|
5341
|
+
|| launchpadShown || onboardingOpen;
|
|
4104
5342
|
if (interruptPanel !== null && screenOpen) {
|
|
4105
5343
|
const node = (_jsx(Box, { flexDirection: "column", width: "100%", paddingX: 1, children: interruptPanel }));
|
|
4106
5344
|
return fullscreen ? node : _jsx(AlternateScreen, { children: node });
|
|
@@ -4126,6 +5364,29 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
4126
5364
|
}, children: renderScene ? renderScene(pluginScene.id, channel) : _jsxs(Text, { children: ["Scene unavailable: ", pluginScene.id] }) }));
|
|
4127
5365
|
return fullscreen ? node : _jsx(AlternateScreen, { children: node });
|
|
4128
5366
|
}
|
|
5367
|
+
/**
|
|
5368
|
+
* The first-run guide — the FIRST frame of a fresh installation.
|
|
5369
|
+
*
|
|
5370
|
+
* It sits above every other screen because it answers a question that comes
|
|
5371
|
+
* before all of them: "is this thing wired up at all". A launch that needs
|
|
5372
|
+
* setup has nothing useful to show behind a browser or a landing page.
|
|
5373
|
+
*
|
|
5374
|
+
* `activeModel` is deliberately undefined here: the wizard's model step
|
|
5375
|
+
* switches models through `channel.switchModel`, which is the same path the
|
|
5376
|
+
* chat screen uses, so a switch made inside the wizard is already live when
|
|
5377
|
+
* the user lands on the launcher.
|
|
5378
|
+
*/
|
|
5379
|
+
if (onboardingOpen) {
|
|
5380
|
+
const node = (_jsx(Onboarding, { channel: channel, themeHost: themeHost, onClose: closeOnboarding, onApplyLang: applyLang, onRunCommand: (name) => {
|
|
5381
|
+
// 与落地页的 onAction 同一条规则:打开整屏界面的命令要先把向导收掉。
|
|
5382
|
+
// 走 `closeOnboarding('skipped')` 而不是直接置 false——用户是去试命令、
|
|
5383
|
+
// 没答完引导,按 skipped 的口径不记账(下次启动还会问)。
|
|
5384
|
+
if (!overlayCommandNames.has(name))
|
|
5385
|
+
closeOnboarding('skipped');
|
|
5386
|
+
void runCommand(name, '');
|
|
5387
|
+
} }));
|
|
5388
|
+
return fullscreen ? node : _jsx(AlternateScreen, { children: node });
|
|
5389
|
+
}
|
|
4129
5390
|
/**
|
|
4130
5391
|
* The session supervisor: a screen in the same sense as the tree — an early
|
|
4131
5392
|
* return after every hook above has run, so there is no transcript
|
|
@@ -4142,7 +5403,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
4142
5403
|
* while they read the list, which is why closing the screen only repaints
|
|
4143
5404
|
* the transcript when the attached session actually changed.
|
|
4144
5405
|
*/
|
|
4145
|
-
if (supervisorOpen) {
|
|
5406
|
+
if (supervisorOpen && launchpadGate()) {
|
|
4146
5407
|
/**
|
|
4147
5408
|
* Live state per session, from the channel's own agent-view projection.
|
|
4148
5409
|
* Reading the projection rather than a parallel source is what keeps this
|
|
@@ -4150,7 +5411,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
4150
5411
|
* about which session is waiting for input.
|
|
4151
5412
|
*/
|
|
4152
5413
|
const agentRowOf = (sessionId) => agentViewRows.find(row => row.id === sessionId);
|
|
4153
|
-
const supervisorNode = (_jsx(SessionSupervisor, { channel: channel, home: homeDir(), onClose: closeHome, approval: approvalSnapshot, onApprove: outcome => approvals.decide(outcome), onOpenSession: async (sessionId) => {
|
|
5414
|
+
const supervisorNode = (_jsx(SessionSupervisor, { channel: channel, home: homeDir(), onClose: closeHome, approval: approvalSnapshot, onApprove: (outcome, decision) => approvals.decide(outcome, decision), onOpenSession: async (sessionId) => {
|
|
4154
5415
|
// A refusal is reported by the screen itself (see `openSession`):
|
|
4155
5416
|
// the composer that draws channel notifications is not mounted here.
|
|
4156
5417
|
const result = await channel.resumeTo(sessionId);
|
|
@@ -4160,6 +5421,15 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
4160
5421
|
suppressLogoIntroRef.current = true;
|
|
4161
5422
|
setAgentViewReturnId(undefined);
|
|
4162
5423
|
setSupervisorOpen(false);
|
|
5424
|
+
// 第七版:明确选中一个会话 = 有意导航(与 Esc「退出」相对)——浏览页
|
|
5425
|
+
// 与盖在它底下的落地页**一起收**,人落在那个会话的聊天页。只收浏览页
|
|
5426
|
+
// 会露出启动页,正是用户实测的「选完会话还是回到启动页」。落地页的
|
|
5427
|
+
// 草稿/焦点也按 closeLaunchpad 同一口径清掉(进入的是别的会话,旧草稿
|
|
5428
|
+
// 不该跟过去)。
|
|
5429
|
+
setLaunchpadOpen(false);
|
|
5430
|
+
setLaunchpadFocus(-1);
|
|
5431
|
+
setLaunchpadDraft('');
|
|
5432
|
+
setLaunchpadCaret(0);
|
|
4163
5433
|
repaintTranscript();
|
|
4164
5434
|
return result;
|
|
4165
5435
|
}, onNewSession: async (target) => {
|
|
@@ -4168,14 +5438,24 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
4168
5438
|
suppressLogoIntroRef.current = true;
|
|
4169
5439
|
setAgentViewReturnId(undefined);
|
|
4170
5440
|
setSupervisorOpen(false);
|
|
5441
|
+
// 同 onOpenSession:新建/切工作区会话也是有意导航,落地页一并收。
|
|
5442
|
+
setLaunchpadOpen(false);
|
|
5443
|
+
setLaunchpadFocus(-1);
|
|
5444
|
+
setLaunchpadDraft('');
|
|
5445
|
+
setLaunchpadCaret(0);
|
|
4171
5446
|
repaintTranscript();
|
|
4172
5447
|
}
|
|
4173
5448
|
return ok;
|
|
4174
5449
|
}, onStopSession: async (sessionId) => channel.stopBackgroundAgent?.(sessionId) ?? false, liveStateOf: (sessionId) => {
|
|
4175
5450
|
const row = agentRowOf(sessionId);
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
5451
|
+
if (row !== undefined)
|
|
5452
|
+
return { status: row.status, live: row.live, current: row.current, summary: row.summary };
|
|
5453
|
+
// Without agent view, only this terminal's current session has live state.
|
|
5454
|
+
// oxlint-disable-next-line typescript/no-unnecessary-condition -- runtime guard: headless hosts render Chat with a partial channel
|
|
5455
|
+
const hasAgentView = channel.backendCapabilities?.commands.includes('agentview') ?? true;
|
|
5456
|
+
if (hasAgentView || sessionId !== channel.agentId)
|
|
5457
|
+
return undefined;
|
|
5458
|
+
return { status: channel.working ? 'working' : 'idle', live: true, current: true, summary: '' };
|
|
4179
5459
|
} }));
|
|
4180
5460
|
// Inline hosts enter the alternate screen for the duration; full-screen
|
|
4181
5461
|
// hosts are already in it and must not nest a second one.
|
|
@@ -4185,7 +5465,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
4185
5465
|
// conversation (an early return after every hook above has run), so there
|
|
4186
5466
|
// is no transcript underneath to be repainted or bled through. The dropped
|
|
4187
5467
|
// turn's prompt returns through the same fill path a rewind picker uses.
|
|
4188
|
-
if (treeOpen) {
|
|
5468
|
+
if (treeOpen && launchpadGate()) {
|
|
4189
5469
|
const tree = (_jsx(SessionTree, { channel: channel, currentSessionId: channel.agentId, onClose: () => setTreeOpen(false), onRestoreText: (text) => {
|
|
4190
5470
|
// The tree rewound to a node and is handing that turn's prompt back,
|
|
4191
5471
|
// exactly like the picker does. It belongs to the binding the tree
|
|
@@ -4198,21 +5478,47 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
4198
5478
|
// The settings screen follows the browser's rule exactly: it REPLACES the
|
|
4199
5479
|
// conversation (an early return after every hook above has run), so there
|
|
4200
5480
|
// is no transcript underneath to be repainted or bled through.
|
|
4201
|
-
if (settingsOpen) {
|
|
5481
|
+
if (settingsOpen && launchpadGate()) {
|
|
4202
5482
|
const screen = _jsx(Settings, { channel: channel, onClose: () => setSettingsOpen(false) });
|
|
4203
5483
|
return fullscreen ? screen : _jsx(AlternateScreen, { children: screen });
|
|
4204
5484
|
}
|
|
5485
|
+
// Main-screen read-only Agent View: a scene over the mounted Chat, with no
|
|
5486
|
+
// second Channel and no change of the bound session. It borrows the screen
|
|
5487
|
+
// the way the trajectory scene does; Chat stays mounted, so the parent's
|
|
5488
|
+
// rows, draft, pending queue and usage are untouched by the round trip.
|
|
5489
|
+
// Esc returns to wherever the view was opened from.
|
|
5490
|
+
if (agentView !== null && launchpadGate()) {
|
|
5491
|
+
const viewSubagent = channel.subagents.find(s => s.agentId === agentView.agentId);
|
|
5492
|
+
if (!viewSubagent) {
|
|
5493
|
+
// The roster lost this child (session switch): pop the view, don't crash.
|
|
5494
|
+
setAgentView(null);
|
|
5495
|
+
return null;
|
|
5496
|
+
}
|
|
5497
|
+
// Headless stubs mount Chat without a subagentControl at all.
|
|
5498
|
+
const messageControl = channel.subagentControl?.message;
|
|
5499
|
+
const loadTranscript = channel.subagentControl?.history;
|
|
5500
|
+
const viewMessages = messageControl === undefined ? [] : messageControl.messages().filter(m => m.from === agentView.agentId || m.to === agentView.agentId);
|
|
5501
|
+
const viewTarget = agentComposeTargetOf(agentView.agentId, new Map(channel.subagents.map(s => [s.agentId, s.description])));
|
|
5502
|
+
const viewScene = (_jsx(AgentTranscriptScene, { subagent: viewSubagent, source: agentView.source, onExit: () => exitAgentView(agentView.source), ...(loadTranscript === undefined ? {} : { loadTranscript }), messages: viewMessages, ...(messageControl === undefined ? {} : { compose: { control: messageControl, target: viewTarget } }), roster: channel.subagents,
|
|
5503
|
+
// Switching to a sibling or the parent swaps the viewed agent in
|
|
5504
|
+
// place; Esc still returns to the original entry point.
|
|
5505
|
+
onSwitchAgent: switchViewedAgent }));
|
|
5506
|
+
return fullscreen ? viewScene : _jsx(AlternateScreen, { children: viewScene });
|
|
5507
|
+
}
|
|
4205
5508
|
// Subagent detail scene: displays detailed view of a specific subagent.
|
|
4206
5509
|
// Like the browser and settings, it replaces the conversation entirely.
|
|
4207
|
-
if (subagentDetailId !== null) {
|
|
5510
|
+
if (subagentDetailId !== null && launchpadGate()) {
|
|
4208
5511
|
const subagent = channel.subagents.find(s => s.agentId === subagentDetailId);
|
|
4209
5512
|
if (!subagent) {
|
|
4210
|
-
// Agent not found, go back to dashboard
|
|
5513
|
+
// Agent not found, go back to the dashboard (side panel when split).
|
|
4211
5514
|
setSubagentDetailId(null);
|
|
4212
|
-
|
|
5515
|
+
openSubagentDashboard();
|
|
4213
5516
|
return null;
|
|
4214
5517
|
}
|
|
4215
|
-
const
|
|
5518
|
+
const detailControl = channel.subagentControl?.message;
|
|
5519
|
+
const detailMessages = detailControl === undefined ? [] : detailControl.messages().filter(m => m.from === subagent.agentId || m.to === subagent.agentId);
|
|
5520
|
+
const detailTarget = agentComposeTargetOf(subagent.agentId, new Map(channel.subagents.map(s => [s.agentId, s.description])));
|
|
5521
|
+
const scene = (_jsx(SubagentDetailScene, { subagent: subagent, onInterrupt: (id) => channel.subagentControl?.interrupt(id), ...(channel.subagentControl?.history === undefined ? {} : { loadTranscript: channel.subagentControl.history }), onOpenView: () => openAgentView(subagent.agentId, { kind: 'agent-detail', agentId: subagent.agentId }), messages: detailMessages, ...(detailControl === undefined ? {} : { compose: { control: detailControl, target: detailTarget } }), onBack: () => {
|
|
4216
5522
|
setSubagentDetailId(null);
|
|
4217
5523
|
setSubagentDashboardOpen(true);
|
|
4218
5524
|
} }));
|
|
@@ -4220,8 +5526,8 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
4220
5526
|
}
|
|
4221
5527
|
// Jobs panel: background jobs (running/killed) with kill/inspect actions.
|
|
4222
5528
|
// Like the browser and settings, it replaces the conversation entirely.
|
|
4223
|
-
if (jobsPanelOpen) {
|
|
4224
|
-
const panel = (_jsx(JobsPanel, { jobs: channel.backgroundJobs ?? [], onClose: () => setJobsPanelOpen(false), onKill: (id) => {
|
|
5529
|
+
if (jobsPanelOpen && launchpadGate()) {
|
|
5530
|
+
const panel = (_jsx(JobsPanel, { jobs: channel.backgroundJobs ?? [], initialFocusId: jobsPanelFocusId ?? undefined, onClose: () => { setJobsPanelOpen(false); setJobsPanelFocusId(null); }, onWatchOutput: watchJobOutput, onKill: (id) => {
|
|
4225
5531
|
// Stub channels (verify harnesses) have no jobControl — surface
|
|
4226
5532
|
// the same failure toast as a refused kill instead of throwing.
|
|
4227
5533
|
if (channel.jobControl?.kill(id) !== true) {
|
|
@@ -4230,19 +5536,28 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
4230
5536
|
} }));
|
|
4231
5537
|
return fullscreen ? panel : _jsx(AlternateScreen, { children: panel });
|
|
4232
5538
|
}
|
|
5539
|
+
// ⤢ btw thread scene (openPanelFullscreen 'btw'): the whole-terminal form
|
|
5540
|
+
// of the sidebar panel. Esc returns to the sidebar exactly as it was — the
|
|
5541
|
+
// thread and the composer draft live in btwThreads, nothing is cleared.
|
|
5542
|
+
if (btwSceneOpen && launchpadGate()) {
|
|
5543
|
+
const scene = (_jsx(BtwThreadScene, { channel: channel, onClose: () => setBtwSceneOpen(false) }));
|
|
5544
|
+
return fullscreen ? scene : _jsx(AlternateScreen, { children: scene });
|
|
5545
|
+
}
|
|
4233
5546
|
// Subagent dashboard: displays all active and completed subagents.
|
|
4234
5547
|
// Like the browser and settings, it replaces the conversation entirely.
|
|
4235
|
-
if (subagentDashboardOpen) {
|
|
5548
|
+
if (subagentDashboardOpen && launchpadGate()) {
|
|
5549
|
+
// No kernel serves agents from other sessions yet, so the dashboard gets
|
|
5550
|
+
// no `peers`; once one does, pass them here.
|
|
4236
5551
|
const dashboard = (_jsx(SubagentDashboard, { subagents: [...channel.subagents], onSelect: (id) => {
|
|
4237
5552
|
setSubagentDashboardOpen(false);
|
|
4238
5553
|
setSubagentDetailId(id);
|
|
4239
|
-
}, onClose: () => setSubagentDashboardOpen(false) }));
|
|
5554
|
+
}, onOpenView: (id) => openAgentView(id, { kind: 'agents-dashboard' }), messages: channel.subagentControl?.message?.messages(), onClose: () => setSubagentDashboardOpen(false) }));
|
|
4240
5555
|
return fullscreen ? dashboard : _jsx(AlternateScreen, { children: dashboard });
|
|
4241
5556
|
}
|
|
4242
5557
|
/** Prompt input is inert while a modal dialog owns the keyboard. The
|
|
4243
5558
|
* overlay union covers every picker/dialog and /tips in one check;
|
|
4244
5559
|
* message-selection mode and the /btw panel live outside it. */
|
|
4245
|
-
const promptSelectionActive = selectionActive || overlay.kind !== 'none' ||
|
|
5560
|
+
const promptSelectionActive = selectionActive || overlay.kind !== 'none' || btwOverlayOpen;
|
|
4246
5561
|
// These panels replace the visible composer, but PromptInput remains
|
|
4247
5562
|
// mounted (suspended) so an async registry command cannot lose its exact
|
|
4248
5563
|
// text/image draft while it waits for a user decision.
|
|
@@ -4250,7 +5565,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
4250
5565
|
|| dialogSnapshot !== null
|
|
4251
5566
|
|| overlay.kind === 'tips'
|
|
4252
5567
|
|| (recap !== null && (!recap.auto || recap.expanded))
|
|
4253
|
-
||
|
|
5568
|
+
|| btwOverlayOpen
|
|
4254
5569
|
|| questionPanelNode !== null
|
|
4255
5570
|
|| starModal !== null
|
|
4256
5571
|
|| couponVisible;
|
|
@@ -4262,10 +5577,158 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
4262
5577
|
// `<AlternateScreen>` is skipped when the app is already fullscreen —
|
|
4263
5578
|
// nesting it would emit a second DEC 1049, and its unmount would drop the
|
|
4264
5579
|
// whole app back to the main screen.
|
|
4265
|
-
if (sceneOpen) {
|
|
5580
|
+
if (sceneOpen && launchpadGate()) {
|
|
4266
5581
|
const scene = _jsx(TrajectoryScene, { channel: channel, build: trajectory, onClose: closeScene });
|
|
4267
5582
|
return fullscreen ? scene : _jsx(AlternateScreen, { children: scene });
|
|
4268
5583
|
}
|
|
5584
|
+
/**
|
|
5585
|
+
* The launchpad — the landing page an ordinary launch starts on.
|
|
5586
|
+
*
|
|
5587
|
+
* 第七版渲染姿态:early-return 排在**所有整屏界面(会话浏览器 / 设置 /
|
|
5588
|
+
* 任务面板 / 家谱 / 子代理 / 轨迹场景)之后**——从落地页打开的整屏盖在
|
|
5589
|
+
* 落地页之上,Esc 退出整屏回到这里(草稿/参数/焦点原样保留)。硬约束:
|
|
5590
|
+
* 从启动页进入对话页的唯一路径是**提交一条非命令消息**(Enter 发送);
|
|
5591
|
+
* 任何 Esc/返回都回到启动页。参数行点开的选择器经 `pickerPanels` +
|
|
5592
|
+
* `inputPaused` 渲染在本屏之上,Esc 关掉它也回到这里。
|
|
5593
|
+
*/
|
|
5594
|
+
if (launchpadShown) {
|
|
5595
|
+
// 参数行的「模式/权限」两段(第三版):模式看 channel.mode.plan;权限看
|
|
5596
|
+
// permissionPresets() 的当前身份——只认 runtime 名册,legacy/unavailable 与
|
|
5597
|
+
// 抛错都按「拿不到」处理(缺省不画那一段,两段都可选)。
|
|
5598
|
+
let launchpadPermission;
|
|
5599
|
+
try {
|
|
5600
|
+
const snapshot = channel.permissionPresets();
|
|
5601
|
+
launchpadPermission = snapshot.availability === 'runtime' ? snapshot.current?.name : undefined;
|
|
5602
|
+
}
|
|
5603
|
+
catch {
|
|
5604
|
+
launchpadPermission = undefined;
|
|
5605
|
+
}
|
|
5606
|
+
// 第七版动作表:状态快照全部来自既有数据源(详见 launchpadActions.ts)——
|
|
5607
|
+
// - lastSessionTitle = agentViewRows(含持久化名册)里最近一条非当前会话
|
|
5608
|
+
// 的标题——listing 是异步的,落地前没有 Continue、落地后自动长出来;
|
|
5609
|
+
// - jobsRunning / updateAvailable / starDue = 条件位三连(后台任务面 /
|
|
5610
|
+
// checkForTuiUpdate / usageStats 里程碑口径)。
|
|
5611
|
+
const resumableRows = agentViewRows
|
|
5612
|
+
.filter(row => !row.current && row.id !== channel.agentId && row.title.trim() !== '');
|
|
5613
|
+
const latestRow = resumableRows.reduce((best, row) => (best === undefined || row.updatedAt > best.updatedAt ? row : best), undefined);
|
|
5614
|
+
const launchpadActions = resolveLaunchpadActions({
|
|
5615
|
+
lastSessionTitle: latestRow?.title,
|
|
5616
|
+
// 条件位①:后台任务面是真数据(JobsPanel 同一个 channel.backgroundJobs),
|
|
5617
|
+
// running/stopping 都算「在跑」。
|
|
5618
|
+
jobsRunning: (channel.backgroundJobs ?? []).some(job => job.status === 'running' || job.status === 'stopping'),
|
|
5619
|
+
updateAvailable: launchpadUpdateAvailable,
|
|
5620
|
+
starDue: launchpadStarDue,
|
|
5621
|
+
// 内核入口带名(「内核 · Claude」):backendId 是内核身份的唯一来源。
|
|
5622
|
+
backendId: kernelCurrentId,
|
|
5623
|
+
});
|
|
5624
|
+
const launchpad = (_jsx(Launchpad, { query: launchpadDraft, cursorOffset: launchpadCaret, focusIndex: launchpadFocus, isTerminalFocused: terminalFocused, whale: channel.whale, whaleIdle: channel.whaleIdle, whaleGirl: channel.whaleGirl, fontId: splashFontIdOf(channel.splashFont), brand: brand, starred: starred, onStarClick: runStarAction, firstRun: onboardingPending, actions: launchpadActions,
|
|
5625
|
+
// 参数行四段点开的既有选择器(第五版):pickerPanels 与聊天页共用
|
|
5626
|
+
// 同一份 JSX,盖在落地页之上;选择器开着时落地页键盘让位(inputPaused)。
|
|
5627
|
+
overlayPanel: launchpadOverlayUp ? pickerPanels : undefined, inputPaused: launchpadOverlayUp, onParamPick: (segment) => {
|
|
5628
|
+
// 四段 → 既有命令:model→/model、effort→/effort、preset→/preset、
|
|
5629
|
+
// permission→/permission。全部在 overlayCommandNames 白名单里,
|
|
5630
|
+
// 落地页不收,选择器盖上来。
|
|
5631
|
+
// 第八版切换式(用户原话「点一下是展开 再点一下收起来」):**同一段**
|
|
5632
|
+
// 再点/再按 Enter = 收起(展开 ↔ 收起,键盘与鼠标同一条 onParamPick)。
|
|
5633
|
+
// 点另一段仍直接切换,点空白/Esc 仍收起(上一版契约不回退)。
|
|
5634
|
+
if (overlay.kind === segment) {
|
|
5635
|
+
dispatchOverlay({ type: 'close' });
|
|
5636
|
+
return;
|
|
5637
|
+
}
|
|
5638
|
+
// BUG 3(点另一段直接切换):/effort 的选择器是异步 open-if(when:
|
|
5639
|
+
// ['none']),盖着别的选择器时会被丢弃——这就是"点了没反应"的根因。
|
|
5640
|
+
// 先把屏上的参数选择器收掉再开新的,一个在屏、且就是点的那段。
|
|
5641
|
+
if (overlay.kind !== 'none') {
|
|
5642
|
+
dispatchOverlay({ type: 'close' });
|
|
5643
|
+
}
|
|
5644
|
+
void runCommand(segment, '');
|
|
5645
|
+
}, onQueryChange: (text, cursor) => {
|
|
5646
|
+
setLaunchpadDraft(text);
|
|
5647
|
+
setLaunchpadCaret(cursor);
|
|
5648
|
+
}, onSubmit: closeLaunchpad, onFocusChange: setLaunchpadFocus, onAction: (action) => {
|
|
5649
|
+
// 第八版(用户实测:「刚点帮助,不知道为什么直接进入聊天页面了」):
|
|
5650
|
+
// 帮助**不属于**离开启动页的两条路(Enter 发非命令消息 / 会话浏览
|
|
5651
|
+
// 里选中会话)——它盖在落地页之上(overlay kind 'help'),再点同一
|
|
5652
|
+
// 入口 = 收起(与参数段同一条切换语义)。
|
|
5653
|
+
if (action.command === 'help') {
|
|
5654
|
+
dispatchOverlay(overlay.kind === 'help'
|
|
5655
|
+
? { type: 'close' }
|
|
5656
|
+
: { type: 'open', overlay: { kind: 'help' } });
|
|
5657
|
+
return;
|
|
5658
|
+
}
|
|
5659
|
+
// 第七版姿态:覆盖层命令(overlayCommandNames)盖在落地页之上;
|
|
5660
|
+
// **整屏命令**(launchpadScreenCommands:会话与工作区 / 设置 / 后台
|
|
5661
|
+
// 任务 / 家谱 / 子代理 / 引导)也盖在落地页之上——落地页不收,
|
|
5662
|
+
// Esc 退出整屏回到落地页(草稿/参数/焦点都在)。整屏要先过
|
|
5663
|
+
// launchpadGate 的授权位(防御:异步误置的整屏状态盖不走启动页)。
|
|
5664
|
+
// 其余命令(star / update——反馈在对话页的转录/通知)仍收掉落地页
|
|
5665
|
+
// 再执行,这是用户主动执行命令,不是「返回」。
|
|
5666
|
+
if (launchpadScreenCommands.has(action.command)) {
|
|
5667
|
+
authorizeLaunchpadCover();
|
|
5668
|
+
}
|
|
5669
|
+
else if (!overlayCommandNames.has(action.command)) {
|
|
5670
|
+
setLaunchpadOpen(false);
|
|
5671
|
+
}
|
|
5672
|
+
void runCommand(action.command, '');
|
|
5673
|
+
}, onEscape: (intent) => {
|
|
5674
|
+
if (intent === 'exit') {
|
|
5675
|
+
requestExit();
|
|
5676
|
+
return;
|
|
5677
|
+
}
|
|
5678
|
+
// 空输入按 Esc:这一屏的"下一步"通常是去挑工作区/会话。第七版:
|
|
5679
|
+
// 会话浏览器**盖在落地页之上**(落地页不收)——Esc 退出浏览器回到
|
|
5680
|
+
// 落地页,绝不落到对话页。这是从落地页出发的交互:过闸门授权。
|
|
5681
|
+
agentViewOpenSessionRef.current = channel.agentId;
|
|
5682
|
+
authorizeLaunchpadCover();
|
|
5683
|
+
setSupervisorOpen(true);
|
|
5684
|
+
}, onBlankClick: () => {
|
|
5685
|
+
// BUG 3(点别处关掉选择器):沿用"点空白收回焦点"的兜底路径——
|
|
5686
|
+
// 有参数选择器盖在落地页之上时,空白点击先把选择器收掉(焦点照旧
|
|
5687
|
+
// 收回输入框)。选择器内部的点击已被 Launchpad 的浮层包装拦住
|
|
5688
|
+
// 冒泡,不会走到这里。
|
|
5689
|
+
if (overlay.kind !== 'none')
|
|
5690
|
+
dispatchOverlay({ type: 'close' });
|
|
5691
|
+
setLaunchpadFocus(-1);
|
|
5692
|
+
}, model: channel.modelDisplay ?? channel.model, effort: channel.reasoningEffort, preset: channel.agentPreset === undefined
|
|
5693
|
+
? undefined
|
|
5694
|
+
: presetOptions.find(option => option.id === channel.agentPreset)?.name ?? channel.agentPreset, permission: launchpadPermission, commands: launchpadOverlayUp || !launchpadDraft.startsWith('/')
|
|
5695
|
+
? undefined
|
|
5696
|
+
: channel.commandCompletions(launchpadDraft), onCommandPick: (commandLine) => {
|
|
5697
|
+
// 补全面板选中(Enter/Tab/点击):走 runCommand,与快捷入口同一条
|
|
5698
|
+
// 白名单口径——覆盖层与整屏命令(第七版 launchpadScreenCommands)
|
|
5699
|
+
// 不收落地页(盖在它之上),其余收掉再执行。/help 与快捷入口同一条
|
|
5700
|
+
// 拦截:盖屏浮层,不进对话页(第八版)。
|
|
5701
|
+
const parsed = parseCommandName(commandLine);
|
|
5702
|
+
if (parsed === undefined)
|
|
5703
|
+
return;
|
|
5704
|
+
if (parsed.name === 'help') {
|
|
5705
|
+
dispatchOverlay({ type: 'open', overlay: { kind: 'help' } });
|
|
5706
|
+
return;
|
|
5707
|
+
}
|
|
5708
|
+
if (launchpadScreenCommands.has(parsed.name)) {
|
|
5709
|
+
authorizeLaunchpadCover();
|
|
5710
|
+
}
|
|
5711
|
+
else if (!overlayCommandNames.has(parsed.name)) {
|
|
5712
|
+
setLaunchpadOpen(false);
|
|
5713
|
+
}
|
|
5714
|
+
void runCommand(parsed.name, parsed.rawInput);
|
|
5715
|
+
}, cwd: channel.displayCwd, branch: channel.gitBranch, tuiVersion: tuiVersion,
|
|
5716
|
+
// 右下角的内核行:与选择器同一份目录,标出当前内核,点它打开选择器。
|
|
5717
|
+
kernels: kernelOptions, onKernelPick: () => openKernelPicker(),
|
|
5718
|
+
// 左下角工作目录铭牌(第七版):点开/回车开既有 /workspace 菜单——
|
|
5719
|
+
// workspace-menu 在 LAUNCHPAD_OVERLAY_KINDS 里,选择器盖在落地页之上,
|
|
5720
|
+
// Esc 回落地页(与参数行选择器同一姿态),不新造面板。
|
|
5721
|
+
onOpenWorkspace: () => { void runCommand('workspace', ''); } }));
|
|
5722
|
+
// 落地页这一屏的完整树(AC-4):Tooltip 单例层挂在**最外层最后**——与下面
|
|
5723
|
+
// 聊天主树末尾那处(SidePanelLayout 里)是同一个组件、同一条"单例层挂树尾"
|
|
5724
|
+
// 姿态;参数行被截断的段(ParamChip 写的锚点)hover 600ms 后由它画完整名。
|
|
5725
|
+
// 本屏没有滚动、也没有面板几何过渡 ⇒ 不需要 subscribeInvalidation;但**必须**给
|
|
5726
|
+
// invalidationKey:选择器是**盖在落地页之上**的浮层,落地页不卸载、指针也不一定
|
|
5727
|
+
// 离开被悬停的那一段,没有这个键时旧卡片会继续画在选择器上方(复核场景回归见
|
|
5728
|
+
// `verify-launchpad-onboarding-chat` 的 R4)。
|
|
5729
|
+
const node = (_jsxs(_Fragment, { children: [launchpad, _jsx(TooltipLayer, { invalidationKey: overlay.kind })] }));
|
|
5730
|
+
return fullscreen ? node : _jsx(AlternateScreen, { children: node });
|
|
5731
|
+
}
|
|
4269
5732
|
// 浮层整体挂载条件:与内部各面板的可见条件同值(数据门在
|
|
4270
5733
|
// dialogOverlayVisible 里逐面板镜像)。关闭时把整个 absolute 浮层从树里
|
|
4271
5734
|
// 移除——渲染器的"移除 absolute 节点"检测只看被移除子树自身的
|
|
@@ -4276,6 +5739,7 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
4276
5739
|
workspaceTargetCount: workspaceTargets.length,
|
|
4277
5740
|
effortOptionCount: effortOptions.length,
|
|
4278
5741
|
presetOptionCount: presetOptions.length,
|
|
5742
|
+
panelCount: panelPickerRows.length,
|
|
4279
5743
|
}) && !(overlay.kind === 'permission'
|
|
4280
5744
|
&& (approvalSnapshot !== null || questionSnapshot !== null || dialogSnapshot !== null));
|
|
4281
5745
|
// The sticky header pins the turn owning the viewport top row once its
|
|
@@ -4298,8 +5762,8 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
4298
5762
|
// the transcript viewport height from the ScrollBox handle and the content
|
|
4299
5763
|
// column width. The full-screen (editor-open) placement uses the terminal.
|
|
4300
5764
|
const imagePreviewRegion = promptEditorOpen
|
|
4301
|
-
? { columns:
|
|
4302
|
-
: { columns:
|
|
5765
|
+
? { columns: chatColumns, rows: terminalRows }
|
|
5766
|
+
: { columns: chatColumns, rows: handle?.getViewportHeight() ?? terminalRows };
|
|
4303
5767
|
const imagePreviewNode = activePreview !== null && (activePreview.peek || imagePreviewOwned)
|
|
4304
5768
|
? (_jsx(ImagePreviewOverlay, { image: activePreview.image, title: activePreview.title, navigation: previewGallery.length > 1 && previewIndex >= 0 ? {
|
|
4305
5769
|
index: previewIndex, total: previewGallery.length,
|
|
@@ -4308,253 +5772,128 @@ export function Chat({ channel, questionStore, approvalStore, extensionDialogs,
|
|
|
4308
5772
|
? () => setPeekSuppressed(peekKey(activePreview.image, activePreview.title))
|
|
4309
5773
|
: () => dispatchOverlay({ type: 'close-if', kind: 'image-preview' }), region: imagePreviewRegion }))
|
|
4310
5774
|
: null;
|
|
4311
|
-
return (_jsxs(Box, { ref: wakeTickRef, flexDirection: "column", flexGrow: 1, width: "100%", children: [
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
if (recap.auto) {
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
}
|
|
4373
|
-
}, onCopy: () => {
|
|
4374
|
-
void setClipboard(recap.summary ?? '').then(raw => { if (raw)
|
|
4375
|
-
writeRaw?.(raw); });
|
|
4376
|
-
channel.notify(t('copied-chars', { n: (recap.summary ?? '').length }), { timeoutMs: 1500 });
|
|
4377
|
-
}, onApplyTitle: () => {
|
|
4378
|
-
if (recap.title === undefined || recap.titleApplied)
|
|
4379
|
-
return;
|
|
4380
|
-
channel.renameSession(recap.title);
|
|
4381
|
-
setRecap(prev => (prev ? { ...prev, titleApplied: true } : prev));
|
|
4382
|
-
channel.notify(t('recap-title-applied-notify', { title: recap.title }), { color: 'success' });
|
|
4383
|
-
} }) })) : btw !== null ? (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(BtwPanel, { question: btw.question, answer: btw.answer, error: btw.error, streaming: !btw.done, onClose: closeBtw, onCopy: () => {
|
|
4384
|
-
void setClipboard(btw.answer ?? '').then(raw => { if (raw)
|
|
4385
|
-
writeRaw?.(raw); });
|
|
4386
|
-
channel.notify(t('copied-chars', { n: (btw.answer ?? '').length }), { timeoutMs: 1500 });
|
|
4387
|
-
} }) })) : questionPanelNode !== null ? (questionPanelNode) : null, _jsx(PromptInput, { channel: channel, suspended: promptReplacementOpen, draftCache: promptDraftRef.current, helpOpen: helpOpen, onToggleHelp: () => { setHelpOpen(previous => !previous); }, onRunCommand: runCommand, selectionActive: promptSelectionActive, fillText: historyFill, onFillConsumed: () => setHistoryFill(null), onRewindRequest: openRewind, onBackgroundRequest: backgroundToAgentView,
|
|
4388
|
-
// The 🏠 at the head of the input row opens the same session screen
|
|
4389
|
-
// `/resume` and `/agentview` open — one surface, three doors. It is
|
|
4390
|
-
// gated on this prop rather than a setting, so hosts that mount the
|
|
4391
|
-
// prompt without a session screen (and the layout regressions that
|
|
4392
|
-
// pin the row's column budget) keep the row they had.
|
|
4393
|
-
onOpenSessions: () => {
|
|
4394
|
-
agentViewOpenSessionRef.current = channel.agentId;
|
|
4395
|
-
setSupervisorOpen(true);
|
|
4396
|
-
}, backgroundAgentsNeedingInput:
|
|
4397
|
-
// Only the real channel supplies the seam; pre-agent-view test
|
|
4398
|
-
// stubs must not grow the footer row (layout-dependent
|
|
4399
|
-
// regressions pin the visible row count). The footer only
|
|
4400
|
-
// renders while some session actually waits (N > 0): a
|
|
4401
|
-
// permanent idle row would steal a transcript row on every
|
|
4402
|
-
// real channel — one row is enough to scroll the startup
|
|
4403
|
-
// header fully off a short terminal, pausing its viewport
|
|
4404
|
-
// clock and shifting every row-count layout invariant.
|
|
4405
|
-
channel.agentViewRows !== undefined && backgroundAgentsNeedingInput > 0
|
|
4406
|
-
? backgroundAgentsNeedingInput
|
|
4407
|
-
: undefined, controllerRef: promptControllerRef, onCaretImage: handleCaretImage, caretPreviewOpen: peekPreview !== null, onDismissCaretPreview: dismissPeek }, "prompt-input"), _jsx(StatusLine, { channel: channel, activity: workingActivity, selectionActive: selectionActive, helpOpen: helpOpen, wake: wakeBand === undefined
|
|
4408
|
-
? undefined
|
|
4409
|
-
: {
|
|
4410
|
-
band: wakeBand,
|
|
4411
|
-
hint: trajectorySeen ? undefined : primaryComboString('trajectory'),
|
|
4412
|
-
tick: Math.floor(wakeTime / 120),
|
|
4413
|
-
onOpen: openScene,
|
|
4414
|
-
hoverHint: primaryComboString('trajectory'),
|
|
4415
|
-
} }), dialogOverlayOpen && (_jsxs(OverlayAbove, { maxHeight: Math.max(terminalRows - 8, 1), children: [overlay.kind === 'thinking' && (_jsx(ThinkingToggle, { currentValue: thinkingVisible, focusIndex: overlay.focus, onPick: (index) => {
|
|
4416
|
-
// 点击行 = 设焦点 + 应用(与 Enter 同一条路径)
|
|
4417
|
-
const visible = index === 0;
|
|
4418
|
-
setThinkingVisible(visible);
|
|
4419
|
-
dispatchOverlay({ type: 'close' });
|
|
4420
|
-
channel.notify(t('thinking-toggled', { state: visible ? t('thinking-on') : t('thinking-off') }));
|
|
4421
|
-
} })), overlay.kind === 'workspace-picker' && workspaceTargets.length > 0 && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(WorkspacePicker, { targets: workspaceTargets, focusIndex: overlay.index, currentCwd: channel.cwd, onPick: (index) => {
|
|
4422
|
-
// 点击行 = 切换该行目标(与 Enter 同一条路径)
|
|
4423
|
-
const target = workspaceTargets[index];
|
|
4424
|
-
dispatchOverlay({ type: 'close' });
|
|
4425
|
-
if (target !== undefined)
|
|
4426
|
-
void channel.switchWorkspace(target);
|
|
4427
|
-
} }) })), overlay.kind === 'workspace-menu' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(WorkspaceMenuPicker, { options: workspaceMenuOptions, focusIndex: overlay.index, onPick: (index) => {
|
|
4428
|
-
// 点击行 = 执行该行(与 Enter 同一条路径)
|
|
4429
|
-
runWorkspaceMenuOption(workspaceMenuOptions[index]);
|
|
4430
|
-
} }) })), overlay.kind === 'workspace-flow' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(WorkspaceFlowPicker, { title: overlay.flow.title, choices: overlay.flow.choices, focusIndex: overlay.index, busy: overlay.busy, input: overlay.input, onPick: (index) => {
|
|
4431
|
-
// 点击行 = 设焦点 + 执行分支(与 Enter 同一条路径);
|
|
4432
|
-
// busy/输入态在组件侧禁点
|
|
4433
|
-
const choice = overlay.flow.choices[index];
|
|
4434
|
-
if (choice === undefined)
|
|
4435
|
-
return;
|
|
4436
|
-
dispatchOverlay({ type: 'set-index', kind: 'workspace-flow', index });
|
|
4437
|
-
runWorkspaceFlowAction(signal => choice.choose(signal));
|
|
4438
|
-
} }) })), overlay.kind === 'model' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: models.length === 0 ? (_jsx(ModelPickerLoading, {})) : activeModelGroup === undefined ? (_jsx(ModelPicker, { groups: modelGroups, focusIndex: overlay.index, currentProvider: channel.provider, onPick: (index) => {
|
|
4439
|
-
// 点击分组行 = 进入该组(与 Enter 同一条路径)
|
|
4440
|
-
const group = modelGroups[index];
|
|
4441
|
-
if (!group)
|
|
4442
|
-
return;
|
|
4443
|
-
setModelGroup(group.provider);
|
|
4444
|
-
if (group.provider === RECENTS_GROUP_PROVIDER) {
|
|
4445
|
-
dispatchOverlay({ type: 'set-index', kind: 'model', index: 0 });
|
|
4446
|
-
return;
|
|
4447
|
-
}
|
|
4448
|
-
const landing = modelPickerLanding(models.filter(model => model.provider === group.provider), channel.provider, channel.model);
|
|
4449
|
-
dispatchOverlay({ type: 'set-index', kind: 'model', index: landing.index });
|
|
4450
|
-
} })) : (_jsx(ModelPicker, { models: groupModels, groupLabel: activeModelGroup === RECENTS_GROUP_PROVIDER
|
|
4451
|
-
? t('picker-group-recent')
|
|
4452
|
-
: modelGroups.find(group => group.provider === activeModelGroup)?.label, showBack: modelGroups.length > 1 && !modelPickerDirect, showProviderPrefix: activeModelGroup === RECENTS_GROUP_PROVIDER, focusIndex: overlay.index, currentModel: `${channel.provider}/${channel.model}`, onPick: (index) => {
|
|
4453
|
-
// 点击行 = 应用该行模型(与 Enter 同一条路径)
|
|
4454
|
-
const model = groupModels[index];
|
|
4455
|
-
if (!model)
|
|
4456
|
-
return;
|
|
4457
|
-
dispatchOverlay({ type: 'close' });
|
|
4458
|
-
void switchModelRecorded(model.provider, model.id, model.name);
|
|
4459
|
-
} })) })), overlay.kind === 'migrate' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(MigratePicker, { rows: migrateRows ?? [], focusIndex: overlay.index, checked: migrateChecked, loading: migrateRows === null, onPick: (index) => {
|
|
4460
|
-
const row = (migrateRows ?? [])[index];
|
|
4461
|
-
if (!row)
|
|
4462
|
-
return;
|
|
4463
|
-
setMigrateChecked(current => {
|
|
4464
|
-
const next = new Set(current);
|
|
4465
|
-
if (next.has(row.agentId))
|
|
4466
|
-
next.delete(row.agentId);
|
|
4467
|
-
else
|
|
4468
|
-
next.add(row.agentId);
|
|
4469
|
-
return next;
|
|
4470
|
-
});
|
|
4471
|
-
} }) })), overlay.kind === 'migrate-confirm' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(MigrateConfirm, { rows: migratePending }) })), overlay.kind === 'skills' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: skillsList === null ? (_jsx(SkillsPickerLoading, {})) : (_jsx(SkillsPicker, { skills: skillsList, focusIndex: overlay.index, onPick: (index) => {
|
|
4472
|
-
const skill = skillsList[index];
|
|
4473
|
-
if (!skill)
|
|
4474
|
-
return;
|
|
4475
|
-
dispatchOverlay({ type: 'close' });
|
|
4476
|
-
if (skill.userInvocable)
|
|
4477
|
-
setHistoryFill(`/${skill.name} `);
|
|
4478
|
-
} })) })), overlay.kind === 'activity' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(ActivityPicker, { focusIndex: overlay.index, currentPreset: channel.activityFrames, onPick: (index) => {
|
|
4479
|
-
dispatchOverlay({ type: 'close' });
|
|
4480
|
-
const name = PRESET_NAMES[index];
|
|
4481
|
-
if (name)
|
|
4482
|
-
channel.setActivityFrames(name);
|
|
4483
|
-
} }) })), overlay.kind === 'color' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(ColorPicker, { focusIndex: overlay.index, currentColor: channel.sessionColor, onPick: (index) => {
|
|
4484
|
-
dispatchOverlay({ type: 'close' });
|
|
4485
|
-
const name = SESSION_COLOR_NAMES[index];
|
|
4486
|
-
if (name) {
|
|
4487
|
-
channel.setSessionColor(name);
|
|
4488
|
-
channel.notify(t('color-set', { name }), { color: 'success' });
|
|
4489
|
-
}
|
|
4490
|
-
} }) })), overlay.kind === 'effort' && effortOptions.length > 1 && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(EffortSlider, { options: effortOptions, focusIndex: overlay.index, currentId: channel.reasoningEffort,
|
|
4491
|
-
// 点击档位 = 移到该档并即时应用(与 ←/→ 同语义)
|
|
4492
|
-
onPick: (index) => {
|
|
4493
|
-
dispatchOverlay({ type: 'set-index', kind: 'effort', index });
|
|
4494
|
-
const option = effortOptions[index];
|
|
4495
|
-
if (option)
|
|
4496
|
-
void channel.setEffort(option.id);
|
|
4497
|
-
} }) })), overlay.kind === 'preset' && presetOptions.length > 0 && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(PresetPicker, { presets: presetOptions, focusIndex: overlay.index, currentPreset: channel.agentPreset, onPick: (index) => {
|
|
4498
|
-
dispatchOverlay({ type: 'close' });
|
|
4499
|
-
const option = presetOptions[index];
|
|
4500
|
-
if (option)
|
|
4501
|
-
void channel.switchPreset(option.id);
|
|
4502
|
-
} }) })), overlay.kind === 'permission' && overlay.snapshot.options.length > 0 && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(PermissionsPicker, { options: overlay.snapshot.options, focusIndex: overlay.index, currentValue: overlay.snapshot.current?.value, cwd: channel.cwd, onPick: (index) => {
|
|
4503
|
-
if (approvalSnapshot !== null || questionSnapshot !== null || dialogSnapshot !== null)
|
|
4504
|
-
return;
|
|
4505
|
-
const option = overlay.snapshot.options[index];
|
|
4506
|
-
dispatchOverlay({ type: 'close' });
|
|
4507
|
-
if (option !== undefined)
|
|
4508
|
-
void runPermissionCommand(` ${option.value}`);
|
|
4509
|
-
} }) })), overlay.kind === 'plan' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(PlanPicker, { focusIndex: overlay.index, currentOn: channel.mode.plan === true, onPick: (index) => {
|
|
4510
|
-
dispatchOverlay({ type: 'close' });
|
|
4511
|
-
const on = index === 0;
|
|
4512
|
-
void runExternalCommand('plan', on ? '' : ' off');
|
|
4513
|
-
} }) })), overlay.kind === 'lang' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(LangPicker, { focusIndex: overlay.index, currentLang: getLang(), onPick: (index) => {
|
|
4514
|
-
const lang = LANGS[index];
|
|
4515
|
-
if (lang === undefined)
|
|
4516
|
-
return;
|
|
4517
|
-
dispatchOverlay({ type: 'close' });
|
|
4518
|
-
applyLang(lang);
|
|
4519
|
-
} }) })), overlay.kind === 'theme' && (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(ThemePicker, { focusIndex: overlay.index, currentTheme: themeName, themeHost: themeHost, onPick: (index) => {
|
|
4520
|
-
dispatchOverlay({ type: 'close' });
|
|
4521
|
-
const name = getThemeOptions(themeHost)[index]?.value;
|
|
4522
|
-
if (name !== undefined) {
|
|
4523
|
-
const ok = setTheme(name);
|
|
4524
|
-
channel.notify(ok ? t('theme-switched-saved', { name }) : t('theme-switch-failed', { name }), { color: ok ? 'success' : 'error' });
|
|
5775
|
+
return (_jsxs(Box, { ref: wakeTickRef, flexDirection: "column", flexGrow: 1, width: "100%", children: [_jsxs(SidePanelLayout, { geometry: sidePanel.geometry, focus: sidePanel.focus, onActivateChat: sidePanel.focusChat, onActivatePanel: sidePanel.focusPanel, side: _jsx(SidePanelColumn, { width: sidePanel.panelColumns, controller: sidePanel, channel: channel, activity: workingActivity, attention: {
|
|
5776
|
+
approvals: approvalSnapshot !== null ? 1 : 0,
|
|
5777
|
+
questions: questionSnapshot !== null ? 1 : 0,
|
|
5778
|
+
}, trajectory: trajectory, onExpand: openPanelFullscreen }), children: [!isSticky && timeline.activeId !== null && (_jsx(PinnedTurnHeader, { text: anchorUserText || null, onClick: () => {
|
|
5779
|
+
// Click snaps the pinned prompt to the viewport top. Jump by the
|
|
5780
|
+
// SAME content coordinate the
|
|
5781
|
+
// rail's tick uses (timeline turn top = the prompt TEXT top):
|
|
5782
|
+
// the element-based seek lands the row wrapper's margin at the
|
|
5783
|
+
// top instead — one row shy of the text top the anchor rule
|
|
5784
|
+
// compares against — and the header would flip to the previous
|
|
5785
|
+
// turn immediately after the click.
|
|
5786
|
+
const turn = timeline.turns.find(t => t.id === anchorUserRowId);
|
|
5787
|
+
if (turn)
|
|
5788
|
+
handle?.scrollTo(turn.top);
|
|
5789
|
+
else if (anchorUserRowId !== null)
|
|
5790
|
+
seekRow(anchorUserRowId);
|
|
5791
|
+
else
|
|
5792
|
+
handle?.scrollToBottom();
|
|
5793
|
+
} })), _jsxs(Box, { flexDirection: "row", flexGrow: 1, flexShrink: 1, marginRight: sidePanel.split ? 0 : -pageInsetX, children: [_jsxs(ScrollBox, { ref: setHandle, flexDirection: "column", flexGrow: 1, flexShrink: 1, stickyScroll: true, children: [_jsx(LogoHeader, { model: channel.modelDisplay ?? channel.model, effort: channel.reasoningEffort, cwd: channel.displayCwd,
|
|
5794
|
+
// 大字字面(设置项 `dsh-tui.splashFont`):`daily` 交回按天轮换
|
|
5795
|
+
// (`undefined`),其余 pin 住一款。
|
|
5796
|
+
fontId: splashFontIdOf(channel.splashFont), whale: channel.whale, whaleIdle: channel.whaleIdle && whaleArtVisible, whaleGirl: channel.whaleGirl, brand: brand, starred: starred, onStarClick: runStarAction, working: channel.working,
|
|
5797
|
+
// Resuming a long session skips the ~3.4s opening animation: it
|
|
5798
|
+
// keeps firing low-frequency React commits that compete with the
|
|
5799
|
+
// transcript mount batches (and the first wheel events) for the
|
|
5800
|
+
// frame budget right when the user wants to read history. Fresh
|
|
5801
|
+
// sessions keep the full intro; restored ones settle instantly.
|
|
5802
|
+
// A remount after a whole screen closed also settles instantly
|
|
5803
|
+
// (see suppressLogoIntroRef).
|
|
5804
|
+
skipIntro: suppressLogoIntroRef.current || channel.rows.length > 30 }, logoNonce), loadedContextVisible && (_jsx(LoadedContextPanel, { context: channel.loadedContext, open: loadedContextOpen, onToggle: toggleLoadedContext })), _jsx(MessageList, { rows: channel.rows, failureHintRowId: failureHintRowId, failureHint: t('traj-hint-failure', { key: primaryComboString('trajectory') }), expanded: expanded, expandedRows: expandedRows, selectedId: selectionActive ? selectedId : null, onToggleRow: toggleRowExpanded, streamViewToggledRows: streamViewToggledRows, onToggleStreamView: toggleStreamView, model: channel.modelDisplay ?? channel.model, diffLayout: channel.diffLayout, thinkingFold: channel.thinkingFold, jobGroupFold: channel.jobGroupFold, toolBackground: channel.toolBackground, foldTerminalCommand: channel.foldTerminalCommand, turnUsageRow: channel.turnUsageRow, smoothStreaming: channel.smoothStreaming, activityFrames: channel.activityFrames, showAll: showAllMessages, thinkingVisible: thinkingVisible, historyPaintEnabled: !fullscreen, fullscreen: fullscreen, onToggleAll: () => { setShowAllMessages(previous => !previous); }, onLoadOlder: () => channel.loadOlder(), registerRowRef: registerRowRef, scrollHandle: handle, forceMountRowId: forceMountRowId, newSinceRowId: isSticky ? null : lastSeenRowIdRef.current, onUnseenCount: setUnseenCount, onTimeline: setTimeline, onOpenSubagent: setSubagentDetailId, onOpenSubagentView: openSubagentViewFromCard, onOpenJobs: openJobsPanel, onOpenFile: openFileActions, sessionCwd: channel.cwd, onPreviewImage: openImagePreview, suppressImageGraphics: activePreview !== null, olderHistory: channel.olderHistory, onWatchJobOutput: watchJobOutput })] }), (() => {
|
|
5805
|
+
// Gutter mode (settings `dsh-tui.scrollGutter`): the timeline
|
|
5806
|
+
// rail (default), the proportional scrollbar, or nothing. The
|
|
5807
|
+
// slot keeps its 2 columns in both rendered modes (Qwen's
|
|
5808
|
+
// permanent-gutter rule — an appearing/disappearing gutter
|
|
5809
|
+
// changes the transcript width and rewraps everything).
|
|
5810
|
+
const gutter = normalizeScrollGutter(channel.scrollGutter);
|
|
5811
|
+
if (gutter === 'hidden')
|
|
5812
|
+
return null;
|
|
5813
|
+
if (gutter === 'scrollbar') {
|
|
5814
|
+
return _jsx(ScrollbarGutter, { handle: handle, terminalWidth: chatColumns });
|
|
5815
|
+
}
|
|
5816
|
+
return (_jsx(TimelineRail, { handle: handle, turns: timeline.turns, activeId: timeline.activeId, upId: timeline.upId, downId: timeline.downId, terminalWidth: chatColumns, hoverEnabled: !promptSelectionActive, onRevealTurn: revealAndSeekRow }));
|
|
5817
|
+
})(), !promptEditorOpen && imagePreviewNode] }), _jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [showPill && (_jsx(NewMessagesPill, { count: unseenCount, onClick: () => handle?.scrollToBottom() })), channel.working &&
|
|
5818
|
+
(activitySlot &&
|
|
5819
|
+
workingActivity !== undefined &&
|
|
5820
|
+
workingActivity.line !== '' &&
|
|
5821
|
+
workingActivity.phase !== 'idle' ? (_jsx(Box, { marginTop: 1, children: _jsx(ActivityLine, { activity: workingActivity, activityFrames: channel.activityFrames, warnPct: activityWarnPct, warnDanger: activityWarnPct !== undefined && activityWarnPct >= 95,
|
|
5822
|
+
// Upload = real tokens of the last request; download =
|
|
5823
|
+
// the animated chars/4 estimate, matching the classic
|
|
5824
|
+
// spinner's counter (the suffix used raw chars before,
|
|
5825
|
+
// inflating the reading next to a real upload number). An
|
|
5826
|
+
// automatic compaction mid-turn badges THIS line too — it is
|
|
5827
|
+
// the spinner slot whenever real activity data exists.
|
|
5828
|
+
suffix: `${lastUploadTokens > 0 ? ` · ↑ ${formatTokens(lastUploadTokens)}` : ''} · ↓ ${formatTokens(Math.round(channel.responseChars / 4))} tokens${compactionBadge === undefined ? '' : ` · ${compactionBadge}`}` }) })) : (_jsx(WorkingSpinner, { mode: channel.spinnerMode, hasActiveTools: channel.activeToolCount > 0, responseLengthRef: responseLengthRef, uploadTokensRef: uploadTokensRef, loadingStartTimeRef: loadingStartTimeRef, totalPausedMsRef: totalPausedMsRef, pauseStartTimeRef: pauseStartTimeRef, thinkingStatus: thinkingStatus, suffix: compactionBadge }))), !channel.working && channel.compaction !== undefined && (_jsx(CompactionStatusRow, { compaction: channel.compaction, activityPreset: activitySlot ? channel.activityFrames : undefined })), !(sidePanel.split && sidePanel.enabledPanelIds.includes('todo')) && (_jsx(GoalTodoPanel, { channel: channel, collapsed: todoCollapsed, onToggle: () => setTodoCollapsed(previous => !previous) })), recap !== null && recap.auto && !recap.expanded && (_jsx(AutoRecapRow, { summary: recap.summary, streaming: !recap.done, onExpand: () => setRecap(prev => (prev ? { ...prev, expanded: true } : prev)), onDismiss: () => closeRecap() })), balance !== null && (_jsx(BalanceReportRow, { result: balance.result, refreshing: balance.refreshing, tokens: channel.tokens, model: channel.modelDisplay ?? channel.model, provider: channel.provider, mainCost: channel.mainCost, subagentCost: channel.subagentCost, onRefresh: runBalance, onDismiss: () => setBalance(null) })), statusEntries.length > 0 && (_jsx(Text, { dimColor: true, wrap: "truncate", children: statusEntries.map(entry => entry.text).join(' · ') })), activePreview === null && statusViews.map(view => (_jsx(PluginStatusViewBoundary, { viewKey: view.key, onError: (key, error) => statusContributions.reportViewError(key, error), children: _jsx(Box, { flexDirection: "column", flexShrink: 0, maxHeight: view.maxRows, overflow: "hidden", children: _jsx(Box, { flexDirection: "column", flexShrink: 0, children: React.createElement(view.component, {
|
|
5829
|
+
React,
|
|
5830
|
+
ui: STATUS_VIEW_UI,
|
|
5831
|
+
}) }) }) }, `${view.key}:${view.registrationId}`))), _jsxs(Box, { flexDirection: "column", flexShrink: 0, children: [approvalPanelNode !== null ? (approvalPanelNode) : dialogSnapshot !== null ? (_jsx(ExtensionDialog, { dialog: dialogSnapshot, onDecide: value => dialogs.decide(dialogSnapshot.key, value), onCancel: () => dialogs.cancel(dialogSnapshot.key) }, dialogSnapshot.key)) : overlay.kind === 'tips' ? (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(TipsPanel, { onClose: () => dispatchOverlay({ type: 'close-if', kind: 'tips' }) }) })) : recap !== null && (!recap.auto || recap.expanded) ? (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(RecapPanel, { summary: recap.summary, title: recap.title, error: recap.error, streaming: !recap.done, titleApplied: recap.titleApplied, onClose: () => {
|
|
5832
|
+
// An expanded auto recap collapses back to its dim row;
|
|
5833
|
+
// a manual /recap closes outright.
|
|
5834
|
+
if (recap.auto) {
|
|
5835
|
+
setRecap(prev => (prev ? { ...prev, expanded: false } : prev));
|
|
4525
5836
|
}
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
const entry = historyMatches[index];
|
|
4529
|
-
if (entry) {
|
|
4530
|
-
setHistoryFill(entry.text);
|
|
4531
|
-
dispatchOverlay({ type: 'close' });
|
|
5837
|
+
else {
|
|
5838
|
+
closeRecap();
|
|
4532
5839
|
}
|
|
4533
|
-
}
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
if (row === null)
|
|
4540
|
-
return;
|
|
4541
|
-
dispatchOverlay({ type: 'close' });
|
|
4542
|
-
void performRewind(row);
|
|
4543
|
-
}, onPickMode: (index) => {
|
|
4544
|
-
// 模式列表点击直接执行该模式(与 Enter 同路径)
|
|
4545
|
-
const row = overlay.confirm;
|
|
4546
|
-
if (row === null)
|
|
5840
|
+
}, onCopy: () => {
|
|
5841
|
+
void setClipboard(recap.summary ?? '').then(raw => { if (raw)
|
|
5842
|
+
writeRaw?.(raw); });
|
|
5843
|
+
channel.notify(t('copied-chars', { n: (recap.summary ?? '').length }), { timeoutMs: 1500 });
|
|
5844
|
+
}, onApplyTitle: () => {
|
|
5845
|
+
if (recap.title === undefined || recap.titleApplied)
|
|
4547
5846
|
return;
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
|
|
4557
|
-
|
|
5847
|
+
channel.renameSession(recap.title);
|
|
5848
|
+
setRecap(prev => (prev ? { ...prev, titleApplied: true } : prev));
|
|
5849
|
+
channel.notify(t('recap-title-applied-notify', { title: recap.title }), { color: 'success' });
|
|
5850
|
+
} }) })) : btwOverlayOpen && !sidePanel.enabledPanelIds.includes('btw') ? (_jsx(Box, { flexDirection: "column", marginTop: 1, children: _jsx(BtwPanelFallback, { thread: btwOverlayThread, onClose: closeBtwOverlay, onCopy: answer => {
|
|
5851
|
+
void setClipboard(answer).then(raw => { if (raw)
|
|
5852
|
+
writeRaw?.(raw); });
|
|
5853
|
+
channel.notify(t('copied-chars', { n: answer.length }), { timeoutMs: 1500 });
|
|
5854
|
+
} }) })) : questionPanelNode !== null ? (questionPanelNode) : null, _jsx(PromptInput, { channel: channel, suspended: promptReplacementOpen,
|
|
5855
|
+
// 宠物面板是活动面板时,通知由它的头顶气泡「说出来」,输入框上方
|
|
5856
|
+
// 不再重复弹同一条(error 色除外——可能要行动的信号永远走 toast)。
|
|
5857
|
+
// 渲染期判定(split + activePanelId),与气泡同一次提交切换,不会
|
|
5858
|
+
// 先闪一帧 toast 再消失。
|
|
5859
|
+
toastSuppressed: petSaysNotices, draftCache: promptDraftRef.current, helpOpen: helpOpen, onToggleHelp: () => { setHelpOpen(previous => !previous); }, onRunCommand: runCommand, selectionActive: promptSelectionActive, fillText: historyFill, onFillConsumed: () => setHistoryFill(null), onRewindRequest: openRewind, onBackgroundRequest: backgroundToAgentView,
|
|
5860
|
+
// The 🏠 at the head of the input row opens the same session screen
|
|
5861
|
+
// `/resume` and `/agentview` open — one surface, three doors. It is
|
|
5862
|
+
// gated on this prop rather than a setting, so hosts that mount the
|
|
5863
|
+
// prompt without a session screen (and the layout regressions that
|
|
5864
|
+
// pin the row's column budget) keep the row they had.
|
|
5865
|
+
onOpenSessions: () => {
|
|
5866
|
+
agentViewOpenSessionRef.current = channel.agentId;
|
|
5867
|
+
setSupervisorOpen(true);
|
|
5868
|
+
}, backgroundAgentsNeedingInput:
|
|
5869
|
+
// Only the real channel supplies the seam; pre-agent-view test
|
|
5870
|
+
// stubs must not grow the footer row (layout-dependent
|
|
5871
|
+
// regressions pin the visible row count). The footer only
|
|
5872
|
+
// renders while some session actually waits (N > 0): a
|
|
5873
|
+
// permanent idle row would steal a transcript row on every
|
|
5874
|
+
// real channel — one row is enough to scroll the startup
|
|
5875
|
+
// header fully off a short terminal, pausing its viewport
|
|
5876
|
+
// clock and shifting every row-count layout invariant.
|
|
5877
|
+
channel.agentViewRows !== undefined && backgroundAgentsNeedingInput > 0
|
|
5878
|
+
? backgroundAgentsNeedingInput
|
|
5879
|
+
: undefined, controllerRef: promptControllerRef, onCaretImage: handleCaretImage, caretPreviewOpen: peekPreview !== null, onDismissCaretPreview: dismissPeek }, "prompt-input"), _jsx(StatusLine, { channel: channel, activity: workingActivity, selectionActive: selectionActive, helpOpen: helpOpen,
|
|
5880
|
+
// Backend-native permission modes: the footer mode segment always
|
|
5881
|
+
// shows (the base mode included) and clicks into the same
|
|
5882
|
+
// /permission picker the command opens (the launchpad param row's
|
|
5883
|
+
// route). DSH answers an empty list here — no prop, byte-identical
|
|
5884
|
+
// rendering.
|
|
5885
|
+
backendMode: backendModeStatus,
|
|
5886
|
+
// 模型段/思考档位段:能力位在才可点,点击走既有 /model · /effort
|
|
5887
|
+
// 命令(与模式段打开 /permission 完全同构)。
|
|
5888
|
+
modelPicker: modelPickerStatus, effortPicker: effortPickerStatus, wake: wakeBand === undefined
|
|
5889
|
+
? undefined
|
|
5890
|
+
: {
|
|
5891
|
+
band: wakeBand,
|
|
5892
|
+
hint: trajectorySeen ? undefined : primaryComboString('trajectory'),
|
|
5893
|
+
tick: Math.floor(wakeTime / 120),
|
|
5894
|
+
onOpen: openScene,
|
|
5895
|
+
hoverHint: primaryComboString('trajectory'),
|
|
5896
|
+
} }), dialogOverlayOpen && (_jsx(OverlayAbove, { maxHeight: Math.max(terminalRows - 8, 1), children: pickerPanels }))] })] }), _jsx(TooltipLayer, { invalidationKey: `${overlay.kind}:${dialogOverlayOpen}:${btwOverlayOpen}`, subscribeInvalidation: subscribeTooltipInvalidation })] }), _jsx(PromptEditorLayer, {}), promptEditorOpen && imagePreviewNode, starModal !== null && STAR_MILESTONES[starModal.index] !== undefined && (_jsx(StarPrompt, { milestone: STAR_MILESTONES[starModal.index], actions: starModalActions, onClose: closeStarModal, initialPhase: starModal.phase })), couponVisible && coupon !== null && (_jsx(WhaleCouponPrompt, { notice: coupon, onShown: markCouponShown, onClose: closeCoupon }))] }));
|
|
4558
5897
|
}
|
|
4559
5898
|
/**
|
|
4560
5899
|
* The pinned prompt header shown above the ScrollBox while the user has
|