模板渲染器Skill template-renderer

模板渲染技能:用于渲染模板,通过替换{{TOKEN}}占位符为实际值,支持规范、计划、任务三种模板类型,具备模式验证、安全控制(令牌白名单、值净化)功能,适用于软件开发、项目管理、文档生成等场景。关键词:模板渲染、占位符替换、安全验证、模式验证、项目管理、文档生成、令牌处理、自动化文档、软件开发工具。

项目管理 0 次安装 0 次浏览 更新于 3/10/2026

名称: 模板渲染器 描述: 通过将{{TOKEN}}占位符替换为实际值来渲染模板,支持所有三种模板(规范、计划、任务),具备模式验证和安全净化功能 版本: 1.0.0 模型: sonnet 调用者: 两者 用户可调用: 是 工具: [读取, 写入, mcp__filesystem__read_text_file, mcp__filesystem__write_file] 参数: ‘<模板名称> <输出路径> [–tokens <json文件>]’ 最佳实践:

  • 净化所有令牌值以防止注入攻击
  • 仅在PROJECT_ROOT内验证模板路径
  • 使用令牌白名单(仅允许预定义令牌)
  • 验证规范模板的输出模式
  • 在令牌替换过程中保持Markdown格式
  • 缺少必需令牌时出错
  • 警告未使用的令牌 错误处理: 严格 流式传输: 不支持 已验证: 否 最后验证时间: 2026-02-19T05:29:09.098Z

模板渲染器

<身份> 模板渲染器技能 - 通过将{{TOKEN}}占位符替换为实际值来渲染模板。支持规范模板.md计划模板.md和任务模板.md,具备模式验证和安全控制(SEC-SPEC-003、SEC-SPEC-004)。 </身份>

<能力>

  • 渲染所有三种模板类型(规范、计划、任务)
  • 令牌替换:{{TOKEN}} → 值替换
  • 安全:令牌值净化(防止注入)
  • 安全:令牌白名单强制执行(仅允许预定义令牌)
  • 安全:模板路径验证(仅PROJECT_ROOT内)
  • 规范模板的模式验证
  • 缺少必需令牌的错误处理
  • 未使用令牌的警告系统
  • 保持Markdown格式和结构 </能力>

<说明> <执行过程>

步骤1: 验证输入(安全 - 必选)

模板路径验证(SEC-SPEC-002):

  • 验证模板文件存在于PROJECT_ROOT内
  • 拒绝任何路径遍历尝试(…/)
  • 仅允许来自.claude/templates/的模板

令牌白名单验证(SEC-SPEC-003):

// 按模板类型允许的令牌
const SPEC_TOKENS = [
  'FEATURE_NAME',
  'VERSION',
  'AUTHOR',
  'DATE',
  'STATUS',
  'ACCEPTANCE_CRITERIA_1',
  'ACCEPTANCE_CRITERIA_2',
  'ACCEPTANCE_CRITERIA_3',
  'TERM_1',
  'TERM_2',
  'TERM_3',
  'HTTP_METHOD',
  'ENDPOINT_PATH',
  'PROJECT_NAME',
];

const PLAN_TOKENS = [
  'PLAN_TITLE',
  'DATE',
  'FRAMEWORK_VERSION',
  'STATUS',
  'EXECUTIVE_SUMMARY',
  'TOTAL_TASKS',
  'FEATURES_COUNT',
  'ESTIMATED_TIME',
  'STRATEGY',
  'KEY_DELIVERABLES_LIST',
  'PHASE_N_NAME',
  'PHASE_N_PURPOSE',
  'PHASE_N_DURATION',
  'DEPENDENCIES',
  'PARALLEL_OK',
  'VERIFICATION_COMMANDS',
];

const TASKS_TOKENS = [
  'FEATURE_NAME',
  'VERSION',
  'AUTHOR',
  'DATE',
  'STATUS',
  'PRIORITY',
  'ESTIMATED_EFFORT',
  'RELATED_SPECS',
  'DEPENDENCIES',
  'FEATURE_DISPLAY_NAME',
  'FEATURE_DESCRIPTION',
  'BUSINESS_VALUE',
  'USER_IMPACT',
  'EPIC_NAME',
  'EPIC_GOAL',
  'SUCCESS_CRITERIA',
];

令牌值净化(SEC-SPEC-004):

