✨ feat(vscode): 会话交接改走阿里云 OSS 收件箱、换 xz 压缩,另加从 env 文件配置移交存储的 URI
- 会话包传到 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 报错
This commit is contained in:
1 parent
81fe14f6dc
commit
fcee4143d4
26 files changed
+542
-515
No files matched your search
@@ -0,0 +1,47 @@
|
||||
import type { ExtensionContext, Uri } from 'vscode'
|
||||
import { promises as fsp } from 'node:fs'
|
||||
import * as path from 'node:path'
|
||||
import { window } from 'vscode'
|
||||
import { logger } from '../logging/logger'
|
||||
import { parseHandoffStoreEnv } from '../oss/handoffStoreEnv'
|
||||
import { saveHandoffStore } from '../oss/handoffStoreSetup'
|
||||
|
||||
/**
|
||||
* 从 env 文件配置移交存储,由 `uriHandler.ts` 分发过来:
|
||||
*
|
||||
* vscode://clurdra.superpowers-vscode-clurdra/configure-handoff-store?envFile=<env 文件的绝对路径>
|
||||
*
|
||||
* 读文件里 `OSS_ENDPOINT` / `OSS_BUCKET_NAME` / `OSS_ACCESS_KEY` / `OSS_SECRET_KEY` 四个变量,
|
||||
* 齐了就和「配置移交存储」命令一样保存;参数不对、文件读不到、缺项都只报错,什么都不改。
|
||||
* 提示和日志里只出现 bucket、endpoint 和变量名,AccessKey 不出现。
|
||||
*/
|
||||
export async function handleConfigureHandoffStoreUri(context: ExtensionContext, uri: Uri): Promise<void> {
|
||||
const envFile = (new URLSearchParams(uri.query).get('envFile') ?? '').trim()
|
||||
if (!envFile) {
|
||||
void window.showErrorMessage('configure-handoff-store URI 缺少 envFile 参数')
|
||||
return
|
||||
}
|
||||
if (!path.isAbsolute(envFile)) {
|
||||
void window.showErrorMessage(`configure-handoff-store URI:envFile 要写绝对路径(${envFile})`)
|
||||
return
|
||||
}
|
||||
let text: string
|
||||
try {
|
||||
text = await fsp.readFile(envFile, 'utf8')
|
||||
}
|
||||
catch (err) {
|
||||
void window.showErrorMessage(`configure-handoff-store URI:读不到 ${envFile}:${err instanceof Error ? err.message : String(err)}`)
|
||||
return
|
||||
}
|
||||
const parsed = parseHandoffStoreEnv(text)
|
||||
if (!parsed.ok) {
|
||||
void window.showErrorMessage(`configure-handoff-store URI:${envFile} 里缺少 ${parsed.missing.join('、')}`)
|
||||
return
|
||||
}
|
||||
await saveHandoffStore(context, parsed.store)
|
||||
logger.add({
|
||||
level: 'info',
|
||||
source: 'uri',
|
||||
message: `URI 已保存移交存储:${parsed.store.bucket}(${parsed.store.endpoint}),来自 ${envFile}`,
|
||||
})
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { ExtensionContext, Uri } from 'vscode'
|
||||
import type { Uri } from 'vscode'
|
||||
import { promises as fsp } from 'node:fs'
|
||||
import { window, workspace } from 'vscode'
|
||||
import { listClaudeProfiles } from '../cc/profiles'
|
||||
@@ -6,34 +6,15 @@ import { logger } from '../logging/logger'
|
||||
import { createCcSessionTab } from '../panel/handlers/managedSessions'
|
||||
|
||||
/**
|
||||
* 外部触发开 cc 会话 tab 的 URI 入口(供 delegate-fix skill 等外部方调用):
|
||||
* 外部触发开 cc 会话 tab(供 delegate-fix skill 等外部方调用),由 `uriHandler.ts` 分发过来:
|
||||
*
|
||||
* vscode://clurdra.superpowers-vscode-clurdra/create-session
|
||||
* ?profile=<profile 名,不带 .json>
|
||||
* &name=<终端 tab 名,如 fix:fable5>
|
||||
* &prompt=<初始 prompt>
|
||||
* &cwd=<绝对路径,可选,缺省用 workspaceRoot>
|
||||
*
|
||||
* 编码契约:VS Code 把外部 URI 交给扩展前会对 query 整体做一次 percent-decode
|
||||
* (vs/base/common/uri.ts 的 URI.parse),这里的 URLSearchParams 是第二次 decode。
|
||||
* 因此发送方对参数值必须做两层 urlencode,值里的 & = % + 等字符才能安全通过。
|
||||
*/
|
||||
export function registerCreateSessionUriHandler(context: ExtensionContext): void {
|
||||
context.subscriptions.push(window.registerUriHandler({
|
||||
handleUri: (uri: Uri): void => {
|
||||
void handleCreateSessionUri(uri).catch((err) => {
|
||||
void window.showErrorMessage(`处理 create-session URI 失败:${err instanceof Error ? err.message : String(err)}`)
|
||||
})
|
||||
},
|
||||
}))
|
||||
}
|
||||
|
||||
async function handleCreateSessionUri(uri: Uri): Promise<void> {
|
||||
if (uri.path !== '/create-session') {
|
||||
void window.showErrorMessage(`未知的 superpowers URI path: ${uri.path}`)
|
||||
return
|
||||
}
|
||||
|
||||
export async function handleCreateSessionUri(uri: Uri): Promise<void> {
|
||||
const params = new URLSearchParams(uri.query)
|
||||
const profileName = (params.get('profile') ?? '').trim()
|
||||
const name = (params.get('name') ?? '').trim()
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
import type { ExtensionContext, Uri } from 'vscode'
|
||||
import { window } from 'vscode'
|
||||
import { handleConfigureHandoffStoreUri } from './configureHandoffStoreUri'
|
||||
import { handleCreateSessionUri } from './createSessionUriHandler'
|
||||
|
||||
/** 每个 path 一个路由,参数说明见各自的文件。 */
|
||||
const ROUTES = new Map<string, (context: ExtensionContext, uri: Uri) => Promise<void>>([
|
||||
['/create-session', (_context, uri) => handleCreateSessionUri(uri)],
|
||||
['/configure-handoff-store', handleConfigureHandoffStoreUri],
|
||||
])
|
||||
|
||||
/**
|
||||
* 扩展的外部 URI 入口 `vscode://clurdra.superpowers-vscode-clurdra/<path>?<参数>`:按 path
|
||||
* 分给 [ROUTES] 里的路由,未知 path 报错。
|
||||
*
|
||||
* 编码契约:VS Code 把外部 URI 交给扩展前会对 query 整体做一次 percent-decode
|
||||
* (vs/base/common/uri.ts 的 URI.parse),路由里的 URLSearchParams 是第二次 decode。
|
||||
* 因此发送方对参数值必须做两层 urlencode,值里的 & = % + 空格等字符才能安全通过。
|
||||
*/
|
||||
export function registerUriHandler(context: ExtensionContext): void {
|
||||
context.subscriptions.push(window.registerUriHandler({
|
||||
handleUri: (uri: Uri): void => {
|
||||
const route = ROUTES.get(uri.path)
|
||||
if (!route) {
|
||||
void window.showErrorMessage(`未知的 superpowers URI path: ${uri.path}`)
|
||||
return
|
||||
}
|
||||
void route(context, uri).catch((err) => {
|
||||
void window.showErrorMessage(`处理 ${uri.path.slice(1)} URI 失败:${err instanceof Error ? err.message : String(err)}`)
|
||||
})
|
||||
},
|
||||
}))
|
||||
}
|
||||
Reference in new issue
Block a user