Files
superwork/vscode/src/cc/prompts.ts
T
cruldra 142af57d9d ✨ 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
2026-09-15 00:11:49 +08:00

89 lines
3.6 KiB
TypeScript

/**
* Prompt templates for the two claude entry points (brainstorm and
* implement-plan). Defaults live in `src/settings/store.ts` (alongside the
* other tunables); these helpers just read the persisted setting and run
* placeholder substitution.
*
* Substitution is a plain global string replace of the placeholder text
* (`{userRequest}` / `{planFile}`) — no template engine. If the user removes
* the placeholder, substitution is a no-op and that's their bug.
*/
import type { ExtensionContext } from 'vscode'
import { getSettings } from '../settings/store'
export function getBrainstormPrompt(
ctx: ExtensionContext,
vars: { userRequest: string, nonce: string, imagePaths?: string[] },
): string {
const tpl = getSettings(ctx).brainstormPrompt
let out = tpl
.split('{userRequest}')
.join(vars.userRequest)
.split('{nonce}')
.join(vars.nonce)
if (vars.imagePaths && vars.imagePaths.length > 0) {
const lines = vars.imagePaths.map(p => `- ${p}`).join('\n')
out += `\n\n参考图片(请用 Read 工具查看):\n${lines}`
}
return out
}
export function getBrainstormContinuePrompt(
ctx: ExtensionContext,
vars: { issueNumber: number, issueRef?: string, prototypeFile?: string },
): string {
const tpl = getSettings(ctx).brainstormContinuePrompt
// For youtrack cards the board number is synthetic; substitute the readable
// id (e.g. LXF-12) so the cc agent references the real issue (readable via
// `opencli yt issues show <id>`), not a non-existent gitea number.
const out = tpl.split('{issueNumber}').join(vars.issueRef ?? String(vars.issueNumber))
return fillPrototypeRef(out, vars.prototypeFile)
}
/**
* `{prototypeRef}` 在模板里独占一段:有原型插件就填一段「先读它」的交代,
* 没有就连同前后空行一起抹掉——否则模板里会留下一个空洞段落。
*/
function fillPrototypeRef(tpl: string, prototypeFile: string | undefined): string {
if (!prototypeFile)
return tpl.replace(/\n*\{prototypeRef\}\n*/g, '\n\n').trimEnd()
const para = `工单已有原型插件 ${prototypeFile},先读它了解已经定下来的界面和交互,在此基础上只对齐还不明确的地方,不要从零重画。`
return tpl.split('{prototypeRef}').join(para)
}
export function getImplementPlanPrompt(ctx: ExtensionContext, vars: { planFile: string, issueNumber: number, issueRef?: string }): string {
const tpl = getSettings(ctx).implementPlanPrompt
return tpl
.split('{planFile}')
.join(vars.planFile)
.split('{issueNumber}')
.join(vars.issueRef ?? String(vars.issueNumber))
}
/**
* 测试会话首个提示词。`prRef` 是给验收技能的定位线索:主 worktree 上是
* 已合并的 PR,worktree 里就是那条分支。
*/
export function getTestPrompt(ctx: ExtensionContext, vars: { issueNumber: number, issueRef?: string, prRef: string }): string {
const tpl = getSettings(ctx).testPrompt
return tpl
.split('{issueNumber}')
.join(vars.issueRef ?? String(vars.issueNumber))
.split('{prRef}')
.join(vars.prRef)
}
/**
* 原型会话首个提示词。只认工单号——原型是照工单正文画界面,与 PR / 分支无关。
*/
export function getPrototypePrompt(ctx: ExtensionContext, vars: { issueNumber: number, issueRef?: string }): string {
const tpl = getSettings(ctx).prototypePrompt
return tpl.split('{issueNumber}').join(vars.issueRef ?? String(vars.issueNumber))
}
export function getReviewPrompt(ctx: ExtensionContext, vars: { prNumber: string }): string {
const tpl = getSettings(ctx).reviewPrompt
return tpl.split('{prNumber}').join(vars.prNumber)
}