✨ feat(vscode): 工单移交的会话包改走阿里云 OSS、换 xz 压缩,两边进度一步步显示

- 会话包传到 OSS 的 spx-handoff/<owner>/<repo>/issue-<N>-<时间>.tar.xz,上传时对象设成私有;不再挂 Gitea 工单附件
- 新命令「配置移交存储」:endpoint、bucket 存扩展设置,AccessKey 存密钥存储;没配时移交 / 接管直接提示,什么都不改
- 共享 state 字段 handoffAttachmentId 改名 handoffBundleKey(含 spx CLI 与 schema)
- 打包换成 xz 1 级(tar -cJf),去掉 100MB 上限检查和先试压一遍的重复压缩
- 发送方提示打包 / 上传了多少 MB;接管方同一条提示依次显示下载、解包、建 worktree、装会话,完成前不消失
- 会话交接(单会话)仍走 Gitea 附件,Gitea 附件白名单没有 .xz,单独保留 gzip 打包
This commit is contained in:
cruldra committed 2026-10-08 07:17:26 +08:00
1 parent a33d3d2251
commit 499cfad7d7
39 files changed
+1039 -526

No files matched your search

+29 -17
View File
@@ -8,8 +8,11 @@ import {
handoffLocalTombstones,
handoffStartedStateExtra,
handoffStartedUiPatch,
transferProgressText,
} from './handoff'
const KEY = 'spx-handoff/o/r/issue-9-20261008T010203Z.tar.xz'
describe('canStartHandoff', () => {
it('gitea 工单、非 done、无待接管、无 assignee 或 assignee 含我 → true', () => {
expect(canStartHandoff({ column: 'in-progress' }, 'me')).toBe(true)
@@ -20,21 +23,30 @@ describe('canStartHandoff', () => {
it('done / youtrack / 已在移交中 / 不是我负责 → false', () => {
expect(canStartHandoff({ column: 'done' }, 'me')).toBe(false)
expect(canStartHandoff({ column: 'review', source: 'youtrack' }, 'me')).toBe(false)
expect(canStartHandoff({ column: 'review', handoffAttachmentId: '9' }, 'me')).toBe(false)
expect(canStartHandoff({ column: 'review', handoffBundleKey: KEY }, 'me')).toBe(false)
expect(canStartHandoff({ column: 'todo', assignees: ['x'] }, 'me')).toBe(false)
expect(canStartHandoff({ column: 'todo', assignees: ['me'] }, undefined)).toBe(false)
})
})
describe('canAcceptHandoff', () => {
it('有附件且 assignee 含我 → true', () => {
expect(canAcceptHandoff({ handoffAttachmentId: '9', assignees: ['me', 'x'] }, 'me')).toBe(true)
it('有待接管的会话包且 assignee 含我 → true', () => {
expect(canAcceptHandoff({ handoffBundleKey: KEY, assignees: ['me', 'x'] }, 'me')).toBe(true)
})
it('无附件 / 不是我的 / 身份未知 / youtrack → false', () => {
it('没有会话包 / 不是我的 / 身份未知 / youtrack → false', () => {
expect(canAcceptHandoff({ assignees: ['me'] }, 'me')).toBe(false)
expect(canAcceptHandoff({ handoffAttachmentId: '9', assignees: ['x'] }, 'me')).toBe(false)
expect(canAcceptHandoff({ handoffAttachmentId: '9', assignees: ['me'] }, undefined)).toBe(false)
expect(canAcceptHandoff({ source: 'youtrack', handoffAttachmentId: '9', assignees: ['me'] }, 'me')).toBe(false)
expect(canAcceptHandoff({ handoffBundleKey: KEY, assignees: ['x'] }, 'me')).toBe(false)
expect(canAcceptHandoff({ handoffBundleKey: KEY, assignees: ['me'] }, undefined)).toBe(false)
expect(canAcceptHandoff({ source: 'youtrack', handoffBundleKey: KEY, assignees: ['me'] }, 'me')).toBe(false)
})
})
describe('transferProgressText', () => {
it('知道总大小时报「已传 / 总共」', () => {
expect(transferProgressText('上传', 3.2 * 1024 * 1024, 32 * 1024 * 1024)).toBe('上传 3.2MB / 32MB')
})
it('总大小未知时只报已传多少', () => {
expect(transferProgressText('下载', 512 * 1024, 0)).toBe('下载 512KB')
})
})
@@ -58,8 +70,8 @@ describe('checkWorktreePushed', () => {
describe('payloads', () => {
it('移交落盘:只写两个共享字段,本机字段留到本机清理跑完后再墓碑', () => {
expect(handoffStartedStateExtra(9, 'chw')).toEqual({
handoffAttachmentId: '9',
expect(handoffStartedStateExtra(KEY, 'chw')).toEqual({
handoffBundleKey: KEY,
handoffFrom: 'chw',
})
})
@@ -95,8 +107,8 @@ describe('payloads', () => {
})
})
it('移交 UI patch 用 null 清字段并更新 assignees', () => {
expect(handoffStartedUiPatch(9, 'chw', 'me', { keepWorktreePath: false })).toEqual({
handoffAttachmentId: '9',
expect(handoffStartedUiPatch(KEY, 'chw', 'me', { keepWorktreePath: false })).toEqual({
handoffBundleKey: KEY,
handoffFrom: 'chw',
assignees: ['me'],
sessionId: null,
@@ -114,11 +126,11 @@ describe('payloads', () => {
})
})
it('移交 UI patch:keepWorktreePath=true 时省略 worktreePath / worktreeExists', () => {
const patch = handoffStartedUiPatch(9, 'chw', 'me', { keepWorktreePath: true })
const patch = handoffStartedUiPatch(KEY, 'chw', 'me', { keepWorktreePath: true })
expect(patch).not.toHaveProperty('worktreePath')
expect(patch).not.toHaveProperty('worktreeExists')
expect(patch).toEqual({
handoffAttachmentId: '9',
handoffBundleKey: KEY,
handoffFrom: 'chw',
assignees: ['me'],
sessionId: null,
@@ -139,7 +151,7 @@ describe('payloads', () => {
profiles: { profilePath: '/p.json' },
worktreePath: '/wt',
})).toEqual({
handoffAttachmentId: '',
handoffBundleKey: '',
handoffFrom: '',
implementSessionId: 'i',
reviewSessionId: 'r',
@@ -155,7 +167,7 @@ describe('payloads', () => {
worktreeExists: true,
missingSessionIds: [],
})).toEqual({
handoffAttachmentId: null,
handoffBundleKey: null,
handoffFrom: null,
sessionId: 's',
worktreePath: '/wt',
@@ -170,7 +182,7 @@ describe('payloads', () => {
worktreeExists: false,
missingSessionIds: [],
})).toEqual({
handoffAttachmentId: null,
handoffBundleKey: null,
handoffFrom: null,
sessionId: 's',
worktreePath: null,
@@ -185,7 +197,7 @@ describe('payloads', () => {
worktreeExists: false,
missingSessionIds: ['r'],
})).toEqual({
handoffAttachmentId: null,
handoffBundleKey: null,
handoffFrom: null,
sessionId: 's',
reviewSessionId: 'r',