fix: show session title and workspace in /sessions picker
Read cwd from session.header (not only meta) and title from sessionTitle service or session/title events; list details in the message body and richer inline buttons. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+20
-3
@@ -44,10 +44,21 @@ function messageUpdate(chatId: number, userId: number, text: string, updateId =
|
||||
}
|
||||
}
|
||||
|
||||
function makeAgent(id: string, followups: UserMessage[]) {
|
||||
function makeAgent(id: string, followups: UserMessage[], opts?: {
|
||||
cwd?: string
|
||||
title?: string
|
||||
}) {
|
||||
const cwd = opts?.cwd ?? `/proj/${id}`
|
||||
const events = opts?.title
|
||||
? [{ type: 'session/title', data: { title: opts.title } }]
|
||||
: []
|
||||
return {
|
||||
id: SessionId(id),
|
||||
session: { meta: { cwd: `/proj/${id}` } },
|
||||
session: {
|
||||
header: { cwd },
|
||||
meta: { cwd },
|
||||
events,
|
||||
},
|
||||
followup(message: UserMessage) {
|
||||
followups.push(message)
|
||||
},
|
||||
@@ -118,7 +129,10 @@ test('/sessions with no live agents shows NO_LIVE', async () => {
|
||||
test('/sessions lists live agents with bind callbacks', async () => {
|
||||
const sent: SentMessage[] = []
|
||||
const followups: UserMessage[] = []
|
||||
const agent = makeAgent('live-aaa', followups)
|
||||
const agent = makeAgent('live-aaa', followups, {
|
||||
cwd: 'D:/gitData/demo-app',
|
||||
title: '演示会话',
|
||||
})
|
||||
const ctx = {
|
||||
logger: { info() {}, warn() {}, error() {} },
|
||||
agents: {
|
||||
@@ -137,6 +151,9 @@ test('/sessions lists live agents with bind callbacks', async () => {
|
||||
})
|
||||
await bridge.processUpdate(messageUpdate(10, 1, '/sessions'))
|
||||
assert.match(sent[0]!.text, /选择要遥控/)
|
||||
assert.match(sent[0]!.text, /演示会话/)
|
||||
assert.match(sent[0]!.text, /D:\/gitData\/demo-app/)
|
||||
assert.match(sent[0]!.replyMarkup!.inline_keyboard![0]![0]!.text, /演示会话/)
|
||||
assert.ok(sent[0]!.replyMarkup?.inline_keyboard?.[0]?.[0]?.callback_data?.startsWith(BIND_CB_PREFIX))
|
||||
})
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import test from 'node:test'
|
||||
import {
|
||||
buttonLabel,
|
||||
describeAgent,
|
||||
detailLines,
|
||||
displayLabel,
|
||||
readSessionCwd,
|
||||
readSessionTitle,
|
||||
workspaceName,
|
||||
} from '../src/label.ts'
|
||||
import { SessionId } from '@deepseek-ai/dsh-session/types'
|
||||
|
||||
test('workspaceName takes last path segment', () => {
|
||||
assert.equal(workspaceName('D:\\gitData\\dsh-telegram-channel'), 'dsh-telegram-channel')
|
||||
assert.equal(workspaceName('/home/me/proj/app'), 'app')
|
||||
})
|
||||
|
||||
test('readSessionCwd prefers header.cwd over meta.cwd', () => {
|
||||
assert.equal(readSessionCwd({ header: { cwd: '/real' }, meta: { cwd: '/old' } }), '/real')
|
||||
assert.equal(readSessionCwd({ meta: { cwd: '/legacy' } }), '/legacy')
|
||||
})
|
||||
|
||||
test('readSessionTitle uses service, then events', () => {
|
||||
const session = {
|
||||
header: { cwd: '/w' },
|
||||
events: [
|
||||
{ type: 'user/message', data: {} },
|
||||
{ type: 'session/title', data: { title: ' 修复登录 ' } },
|
||||
],
|
||||
}
|
||||
assert.equal(readSessionTitle(undefined, session), '修复登录')
|
||||
const ctx = {
|
||||
sessionTitle: { get: () => ({ title: '来自服务' }) },
|
||||
}
|
||||
assert.equal(readSessionTitle(ctx as any, session), '来自服务')
|
||||
})
|
||||
|
||||
test('describeAgent builds title + workspace + id tail', () => {
|
||||
const agent = {
|
||||
id: SessionId('0123456789abcdef-live'),
|
||||
session: {
|
||||
header: { cwd: 'D:/gitData/my-app' },
|
||||
events: [{ type: 'session/title', data: { title: '重构支付' } }],
|
||||
},
|
||||
}
|
||||
const parts = describeAgent(agent as any, 0)
|
||||
assert.equal(parts.title, '重构支付')
|
||||
assert.equal(parts.workspace, 'my-app')
|
||||
assert.match(detailLines(parts), /重构支付/)
|
||||
assert.match(detailLines(parts), /D:\/gitData\/my-app/)
|
||||
assert.match(buttonLabel(parts), /^1\. 重构支付/)
|
||||
assert.match(displayLabel(parts), /重构支付 · my-app/)
|
||||
})
|
||||
|
||||
test('buttonLabel stays within 64 chars', () => {
|
||||
const longTitle = '啊'.repeat(80)
|
||||
const label = buttonLabel({
|
||||
index: 0,
|
||||
title: longTitle,
|
||||
workspace: 'ws',
|
||||
idTail: 'abc',
|
||||
sessionId: 'x',
|
||||
})
|
||||
assert.ok([...label].length <= 64)
|
||||
})
|
||||
Reference in New Issue
Block a user