function sanitizeTokenValue(value) {
  return String(value)
    .replace(/[<>]/g, '') // 防止HTML注入
    .replace(/\$\{/g, '') // 防止模板字面量注入
    .replace(/\{\{/g, '') // 防止嵌套令牌注入
    .trim();
}

步骤2: 读取模板

使用读取或mcp__filesystem__read_text_file读取模板文件:

  • .claude/templates/规范模板.md(46个令牌)
  • .claude/templates/计划模板.md(30+个令牌)
  • .claude/templates/任务模板.md(20+个令牌)

步骤3: 令牌替换

将所有{{TOKEN}}占位符替换为净化后的值:

function renderTemplate(templateContent, tokenMap) {
  let rendered = templateContent;

  // 替换每个令牌
  for (const [token, value] of Object.entries(tokenMap)) {
    // 验证令牌在白名单中
    if (!isAllowedToken(token, templateType)) {
      throw new Error(`令牌不在白名单中: ${token}`);
    }

    // 净化值
    const sanitizedValue = sanitizeTokenValue(value);

    // 替换所有出现
    const regex = new RegExp(`\\{\\{${token}\\}\\}`, 'g');
    rendered = rendered.replace(regex, sanitizedValue);
  }

  // 检查缺少的必需令牌
  const missingTokens = rendered.match(/\{\{[A-Z_0-9]+\}\}/g);
  if (missingTokens) {
    throw new Error(`缺少必需令牌: ${missingTokens.join(', ')}`);
  }

  return rendered;
}

步骤4: 模式验证(仅规范模板)

对于规范模板,根据JSON模式验证渲染后的输出:

// 提取YAML前端码
const yamlMatch = rendered.match(/^---
([\s\S]*?)
---/);
if (!yamlMatch) {
  throw new Error('未找到YAML前端码');
}

// 解析YAML
const yaml = require('js-yaml');
const frontmatter = yaml.load(yamlMatch[1]);

// 根据模式验证
const schema = JSON.parse(
  fs.readFileSync('.claude/schemas/规范模板.schema.json', 'utf8')
);

const Ajv = require('ajv');
const ajv = new Ajv();
const validate = ajv.compile(schema);

if (!validate(frontmatter)) {
  throw new Error(`模式验证失败: ${JSON.stringify(validate.errors)}`);
}

步骤5: 写入输出

使用写入或mcp__filesystem__write_file将渲染后的模板写入输出路径:

  • 验证输出路径在PROJECT_ROOT内
  • 如果需要,创建父目录
  • 以UTF-8编码写入文件

步骤6: 验证

运行渲染后检查:

# 检查是否有未解析的令牌
如果存在"{{"在<输出文件>,则输出"错误: 发现未解析令牌!",否则输出"✓ 所有令牌已解析"

# 对于规范: 验证YAML前端码
head -50 <输出文件> | grep -E "^---$" | wc -l  # 应输出: 2

# 对于规范: 根据模式验证(如果安装ajv)
# ajv validate -s .claude/schemas/规范模板.schema.json -d <输出文件>

</执行过程>

<最佳实践>

  1. 始终验证模板路径: 在读取前使用PROJECT_ROOT验证
  2. 净化所有令牌值: 防止注入攻击(SEC-SPEC-004)
  3. 强制执行令牌白名单: 仅允许预定义令牌(SEC-SPEC-003)
  4. 缺少令牌时出错: 不要静默忽略缺少的必需令牌
  5. 警告未使用令牌: 帮助用户捕获令牌名称中的拼写错误
  6. 保持Markdown格式: 不要更改缩进、项目符号、代码块
  7. 验证规范模式: 为规范模板运行JSON模式验证
  8. 记录所有操作: 将模板、使用的令牌、输出路径记录到内存

</最佳实践>

<错误处理>

缺少必需令牌:

错误: 模板中缺少必需令牌:
  - {{FEATURE_NAME}}
  - {{ACCEPTANCE_CRITERIA_1}}

在令牌映射中提供这些令牌。

无效令牌(不在白名单中):

错误: 令牌不在白名单中: INVALID_TOKEN
规范模板允许的令牌: FEATURE_NAME, VERSION, AUTHOR, DATE, ...

模板路径遍历:

错误: 模板路径超出PROJECT_ROOT
路径: ../../etc/passwd
仅允许来自.claude/templates/的模板。

模式验证失败(规范模板):

错误: 模式验证失败:
  - /version: 必须匹配模式"^\d+\.\d+\.\d+$"
  - /acceptance_criteria: 必须至少有1个项目

未使用令牌警告:

警告: 提供了未使用的令牌:
  - EXTRA_TOKEN_1
  - EXTRA_TOKEN_2

这些令牌不在模板中。检查拼写错误。

</错误处理> </说明>

<示例> <使用示例> 示例1: 渲染规范模板

// 来自另一个技能(例如,规范收集)
技能({
  技能: '模板渲染器',
  参数: {
    模板名称: '规范模板',
    输出路径: '.claude/context/artifacts/specifications/my-feature-spec.md',
    令牌: {
      FEATURE_NAME: '用户身份验证',
      VERSION: '1.0.0',
      AUTHOR: 'Claude',
      DATE: '2026-01-28',
      STATUS: '草案',
      ACCEPTANCE_CRITERIA_1: '用户可以使用邮箱和密码登录',
      ACCEPTANCE_CRITERIA_2: '密码符合复杂度要求',
      ACCEPTANCE_CRITERIA_3: '失败的登录尝试被记录',
    },
  },
});

示例2: 渲染计划模板

技能({
  技能: '模板渲染器',
  参数: {
    模板名称: '计划模板',
    输出路径: '.claude/context/plans/my-feature-plan.md',
    令牌: {
      PLAN_TITLE: '用户身份验证实施计划',
      DATE: '2026-01-28',
      FRAMEWORK_VERSION: 'Agent-Studio v2.2.1',
      STATUS: '阶段0 - 研究',
      EXECUTIVE_SUMMARY: '基于JWT的身份验证实现计划...',
      TOTAL_TASKS: '14个原子任务',
      ESTIMATED_TIME: '2-3周',
      STRATEGY: '基础优先(模式)→ 核心功能',
    },
  },
});

示例3: 渲染任务模板

技能({
  技能: '模板渲染器',
  参数: {
    模板名称: '任务模板',
    输出路径: '.claude/context/artifacts/tasks/auth-tasks.md',
    令牌: {
      FEATURE_NAME: 'user-authentication',
      VERSION: '1.0.0',
      AUTHOR: '工程团队',
      DATE: '2026-01-28',
      FEATURE_DISPLAY_NAME: '用户身份验证',
      FEATURE_DESCRIPTION: '基于JWT的身份验证系统',
      BUSINESS_VALUE: '启用用户账户管理',
      USER_IMPACT: '用户可以安全访问个性化功能',
    },
  },
});

示例4: CLI使用

# 使用CLI包装器(在main.cjs中实现后)
node .claude/skills/template-renderer/scripts/main.cjs \
  --template 规范模板 \
  --output ./my-spec.md \
  --tokens '{"FEATURE_NAME":"我的功能","VERSION":"1.0.0","AUTHOR":"Claude","DATE":"2026-01-28"}'

# 或使用JSON文件
node .claude/skills/template-renderer/scripts/main.cjs \
  --template 计划模板 \
  --output ./my-plan.md \
  --tokens-file ./tokens.json

示例5: 与规范收集集成

// 在规范收集技能中(任务#16):
// 通过渐进式披露收集需求后...

const tokens = {
  FEATURE_NAME: gatheredRequirements.featureName,
  VERSION: '1.0.0',
  AUTHOR: 'Claude',
  DATE: new Date().toISOString().split('T')[0],
  ACCEPTANCE_CRITERIA_1: gatheredRequirements.criteria[0],
  ACCEPTANCE_CRITERIA_2: gatheredRequirements.criteria[1],
  ACCEPTANCE_CRITERIA_3: gatheredRequirements.criteria[2],
  // ... 更多令牌
};

技能({
  技能: '模板渲染器',
  参数: {
    模板名称: '规范模板',
    输出路径: `.claude/context/artifacts/specifications/${featureName}-spec.md`,
    令牌: tokens,
  },
});

</使用示例> </示例>

内存协议(必选)

开始前:

cat .claude/context/memory/learnings.md

完成后:

  • 新模式 -> .claude/context/memory/learnings.md
  • 发现的问题 -> .claude/context/memory/issues.md
  • 做出的决定 -> .claude/context/memory/decisions.md

假设中断: 您的上下文可能重置。如果它不在内存中,它就没有发生。