✨ feat(vscode): 工单挂原型插件,详情面板一键导入 Figma

- prototypeFile 走通 state → Issue → webview 全链路(gitea/youtrack 两个
  loader、两份 KNOWN_STATE_FIELDS、issue/patch、webview types),按 planFile
  同款当共享字段;路径校验换成 .json 版,允许绝对路径
- 详情面板「计划文件」下加「原型插件路径」行:双击开 manifest.json,
  行尾按钮「在 Figma 中导入并打开」;没挂插件时只显示空态
- src/figma/:把 manifest 写进 Figma 桌面版的 localFileExtensions 再拉起
  Figma。坑是 Figma 退出会用内存状态覆盖 settings.json,所以写之前先
  osascript 优雅退出并轮询等它真没了(10s 等不到就让用户手动关,不强杀);
  写前备份 settings.json.bak-<时间戳>;已导入过就跳过写入直接打开;
  非 macOS 只把路径复制到剪贴板
- webhook 里 spec/plan 的 marker 同步改成表驱动,顺带认第三种 prototype
- 提示词:prototype.md 要求画完挂 marker;brainstorm-continue.md 新增
  {prototypeRef} 占位符,有原型插件时让续聊先读它别从零重画,没有时
  连同整段抹掉

Claude-Session: https://claude.ai/code/session_01Kgmb1LvrPmFX3NoUDB4zZC
This commit is contained in:
cruldra committed 2026-09-15 00:11:49 +08:00
1 parent def5f4e88c
commit 142af57d9d
24 files changed
+628 -85

No files matched your search

@@ -37,6 +37,7 @@ interface BottomTabsProps {
onStartPrototypeSession: (issueNumber: number) => void
onResumePrototypeSession: (sessionId: string, issueNumber: number, cwd?: string) => void
onOpenFile: (path: string) => void
onOpenPrototypeInFigma: (issueNumber: number, path: string) => void
onImplement: (issueNumber: number, planFile: string, profilePath?: string, sessionId?: string) => void
onOpenPr: (pr: string) => void
onGeneratePrDiffSummary: (issueNumber: number) => void
@@ -140,6 +141,7 @@ export function BottomTabs(props: BottomTabsProps) {
onStartPrototypeSession={props.onStartPrototypeSession}
onResumePrototypeSession={props.onResumePrototypeSession}
onOpenFile={props.onOpenFile}
onOpenPrototypeInFigma={props.onOpenPrototypeInFigma}
onImplement={props.onImplement}
onOpenPr={props.onOpenPr}
onGeneratePrDiffSummary={props.onGeneratePrDiffSummary}
@@ -69,6 +69,11 @@ interface IssueDetailPanelProps {
onStartPrototypeSession: (issueNumber: number) => void
/** Open a workspace-relative file in the editor. */
onOpenFile: (path: string) => void
/**
* 把工单的 Figma 插件 manifest 导进本机 Figma 桌面版并拉起 Figma。
* 「原型插件路径」行尾那个按钮。
*/
onOpenPrototypeInFigma: (issueNumber: number, path: string) => void
/** Kick off the end-to-end implementation flow for the given plan file. */
onImplement: (issueNumber: number, planFile: string, profilePath?: string, sessionId?: string) => void
/** Open the gitea PR page in the browser. */
@@ -151,6 +156,7 @@ export function IssueDetailPanel({
onStartTestSession,
onStartPrototypeSession,
onOpenFile,
onOpenPrototypeInFigma,
onImplement,
onOpenPr,
onGeneratePrDiffSummary,
@@ -567,6 +573,24 @@ export function IssueDetailPanel({
}]
: [],
},
{
key: 'prototypeFile',
label: '原型插件路径',
type: 'file-link',
description: '双击在编辑器打开 Figma 插件的 manifest.json;点右侧按钮把插件导入本机 Figma 并打开;cc 通过 issue body 的 <!-- spx:prototype=路径 --> 注释同步',
onOpen: (p: string) => onOpenFile(p),
// 没挂原型插件时整个按钮不渲染,行只显示空态。
secondaryActions: issue?.prototypeFile
? [{
icon: <ExternalLink className="size-3.5" />,
title: '在 Figma 中导入并打开',
onClick: () => {
if (issue?.prototypeFile)
onOpenPrototypeInFigma(issue.number, issue.prototypeFile)
},
}]
: [],
},
{
key: 'pr',
label: '合并请求',
@@ -641,7 +665,7 @@ export function IssueDetailPanel({
],
},
],
[onResumeSession, onResumeReviewSession, onResumeTestSession, onStartTestSession, onResumePrototypeSession, onStartPrototypeSession, onOpenFile, onImplement, onOpenPr, onGeneratePrDiffSummary, onOpenWorktree, onDeleteWorktree, onMergeBranch, onCloseSessionTab, onContinueBrainstorm, onClearBrainstormSession, onOpenLogs, issue, locked, lockTitle, globalAutoReview, prDiffSummaryRunning, profiles, isSessionTabPending, onStartReviewSession],
[onResumeSession, onResumeReviewSession, onResumeTestSession, onStartTestSession, onResumePrototypeSession, onStartPrototypeSession, onOpenFile, onOpenPrototypeInFigma, onImplement, onOpenPr, onGeneratePrDiffSummary, onOpenWorktree, onDeleteWorktree, onMergeBranch, onCloseSessionTab, onContinueBrainstorm, onClearBrainstormSession, onOpenLogs, issue, locked, lockTitle, globalAutoReview, prDiffSummaryRunning, profiles, isSessionTabPending, onStartReviewSession],
)
// 同事的工单只读:属性表统一消毒,顶部只留查看类按钮。
@@ -671,6 +695,7 @@ export function IssueDetailPanel({
prototypeProfilePath: matchProfileOption(issue.prototypeProfilePath, profiles) || null,
specFile: issue.specFile ?? null,
planFile: issue.planFile ?? null,
prototypeFile: issue.prototypeFile ?? null,
prDiffFile: issue.prDiffFile ?? null,
pr: issue.pr
? `${issue.pr}${issue.prMerged ? '(已合并)' : ''}`
@@ -994,10 +994,11 @@ export function SettingsModal({
label="头脑风暴续聊提示词"
hint={(
<>
可用占位符
{' '}
可用占位符:
<code>{'{issueNumber}'}</code>
;用于对已有工单继续讨论 / 写 spec/plan 的会话初始指令。
、
<code>{'{prototypeRef}'}</code>
(工单挂了原型插件才填,没挂时该段整段删掉);用于对已有工单继续讨论 / 写 spec/plan 的会话初始指令。
</>
)}
>