- 会话包传到 OSS 上收件人的收件箱 spx-handoff/<owner>/<repo>/session/<收件人>/<sid>!<发送人>!<会话名>.tar.xz,对象私有;owner/repo/收件人转小写 - 待接收列表就是列自己的收件箱;同一会话再交给同一人先删旧包;接收后删包,包已被别处收走时提示并刷新 - 打包换成 xz 1 级,和工单移交共用 packHandoff / unpackHandoff,删掉 gzip 版 - 删掉邮箱工单整套(mailboxIssue、MAILBOX_*、isMailboxIssue 及看板 / webhook 里的过滤、附件名编解码)和不再用的 Gitea 附件、标签、建工单接口 - session-handoff/accept 与待接收项改用 OSS 对象 key 标识 - 没配移交存储时发送、接收、刷新都提示去配,刷新回空列表 - 进度提示照工单移交:同一条提示依次显示打包、上传、下载多少 MB、解包、装会话 - 新增 URI configure-handoff-store?envFile=<绝对路径>:读 OSS_ENDPOINT / OSS_BUCKET_NAME / OSS_ACCESS_KEY / OSS_SECRET_KEY 保存,和命令共用 saveHandoffStore;URI 入口按 path 统一分发,未知 path 报错
116 lines
4.2 KiB
TypeScript
116 lines
4.2 KiB
TypeScript
import type {
|
|
Event,
|
|
ExtensionContext,
|
|
TreeDataProvider,
|
|
TreeItem,
|
|
} from 'vscode'
|
|
import type { CodeReaderApi } from './codeReader/contract'
|
|
import { commands, EventEmitter, window } from 'vscode'
|
|
import { initIdentity } from './auth/identity'
|
|
import { setProfilesDirOverride } from './cc/profiles'
|
|
import { registerCodeReader } from './codeReader'
|
|
import { logger } from './logging/logger'
|
|
import { CONFIGURE_HANDOFF_STORE_COMMAND, configureHandoffStore } from './oss/handoffStoreSetup'
|
|
import { KanbanWebviewPanel } from './panel/KanbanPanel'
|
|
import { offerPromptUpdates } from './settings/promptUpdate'
|
|
import { getSettings, migratePromptTemplates, persistSeededProfiles } from './settings/store'
|
|
import { registerUriHandler } from './uri/uriHandler'
|
|
import { webhookCoordinator } from './webhook/coordinator'
|
|
|
|
/**
|
|
* 侧边栏 TreeView 永远没有 item —— 它存在的唯一目的是接住活动栏图标
|
|
* 点击事件,触发"开 Kanban panel + 切回 File Explorer"的自动跳转。
|
|
*/
|
|
class EmptyTreeProvider implements TreeDataProvider<never> {
|
|
private readonly _onDidChangeTreeData = new EventEmitter<void>()
|
|
readonly onDidChangeTreeData: Event<void> = this._onDidChangeTreeData.event
|
|
|
|
getTreeItem(): TreeItem {
|
|
throw new Error('unreachable')
|
|
}
|
|
|
|
getChildren(): never[] {
|
|
return []
|
|
}
|
|
}
|
|
|
|
/** 对外 API:其他扩展声明 extensionDependencies 后从 exports.codeReader 注册语言插件 / 翻译插件。 */
|
|
export interface SuperpowersApi {
|
|
codeReader: CodeReaderApi
|
|
}
|
|
|
|
export function activate(context: ExtensionContext): SuperpowersApi {
|
|
// Profiles 目录 override 在 panel 未打开时也要生效(list / launch 共用)。
|
|
setProfilesDirOverride(getSettings(context).profilesDirectory || undefined)
|
|
// 存量提示词先迁到 Handlebars,再让 persistSeededProfiles 在迁移结果上补 seed。
|
|
for (const note of migratePromptTemplates(context))
|
|
logger.add({ level: note.level, source: 'settings', message: note.message })
|
|
void offerPromptUpdates(context)
|
|
void persistSeededProfiles(context)
|
|
// Start the webhook server immediately so PR callbacks are received even
|
|
// when the Kanban panel is closed. Disposed automatically via subscriptions.
|
|
webhookCoordinator.init(context)
|
|
context.subscriptions.push(logger, {
|
|
dispose: () => { void webhookCoordinator.dispose() },
|
|
})
|
|
// 状态栏常驻展示当前 Gitea 身份;token 用错人(同步/复制)时第一眼能看出来。
|
|
void initIdentity(context)
|
|
|
|
// vscode://clurdra.superpowers-vscode-clurdra/<path> 外部入口:开 cc 会话 tab、从 env 文件配置移交存储。
|
|
registerUriHandler(context)
|
|
|
|
const treeView = window.createTreeView('superpowers.kanban', {
|
|
treeDataProvider: new EmptyTreeProvider(),
|
|
showCollapseAll: false,
|
|
})
|
|
|
|
let wasVisible = treeView.visible
|
|
let isAutoOpening = false
|
|
|
|
const autoOpenPanelFromActivityBar = async (): Promise<void> => {
|
|
if (isAutoOpening)
|
|
return
|
|
isAutoOpening = true
|
|
try {
|
|
KanbanWebviewPanel.createOrShow(context)
|
|
// 立刻把 sidebar 切回 File Explorer,让 superpowers 的空 sidebar 一闪而过
|
|
try {
|
|
await commands.executeCommand('workbench.view.explorer')
|
|
}
|
|
catch {
|
|
// 不存在 explorer 视图时静默忽略
|
|
}
|
|
}
|
|
finally {
|
|
isAutoOpening = false
|
|
}
|
|
}
|
|
|
|
treeView.onDidChangeVisibility(async (e) => {
|
|
const isVisible = e.visible
|
|
// 仅当从不可见变可见(即用户点击了活动栏图标)时触发
|
|
if (isVisible && !wasVisible && !isAutoOpening)
|
|
await autoOpenPanelFromActivityBar()
|
|
wasVisible = isVisible
|
|
})
|
|
|
|
context.subscriptions.push(
|
|
treeView,
|
|
commands.registerCommand('superpowers.openKanban', () => {
|
|
KanbanWebviewPanel.createOrShow(context)
|
|
}),
|
|
commands.registerCommand('superpowers.refresh', () => {
|
|
KanbanWebviewPanel.refresh()
|
|
}),
|
|
commands.registerCommand('superpowers.setGiteaToken', () => {
|
|
KanbanWebviewPanel.createOrShow(context)
|
|
KanbanWebviewPanel.requestEditAuth()
|
|
}),
|
|
commands.registerCommand(CONFIGURE_HANDOFF_STORE_COMMAND, () => configureHandoffStore(context)),
|
|
)
|
|
|
|
return { codeReader: registerCodeReader(context) }
|
|
}
|
|
|
|
export function deactivate(): void {}
|