Skip to content

feat(cli): add --session/--resume flag with interactive picker and CJK-safe shorten#1716

Merged
RealKai42 merged 3 commits into
mainfrom
kaiyi/chicago
Apr 2, 2026
Merged

feat(cli): add --session/--resume flag with interactive picker and CJK-safe shorten#1716
RealKai42 merged 3 commits into
mainfrom
kaiyi/chicago

Conversation

@RealKai42

@RealKai42 RealKai42 commented Apr 2, 2026

Copy link
Copy Markdown
Collaborator

Related Issue

Resolve #1366

Description

Re-implement the session picker feature (originally PR #1376, reverted in #1608 due to doc/flag naming inconsistencies) with a unified --session/--resume optional-value flag design.

--session/--resume (-S/-r) — optional-value flag

  • Without argument: opens an interactive session picker (shell UI only) using prompt_toolkit.ChoiceInput
  • With session ID: resumes that specific session
  • Session not found: raises an error instead of silently creating a new session (breaking change)
  • Mutually exclusive with --continue/-C

The optional-value behavior is implemented via Click's _flag_needs_value + flag_value mechanism in LazySubcommandGroup.make_context().

CJK-safe shorten() utility

Replaces all textwrap.shorten calls across the codebase with a custom shorten() in kimi_cli.utils.string that truncates gracefully at word boundaries and falls back to hard cut for CJK text without spaces (instead of collapsing to just the placeholder).

Tests

  • 4 new E2E tests: --session/--resume + --continue conflict, picker with print mode, session not found, --resume alias conflict
  • 9 new unit tests for shorten(): short text, exact width, word boundary, CJK hard cut, whitespace normalization, empty string, edge cases, custom placeholder

Open with Devin

Copilot AI review requested due to automatic review settings April 2, 2026 08:02
…K-safe shorten

Add --session/--resume (-S/-r) as an optional-value flag to resume sessions:
- Without argument: open interactive session picker (shell UI only)
- With session ID: resume that specific session (errors if not found)
- Mutually exclusive with --continue

Replace all textwrap.shorten calls with a custom CJK-safe shorten() that
truncates gracefully at word boundaries and falls back to hard cut for
CJK text without spaces.

BREAKING CHANGE: --session ID now errors when the session is not found
instead of silently creating a new session.

Closes #1366

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR reintroduces a session picker/resume capability for the CLI via a unified optional-value --session/--resume flag (aligned with Claude Code’s --resume), and adds a CJK-safe shorten() utility to avoid textwrap.shorten collapsing no-space text to only an ellipsis.

Changes:

  • Add --session/--resume (-S/-r) optional-value flag with shell-only interactive picker and stricter “session not found” behavior.
  • Introduce kimi_cli.utils.string.shorten() and migrate multiple call sites away from textwrap.shorten.
  • Add unit tests for shorten() and E2E snapshot tests for new CLI error cases; update docs/changelogs (EN/ZH), including breaking-change notes.

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/kimi_cli/cli/_lazy_group.py Implements Click parsing hack to support optional-value flags for session_id.
src/kimi_cli/cli/__init__.py Adds --session/--resume options, picker-mode logic, and “not found” error behavior.
src/kimi_cli/utils/string.py Adds CJK-safe shorten() implementation (whitespace normalize + word-boundary cut + hard-cut fallback).
src/kimi_cli/utils/export.py Switches to the new shorten() for exported hints/overviews.
src/kimi_cli/session.py Switches session title derivation to the new shorten().
src/kimi_cli/web/store/sessions.py Switches wire-derived title fallback to the new shorten().
src/kimi_cli/web/api/sessions.py Uses new shorten() for generated/fallback session titles.
tests/utils/test_shorten.py Adds unit tests covering whitespace normalization, word-boundary truncation, and CJK hard-cut behavior.
tests/e2e/test_cli_error_output.py Adds snapshot tests for new flag conflicts, picker misuse in print mode, and not-found session ID.
CHANGELOG.md Documents the new flags, shorten() migration, and breaking change.
docs/en/release-notes/changelog.md Mirrors changelog entries for Unreleased.
docs/en/release-notes/breaking-changes.md Documents the changed behavior for --session ID when session is missing.
docs/en/reference/kimi-command.md Updates CLI reference to include --resume alias and optional argument semantics.
docs/en/guides/sessions.md Updates sessions guide with picker usage and new error behavior.
docs/zh/release-notes/changelog.md Mirrors changelog entries for 未发布.
docs/zh/release-notes/breaking-changes.md Documents the breaking change in Chinese.
docs/zh/reference/kimi-command.md Updates CLI reference in Chinese for --session [ID] / --resume [ID].
docs/zh/guides/sessions.md Updates sessions guide in Chinese with picker usage and new error behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread CHANGELOG.md
## Unreleased

- CLI: Add `--session`/`--resume` (`-S`/`-r`) flag to resume sessions — without an argument opens an interactive session picker (shell UI only); with a session ID resumes that specific session; replaces the reverted `--pick-session`/`--list-sessions` design with a unified optional-value flag
- CLI: Add CJK-safe `shorten()` utility — replaces all `textwrap.shorten` calls so that CJK text without spaces is truncated gracefully instead of collapsing to just the placeholder

Copilot AI Apr 2, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changelog claims this change “replaces all textwrap.shorten calls”, but there is still at least one remaining usage in src/kimi_cli/soul/kimisoul.py (auto-title after first turn). That path will still have the old CJK-collapsing behavior, so either update that call site to use kimi_cli.utils.string.shorten too, or soften this wording to avoid overstating the coverage.

Suggested change
- CLI: Add CJK-safe `shorten()` utility — replaces all `textwrap.shorten` calls so that CJK text without spaces is truncated gracefully instead of collapsing to just the placeholder
- CLI: Add CJK-safe `shorten()` utility — replaces most `textwrap.shorten` calls so that CJK text without spaces is truncated gracefully instead of collapsing to just the placeholder

Copilot uses AI. Check for mistakes.
## Unreleased

- CLI: Add `--session`/`--resume` (`-S`/`-r`) flag to resume sessions — without an argument opens an interactive session picker (shell UI only); with a session ID resumes that specific session; replaces the reverted `--pick-session`/`--list-sessions` design with a unified optional-value flag
- CLI: Add CJK-safe `shorten()` utility — replaces all `textwrap.shorten` calls so that CJK text without spaces is truncated gracefully instead of collapsing to just the placeholder

Copilot AI Apr 2, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This release note says the new shorten() “replaces all textwrap.shorten calls”, but the codebase still has at least one textwrap.shorten usage (src/kimi_cli/soul/kimisoul.py, auto-title). Please either migrate that remaining call site as well (so the CJK fix applies everywhere) or adjust this wording.

Suggested change
- CLI: Add CJK-safe `shorten()` utility — replaces all `textwrap.shorten` calls so that CJK text without spaces is truncated gracefully instead of collapsing to just the placeholder
- CLI: Add CJK-safe `shorten()` utility — now used for most CLI truncation logic so that CJK text without spaces is truncated gracefully instead of collapsing to just the placeholder

Copilot uses AI. Check for mistakes.
## 未发布

- CLI:新增 `--session`/`--resume`(`-S`/`-r`)参数用于恢复会话——不带参数时打开交互式会话选择器(仅 Shell UI);带会话 ID 时恢复指定会话;以统一的可选值参数设计替代了被回退的 `--pick-session`/`--list-sessions`
- CLI:新增 CJK 安全的 `shorten()` 工具函数——替换所有 `textwrap.shorten` 调用,使不含空格的中日韩文本能优雅截断,而非被折叠成仅剩省略号

Copilot AI Apr 2, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里写“替换所有 textwrap.shorten 调用”,但代码里仍有至少一处还在用 textwrap.shortensrc/kimi_cli/soul/kimisoul.py 自动生成标题逻辑)。建议要么把那一处也迁移到 kimi_cli.utils.string.shorten,要么把文案改成不绝对的表述,避免与实际不符。

