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 { KanbanWebviewPanel } from './panel/KanbanPanel' import { getSettings, migratePromptTemplates, persistSeededProfiles } from './settings/store' import { registerCreateSessionUriHandler } from './uri/createSessionUriHandler' import { webhookCoordinator } from './webhook/coordinator' /** * 侧边栏 TreeView 永远没有 item —— 它存在的唯一目的是接住活动栏图标 * 点击事件,触发"开 Kanban panel + 切回 File Explorer"的自动跳转。 */ class EmptyTreeProvider implements TreeDataProvider { private readonly _onDidChangeTreeData = new EventEmitter() readonly onDidChangeTreeData: Event = 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 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/create-session 外部触发开 cc 会话 tab。 registerCreateSessionUriHandler(context) const treeView = window.createTreeView('superpowers.kanban', { treeDataProvider: new EmptyTreeProvider(), showCollapseAll: false, }) let wasVisible = treeView.visible let isAutoOpening = false const autoOpenPanelFromActivityBar = async (): Promise => { 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() }), ) return { codeReader: registerCodeReader(context) } } export function deactivate(): void {}