- 新增 src/client/jobs-client.ts:结构探测 ctx.jobs(watchRows / observe / state / kill),引用计数的按会话 roster 订阅、只观测展开的那一行、 跨树去重(无主任务归到承载它的被观测会话,树外 owner 丢弃)。 - 抽屉与输出浮窗改读该服务:行来自推送 roster(状态 / 时长 / owner / 进度), 输出面换 TerminalBlock 显示宿主为观察者流的保留输出(gapBefore → 截断提示、 error → 失败提示),kill 走 jobs.kill(owner, jobId),两击确认不变。 - 自动激活(use-host-feeds)改骑同一条推送 roster;detectNewJob 增加 「观测起点时钟」参数,避免「页面打开时已在跑的任务」被当成新工作。 - 删除 src/jobs-routes.ts(+ tests/jobs-routes.spec.ts)、index.ts 的三条路由、 api.jobsList/jobOutput/jobKill 与 JobOutputResult、context-types 的 SidebarJobsService(换成 SidebarClientJobsService/SidebarJobsSnapshot/ SidebarObservedJob 镜像,SidebarJobView 补 owner/progress)、 页面里的 jobs.list 轮询与 collectTreeJobs。 - 三个 spec 改用假 ctx.jobs 服务(jobs-view 14 例 / 自动激活 12 例 / 页面 20 例):观测只在展开行、切换与关闭释放观测、watch 隐藏时不建立、 卸载时全部释放、无服务时不渲染任务面。 验证:typecheck / lint 通过;pnpm test 1240 passed / 9 skipped;pnpm build + pack 通过。 (cherry picked from commit 7d9b82e73190218f05910433ed520cb90e4d4ab2)
70 lines
2.3 KiB
TypeScript
70 lines
2.3 KiB
TypeScript
/**
|
|
* Display copy for the host primitives the sidebar renders OUTSIDE the main
|
|
* conversation: `TerminalBlock` (a captured command's output surface) is
|
|
* cordis-free and takes every label as a prop, so the owning render site must
|
|
* supply them.
|
|
*
|
|
* One builder, two consumers (the Side Chat tool card and the Tasks page's
|
|
* background-job output panel): the two surfaces must read identically, and a
|
|
* new required label on the host side has exactly one place to land.
|
|
*/
|
|
import { t } from './locales.ts'
|
|
|
|
/** Labels for the sidebar's markdown / diff / read Block chrome. */
|
|
export interface BlockLabels {
|
|
copy: string
|
|
copied: string
|
|
collapse: string
|
|
collapseAria: string
|
|
expand: (hidden: number) => string
|
|
expandAria: (hidden: number) => string
|
|
}
|
|
|
|
/**
|
|
* The sidebar's Blocks reuse the Side Chat dictionary's chrome family (copy
|
|
* pair + the collapse/expand family that is common to every Block kind).
|
|
*/
|
|
export function blockLabels(): BlockLabels {
|
|
return {
|
|
copy: t('copy'),
|
|
copied: t('copied'),
|
|
collapse: t('sideChatBlockCollapse'),
|
|
collapseAria: t('sideChatBlockCollapseAria'),
|
|
expand: (hidden: number) => t('sideChatBlockExpand', { hidden }),
|
|
expandAria: (hidden: number) => t('sideChatBlockExpandAria', { hidden }),
|
|
}
|
|
}
|
|
|
|
/** The `TerminalBlockLabels` shape (structural mirror; the host owns the type). */
|
|
export interface TerminalLabels {
|
|
signal: (signal: string) => string
|
|
exitCode: (exitCode: number) => string
|
|
noExitCode: string
|
|
running: string
|
|
failed: string
|
|
done: string
|
|
copy: string
|
|
copied: string
|
|
noOutput: string
|
|
collapseAria: string
|
|
collapse: string
|
|
expandAria: (hidden: number) => string
|
|
expand: (hidden: number) => string
|
|
}
|
|
|
|
/** Labels for one `TerminalBlock` (a captured command plus its output). */
|
|
export function terminalBlockLabels(): TerminalLabels {
|
|
return {
|
|
...blockLabels(),
|
|
signal: (signal: string) => t('sideChatBlockSignal', { signal }),
|
|
exitCode: (exitCode: number) => t('sideChatBlockExitCode', { code: exitCode }),
|
|
// DSH 0.1.6-alpha.2 added this pill text: a settle the view cannot
|
|
// name (killed by an unknown signal, or never started).
|
|
noExitCode: t('sideChatBlockNoExitCode'),
|
|
running: t('sideChatBlockRunning'),
|
|
failed: t('sideChatBlockFailed'),
|
|
done: t('sideChatBlockDone'),
|
|
noOutput: t('sideChatBlockNoOutput'),
|
|
}
|
|
}
|