Suggested change
- CLI:新增 CJK 安全的 `shorten()` 工具函数——替换所有 `textwrap.shorten` 调用,使不含空格的中日韩文本能优雅截断,而非被折叠成仅剩省略号
- CLI:新增 CJK 安全的 `shorten()` 工具函数——用于替换 `textwrap.shorten` 调用,使不含空格的中日韩文本能优雅截断,而非被折叠成仅剩省略号

It says "replace all textwrap.shorten calls" here, but there is still at least one place in the code that still uses textwrap.shorten (src/kimi_cli/soul/kimisoul.py automatically generates title logic). It is recommended to either migrate that part to kimi_cli.utils.string.shorten, or change the text to a non-absolute expression to avoid inconsistency with the actual situation.

Suggested change
- CLI:新增 CJK 安全的 `shorten()` 工具函数——替换所有 `textwrap.shorten` 调用,使不含空格的中日韩文本能优雅截断,而非被折叠成仅剩省略号
- CLI: Added CJK-safe `shorten()` utility function - used to replace the `textwrap.shorten` call so that Chinese, Japanese and Korean text without spaces can be gracefully truncated instead of being folded into only ellipsis

Copilot uses AI. Check for mistakes.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 66354867f4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/kimi_cli/cli/__init__.py Outdated
else:
resumed = True # Session was actually found
logger.info("Switching to session: {session_id}", session_id=session.id)
resumed = True

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Emit resume source for --session/--resume resumes

