feat: workspace→session picker and /model switch (v0.3.0)

Align Telegram session list with Web via apiProxy (exclude archived), resume cold sessions on bind, and allow model selection from the phone.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
owo
2026-08-14 18:46:56 +08:00
co-authored by Cursor
parent 9bae1a3702
commit ef0e7f34e3
18 changed files with 1486 additions and 108 deletions
+31 -6
View File
@@ -2,20 +2,28 @@ export const MSG = {
DENIED: '无权限。',
WELCOME: [
'你好,这是 DeepSeek Harness 的手机遥控器。',
'本机会话是真相源:请先在 Web 打开对话,再用 /sessions 选择并附着。',
'本机会话是真相源:请先在 Web 打开对话,再用 /sessions 选择工作区 → 会话并附着。',
'发送 /help 查看命令。',
].join('\n'),
HELP: [
'/sessions — 列出本机正在运行的会话并选择附着',
'/sessions — 按工作区列出本机会话(与 Web 对齐,排除归档)并附着',
'/model — 切换当前绑定会话的模型(下一回合生效)',
'/status — 查看当前绑定',
'/unbind — 断开绑定(不关闭本机会话)',
'/help — 显示帮助',
'',
'绑定后直接发文字,消息会进入该本机会话;Web 与手机看到同一条轨迹。',
'仅白名单用户可用。无 live 会话时请先在 dsh web 开对话。',
'仅白名单用户可用。无会话时请先在 dsh web 开对话或保留历史会话。',
].join('\n'),
NEED_BIND: '尚未绑定本机会话。请先发送 /sessions 选择一个。',
NO_LIVE: '当前没有正在运行的本机会话。请先在 Web(dsh web)打开或继续一个对话,再发 /sessions。',
NO_SESSIONS: '当前没有可附着的本机会话(已排除归档与空白会话)。请先在 Web(dsh web)打开或继续一个对话,再发 /sessions。',
NO_SESSIONS_IN_WS(title: string): string {
return `工作区「${title}」下没有可附着的会话。`
},
/** @deprecated use NO_SESSIONS */
NO_LIVE: '当前没有可附着的本机会话。请先在 Web(dsh web)打开或继续一个对话,再发 /sessions。',
PICKER_STALE: '列表已过期,请重新发送 /sessions。',
RESUME_FAILED: '无法附着该会话(resume 失败)。请确认会话存在于 Web,或先在电脑打开后再试。',
BOUND(label: string): string {
return `已附着本机会话:${label}\n此后消息将进入该会话(与 Web 同轨迹)。`
},
@@ -24,7 +32,21 @@ export const MSG = {
STATUS_BOUND(label: string): string {
return `当前绑定:${label}`
},
GONE: '绑定的会话已不在本机运行(可能已在 Web 关闭)。请重新 /sessions。',
STATUS_BOUND_COLD(label: string): string {
return `当前绑定:${label}\n(会话当前未在内存中运行;发消息时会自动 resume。)`
},
GONE: '绑定的会话已不可用。请重新 /sessions。',
MODEL_UNAVAILABLE: '无法读取模型列表(需要 dsh web / apiProxy)。请确认本机 Harness 已加载 host-apiproxy。',
MODEL_UNROUTABLE(current: string): string {
return `当前模型不可路由:${current}\n请在 Web 或本机配置可用 provider 后再试 /model。`
},
MODEL_EMPTY(current: string): string {
return `当前:${current}\n没有可切换的模型选项。`
},
MODEL_SET(selected: string): string {
return `已切换模型:${selected}\n下一回合生效。`
},
MODEL_FAILED: '切换模型失败。请稍后重试或在 Web 中切换。',
unknown(command: string): string {
return `未知命令 ${command}。发送 /help 查看可用命令。`
},
@@ -34,6 +56,7 @@ export type ParsedCommand =
| { type: 'start'; text: string }
| { type: 'help'; text: string }
| { type: 'sessions'; text: string }
| { type: 'model'; text: string }
| { type: 'status'; text: string }
| { type: 'unbind'; text: string }
| { type: 'unknown'; command: string; text: string }
@@ -51,6 +74,8 @@ export function parseCommand(text: string): ParsedCommand {
case '/sessions':
case '/list':
return { type: 'sessions', text }
case '/model':
return { type: 'model', text }
case '/status':
return { type: 'status', text }
case '/unbind':
@@ -61,5 +86,5 @@ export function parseCommand(text: string): ParsedCommand {
}
}
/** Callback data prefix for session bind buttons. */
/** @deprecated Prefer short index callbacks (ws:/sid:); kept for old messages. */
export const BIND_CB_PREFIX = 'bind:'