This path now always resumes an existing session (resumed = True), but the SessionStart hook source is still computed only from continue_ later in kimi(). In practice, resumes via --session/--resume (including picker selections) are reported as source="startup", so hooks matching resume never fire for these flows. Please derive the hook source from actual resume state (e.g., resumed) instead of only --continue.

Useful? React with 👍 / 👎.

devin-ai-integration[bot]

This comment was marked as resolved.

…hook source

- Revert --session ID behavior to create new session when not found
- Migrate textwrap.shorten in kimisoul.py to kimi_cli.utils.string.shorten
- Fix SessionStart hook source to use resumed flag instead of continue_
- Remove test_session_not_found_is_reported test
- Update docs and changelog to remove breaking change references

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d2649d365d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


# --- SessionStart hook ---
_session_source = "resume" if continue_ else "startup"
_session_source = "resume" if resumed else "startup"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep startup source for newly created reload targets

Deriving SessionStart source from resumed regresses flows that create a fresh session and then reload into it (for example /new creates a session and raises Reload(session_id=...)): _run marks any found session_id as resumed, so these fresh sessions now emit source="resume" and skip startup-matched hooks. This change means startup hooks no longer fire for new-session reload flows introduced by shell commands, even though the session was just created.

Useful? React with 👍 / 👎.

Signed-off-by: Kai <me@kaiyi.cool>
@RealKai42 RealKai42 merged commit 42bb381 into main Apr 2, 2026
14 checks passed
@RealKai42 RealKai42 deleted the kaiyi/chicago branch April 2, 2026 09:02

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d1ceb8f6bd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +812 to 815
session_id = asyncio.run(_pick_session())

try:
switch_target, exit_code = asyncio.run(_reload_loop(session_id))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Handle picker failures in the existing CLI error wrapper

Run-time failures from the new picker path bypass the CLI’s guarded error handling because asyncio.run(_pick_session()) executes before the try/except that normalizes fatal errors. If Session.list() raises (for example due to malformed kimi.json metadata or filesystem errors), users get an uncaught traceback instead of the usual logged error + stable exit path used by _reload_loop, which is a regression specific to --session/--resume without an ID.

Useful? React with 👍 / 👎.

GTC2080 pushed a commit to GTC2080/kimi-cli that referenced this pull request Apr 2, 2026
@woshisbb43

Copy link
Copy Markdown

非常好,session select 真的很需要

Yuandiaodiaodiao added a commit to Yuandiaodiaodiao/kimi-cli that referenced this pull request Apr 3, 2026
…default_plan_mode config

Ports upstream commits:
- 619327e feat(cli): add --plan flag and default_plan_mode config (MoonshotAI#1665)
- 42bb381 feat(cli): add --session/--resume flag with interactive picker (MoonshotAI#1716)
Yuandiaodiaodiao added a commit to Yuandiaodiaodiao/kimi-cli that referenced this pull request Apr 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add arguments for cli to select the history session

3 participants