Initial commit from Spec Kit CN template
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
---
|
||||
description: 在任务生成后, 对 spec.md、plan.md 和 tasks.md 执行非破坏性的跨制品一致性和质量分析.
|
||||
---
|
||||
|
||||
## 用户输入
|
||||
|
||||
```text
|
||||
$ARGUMENTS
|
||||
```
|
||||
|
||||
在继续之前, 你**必须**考虑用户输入(如果不为空).
|
||||
|
||||
## 目标
|
||||
|
||||
在实施之前, 识别三个核心制品(`spec.md`、`plan.md`、`tasks.md`)之间的不一致、重复、模糊和规范不足的项目. 此命令**必须**在 `/speckit.tasks` 成功生成完整的 `tasks.md` 后运行.
|
||||
|
||||
## 操作约束
|
||||
|
||||
**严格只读**: **不要**修改任何文件. 输出结构化分析报告. 提供可选的修复计划(用户必须明确批准后才能手动调用任何后续编辑命令).
|
||||
|
||||
**章程权威**: 项目章程(`.specify/memory/constitution.md`)在此分析范围内是**不可协商的**. 章程冲突自动为严重问题, 需要调整规范、计划或任务——而不是稀释、重新解释或默默忽略原则. 如果原则本身需要更改, 那必须在 `/speckit.analyze` 之外的单独、明确的章程更新中进行.
|
||||
|
||||
## 执行步骤
|
||||
|
||||
### 1. 初始化分析上下文
|
||||
|
||||
从仓库根目录运行一次 `.specify/scripts/powershell/check-prerequisites.ps1 -Json -RequireTasks -IncludeTasks` 并解析 JSON 以获取 FEATURE_DIR 和 AVAILABLE_DOCS. 推导绝对路径:
|
||||
|
||||
- SPEC = FEATURE_DIR/spec.md
|
||||
- PLAN = FEATURE_DIR/plan.md
|
||||
- TASKS = FEATURE_DIR/tasks.md
|
||||
|
||||
如果任何必需文件缺失, 则以错误消息中止(指示用户运行缺失的先决条件命令).
|
||||
对于参数中的单引号, 如 "I'm Groot", 使用转义语法: 例如 'I'\''m Groot'(或尽可能使用双引号: "I'm Groot").
|
||||
|
||||
### 2. 加载制品(渐进式展示)
|
||||
|
||||
仅从每个制品加载最小必需的上下文:
|
||||
|
||||
**从 spec.md: **
|
||||
|
||||
- 概述/上下文
|
||||
- 功能需求
|
||||
- 非功能需求
|
||||
- 用户故事
|
||||
- 边缘情况(如果存在)
|
||||
|
||||
**从 plan.md: **
|
||||
|
||||
- 架构/技术栈选择
|
||||
- 数据模型引用
|
||||
- 阶段
|
||||
- 技术约束
|
||||
|
||||
**从 tasks.md: **
|
||||
|
||||
- 任务 ID
|
||||
- 描述
|
||||
- 阶段分组
|
||||
- 并行标记 [P]
|
||||
- 引用的文件路径
|
||||
|
||||
**从章程: **
|
||||
|
||||
- 加载 `.specify/memory/constitution.md` 进行原则验证
|
||||
|
||||
### 3. 构建语义模型
|
||||
|
||||
创建内部表示(输出中不包含原始制品):
|
||||
|
||||
- **需求清单**: 每个功能和非功能需求, 带有稳定键(基于祈使短语推导 slug; 例如, "User can upload file" → `user-can-upload-file`)
|
||||
- **用户故事/操作清单**: 带有验收标准的离散用户操作
|
||||
- **任务覆盖映射**: 将每个任务映射到一个或多个需求或故事(通过关键词/显式引用模式推断, 如 ID 或关键短语)
|
||||
- **章程规则集**: 提取原则名称和 MUST/SHOULD 规范性声明
|
||||
|
||||
### 4. 检测过程(高效令牌分析)
|
||||
|
||||
专注于高信号发现. 限制总共 50 个发现; 在溢出摘要中聚合其余部分.
|
||||
|
||||
#### A. 重复检测
|
||||
|
||||
- 识别近似重复的需求
|
||||
- 标记较低质量的表述以进行合并
|
||||
|
||||
#### B. 模糊性检测
|
||||
|
||||
- 标记缺乏可测量标准的模糊形容词(快速、可扩展、安全、直观、稳健)
|
||||
- 标记未解决的占位符(TODO、TKTK、???、`<placeholder>` 等)
|
||||
|
||||
#### C. 规范不足
|
||||
|
||||
- 有动词但缺少对象或可测量结果的需求
|
||||
- 缺少验收标准对齐的用户故事
|
||||
- 引用规范/计划中未定义的文件或组件的任务
|
||||
|
||||
#### D. 章程对齐
|
||||
|
||||
- 与 MUST 原则冲突的任何需求或计划元素
|
||||
- 章程中缺失的强制部分或质量门控
|
||||
|
||||
#### E. 覆盖缺口
|
||||
|
||||
- 没有关联任务的需求
|
||||
- 没有映射需求/故事的任务
|
||||
- 未在任务中反映的非功能需求(例如, 性能、安全性)
|
||||
|
||||
#### F. 不一致性
|
||||
|
||||
- 术语漂移(相同概念在不同文件中命名不同)
|
||||
- 计划中引用但在规范中缺失的数据实体(反之亦然)
|
||||
- 任务排序矛盾(例如, 集成任务在基础设置任务之前而没有依赖说明)
|
||||
- 冲突需求(例如, 一个要求 Next.js 而另一个指定 Vue)
|
||||
|
||||
### 5. 严重性分配
|
||||
|
||||
使用此启发式方法对发现进行优先级排序:
|
||||
|
||||
- **严重**: 违反章程 MUST、缺失核心规范制品, 或零覆盖的需求阻止基线功能
|
||||
- **高**: 重复或冲突需求、模糊的安全/性能属性、不可测试的验收标准
|
||||
- **中**: 术语漂移、缺失非功能任务覆盖、规范不足的边缘情况
|
||||
- **低**: 风格/措辞改进、不影响执行顺序的轻微冗余
|
||||
|
||||
### 6. 生成紧凑分析报告
|
||||
|
||||
输出 Markdown 报告(不写入文件), 结构如下:
|
||||
|
||||
## 规范分析报告
|
||||
|
||||
| ID | 类别 | 严重性 | 位置 | 摘要 | 建议 |
|
||||
|----|------|--------|------|------|------|
|
||||
| A1 | 重复 | 高 | spec.md:L120-134 | 两个相似需求... | 合并表述; 保留更清晰的版本 |
|
||||
|
||||
(每个发现添加一行; 生成以类别首字母为前缀的稳定 ID. )
|
||||
|
||||
**覆盖摘要表: **
|
||||
|
||||
| 需求键 | 有任务? | 任务 ID | 备注 |
|
||||
|--------|----------|---------|------|
|
||||
|
||||
**章程对齐问题: **(如果有)
|
||||
|
||||
**未映射任务: **(如果有)
|
||||
|
||||
**指标: **
|
||||
|
||||
- 总需求数
|
||||
- 总任务数
|
||||
- 覆盖率%(有 >=1 个任务的需求)
|
||||
- 模糊性计数
|
||||
- 重复计数
|
||||
- 严重问题计数
|
||||
|
||||
### 7. 提供下一步操作
|
||||
|
||||
在报告末尾, 输出简洁的下一步操作块:
|
||||
|
||||
- 如果存在严重问题: 建议在 `/speckit.implement` 之前解决
|
||||
- 如果只有低/中问题: 用户可以继续, 但提供改进建议
|
||||
- 提供明确的命令建议: 例如, "运行 /speckit.specify 进行细化"、"运行 /speckit.plan 调整架构"、"手动编辑 tasks.md 为 'performance-metrics' 添加覆盖"
|
||||
|
||||
### 8. 提供修复
|
||||
|
||||
询问用户: "你希望我为前 N 个问题建议具体的修复编辑吗?"(不要自动应用它们. )
|
||||
|
||||
## 操作原则
|
||||
|
||||
### 上下文效率
|
||||
|
||||
- **最小高信噪比令牌**: 专注于可操作的发现, 而不是详尽的文档
|
||||
- **渐进式展示**: 增量加载制品; 不要将所有内容倾倒到分析中
|
||||
- **高效令牌输出**: 限制发现表为 50 行; 总结溢出部分
|
||||
- **确定性结果**: 无更改重新运行应产生一致的 ID 和计数
|
||||
|
||||
### 分析指南
|
||||
|
||||
- **绝不修改文件**(这是只读分析)
|
||||
- **绝不虚构缺失部分**(如果缺失, 准确报告)
|
||||
- **优先处理章程违规**(这些总是严重的)
|
||||
- **使用示例而非详尽规则**(引用具体实例, 而不是通用模式)
|
||||
- **优雅报告零问题**(发出带有覆盖统计的成功报告)
|
||||
|
||||
## 上下文
|
||||
|
||||
$ARGUMENTS
|
||||
@@ -0,0 +1,287 @@
|
||||
---
|
||||
description: 基于用户需求为当前功能生成自定义检查清单.
|
||||
---
|
||||
|
||||
## 清单目的: "需求编写的单元测试"
|
||||
|
||||
**核心概念**: 清单是**需求编写的单元测试** - 它们验证特定领域中需求的质量、清晰度和完整性.
|
||||
|
||||
**不用于验证/测试**:
|
||||
- ❌ 不是"验证按钮点击正确"
|
||||
- ❌ 不是"测试错误处理有效"
|
||||
- ❌ 不是"确认 API 返回 200"
|
||||
- ❌ 不是检查代码/实现是否符合规范
|
||||
|
||||
**用于需求质量验证**:
|
||||
- ✅ "是否为所有卡片类型定义了视觉层次需求?"(完整性)
|
||||
- ✅ "'突出显示'是否通过具体尺寸/位置进行了量化?"(清晰度)
|
||||
- ✅ "所有交互元素的悬停状态需求是否一致?"(一致性)
|
||||
- ✅ "是否为键盘导航定义了可访问性需求?"(覆盖度)
|
||||
- ✅ "规范是否定义了 logo 图像加载失败时的处理?"(边缘情况)
|
||||
|
||||
**比喻**: 如果你的规范是用英文编写的代码, 那么清单就是它的单元测试套件. 你测试的是需求是否编写良好、完整、明确并准备好实施 - 而不是实现是否有效.
|
||||
|
||||
## 用户输入
|
||||
|
||||
```text
|
||||
$ARGUMENTS
|
||||
```
|
||||
|
||||
在继续之前, 你**必须**考虑用户输入(如果不为空).
|
||||
|
||||
## 执行步骤
|
||||
|
||||
1. **设置**: 从仓库根目录运行 `.specify/scripts/powershell/check-prerequisites.ps1 -Json` 并解析JSON以获取FEATURE_DIR和AVAILABLE_DOCS列表.
|
||||
- 所有文件路径必须是绝对路径.
|
||||
- 对于参数中的单引号如"I'm Groot", 使用转义语法: 例如 'I'\''m Groot'(或者尽可能使用双引号: "I'm Groot").
|
||||
|
||||
2. **澄清意图(动态)**: 推导最多三个初始上下文澄清问题(无预编目录). 它们必须:
|
||||
- 从用户的表述 + 从规范/计划/任务中提取的信号生成
|
||||
- 只询问实质上改变清单内容的信息
|
||||
- 如果在`$ARGUMENTS`中已经明确, 则单独跳过
|
||||
- 优先考虑精确性而非广度
|
||||
|
||||
Generation algorithm:
|
||||
1. Extract signals: feature domain keywords (e.g., auth, latency, UX, API), risk indicators ("critical", "must", "compliance"), stakeholder hints ("QA", "review", "security team"), and explicit deliverables ("a11y", "rollback", "contracts").
|
||||
2. Cluster signals into candidate focus areas (max 4) ranked by relevance.
|
||||
3. Identify probable audience & timing (author, reviewer, QA, release) if not explicit.
|
||||
4. Detect missing dimensions: scope breadth, depth/rigor, risk emphasis, exclusion boundaries, measurable acceptance criteria.
|
||||
5. Formulate questions chosen from these archetypes:
|
||||
- Scope refinement (e.g., "Should this include integration touchpoints with X and Y or stay limited to local module correctness?")
|
||||
- Risk prioritization (e.g., "Which of these potential risk areas should receive mandatory gating checks?")
|
||||
- Depth calibration (e.g., "Is this a lightweight pre-commit sanity list or a formal release gate?")
|
||||
- Audience framing (e.g., "Will this be used by the author only or peers during PR review?")
|
||||
- Boundary exclusion (e.g., "Should we explicitly exclude performance tuning items this round?")
|
||||
- Scenario class gap (e.g., "No recovery flows detected—are rollback / partial failure paths in scope?")
|
||||
|
||||
Question formatting rules:
|
||||
- If presenting options, generate a compact table with columns: Option | Candidate | Why It Matters
|
||||
- Limit to A–E options maximum; omit table if a free-form answer is clearer
|
||||
- Never ask the user to restate what they already said
|
||||
- Avoid speculative categories (no hallucination). If uncertain, ask explicitly: "Confirm whether X belongs in scope."
|
||||
|
||||
Defaults when interaction impossible:
|
||||
- Depth: Standard
|
||||
- Audience: Reviewer (PR) if code-related; Author otherwise
|
||||
- Focus: Top 2 relevance clusters
|
||||
|
||||
Output the questions (label Q1/Q2/Q3). After answers: if ≥2 scenario classes (Alternate / Exception / Recovery / Non-Functional domain) remain unclear, you MAY ask up to TWO more targeted follow‑ups (Q4/Q5) with a one-line justification each (e.g., "Unresolved recovery path risk"). Do not exceed five total questions. Skip escalation if user explicitly declines more.
|
||||
|
||||
3. **理解用户请求**: 结合 `$ARGUMENTS` + 澄清答案:
|
||||
- 推导清单主题(例如: security, review, deploy, ux)
|
||||
- 整合用户明确提到的必需项目
|
||||
- 将焦点选择映射到类别框架
|
||||
- 从规范/计划/任务中推断任何缺失的上下文(不要虚构)
|
||||
|
||||
4. **加载功能上下文**: 从 FEATURE_DIR 读取:
|
||||
- spec.md: 功能需求和范围
|
||||
- plan.md(如果存在): 技术细节、依赖关系
|
||||
- tasks.md(如果存在): 实施任务
|
||||
|
||||
**上下文加载策略**:
|
||||
- 仅加载与活动焦点区域相关的必要部分(避免全文转储)
|
||||
- 优先将长部分总结为简洁的场景/需求要点
|
||||
- 使用渐进式披露: 仅在检测到差距时添加后续检索
|
||||
- 如果源文档很大, 生成临时摘要项目而不是嵌入原始文本
|
||||
|
||||
5. **生成清单** - 创建"需求的单元测试":
|
||||
- Create `FEATURE_DIR/checklists/` directory if it doesn't exist
|
||||
- Generate unique checklist filename:
|
||||
- Use short, descriptive name based on domain (e.g., `ux.md`, `api.md`, `security.md`)
|
||||
- Format: `[domain].md`
|
||||
- If file exists, append to existing file
|
||||
- Number items sequentially starting from CHK001
|
||||
- Each `/speckit.checklist` run creates a NEW file (never overwrites existing checklists)
|
||||
|
||||
**核心原则 - 测试需求, 而非实现**:
|
||||
每个清单项目必须评估需求本身, 检查:
|
||||
- **完整性**: 所有必要的需求是否存在?
|
||||
- **清晰度**: 需求是否明确无歧义且具体?
|
||||
- **一致性**: 需求之间是否相互一致?
|
||||
- **可测量性**: 需求是否可以客观验证?
|
||||
- **覆盖度**: 是否涵盖了所有场景/边缘情况?
|
||||
|
||||
**类别结构** - 按需求质量维度分组项目:
|
||||
- **需求完整性**(所有必要的需求是否已记录?)
|
||||
- **需求清晰度**(需求是否具体且无歧义?)
|
||||
- **需求一致性**(需求是否一致且无冲突?)
|
||||
- **验收标准质量**(成功标准是否可测量?)
|
||||
- **场景覆盖度**(是否涵盖了所有流程/情况?)
|
||||
- **边缘情况覆盖度**(是否定义了边界条件?)
|
||||
- **非功能性需求**(性能、安全性、可访问性等 - 是否已指定?)
|
||||
- **依赖关系和假设**(是否已记录和验证?)
|
||||
- **歧义和冲突**(什么 NEEDS CLARIFICATION?)
|
||||
|
||||
**如何编写清单项目 - "需求编写的单元测试"**:
|
||||
|
||||
❌ **WRONG** (Testing implementation):
|
||||
- "Verify landing page displays 3 episode cards"
|
||||
- "Test hover states work on desktop"
|
||||
- "Confirm logo click navigates home"
|
||||
|
||||
✅ **CORRECT** (Testing requirements quality):
|
||||
- "Are the exact number and layout of featured episodes specified?" [Completeness]
|
||||
- "Is 'prominent display' quantified with specific sizing/positioning?" [Clarity]
|
||||
- "Are hover state requirements consistent across all interactive elements?" [Consistency]
|
||||
- "Are keyboard navigation requirements defined for all interactive UI?" [Coverage]
|
||||
- "Is the fallback behavior specified when logo image fails to load?" [Edge Cases]
|
||||
- "Are loading states defined for asynchronous episode data?" [Completeness]
|
||||
- "Does the spec define visual hierarchy for competing UI elements?" [Clarity]
|
||||
|
||||
**项目结构**:
|
||||
Each item should follow this pattern:
|
||||
- Question format asking about requirement quality
|
||||
- Focus on what's WRITTEN (or not written) in the spec/plan
|
||||
- Include quality dimension in brackets [Completeness/Clarity/Consistency/etc.]
|
||||
- Reference spec section `[Spec §X.Y]` when checking existing requirements
|
||||
- Use `[Gap]` marker when checking for missing requirements
|
||||
|
||||
**按质量维度分类的示例**:
|
||||
|
||||
完整性:
|
||||
- "Are error handling requirements defined for all API failure modes? [Gap]"
|
||||
- "Are accessibility requirements specified for all interactive elements? [Completeness]"
|
||||
- "Are mobile breakpoint requirements defined for responsive layouts? [Gap]"
|
||||
|
||||
清晰度:
|
||||
- "Is 'fast loading' quantified with specific timing thresholds? [Clarity, Spec §NFR-2]"
|
||||
- "Are 'related episodes' selection criteria explicitly defined? [Clarity, Spec §FR-5]"
|
||||
- "Is 'prominent' defined with measurable visual properties? [Ambiguity, Spec §FR-4]"
|
||||
|
||||
一致性:
|
||||
- "Do navigation requirements align across all pages? [Consistency, Spec §FR-10]"
|
||||
- "Are card component requirements consistent between landing and detail pages? [Consistency]"
|
||||
|
||||
覆盖度:
|
||||
- "Are requirements defined for zero-state scenarios (no episodes)? [Coverage, Edge Case]"
|
||||
- "Are concurrent user interaction scenarios addressed? [Coverage, Gap]"
|
||||
- "Are requirements specified for partial data loading failures? [Coverage, Exception Flow]"
|
||||
|
||||
可测量性:
|
||||
- "Are visual hierarchy requirements measurable/testable? [Acceptance Criteria, Spec §FR-1]"
|
||||
- "Can 'balanced visual weight' be objectively verified? [Measurability, Spec §FR-2]"
|
||||
|
||||
**场景分类与覆盖度**(需求质量焦点):
|
||||
- Check if requirements exist for: Primary, Alternate, Exception/Error, Recovery, Non-Functional scenarios
|
||||
- For each scenario class, ask: "Are [scenario type] requirements complete, clear, and consistent?"
|
||||
- If scenario class missing: "Are [scenario type] requirements intentionally excluded or missing? [Gap]"
|
||||
- Include resilience/rollback when state mutation occurs: "Are rollback requirements defined for migration failures? [Gap]"
|
||||
|
||||
**可追溯性要求**:
|
||||
- MINIMUM: ≥80% of items MUST include at least one traceability reference
|
||||
- Each item should reference: spec section `[Spec §X.Y]`, or use markers: `[Gap]`, `[Ambiguity]`, `[Conflict]`, `[Assumption]`
|
||||
- If no ID system exists: "Is a requirement & acceptance criteria ID scheme established? [Traceability]"
|
||||
|
||||
**发现和解决问题**(需求质量问题):
|
||||
Ask questions about the requirements themselves:
|
||||
- Ambiguities: "Is the term 'fast' quantified with specific metrics? [Ambiguity, Spec §NFR-1]"
|
||||
- Conflicts: "Do navigation requirements conflict between §FR-10 and §FR-10a? [Conflict]"
|
||||
- Assumptions: "Is the assumption of 'always available podcast API' validated? [Assumption]"
|
||||
- Dependencies: "Are external podcast API requirements documented? [Dependency, Gap]"
|
||||
- Missing definitions: "Is 'visual hierarchy' defined with measurable criteria? [Gap]"
|
||||
|
||||
**内容整合**:
|
||||
- Soft cap: If raw candidate items > 40, prioritize by risk/impact
|
||||
- Merge near-duplicates checking the same requirement aspect
|
||||
- If >5 low-impact edge cases, create one item: "Are edge cases X, Y, Z addressed in requirements? [Coverage]"
|
||||
|
||||
**🚫 ABSOLUTELY PROHIBITED** - These make it an implementation test, not a requirements test:
|
||||
- ❌ Any item starting with "Verify", "Test", "Confirm", "Check" + implementation behavior
|
||||
- ❌ References to code execution, user actions, system behavior
|
||||
- ❌ "Displays correctly", "works properly", "functions as expected"
|
||||
- ❌ "Click", "navigate", "render", "load", "execute"
|
||||
- ❌ Test cases, test plans, QA procedures
|
||||
- ❌ Implementation details (frameworks, APIs, algorithms)
|
||||
|
||||
**✅ REQUIRED PATTERNS** - These test requirements quality:
|
||||
- ✅ "Are [requirement type] defined/specified/documented for [scenario]?"
|
||||
- ✅ "Is [vague term] quantified/clarified with specific criteria?"
|
||||
- ✅ "Are requirements consistent between [section A] and [section B]?"
|
||||
- ✅ "Can [requirement] be objectively measured/verified?"
|
||||
- ✅ "Are [edge cases/scenarios] addressed in requirements?"
|
||||
- ✅ "Does the spec define [missing aspect]?"
|
||||
|
||||
6. **结构参考**: 按照 `.specify/templates/checklist-template.md` 中的规范模板生成清单, 包括标题、元部分、类别标题和 ID 格式. 如果模板不可用, 使用: H1 标题、purpose/created 元行、包含 `- [ ] CHK### <requirement item>` 行的 `##` 类别部分, ID 从 CHK001 开始全局递增.
|
||||
|
||||
7. **报告**: 输出创建清单的完整路径、项目数量, 并提醒用户每次运行都会创建新文件. 总结:
|
||||
- 选择的焦点区域
|
||||
- 深度级别
|
||||
- 执行者/时间
|
||||
- 任何整合的用户明确指定的必需项目
|
||||
|
||||
**重要说明**: 每次 `/speckit.checklist` 命令调用都会创建一个使用简短描述性名称的清单文件, 除非文件已存在. 这允许:
|
||||
|
||||
- 创建多种不同类型的清单(例如: `ux.md`, `test.md`, `security.md`)
|
||||
- 使用简单、易记的文件名来表明清单用途
|
||||
- 在 `checklists/` 文件夹中轻松识别和导航
|
||||
|
||||
为避免混乱, 请使用描述性类型, 并在完成后清理过时的清单.
|
||||
|
||||
## 示例清单类型和示例项目
|
||||
|
||||
**UX 需求质量**: `ux.md`
|
||||
|
||||
示例项目(测试需求, 而非实现):
|
||||
- "Are visual hierarchy requirements defined with measurable criteria? [Clarity, Spec §FR-1]"
|
||||
- "Is the number and positioning of UI elements explicitly specified? [Completeness, Spec §FR-1]"
|
||||
- "Are interaction state requirements (hover, focus, active) consistently defined? [Consistency]"
|
||||
- "Are accessibility requirements specified for all interactive elements? [Coverage, Gap]"
|
||||
- "Is fallback behavior defined when images fail to load? [Edge Case, Gap]"
|
||||
- "Can 'prominent display' be objectively measured? [Measurability, Spec §FR-4]"
|
||||
|
||||
**API 需求质量**: `api.md`
|
||||
|
||||
示例项目:
|
||||
- "Are error response formats specified for all failure scenarios? [Completeness]"
|
||||
- "Are rate limiting requirements quantified with specific thresholds? [Clarity]"
|
||||
- "Are authentication requirements consistent across all endpoints? [Consistency]"
|
||||
- "Are retry/timeout requirements defined for external dependencies? [Coverage, Gap]"
|
||||
- "Is versioning strategy documented in requirements? [Gap]"
|
||||
|
||||
**性能需求质量**: `performance.md`
|
||||
|
||||
示例项目:
|
||||
- "Are performance requirements quantified with specific metrics? [Clarity]"
|
||||
- "Are performance targets defined for all critical user journeys? [Coverage]"
|
||||
- "Are performance requirements under different load conditions specified? [Completeness]"
|
||||
- "Can performance requirements be objectively measured? [Measurability]"
|
||||
- "Are degradation requirements defined for high-load scenarios? [Edge Case, Gap]"
|
||||
|
||||
**安全需求质量**: `security.md`
|
||||
|
||||
示例项目:
|
||||
- "Are authentication requirements specified for all protected resources? [Coverage]"
|
||||
- "Are data protection requirements defined for sensitive information? [Completeness]"
|
||||
- "Is the threat model documented and requirements aligned to it? [Traceability]"
|
||||
- "Are security requirements consistent with compliance obligations? [Consistency]"
|
||||
- "Are security failure/breach response requirements defined? [Gap, Exception Flow]"
|
||||
|
||||
## 反例: 什么不要做
|
||||
|
||||
**❌ 错误 - 这些测试实现, 而非需求: **
|
||||
|
||||
```markdown
|
||||
- [ ] CHK001 - Verify landing page displays 3 episode cards [Spec §FR-001]
|
||||
- [ ] CHK002 - Test hover states work correctly on desktop [Spec §FR-003]
|
||||
- [ ] CHK003 - Confirm logo click navigates to home page [Spec §FR-010]
|
||||
- [ ] CHK004 - Check that related episodes section shows 3-5 items [Spec §FR-005]
|
||||
```
|
||||
|
||||
**✅ 正确 - 这些测试需求质量: **
|
||||
|
||||
```markdown
|
||||
- [ ] CHK001 - Are the number and layout of featured episodes explicitly specified? [Completeness, Spec §FR-001]
|
||||
- [ ] CHK002 - Are hover state requirements consistently defined for all interactive elements? [Consistency, Spec §FR-003]
|
||||
- [ ] CHK003 - Are navigation requirements clear for all clickable brand elements? [Clarity, Spec §FR-010]
|
||||
- [ ] CHK004 - Is the selection criteria for related episodes documented? [Gap, Spec §FR-005]
|
||||
- [ ] CHK005 - Are loading state requirements defined for asynchronous episode data? [Gap]
|
||||
- [ ] CHK006 - Can "visual hierarchy" requirements be objectively measured? [Measurability, Spec §FR-001]
|
||||
```
|
||||
|
||||
**关键区别: **
|
||||
- 错误: 测试系统是否正常工作
|
||||
- 正确: 测试需求是否编写正确
|
||||
- 错误: 验证行为
|
||||
- 正确: 验证需求质量
|
||||
- 错误: "它是否做 X?"
|
||||
- 正确: "X 是否明确指定?"
|
||||
@@ -0,0 +1,179 @@
|
||||
---
|
||||
description: 通过提出最多 5 个高度针对性的澄清问题, 识别当前功能规范中未充分说明的领域, 并将答案编码回规范中.
|
||||
handoffs:
|
||||
- label: 构建技术计划
|
||||
agent: speckit.plan
|
||||
prompt: 为规范创建计划。我正在构建...
|
||||
---
|
||||
|
||||
## 用户输入
|
||||
|
||||
```text
|
||||
$ARGUMENTS
|
||||
```
|
||||
|
||||
在继续之前, 你**必须**考虑用户输入(如果不为空).
|
||||
|
||||
## 概述
|
||||
|
||||
目标: 检测并减少活跃功能规范中的模糊性或缺失的决策点, 并将澄清内容直接记录在规范文件中.
|
||||
|
||||
注意: 此澄清工作流应在调用 `/speckit.plan` 之前运行(并完成). 如果用户明确表示他们跳过澄清(例如, 探索性原型), 你可以继续, 但必须警告下游返工风险增加.
|
||||
|
||||
执行步骤:
|
||||
|
||||
1. 从仓库根目录运行 `.specify/scripts/powershell/check-prerequisites.ps1 -Json -PathsOnly` **一次**(组合 `--json --paths-only` 模式 / `-Json -PathsOnly`). 解析最小 JSON 负载字段:
|
||||
- `FEATURE_DIR`
|
||||
- `FEATURE_SPEC`
|
||||
- (可选捕获 `IMPL_PLAN`、`TASKS` 用于未来的链式流程. )
|
||||
- 如果 JSON 解析失败, 中止并指示用户重新运行 `/speckit.specify` 或验证功能分支环境.
|
||||
- 对于参数中包含单引号的情况(如 "I'm Groot"), 使用转义语法: 例如 'I'\''m Groot'(或优先使用双引号: "I'm Groot").
|
||||
|
||||
2. 加载当前规范文件. 使用此分类法执行结构化模糊性和覆盖范围扫描. 对于每个类别, 标记状态: 清晰 / 部分 / 缺失. 生成用于优先级排序的内部覆盖范围图(除非不会提问, 否则不输出原始图).
|
||||
|
||||
功能范围与行为:
|
||||
- 核心用户目标和成功标准
|
||||
- 明确的超出范围声明
|
||||
- 用户角色 / 角色区分
|
||||
|
||||
领域与数据模型:
|
||||
- 实体、属性、关系
|
||||
- 身份和唯一性规则
|
||||
- 生命周期 / 状态转换
|
||||
- 数据量 / 规模假设
|
||||
|
||||
交互与 UX 流程:
|
||||
- 关键用户旅程 / 序列
|
||||
- 错误 / 空白 / 加载状态
|
||||
- 可访问性或本地化说明
|
||||
|
||||
非功能性质量属性:
|
||||
- 性能(延迟、吞吐量目标)
|
||||
- 可扩展性(水平 / 垂直、限制)
|
||||
- 可靠性和可用性(正常运行时间、恢复期望)
|
||||
- 可观察性(日志、指标、追踪信号)
|
||||
- 安全性和隐私(身份验证 / 授权、数据保护、威胁假设)
|
||||
- 合规性 / 监管约束(如有)
|
||||
|
||||
集成与外部依赖:
|
||||
- 外部服务 / API 和故障模式
|
||||
- 数据导入 / 导出格式
|
||||
- 协议 / 版本控制假设
|
||||
|
||||
边缘情况与故障处理:
|
||||
- 负面场景
|
||||
- 速率限制 / 节流
|
||||
- 冲突解决(例如, 并发编辑)
|
||||
|
||||
约束与权衡:
|
||||
- 技术约束(语言、存储、托管)
|
||||
- 明确的权衡或被拒绝的替代方案
|
||||
|
||||
术语与一致性:
|
||||
- 规范术语表术语
|
||||
- 避免的同义词 / 已弃用术语
|
||||
|
||||
完成信号:
|
||||
- 验收标准可测试性
|
||||
- 可衡量的完成定义风格指标
|
||||
|
||||
其他 / 占位符:
|
||||
- TODO 标记 / 未解决的决策
|
||||
- 缺少量化的模糊形容词("robust"、"intuitive")
|
||||
|
||||
对于每个处于部分或缺失状态的类别, 添加候选问题机会, 除非:
|
||||
- 澄清不会实质性地改变实施或验证策略
|
||||
- 信息更适合推迟到规划阶段(内部记录)
|
||||
|
||||
3. (内部)生成候选澄清问题的优先级队列(最多5个). 不要一次性输出所有问题. 应用这些约束:
|
||||
- 整个会话最多10个问题.
|
||||
- 每个问题必须可以用以下任一方式回答:
|
||||
* 简短的多项选择(2-5个不同的、互斥的选项), 或
|
||||
* 单词 / 短语答案(明确约束: "Answer in <=5 words").
|
||||
- 仅包含答案实质上影响架构、数据建模、任务分解、测试设计、UX 行为、运营准备或合规性验证的问题.
|
||||
- 确保类别覆盖平衡: 尝试首先覆盖最高影响的未解决类别; 避免在单个高影响领域(例如, 安全态势)未解决时询问两个低影响问题.
|
||||
- 排除已回答的问题、琐碎的风格偏好或规划级别的执行细节(除非阻碍正确性).
|
||||
- 偏好减少下游返工风险或防止不一致验收测试的澄清.
|
||||
- 如果超过5个类别仍未解决, 通过(影响 * 不确定性)启发式选择前5个.
|
||||
|
||||
4. 顺序提问流程(交互式):
|
||||
- 一次只提出**确切一个**问题.
|
||||
- 对于多项选择题:
|
||||
* **分析所有选项**并基于以下确定**最合适的选项**:
|
||||
- 项目类型的最佳实践
|
||||
- 类似实现中的常见模式
|
||||
- 风险降低(安全性、性能、可维护性)
|
||||
- 与规范中可见的任何明确项目目标或约束的一致性
|
||||
* 在顶部突出显示你的**推荐选项**并附上清晰推理(1-2句话解释为什么这是最佳选择).
|
||||
* 格式为: `**Recommended:** Option [X] - <reasoning>`
|
||||
* 然后将所有选项渲染为 Markdown 表格:
|
||||
|
||||
| Option | Description |
|
||||
|--------|-------------|
|
||||
| A | <Option A description> |
|
||||
| B | <Option B description> |
|
||||
| C | <Option C description> | (根据需要添加 D/E, 最多5个)
|
||||
| Short | Provide a different short answer (<=5 words) | (仅在自由形式替代方案合适时包含)
|
||||
* 表格后添加: `You can reply with the option letter (e.g., "A"), accept the recommendation by saying "yes" or "recommended", or provide your own short answer.`
|
||||
- 对于简答题风格(没有有意义的不同选项):
|
||||
* 基于最佳实践和上下文提供你的**建议答案**.
|
||||
* 格式为: `**Suggested:** <your proposed answer> - <brief reasoning>`
|
||||
* 然后输出: `Format: Short answer (<=5 words). You can accept the suggestion by saying "yes" or "suggested", or provide your own answer.`
|
||||
- 用户回答后:
|
||||
* 如果用户回复 "yes"、"recommended" 或 "suggested", 使用你之前陈述的推荐 / 建议作为答案.
|
||||
* 否则, 验证答案映射到一个选项或符合 <=5 个词的约束.
|
||||
* 如果模糊, 要求快速消除歧义(计数仍属于同一问题; 不前进).
|
||||
* 一旦满意, 将其记录在工作内存中(尚未写入磁盘)并移动到下一个排队的问题.
|
||||
- 在以下情况时停止进一步提问:
|
||||
* 所有关键模糊性早期解决(剩余排队项目变得不必要), 或
|
||||
* 用户发出完成信号("done"、"good"、"no more"), 或
|
||||
* 你达到5个已问问题.
|
||||
- 永远不要提前揭示未来的排队问题.
|
||||
- 如果开始时没有有效问题, 立即报告没有关键模糊性.
|
||||
|
||||
5. 每次接受答案后的集成(增量更新方法):
|
||||
- 维护规范的内存表示(开始时加载一次)加上原始文件内容.
|
||||
- 对于此会话中第一个集成的答案:
|
||||
* 确保 `## Clarifications` 部分存在(如果缺失, 根据规范模板在最高级别的上下文 / 概述部分之后创建).
|
||||
* 在其下, 创建(如果不存在)今天的 `### Session YYYY-MM-DD` 子标题.
|
||||
- 接受后立即追加项目符号行: `- Q: <question> → A: <final answer>`.
|
||||
- 然后立即将澄清应用到最合适的部分:
|
||||
* 功能模糊性 → 更新或在功能需求中添加项目符号.
|
||||
* 用户交互 / 角色区分 → 更新用户故事或角色子部分(如果存在), 包含澄清的角色、约束或场景.
|
||||
* 数据形状 / 实体 → 更新数据模型(添加字段、类型、关系)保持顺序; 简洁地记录添加的约束.
|
||||
* 非功能性约束 → 在非功能性 / 质量属性部分添加 / 修改可衡量标准(将模糊形容词转换为指标或明确目标).
|
||||
* 边缘情况 / 负面流程 → 在边缘情况 / 错误处理下添加新项目符号(或如果模板提供占位符则创建此类子部分).
|
||||
* 术语冲突 → 在整个规范中规范化术语; 仅在必要时通过添加一次 `(formerly referred to as "X")` 保留原始术语.
|
||||
- 如果澄清使早期模糊声明无效, 替换该声明而不是重复; 不留用过时的矛盾文本.
|
||||
- 每次集成后保存规范文件以最小化上下文丢失风险(原子覆盖).
|
||||
- 保持格式: 不重新排序不相关的部分; 保持标题层次结构完整.
|
||||
- 保持每个插入的澄清最小化和可测试(避免叙述性偏离).
|
||||
|
||||
6. 验证(每次写入后执行, 最终再进行一次完整检查):
|
||||
- 澄清会话每个接受的答案只包含一个项目符号(无重复).
|
||||
- 总共询问(接受)的问题 ≤ 5.
|
||||
- 更新的部分不包含新答案旨在解决的持续模糊占位符.
|
||||
- 没有矛盾的早期声明保留(扫描已删除的现在无效的替代选择).
|
||||
- Markdown 结构有效; 仅允许新标题: `## Clarifications`、`### Session YYYY-MM-DD`.
|
||||
- 术语一致性: 所有更新部分使用相同的规范术语.
|
||||
|
||||
7. 将更新的规范写回 `FEATURE_SPEC`.
|
||||
|
||||
8. 报告完成(提问循环结束或提前终止后):
|
||||
- 询问和回答的问题数量.
|
||||
- 更新规范的路径.
|
||||
- 涉及的部分(列出名称).
|
||||
- 覆盖范围摘要表, 列出每个分类类别及状态: 已解决(曾是部分 / 缺失并已处理)、已推迟(超过问题配额或更适合规划)、清晰(已足够)、未完成(仍是部分 / 缺失但影响低).
|
||||
- 如果有任何未完成或已推迟的剩余, 建议是继续到 `/speckit.plan` 还是在规划后再次运行 `/speckit.clarify`.
|
||||
- 建议的下一个命令.
|
||||
|
||||
行为规则:
|
||||
- 如果没有发现有意义的模糊性(或所有潜在问题都是低影响的), 回应: "No critical ambiguities detected worth formal clarification." 并建议继续.
|
||||
- 如果规范文件缺失, 指示用户首先运行 `/speckit.specify`(不要在此创建新规范).
|
||||
- 永远不要超过总共5个询问的问题(单个问题的澄清重试不计为新问题).
|
||||
- 避免推测性技术堆栈问题, 除非缺失阻碍功能清晰性.
|
||||
- 尊重用户提前终止信号("stop"、"done"、"proceed").
|
||||
- 如果由于完全覆盖而没有提问, 输出紧凑的覆盖范围摘要(所有类别清晰)然后建议前进.
|
||||
- 如果达到配额但仍有未解决的高影响类别, 在已推迟下明确标记它们并附上理由.
|
||||
|
||||
优先级排序的上下文: $ARGUMENTS
|
||||
@@ -0,0 +1,81 @@
|
||||
---
|
||||
description: 从交互式或提供的原则输入创建或更新项目章程, 确保所有依赖模板保持同步.
|
||||
handoffs:
|
||||
- label: 构建规范
|
||||
agent: speckit.specify
|
||||
prompt: 基于更新的章程实现功能规范。我想要构建...
|
||||
---
|
||||
|
||||
## 用户输入
|
||||
|
||||
```text
|
||||
$ARGUMENTS
|
||||
```
|
||||
|
||||
在继续之前, 你**必须**考虑用户输入(如果不为空).
|
||||
|
||||
## 概述
|
||||
|
||||
你正在更新位于 `.specify/memory/constitution.md` 的项目章程. 该文件是一个包含方括号占位符标记的模板(例如 `[PROJECT_NAME]`、`[PRINCIPLE_1_NAME]`). 你的工作是(a)收集/推导具体值, (b)精确填充模板, 以及(c)将任何修改传播到相关依赖项中.
|
||||
|
||||
遵循此执行流程:
|
||||
|
||||
1. 加载位于 `.specify/memory/constitution.md` 的现有章程模板.
|
||||
- 识别每个 `[ALL_CAPS_IDENTIFIER]` 形式的占位符标记.
|
||||
**重要提示**: 用户可能需要比模板中使用的原则更少或更多. 如果指定了数字, 请遵循该数字 - 遵循通用模板. 你将相应地更新文档.
|
||||
|
||||
2. 为占位符收集/推导值:
|
||||
- 如果用户输入(对话)提供了值, 则使用它.
|
||||
- 否则从现有仓库上下文推断(README、文档、先前的章程版本(如果嵌入)).
|
||||
- 对于治理日期: `RATIFICATION_DATE` 是原始采用日期(如果未知, 请询问或标记 TODO), `LAST_AMENDED_DATE` 是今天(如果进行了更改), 否则保留之前的日期.
|
||||
- `CONSTITUTION_VERSION` 必须根据语义版本控制规则递增:
|
||||
* MAJOR(主版本): 向后不兼容的治理/原则删除或重新定义.
|
||||
* MINOR(次版本): 新原则/部分添加或实质性扩展指导.
|
||||
* PATCH(补丁版本): 澄清、措辞、拼写错误修复、非语义优化.
|
||||
- 如果版本递增类型不明确, 请在最终确定之前提出理由.
|
||||
|
||||
3. 起草更新后的章程内容:
|
||||
- 用具体文本替换每个占位符(除了项目选择尚未定义的故意保留的模板槽位外, 不留下括号标记——明确说明任何保留的槽位).
|
||||
- 保留标题层次结构, 一旦替换可以删除注释, 除非它们仍然提供澄清指导.
|
||||
- 确保每个原则部分: 简洁的名称行、捕获不可协商规则的段落(或项目符号列表)、如果不明显则提供明确的理由.
|
||||
- 确保治理部分列出修改程序、版本控制策略和合规审查期望.
|
||||
|
||||
4. 一致性传播检查清单(将先前的检查清单转换为主动验证):
|
||||
- 读取 `.specify/templates/plan-template.md` 并确保任何"章程检查"或规则与更新的原则保持一致.
|
||||
- 读取 `.specify/templates/spec-template.md` 进行范围/需求对齐——如果章程添加/删除强制部分或约束, 则更新.
|
||||
- 读取 `.specify/templates/tasks-template.md` 并确保任务分类反映新的或删除的原则驱动的任务类型(例如, 可观测性、版本控制、测试纪律).
|
||||
- 读取 `.specify/templates/commands/*.md` 中的每个命令文件(包括此文件)以验证在需要通用指导时没有过时的引用(如仅限 CLAUDE 的代理特定名称).
|
||||
- 读取任何运行时指导文档(例如 `README.md`、`docs/quickstart.md` 或代理特定指导文件(如果存在)). 更新对已更改原则的引用.
|
||||
|
||||
5. 生成同步影响报告(在更新后作为 HTML 注释前置到章程文件顶部):
|
||||
- 版本更改: 旧版本 → 新版本
|
||||
- 修改的原则列表(如果重命名, 则为旧标题 → 新标题)
|
||||
- 添加的部分
|
||||
- 删除的部分
|
||||
- 需要更新的模板(✅ 已更新 / ⚠ 待处理)及文件路径
|
||||
- 如果有任何占位符故意延迟, 则提供后续 TODO.
|
||||
|
||||
6. 最终输出前的验证:
|
||||
- 没有剩余的未解释的括号标记.
|
||||
- 版本行与报告匹配.
|
||||
- 日期采用 ISO 格式 YYYY-MM-DD.
|
||||
- 原则是声明性的、可测试的, 并且没有模糊语言("should" → 在适当的地方用 MUST/SHOULD 理由替换).
|
||||
|
||||
7. 将完成的章程写回 `.specify/memory/constitution.md`(覆盖).
|
||||
|
||||
8. 向用户输出最终摘要, 包括:
|
||||
- 新版本和递增理由.
|
||||
- 任何标记为手动后续处理的文件.
|
||||
- 建议的提交消息(例如 `docs: amend constitution to vX.Y.Z (principle additions + governance update)`).
|
||||
|
||||
格式和样式要求:
|
||||
- 完全按照模板使用 Markdown 标题(不要降级/升级级别).
|
||||
- 换行长理由行以保持可读性(理想情况下 <100 个字符), 但不要用尴尬的换行强制执行.
|
||||
- 在部分之间保持单个空行.
|
||||
- 避免尾随空白.
|
||||
|
||||
如果用户提供部分更新(例如, 仅一个原则修订), 仍然执行验证和版本决策步骤.
|
||||
|
||||
如果缺少关键信息(例如, 批准日期确实未知), 请插入 `TODO(<FIELD_NAME>): explanation` 并包含在同步影响报告中的延迟项下.
|
||||
|
||||
不要创建新模板; 始终操作现有的 `.specify/memory/constitution.md` 文件.
|
||||
@@ -0,0 +1,74 @@
|
||||
---
|
||||
description: 针对项目中的bug进行精确修复,尽量减少对其他代码的影响
|
||||
---
|
||||
|
||||
## 用户输入
|
||||
|
||||
```text
|
||||
$ARGUMENTS
|
||||
```
|
||||
|
||||
在继续之前,你**必须**考虑用户输入(如果不为空)。用户应该提供bug描述、相关文件路径和可能的修复方向。
|
||||
|
||||
## 目标
|
||||
|
||||
提供一个结构化的bug修复流程,通过精确的修改定位和最小化的代码变更,修复项目中的bug,同时避免引入新的问题或破坏现有功能。
|
||||
|
||||
## 操作约束
|
||||
|
||||
**最小化修改原则**:只修改与bug直接相关的代码,避免对其他功能造成影响。
|
||||
|
||||
**完整性保证**:确保bug修复是完整的,不仅解决表面症状,还要处理根本原因。
|
||||
|
||||
**测试优先**:在进行修复前,确保有适当的测试来验证bug的存在和修复的有效性。
|
||||
|
||||
**文档更新**:如果bug修复影响了API或行为,确保更新相应的文档。
|
||||
|
||||
## 执行步骤
|
||||
|
||||
### 1. 初始化bug修复上下文
|
||||
|
||||
从仓库根目录运行一次 `.specify/scripts/powershell/check-prerequisites.ps1 -Json` 并解析 JSON 以获取项目环境信息。这将帮助我们了解项目的基本结构和工具链。
|
||||
|
||||
### 2. 收集和分析bug信息
|
||||
|
||||
- **理解bug**:根据用户输入,明确理解bug的症状、复现步骤和预期行为
|
||||
- **定位相关文件**:确定可能包含bug的文件和代码区域
|
||||
- **分析错误日志**:如果有错误日志,分析异常堆栈和错误信息
|
||||
- **版本历史检查**:查看最近的代码变更,识别可能引入bug的提交
|
||||
|
||||
### 3. 创建修复环境
|
||||
|
||||
- **创建bug修复分支**:基于当前主分支创建一个专门的bug修复分支
|
||||
- **设置测试环境**:确保有适当的测试环境可以验证bug和修复
|
||||
- **备份相关文件**:在修改前备份可能受影响的关键文件
|
||||
|
||||
### 4. 实施修复
|
||||
|
||||
- **精确修改**:针对已识别的问题进行最小化的代码修改
|
||||
- **遵循代码风格**:确保修复代码遵循项目现有的代码风格和规范
|
||||
- **添加必要注释**:为修复添加清晰的注释,说明修复的原因和方法
|
||||
- **考虑边界情况**:确保修复不会在边界情况下导致新的问题
|
||||
|
||||
### 5. 验证修复
|
||||
|
||||
- **执行测试**:运行项目的测试套件,确保所有测试通过
|
||||
- **复现验证**:使用原始的复现步骤,确认bug已被修复
|
||||
- **回归测试**:执行可能受影响功能的回归测试
|
||||
- **性能检查**:如果适用,验证修复不会对性能造成负面影响
|
||||
|
||||
### 6. 文档和提交
|
||||
|
||||
- **更新文档**:如果修复影响了API或功能行为,更新相应的文档
|
||||
- **编写清晰的提交信息**:提交信息应包含bug描述、修复方法和相关问题引用
|
||||
- **代码审查准备**:准备修复的代码审查材料,包括问题描述、修复策略和测试结果
|
||||
|
||||
## 输出格式
|
||||
|
||||
修复过程完成后,输出一个结构化的报告,包括:
|
||||
|
||||
1. **Bug摘要**:对bug的简要描述和影响范围
|
||||
2. **修复概述**:所做的修改概述和修复原理
|
||||
3. **验证结果**:测试结果和验证方法
|
||||
4. **潜在风险**:任何可能的风险或需要后续关注的问题
|
||||
5. **建议的后续步骤**:例如代码审查、部署计划等
|
||||
@@ -0,0 +1,131 @@
|
||||
---
|
||||
description: 通过处理和执行 tasks.md 中定义的所有任务来执行实施计划
|
||||
---
|
||||
|
||||
## 用户输入
|
||||
|
||||
```text
|
||||
$ARGUMENTS
|
||||
```
|
||||
|
||||
在继续之前, 你**必须**考虑用户输入(如果不为空).
|
||||
|
||||
## 概要
|
||||
|
||||
1. 从仓库根目录运行 `.specify/scripts/powershell/check-prerequisites.ps1 -Json -RequireTasks -IncludeTasks` 并解析 FEATURE_DIR 和 AVAILABLE_DOCS 列表. 所有路径必须是绝对路径. 对于参数中的单引号如 "I'm Groot", 使用转义语法: 例如 'I'\''m Groot'(或尽可能使用双引号: "I'm Groot").
|
||||
|
||||
2. **检查清单状态**(如果 FEATURE_DIR/checklists/ 存在):
|
||||
- 扫描 checklists/ 目录中的所有清单文件
|
||||
- 对于每个清单, 统计:
|
||||
* 总项目数: 所有匹配 `- [ ]` 或 `- [X]` 或 `- [x]` 的行
|
||||
* 已完成项目数: 匹配 `- [X]` 或 `- [x]` 的行
|
||||
* 未完成项目数: 匹配 `- [ ]` 的行
|
||||
- 创建状态表:
|
||||
```
|
||||
| Checklist | Total | Completed | Incomplete | Status |
|
||||
|-----------|-------|-----------|------------|--------|
|
||||
| ux.md | 12 | 12 | 0 | ✓ PASS |
|
||||
| test.md | 8 | 5 | 3 | ✗ FAIL |
|
||||
| security.md | 6 | 6 | 0 | ✓ PASS |
|
||||
```
|
||||
- 计算总体状态:
|
||||
* **PASS**: 所有清单都有 0 个未完成项目
|
||||
* **FAIL**: 一个或多个清单有未完成项目
|
||||
|
||||
- **如果任何清单未完成**:
|
||||
* 显示包含未完成项目数的表格
|
||||
* **停止**并询问: "Some checklists are incomplete. Do you want to proceed with implementation anyway? (yes/no)"
|
||||
* 在继续之前等待用户响应
|
||||
* 如果用户说 "no" 或 "wait" 或 "stop", 停止执行
|
||||
* 如果用户说 "yes" 或 "proceed" 或 "continue", 继续到步骤 3
|
||||
|
||||
- **如果所有清单都已完成**:
|
||||
* 显示显示所有清单通过的表格
|
||||
* 自动继续到步骤 3
|
||||
|
||||
3. 加载和分析实施上下文:
|
||||
- **必需**: 读取 tasks.md 获取完整任务列表和执行计划
|
||||
- **必需**: 读取 plan.md 获取技术栈、架构和文件结构
|
||||
- **如果存在**: 读取 data-model.md 获取实体和关系
|
||||
- **如果存在**: 读取 contracts/ 获取 API 规范和测试要求
|
||||
- **如果存在**: 读取 research.md 获取技术决策和约束
|
||||
- **如果存在**: 读取 quickstart.md 获取集成场景
|
||||
|
||||
4. **项目设置验证**:
|
||||
- **必需**: 基于实际项目设置创建/验证忽略文件:
|
||||
|
||||
**检测和创建逻辑**:
|
||||
- 检查以下命令是否成功以确定是否为 git 仓库(如果是, 创建/验证 .gitignore):
|
||||
|
||||
```sh
|
||||
git rev-parse --git-dir 2>/dev/null
|
||||
```
|
||||
- 检查 Dockerfile* 是否存在或 plan.md 中是否提到 Docker → 创建/验证 .dockerignore
|
||||
- 检查 .eslintrc* 或 eslint.config.* 是否存在 → 创建/验证 .eslintignore
|
||||
- 检查 .prettierrc* 是否存在 → 创建/验证 .prettierignore
|
||||
- 检查 .npmrc 或 package.json 是否存在 → 创建/验证 .npmignore(如果发布)
|
||||
- 检查 terraform 文件(*.tf)是否存在 → 创建/验证 .terraformignore
|
||||
- 检查是否需要 .helmignore(存在 helm charts)→ 创建/验证 .helmignore
|
||||
|
||||
**如果忽略文件存在**: 验证它包含基本模式, 仅追加缺失的关键模式
|
||||
**如果忽略文件缺失**: 为检测到的技术创建完整模式集
|
||||
|
||||
**按技术的通用模式**(来自 plan.md 技术栈):
|
||||
- **Node.js/JavaScript**: `node_modules/`, `dist/`, `build/`, `*.log`, `.env*`
|
||||
- **Python**: `__pycache__/`, `*.pyc`, `.venv/`, `venv/`, `dist/`, `*.egg-info/`
|
||||
- **Java**: `target/`, `*.class`, `*.jar`, `.gradle/`, `build/`
|
||||
- **C#/.NET**: `bin/`, `obj/`, `*.user`, `*.suo`, `packages/`
|
||||
- **Go**: `*.exe`, `*.test`, `vendor/`, `*.out`
|
||||
- **Ruby**: `.bundle/`, `log/`, `tmp/`, `*.gem`, `vendor/bundle/`
|
||||
- **PHP**: `vendor/`, `*.log`, `*.cache`, `*.env`
|
||||
- **Rust**: `target/`, `debug/`, `release/`, `*.rs.bk`, `*.rlib`, `*.prof*`, `.idea/`, `*.log`, `.env*`
|
||||
- **Kotlin**: `build/`, `out/`, `.gradle/`, `.idea/`, `*.class`, `*.jar`, `*.iml`, `*.log`, `.env*`
|
||||
- **C++**: `build/`, `bin/`, `obj/`, `out/`, `*.o`, `*.so`, `*.a`, `*.exe`, `*.dll`, `.idea/`, `*.log`, `.env*`
|
||||
- **C**: `build/`, `bin/`, `obj/`, `out/`, `*.o`, `*.a`, `*.so`, `*.exe`, `Makefile`, `config.log`, `.idea/`, `*.log`, `.env*`
|
||||
- **Swift**: `.build/`, `DerivedData/`, `*.swiftpm/`, `Packages/`
|
||||
- **R**: `.Rproj.user/`, `.Rhistory`, `.RData`, `.Ruserdata`, `*.Rproj`, `packrat/`, `renv/`
|
||||
- **通用**: `.DS_Store`, `Thumbs.db`, `*.tmp`, `*.swp`, `.vscode/`, `.idea/`
|
||||
|
||||
**工具特定模式**:
|
||||
- **Docker**: `node_modules/`, `.git/`, `Dockerfile*`, `.dockerignore`, `*.log*`, `.env*`, `coverage/`
|
||||
- **ESLint**: `node_modules/`, `dist/`, `build/`, `coverage/`, `*.min.js`
|
||||
- **Prettier**: `node_modules/`, `dist/`, `build/`, `coverage/`, `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`
|
||||
- **Terraform**: `.terraform/`, `*.tfstate*`, `*.tfvars`, `.terraform.lock.hcl`
|
||||
- **Kubernetes/k8s**: `*.secret.yaml`, `secrets/`, `.kube/`, `kubeconfig*`, `*.key`, `*.crt`
|
||||
|
||||
5. 解析 tasks.md 结构并提取:
|
||||
- **任务阶段**: 设置、测试、核心、集成、完善
|
||||
- **任务依赖**: 顺序执行与并行执行规则
|
||||
- **任务详情**: ID、描述、文件路径、并行标记 [P]
|
||||
- **执行流程**: 顺序和依赖要求
|
||||
|
||||
6. 按照任务计划执行实施:
|
||||
- **分阶段执行**: 在进入下一阶段之前完成每个阶段
|
||||
- **遵循依赖**: 按顺序运行顺序任务, 并行任务 [P] 可以一起运行
|
||||
- **遵循 TDD 方法**: 在相应的实施任务之前执行测试任务
|
||||
- **基于文件的协调**: 影响相同文件的任务必须顺序运行
|
||||
- **验证检查点**: 在继续之前验证每个阶段的完成
|
||||
|
||||
7. 实施执行规则:
|
||||
- **首先设置**: 初始化项目结构、依赖、配置
|
||||
- **代码前测试**: 如果需要为合约、实体和集成场景编写测试
|
||||
- **核心开发**: 实施模型、服务、CLI 命令、端点
|
||||
- **集成工作**: 数据库连接、中间件、日志、外部服务
|
||||
- **完善和验证**: 单元测试、性能优化、文档
|
||||
|
||||
8. 进度跟踪和错误处理:
|
||||
- 在每个完成的任务后报告进度
|
||||
- 如果任何非并行任务失败, 停止执行
|
||||
- 对于并行任务 [P], 继续成功的任务, 报告失败的任务
|
||||
- 提供带有调试上下文的清晰错误消息
|
||||
- 如果实施无法继续, 建议下一步操作
|
||||
- **重要** 对于已完成的任务, 确保在任务文件中将任务标记为 [X].
|
||||
|
||||
9. 完成验证:
|
||||
- 验证所有必需任务已完成
|
||||
- 检查实施的功能是否与原始规范匹配
|
||||
- 验证测试通过且覆盖率满足要求
|
||||
- 确认实施遵循技术计划
|
||||
- 报告最终状态并附上已完成工作的摘要
|
||||
|
||||
注意: 此命令假设 tasks.md 中存在完整的任务分解. 如果任务不完整或缺失, 建议首先运行 `/tasks` 重新生成任务列表.
|
||||
@@ -0,0 +1,89 @@
|
||||
---
|
||||
description: 执行实施规划工作流, 使用计划模板生成设计制品.
|
||||
handoffs:
|
||||
- label: 创建任务
|
||||
agent: speckit.tasks
|
||||
prompt: 将计划分解为任务
|
||||
send: true
|
||||
- label: 创建检查清单
|
||||
agent: speckit.checklist
|
||||
prompt: 为需求创建质量检查清单
|
||||
send: true
|
||||
---
|
||||
|
||||
## 用户输入
|
||||
|
||||
```text
|
||||
$ARGUMENTS
|
||||
```
|
||||
|
||||
在继续之前, 你**必须**考虑用户输入(如果不为空).
|
||||
|
||||
## 大纲
|
||||
|
||||
1. **设置**: 从仓库根目录运行 `.specify/scripts/powershell/setup-plan.ps1 -Json` 并解析 JSON 获取 FEATURE_SPEC、IMPL_PLAN、SPECS_DIR、BRANCH. 对于参数中的单引号如 "I'm Groot", 使用转义语法: 例如 'I'\''m Groot'(或尽可能使用双引号: "I'm Groot").
|
||||
|
||||
2. **加载上下文**: 读取 FEATURE_SPEC 和 `.specify/memory/constitution.md`. 加载 IMPL_PLAN 模板(已复制).
|
||||
|
||||
3. **执行计划工作流**: 按照 IMPL_PLAN 模板中的结构:
|
||||
- 填充技术上下文(将未知项标记为 NEEDS CLARIFICATION)
|
||||
- 从章程文档填充章程检查部分
|
||||
- 评估关卡(如果违规无正当理由则报错)
|
||||
- 阶段 0: 生成 research.md(解决所有 NEEDS CLARIFICATION)
|
||||
- 阶段 1: 生成 data-model.md、contracts/、quickstart.md
|
||||
- 阶段 1: 通过运行代理脚本更新代理上下文
|
||||
- 设计后重新评估章程检查
|
||||
|
||||
4. **停止并报告**: 命令在阶段 2 规划后结束. 报告分支、IMPL_PLAN 路径和生成的制品.
|
||||
|
||||
## 阶段
|
||||
|
||||
### 阶段 0: 大纲与研究
|
||||
|
||||
1. **从上述技术上下文中提取未知项**:
|
||||
- 每个 NEEDS CLARIFICATION → 研究任务
|
||||
- 每个依赖项 → 最佳实践任务
|
||||
- 每个集成 → 模式任务
|
||||
|
||||
2. **生成和分发研究代理**:
|
||||
```
|
||||
For each unknown in Technical Context:
|
||||
Task: "Research {unknown} for {feature context}"
|
||||
For each technology choice:
|
||||
Task: "Find best practices for {tech} in {domain}"
|
||||
```
|
||||
|
||||
3. **在 `research.md` 中整合发现**, 使用格式:
|
||||
- Decision: [选择了什么]
|
||||
- Rationale: [为什么选择]
|
||||
- Alternatives considered: [还评估了什么]
|
||||
|
||||
**输出**: research.md, 所有 NEEDS CLARIFICATION 已解决
|
||||
|
||||
### 阶段 1: 设计与合同
|
||||
|
||||
**前提条件**: `research.md` 完成
|
||||
|
||||
1. **从功能规范中提取实体** → `data-model.md`:
|
||||
- 实体名称、字段、关系
|
||||
- 来自需求的验证规则
|
||||
- 状态转换(如适用)
|
||||
|
||||
2. **从功能需求生成 API 合同**:
|
||||
- 每个用户操作 → 端点
|
||||
- 使用标准 REST/GraphQL 模式
|
||||
- 将 OpenAPI/GraphQL 模式输出到 `/contracts/`
|
||||
|
||||
3. **代理上下文更新**:
|
||||
- 运行 `.specify/scripts/powershell/update-agent-context.ps1 -AgentType claude`
|
||||
- 这些脚本检测正在使用哪个 AI 代理
|
||||
- 更新相应的代理特定上下文文件
|
||||
- 仅添加当前计划中的新技术
|
||||
- 保留标记之间的手动添加内容
|
||||
|
||||
**输出**: data-model.md、/contracts/*、quickstart.md、代理特定文件
|
||||
|
||||
## 关键规则
|
||||
|
||||
- 使用绝对路径
|
||||
- 关卡失败或未解决的澄清事项时报错
|
||||
@@ -0,0 +1,237 @@
|
||||
---
|
||||
description: 从自然语言功能描述创建或更新功能规范.
|
||||
handoffs:
|
||||
- label: 构建技术计划
|
||||
agent: speckit.plan
|
||||
prompt: 为规范创建计划。我正在构建...
|
||||
- label: 澄清规范需求
|
||||
agent: speckit.clarify
|
||||
prompt: 分析规范的完整性和清晰度
|
||||
send: true
|
||||
---
|
||||
|
||||
## 用户输入
|
||||
|
||||
```text
|
||||
$ARGUMENTS
|
||||
```
|
||||
|
||||
在继续之前, 你**必须**考虑用户输入(如果不为空).
|
||||
|
||||
## 概述
|
||||
|
||||
用户在触发消息中 `/speckit.specify` 后输入的文本**就是**功能描述. 假设你始终可以在本次对话中访问它, 即使下面字面上显示 `$ARGUMENTS`. 除非用户提供了空命令, 否则不要要求用户重复.
|
||||
|
||||
基于该功能描述, 执行以下操作:
|
||||
|
||||
1. **为分支生成一个简短名称**(2-4个词):
|
||||
- 分析功能描述并提取最有意义的关键词
|
||||
- 创建一个2-4个词的简短名称, 捕捉功能的核心
|
||||
- 尽可能使用动-名词格式(例如, "add-user-auth", "fix-payment-bug")
|
||||
- 保留技术术语和缩写(OAuth2、API、JWT等)
|
||||
- 保持简洁但足够描述性, 便于快速理解功能
|
||||
- 示例:
|
||||
- "I want to add user authentication" → "user-auth"
|
||||
- "Implement OAuth2 integration for the API" → "oauth2-api-integration"
|
||||
- "Create a dashboard for analytics" → "analytics-dashboard"
|
||||
- "Fix payment processing timeout bug" → "fix-payment-timeout"
|
||||
|
||||
2. 从仓库根目录运行脚本 `.specify/scripts/powershell/create-new-feature.ps1 -Json "$ARGUMENTS"` **使用简短名称参数**并解析其 JSON 输出以获取 BRANCH_NAME 和 SPEC_FILE. 所有文件路径必须是绝对路径.
|
||||
|
||||
**重要说明**:
|
||||
|
||||
- 将第1步创建的2-4词简短名称作为参数附加到 `.specify/scripts/powershell/create-new-feature.ps1 -Json "$ARGUMENTS"` 命令, 功能描述作为最终参数.
|
||||
- Bash 示例: `--short-name "your-generated-short-name" "功能描述内容"`
|
||||
- PowerShell 示例: `-ShortName "your-generated-short-name" "功能描述内容"`
|
||||
- 对于参数中包含单引号的情况(如 "I'm Groot"), 使用转义语法: 例如 'I'\''m Groot'(或优先使用双引号: "I'm Groot")
|
||||
- 你必须且只能运行此脚本一次
|
||||
- JSON 输出会显示在终端中 - 请始终参考该输出来获取你要查找的实际内容
|
||||
|
||||
3. 加载 `.specify/templates/spec-template.md` 以了解必需的章节.
|
||||
|
||||
4. 遵循此执行流程:
|
||||
|
||||
1. 从输入解析用户描述
|
||||
如果为空: 错误 "未提供功能描述"
|
||||
2. 从描述中提取关键概念
|
||||
识别: 参与者、操作、数据、约束
|
||||
3. 对于不明确的方面:
|
||||
- 基于上下文和行业标准做出有根据的猜测
|
||||
- 仅在以下情况下标记为 [NEEDS CLARIFICATION: 具体问题]:
|
||||
- 选择显著影响功能范围或用户体验
|
||||
- 存在多个合理的解释且有不同的含义
|
||||
- 没有合理的默认值
|
||||
- **限制: 最多 3 个 [NEEDS CLARIFICATION] 标记**
|
||||
- 按影响优先级排序: 范围 > 安全/隐私 > 用户体验 > 技术细节
|
||||
4. 填写用户场景和测试章节
|
||||
如果没有明确的用户流程: 错误 "无法确定用户场景"
|
||||
5. 生成功能需求
|
||||
每个需求必须是可测试的
|
||||
对未指定的细节使用合理的默认值(在假设章节中记录假设)
|
||||
6. 定义成功标准
|
||||
创建可衡量的、技术无关的结果
|
||||
包括定量指标(时间、性能、数量)和定性措施(用户满意度、任务完成)
|
||||
每个标准必须无需实现细节即可验证
|
||||
7. 识别关键实体(如果涉及数据)
|
||||
8. 返回: 成功(规范准备好进行规划)
|
||||
|
||||
5. 使用模板结构将规范写入 SPEC_FILE, 用从功能描述(参数)派生的具体细节替换占位符, 同时保持章节顺序和标题.
|
||||
|
||||
6. **规范质量验证**: 编写初始规范后, 根据质量标准进行验证:
|
||||
|
||||
a. **创建规范质量检查清单**: 使用检查清单模板结构在 `FEATURE_DIR/checklists/requirements.md` 生成检查清单文件, 包含这些验证项目:
|
||||
|
||||
```markdown
|
||||
# 规范质量检查清单: [功能名称]
|
||||
|
||||
**目的**: 在继续规划之前验证规范的完整性和质量
|
||||
**创建时间**: [日期]
|
||||
**功能**: [指向 spec.md 的链接]
|
||||
|
||||
## 内容质量
|
||||
|
||||
- [ ] 无实现细节(语言、框架、API)
|
||||
- [ ] 专注于用户价值和业务需求
|
||||
- [ ] 为非技术利益相关者编写
|
||||
- [ ] 所有必需章节已完成
|
||||
|
||||
## 需求完整性
|
||||
|
||||
- [ ] 没有 [NEEDS CLARIFICATION] 标记剩余
|
||||
- [ ] 需求是可测试且明确的
|
||||
- [ ] 成功标准是可衡量的
|
||||
- [ ] 成功标准是技术无关的(无实现细节)
|
||||
- [ ] 所有验收场景已定义
|
||||
- [ ] 边缘情况已识别
|
||||
- [ ] 范围明确界定
|
||||
- [ ] 依赖关系和假设已识别
|
||||
|
||||
## 功能准备就绪
|
||||
|
||||
- [ ] 所有功能需求都有明确的验收标准
|
||||
- [ ] 用户场景覆盖主要流程
|
||||
- [ ] 功能满足成功标准中定义的可衡量结果
|
||||
- [ ] 没有实现细节泄漏到规范中
|
||||
|
||||
## 备注
|
||||
|
||||
- 标记为不完整的项目需要在 `/speckit.clarify` 或 `/speckit.plan` 之前更新规范
|
||||
```
|
||||
|
||||
b. **运行验证检查**: 根据每个检查清单项目审查规范:
|
||||
- 对于每个项目, 确定是否通过或失败
|
||||
- 记录发现的具体问题(引用相关规范章节)
|
||||
|
||||
c. **处理验证结果**:
|
||||
|
||||
- **如果所有项目都通过**: 标记检查清单完成并继续步骤 7
|
||||
|
||||
- **如果项目失败(不包括 [NEEDS CLARIFICATION])**:
|
||||
1. 列出失败的项目和具体问题
|
||||
2. 更新规范以解决每个问题
|
||||
3. 重新运行验证直到所有项目都通过(最多 3 次迭代)
|
||||
4. 如果 3 次迭代后仍然失败, 在检查清单备注中记录剩余问题并警告用户
|
||||
|
||||
- **如果 [NEEDS CLARIFICATION] 标记仍然存在**:
|
||||
1. 从规范中提取所有 [NEEDS CLARIFICATION: ...] 标记
|
||||
2. **限制检查**: 如果存在超过 3 个标记, 仅保留 3 个最关键的(按范围/安全/用户体验影响)并为其余部分做出有根据的猜测
|
||||
3. 对于每个需要的澄清(最多 3 个), 以以下格式向用户呈现选项:
|
||||
|
||||
```markdown
|
||||
## 问题 [N]: [主题]
|
||||
|
||||
**上下文**: [引用相关规范章节]
|
||||
|
||||
**我们需要了解**: [来自 NEEDS CLARIFICATION 标记的具体问题]
|
||||
|
||||
**建议答案**:
|
||||
|
||||
| 选项 | 答案 | 含义 |
|
||||
|--------|--------|--------------|
|
||||
| A | [第一个建议答案] | [这对功能意味着什么] |
|
||||
| B | [第二个建议答案] | [这对功能意味着什么] |
|
||||
| C | [第三个建议答案] | [这对功能意味着什么] |
|
||||
| 自定义 | 提供你自己的答案 | [解释如何提供自定义输入] |
|
||||
|
||||
**你的选择**: _[等待用户响应]_
|
||||
```
|
||||
|
||||
4. **关键 - 表格格式**: 确保 markdown 表格格式正确:
|
||||
- 使用一致的间距, 管道符对齐
|
||||
- 每个单元格内容周围应有空格: `| 内容 |` 而不是 `|内容|`
|
||||
- 标题分隔符必须至少有 3 个破折号: `|--------|`
|
||||
- 测试表格在 markdown 预览中正确渲染
|
||||
5. 按顺序编号问题(Q1、Q2、Q3 - 最多 3 个)
|
||||
6. 在等待响应之前一起呈现所有问题
|
||||
7. 等待用户响应所有问题的选择(例如, "Q1: A, Q2: 自定义 - [详情], Q3: B")
|
||||
8. 通过用用户选择或提供的答案替换每个 [NEEDS CLARIFICATION] 标记来更新规范
|
||||
9. 在所有澄清解决后重新运行验证
|
||||
|
||||
d. **更新检查清单**: 每次验证迭代后, 使用当前的通过/失败状态更新检查清单文件
|
||||
|
||||
7. 报告完成情况, 包括分支名称、规范文件路径、检查清单结果以及下一阶段(`/speckit.clarify` 或 `/speckit.plan`)的准备就绪状态.
|
||||
|
||||
**注意**: 脚本在写入之前创建并检出新分支并初始化规范文件.
|
||||
|
||||
## 通用指南
|
||||
|
||||
## 快速指南
|
||||
|
||||
- 专注于用户需要**什么**和**为什么**.
|
||||
- 避免如何实现(不涉及技术栈、API、代码结构).
|
||||
- 为业务利益相关者编写, 而不是为开发者.
|
||||
- 不要创建嵌入规范中的任何检查清单. 那将是一个单独的命令.
|
||||
|
||||
### 章节要求
|
||||
|
||||
- **必需章节**: 每个功能必须完成
|
||||
- **可选章节**: 仅在与功能相关时包含
|
||||
- 当章节不适用时, 完全删除它(不要保留为 "N/A")
|
||||
|
||||
### AI 生成
|
||||
|
||||
当从用户提示创建此规范时:
|
||||
|
||||
1. **做出有根据的猜测**: 使用上下文、行业标准和常见模式来填补空白
|
||||
2. **记录假设**: 在假设章节中记录合理的默认值
|
||||
3. **限制澄清**: 最多 3 个 [NEEDS CLARIFICATION] 标记 - 仅用于关键决策:
|
||||
- 显著影响功能范围或用户体验
|
||||
- 存在多个合理的解释且有不同的含义
|
||||
- 缺乏任何合理的默认值
|
||||
4. **优先澄清**: 范围 > 安全/隐私 > 用户体验 > 技术细节
|
||||
5. **像测试人员一样思考**: 每个模糊的需求都应该在"可测试且明确"的检查清单项目上失败
|
||||
6. **NEEDS CLARIFICATION 的常见领域**(仅在没有合理默认值时):
|
||||
- 功能范围和边界(包含/排除特定用例)
|
||||
- 用户类型和权限(如果可能存在多个冲突的解释)
|
||||
- 安全/合规要求(当具有法律/财务重要性时)
|
||||
|
||||
**合理默认值的示例**(不要询问这些):
|
||||
|
||||
- 数据保留: 该行业的行业标准实践
|
||||
- 性能目标: 标准 Web/移动应用期望, 除非另有说明
|
||||
- 错误处理: 用户友好的消息和适当的回退
|
||||
- 认证方法: Web 应用的标准基于会话或 OAuth2
|
||||
- 集成模式: RESTful API, 除非另有说明
|
||||
|
||||
### 成功标准指南
|
||||
|
||||
成功标准必须是:
|
||||
|
||||
1. **可衡量的**: 包括具体指标(时间、百分比、计数、速率)
|
||||
2. **技术无关的**: 不提及框架、语言、数据库或工具
|
||||
3. **以用户为中心的**: 从用户/业务角度描述结果, 而不是系统内部
|
||||
4. **可验证的**: 无需了解实现细节即可测试/验证
|
||||
|
||||
**好的示例**:
|
||||
|
||||
- "用户可以在 3 分钟内完成结账"
|
||||
- "系统支持 10,000 个并发用户"
|
||||
- "95% 的搜索在 1 秒内返回结果"
|
||||
- "任务完成率提高 40%"
|
||||
|
||||
**坏的示例**(以实现为中心):
|
||||
|
||||
- "API 响应时间在 200ms 以下"(太技术化, 使用"用户立即看到结果")
|
||||
- "数据库可以处理 1000 TPS"(实现细节, 使用面向用户的指标)
|
||||
- "React 组件高效渲染"(框架特定)
|
||||
- "Redis 缓存命中率超过 80%"(技术特定)
|
||||
@@ -0,0 +1,120 @@
|
||||
---
|
||||
description: 基于可用的设计文档, 为功能特性生成可执行的、按依赖关系排序的 tasks.md 文件.
|
||||
handoffs:
|
||||
- label: 分析一致性
|
||||
agent: speckit.analyze
|
||||
prompt: 运行项目一致性分析
|
||||
send: true
|
||||
- label: 实施项目
|
||||
agent: speckit.implement
|
||||
prompt: 实施项目
|
||||
send: true
|
||||
---
|
||||
|
||||
## 用户输入
|
||||
|
||||
```text
|
||||
$ARGUMENTS
|
||||
```
|
||||
|
||||
在继续之前, 你**必须**考虑用户输入(如果不为空).
|
||||
|
||||
## 概述
|
||||
|
||||
1. **设置**: 从仓库根目录运行 `.specify/scripts/powershell/check-prerequisites.ps1 -Json` 并解析 FEATURE_DIR 和 AVAILABLE_DOCS 列表. 所有路径必须是绝对路径. 对于参数值中的单引号如 "I'm Groot", 使用转义语法: 例如 'I'\''m Groot'(或尽可能使用双引号: "I'm Groot").
|
||||
|
||||
2. **加载设计文档**: 从 FEATURE_DIR 读取:
|
||||
- **必需**: plan.md(技术栈、库、结构), spec.md(带优先级的用户故事)
|
||||
- **可选**: data-model.md(实体), contracts/(API 端点), research.md(决策), quickstart.md(测试场景)
|
||||
- 注意: 并非所有项目都有所有文档. 基于可用内容生成任务.
|
||||
|
||||
3. **执行任务生成流程**(遵循模板结构):
|
||||
- 加载 plan.md 并提取技术栈、库、项目结构
|
||||
- **加载 spec.md 并提取带优先级的用户故事(P1、P2、P3 等)**
|
||||
- 如果存在 data-model.md: 提取实体 → 映射到用户故事
|
||||
- 如果存在 contracts/: 每个文件 → 映射端点到用户故事
|
||||
- 如果存在 research.md: 提取决策 → 生成设置任务
|
||||
- **按用户故事组织生成任务(重点)**:
|
||||
- 设置任务(所有故事需要的共享基础设施)
|
||||
- **基础任务(任何用户故事开始前必须完成的先决条件)**
|
||||
- 对于每个用户故事(按优先级顺序 P1、P2、P3...):
|
||||
- 组合完成该故事所需的所有任务
|
||||
- 包含该故事特定的模型、服务、端点、UI 组件
|
||||
- 标记哪些任务是 [P] 可并行的
|
||||
- 如果请求测试: 包含该故事特定的测试
|
||||
- 完善/集成任务(横切关注点)
|
||||
- **测试是可选的**: 仅在功能规范中明确请求或用户要求 TDD 方法时生成测试任务
|
||||
- 应用任务规则:
|
||||
- 不同文件 = 标记 [P] 表示并行
|
||||
- 相同文件 = 顺序执行(无 [P])
|
||||
- 如果请求测试: 测试在实现之前(TDD 顺序)
|
||||
- 按顺序编号任务(T001、T002...)
|
||||
- 生成显示用户故事完成顺序的依赖关系图
|
||||
- 为每个用户故事创建并行执行示例
|
||||
- 验证任务完整性(每个用户故事都有所有必需任务, 可独立测试)
|
||||
|
||||
4. **生成 tasks.md**: 使用 `.specify/templates/tasks-template.md` 作为结构, 填充:
|
||||
- 来自 plan.md 的正确功能名称
|
||||
- 阶段 1: 设置任务(项目初始化)
|
||||
- 阶段 2: 基础任务(所有用户故事的阻塞先决条件)
|
||||
- 阶段 3+: 每个用户故事一个阶段(按 spec.md 中的优先级顺序)
|
||||
- 每个阶段包括: 故事目标、独立测试标准、测试(如果请求)、实现任务
|
||||
- 每个任务的清晰 [Story] 标签(US1、US2、US3...)
|
||||
- 每个故事内可并行任务的 [P] 标记
|
||||
- 每个故事阶段后的检查点标记
|
||||
- 最终阶段: 完善与横切关注点
|
||||
- 按执行顺序编号的任务(T001、T002...)
|
||||
- 每个任务的清晰文件路径
|
||||
- 显示故事完成顺序的依赖关系部分
|
||||
- 每个故事的并行执行示例
|
||||
- 实现策略部分(MVP 优先, 增量交付)
|
||||
|
||||
5. **报告**: 输出生成的 tasks.md 路径和摘要:
|
||||
- 总任务数
|
||||
- 每个用户故事的任务数
|
||||
- 识别的并行机会
|
||||
- 每个故事的独立测试标准
|
||||
- 建议的 MVP 范围(通常只是用户故事 1)
|
||||
|
||||
任务生成上下文: $ARGUMENTS
|
||||
|
||||
tasks.md 应该立即可执行 - 每个任务必须足够具体, 以便 LLM 可以在没有额外上下文的情况下完成它.
|
||||
|
||||
## 任务生成规则
|
||||
|
||||
**重要**: 测试是可选的. 仅当用户在功能规范中明确请求测试或 TDD 方法时才生成测试任务.
|
||||
|
||||
**关键**: 任务必须按用户故事组织, 以实现独立的实现和测试.
|
||||
|
||||
1. **来自用户故事(spec.md)** - 主要组织方式:
|
||||
- 每个用户故事(P1、P2、P3...)都有自己的阶段
|
||||
- 将所有相关组件映射到它们的故事:
|
||||
- 该故事所需的模型
|
||||
- 该故事所需的服务
|
||||
- 该故事所需的端点/UI
|
||||
- 如果请求测试: 该故事特定的测试
|
||||
- 标记故事依赖关系(大多数故事应该是独立的)
|
||||
|
||||
2. **来自合约**:
|
||||
- 将每个合约/端点 → 映射到它服务的用户故事
|
||||
- 如果请求测试: 每个合约 → 在该故事阶段的实现之前的合约测试任务 [P]
|
||||
|
||||
3. **来自数据模型**:
|
||||
- 将每个实体 → 映射到需要它的用户故事
|
||||
- 如果实体服务多个故事: 放在最早的故事或设置阶段
|
||||
- 关系 → 适当故事阶段的服务层任务
|
||||
|
||||
4. **来自设置/基础设施**:
|
||||
- 共享基础设施 → 设置阶段(阶段 1)
|
||||
- 基础/阻塞任务 → 基础阶段(阶段 2)
|
||||
- 示例: 数据库模式设置、认证框架、核心库、基础配置
|
||||
- 这些必须在任何用户故事可以实现之前完成
|
||||
- 故事特定的设置 → 在该故事的阶段内
|
||||
|
||||
5. **排序**:
|
||||
- 阶段 1: 设置(项目初始化)
|
||||
- 阶段 2: 基础(阻塞先决条件 - 必须在用户故事之前完成)
|
||||
- 阶段 3+: 按优先级顺序的用户故事(P1、P2、P3...)
|
||||
- 每个故事内: 测试(如果请求)→ 模型 → 服务 → 端点 → 集成
|
||||
- 最终阶段: 完善与横切关注点
|
||||
- 每个用户故事阶段应该是一个完整的、可独立测试的增量
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
description: 将现有任务转换为可操作的、按依赖关系排序的 GitHub 议题,基于可用的设计制品。
|
||||
tools: ['github/github-mcp-server/issue_write']
|
||||
---
|
||||
|
||||
## 用户输入
|
||||
|
||||
```text
|
||||
$ARGUMENTS
|
||||
```
|
||||
|
||||
你必须**在继续之前考虑用户输入**(如果非空)。
|
||||
|
||||
## 大纲
|
||||
|
||||
1. 从仓库根目录运行 `.specify/scripts/powershell/check-prerequisites.ps1 -Json -RequireTasks -IncludeTasks` 并解析 FEATURE_DIR 和 AVAILABLE_DOCS 列表。所有路径必须是绝对路径。对于参数中的单引号如 "I'm Groot",使用转义语法:例如 'I'\''m Groot'(或尽可能使用双引号:"I'm Groot")。
|
||||
1. 从执行的脚本中,提取 **任务** 的路径。
|
||||
1. 通过运行以下命令获取 Git 远程仓库:
|
||||
|
||||
```bash
|
||||
git config --get remote.origin.url
|
||||
```
|
||||
|
||||
**仅当远程仓库是 GITHUB URL 时才继续下一步**
|
||||
|
||||
1. 对于列表中的每个任务,使用 GitHub MCP 服务器在与 Git 远程仓库对应的仓库中创建一个新议题。
|
||||
|
||||
**在任何情况下都不要在与远程 URL 不匹配的仓库中创建议题**
|
||||
@@ -0,0 +1,50 @@
|
||||
# [PROJECT_NAME] 项目章程
|
||||
<!-- 示例: Spec 章程, TaskFlow 章程等 -->
|
||||
|
||||
## 核心原则
|
||||
|
||||
### [PRINCIPLE_1_NAME]
|
||||
<!-- 示例: I. 库优先 -->
|
||||
[PRINCIPLE_1_DESCRIPTION]
|
||||
<!-- 示例: 每个功能都从独立的库开始; 库必须是自包含的、可独立测试的、有文档的; 需要明确的目的 - 不允许仅用于组织的库 -->
|
||||
|
||||
### [PRINCIPLE_2_NAME]
|
||||
<!-- 示例: II. CLI 接口 -->
|
||||
[PRINCIPLE_2_DESCRIPTION]
|
||||
<!-- 示例: 每个库都通过 CLI 暴露功能; 文本输入/输出协议: stdin/args → stdout, 错误 → stderr; 支持 JSON + 人类可读格式 -->
|
||||
|
||||
### [PRINCIPLE_3_NAME]
|
||||
<!-- 示例: III. 测试优先(不可协商) -->
|
||||
[PRINCIPLE_3_DESCRIPTION]
|
||||
<!-- 示例: TDD 强制要求: 编写测试 → 用户批准 → 测试失败 → 然后实现; 严格执行红-绿-重构循环 -->
|
||||
|
||||
### [PRINCIPLE_4_NAME]
|
||||
<!-- 示例: IV. 集成测试 -->
|
||||
[PRINCIPLE_4_DESCRIPTION]
|
||||
<!-- 示例: 需要集成测试的重点领域: 新库契约测试、契约变更、服务间通信、共享模式 -->
|
||||
|
||||
### [PRINCIPLE_5_NAME]
|
||||
<!-- 示例: V. 可观测性, VI. 版本控制和破坏性变更, VII. 简单性 -->
|
||||
[PRINCIPLE_5_DESCRIPTION]
|
||||
<!-- 示例: 文本 I/O 确保可调试性; 需要结构化日志; 或者: MAJOR.MINOR.BUILD 格式; 或者: 从简单开始, YAGNI 原则 -->
|
||||
|
||||
## [SECTION_2_NAME]
|
||||
<!-- 示例: 附加约束、安全要求、性能标准等 -->
|
||||
|
||||
[SECTION_2_CONTENT]
|
||||
<!-- 示例: 技术栈要求、合规标准、部署策略等 -->
|
||||
|
||||
## [SECTION_3_NAME]
|
||||
<!-- 示例: 开发工作流程、审查流程、质量门禁等 -->
|
||||
|
||||
[SECTION_3_CONTENT]
|
||||
<!-- 示例: 代码审查要求、测试门禁、部署审批流程等 -->
|
||||
|
||||
## 治理
|
||||
<!-- 示例: 章程优先于所有其他实践; 修正需要文档化、批准、迁移计划 -->
|
||||
|
||||
[GOVERNANCE_RULES]
|
||||
<!-- 示例: 所有 PR/审查必须验证合规性; 复杂性必须得到证明; 使用 [GUIDANCE_FILE] 进行运行时开发指导 -->
|
||||
|
||||
**版本**: [CONSTITUTION_VERSION] | **批准日期**: [RATIFICATION_DATE] | **最后修正**: [LAST_AMENDED_DATE]
|
||||
<!-- 示例: 版本: 2.1.1 | 批准日期: 2025-06-13 | 最后修正: 2025-07-16 -->
|
||||
@@ -0,0 +1,148 @@
|
||||
#!/usr/bin/env pwsh
|
||||
|
||||
# Consolidated prerequisite checking script (PowerShell)
|
||||
#
|
||||
# This script provides unified prerequisite checking for Spec-Driven Development workflow.
|
||||
# It replaces the functionality previously spread across multiple scripts.
|
||||
#
|
||||
# Usage: ./check-prerequisites.ps1 [OPTIONS]
|
||||
#
|
||||
# OPTIONS:
|
||||
# -Json Output in JSON format
|
||||
# -RequireTasks Require tasks.md to exist (for implementation phase)
|
||||
# -IncludeTasks Include tasks.md in AVAILABLE_DOCS list
|
||||
# -PathsOnly Only output path variables (no validation)
|
||||
# -Help, -h Show help message
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[switch]$Json,
|
||||
[switch]$RequireTasks,
|
||||
[switch]$IncludeTasks,
|
||||
[switch]$PathsOnly,
|
||||
[switch]$Help
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# Show help if requested
|
||||
if ($Help) {
|
||||
Write-Output @"
|
||||
Usage: check-prerequisites.ps1 [OPTIONS]
|
||||
|
||||
Consolidated prerequisite checking for Spec-Driven Development workflow.
|
||||
|
||||
OPTIONS:
|
||||
-Json Output in JSON format
|
||||
-RequireTasks Require tasks.md to exist (for implementation phase)
|
||||
-IncludeTasks Include tasks.md in AVAILABLE_DOCS list
|
||||
-PathsOnly Only output path variables (no prerequisite validation)
|
||||
-Help, -h Show this help message
|
||||
|
||||
EXAMPLES:
|
||||
# Check task prerequisites (plan.md required)
|
||||
.\check-prerequisites.ps1 -Json
|
||||
|
||||
# Check implementation prerequisites (plan.md + tasks.md required)
|
||||
.\check-prerequisites.ps1 -Json -RequireTasks -IncludeTasks
|
||||
|
||||
# Get feature paths only (no validation)
|
||||
.\check-prerequisites.ps1 -PathsOnly
|
||||
|
||||
"@
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Source common functions
|
||||
. "$PSScriptRoot/common.ps1"
|
||||
|
||||
# Get feature paths and validate branch
|
||||
$paths = Get-FeaturePathsEnv
|
||||
|
||||
if (-not (Test-FeatureBranch -Branch $paths.CURRENT_BRANCH -HasGit:$paths.HAS_GIT)) {
|
||||
exit 1
|
||||
}
|
||||
|
||||
# If paths-only mode, output paths and exit (support combined -Json -PathsOnly)
|
||||
if ($PathsOnly) {
|
||||
if ($Json) {
|
||||
[PSCustomObject]@{
|
||||
REPO_ROOT = $paths.REPO_ROOT
|
||||
BRANCH = $paths.CURRENT_BRANCH
|
||||
FEATURE_DIR = $paths.FEATURE_DIR
|
||||
FEATURE_SPEC = $paths.FEATURE_SPEC
|
||||
IMPL_PLAN = $paths.IMPL_PLAN
|
||||
TASKS = $paths.TASKS
|
||||
} | ConvertTo-Json -Compress
|
||||
} else {
|
||||
Write-Output "REPO_ROOT: $($paths.REPO_ROOT)"
|
||||
Write-Output "BRANCH: $($paths.CURRENT_BRANCH)"
|
||||
Write-Output "FEATURE_DIR: $($paths.FEATURE_DIR)"
|
||||
Write-Output "FEATURE_SPEC: $($paths.FEATURE_SPEC)"
|
||||
Write-Output "IMPL_PLAN: $($paths.IMPL_PLAN)"
|
||||
Write-Output "TASKS: $($paths.TASKS)"
|
||||
}
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Validate required directories and files
|
||||
if (-not (Test-Path $paths.FEATURE_DIR -PathType Container)) {
|
||||
Write-Output "ERROR: Feature directory not found: $($paths.FEATURE_DIR)"
|
||||
Write-Output "Run /speckit.specify first to create the feature structure."
|
||||
exit 1
|
||||
}
|
||||
|
||||
if (-not (Test-Path $paths.IMPL_PLAN -PathType Leaf)) {
|
||||
Write-Output "ERROR: plan.md not found in $($paths.FEATURE_DIR)"
|
||||
Write-Output "Run /speckit.plan first to create the implementation plan."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check for tasks.md if required
|
||||
if ($RequireTasks -and -not (Test-Path $paths.TASKS -PathType Leaf)) {
|
||||
Write-Output "ERROR: tasks.md not found in $($paths.FEATURE_DIR)"
|
||||
Write-Output "Run /speckit.tasks first to create the task list."
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Build list of available documents
|
||||
$docs = @()
|
||||
|
||||
# Always check these optional docs
|
||||
if (Test-Path $paths.RESEARCH) { $docs += 'research.md' }
|
||||
if (Test-Path $paths.DATA_MODEL) { $docs += 'data-model.md' }
|
||||
|
||||
# Check contracts directory (only if it exists and has files)
|
||||
if ((Test-Path $paths.CONTRACTS_DIR) -and (Get-ChildItem -Path $paths.CONTRACTS_DIR -ErrorAction SilentlyContinue | Select-Object -First 1)) {
|
||||
$docs += 'contracts/'
|
||||
}
|
||||
|
||||
if (Test-Path $paths.QUICKSTART) { $docs += 'quickstart.md' }
|
||||
|
||||
# Include tasks.md if requested and it exists
|
||||
if ($IncludeTasks -and (Test-Path $paths.TASKS)) {
|
||||
$docs += 'tasks.md'
|
||||
}
|
||||
|
||||
# Output results
|
||||
if ($Json) {
|
||||
# JSON output
|
||||
[PSCustomObject]@{
|
||||
FEATURE_DIR = $paths.FEATURE_DIR
|
||||
AVAILABLE_DOCS = $docs
|
||||
} | ConvertTo-Json -Compress
|
||||
} else {
|
||||
# Text output
|
||||
Write-Output "FEATURE_DIR:$($paths.FEATURE_DIR)"
|
||||
Write-Output "AVAILABLE_DOCS:"
|
||||
|
||||
# Show status of each potential document
|
||||
Test-FileExists -Path $paths.RESEARCH -Description 'research.md' | Out-Null
|
||||
Test-FileExists -Path $paths.DATA_MODEL -Description 'data-model.md' | Out-Null
|
||||
Test-DirHasFiles -Path $paths.CONTRACTS_DIR -Description 'contracts/' | Out-Null
|
||||
Test-FileExists -Path $paths.QUICKSTART -Description 'quickstart.md' | Out-Null
|
||||
|
||||
if ($IncludeTasks) {
|
||||
Test-FileExists -Path $paths.TASKS -Description 'tasks.md' | Out-Null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
#!/usr/bin/env pwsh
|
||||
# Common PowerShell functions analogous to common.sh
|
||||
|
||||
function Get-RepoRoot {
|
||||
try {
|
||||
$result = git rev-parse --show-toplevel 2>$null
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
return $result
|
||||
}
|
||||
} catch {
|
||||
# Git command failed
|
||||
}
|
||||
|
||||
# Fall back to script location for non-git repos
|
||||
return (Resolve-Path (Join-Path $PSScriptRoot "../../..")).Path
|
||||
}
|
||||
|
||||
function Get-CurrentBranch {
|
||||
# First check if SPECIFY_FEATURE environment variable is set
|
||||
if ($env:SPECIFY_FEATURE) {
|
||||
return $env:SPECIFY_FEATURE
|
||||
}
|
||||
|
||||
# Then check git if available
|
||||
try {
|
||||
$result = git rev-parse --abbrev-ref HEAD 2>$null
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
return $result
|
||||
}
|
||||
} catch {
|
||||
# Git command failed
|
||||
}
|
||||
|
||||
# For non-git repos, try to find the latest feature directory
|
||||
$repoRoot = Get-RepoRoot
|
||||
$specsDir = Join-Path $repoRoot "specs"
|
||||
|
||||
if (Test-Path $specsDir) {
|
||||
$latestFeature = ""
|
||||
$highest = 0
|
||||
|
||||
Get-ChildItem -Path $specsDir -Directory | ForEach-Object {
|
||||
if ($_.Name -match '^(\d{3})-') {
|
||||
$num = [int]$matches[1]
|
||||
if ($num -gt $highest) {
|
||||
$highest = $num
|
||||
$latestFeature = $_.Name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($latestFeature) {
|
||||
return $latestFeature
|
||||
}
|
||||
}
|
||||
|
||||
# Final fallback
|
||||
return "main"
|
||||
}
|
||||
|
||||
function Test-HasGit {
|
||||
try {
|
||||
git rev-parse --show-toplevel 2>$null | Out-Null
|
||||
return ($LASTEXITCODE -eq 0)
|
||||
} catch {
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Test-FeatureBranch {
|
||||
param(
|
||||
[string]$Branch,
|
||||
[bool]$HasGit = $true
|
||||
)
|
||||
|
||||
# For non-git repos, we can't enforce branch naming but still provide output
|
||||
if (-not $HasGit) {
|
||||
Write-Warning "[specify] Warning: Git repository not detected; skipped branch validation"
|
||||
return $true
|
||||
}
|
||||
|
||||
if ($Branch -notmatch '^[0-9]{3}-') {
|
||||
Write-Output "ERROR: Not on a feature branch. Current branch: $Branch"
|
||||
Write-Output "Feature branches should be named like: 001-feature-name"
|
||||
return $false
|
||||
}
|
||||
return $true
|
||||
}
|
||||
|
||||
function Get-FeatureDir {
|
||||
param([string]$RepoRoot, [string]$Branch)
|
||||
Join-Path $RepoRoot "specs/$Branch"
|
||||
}
|
||||
|
||||
function Get-FeaturePathsEnv {
|
||||
$repoRoot = Get-RepoRoot
|
||||
$currentBranch = Get-CurrentBranch
|
||||
$hasGit = Test-HasGit
|
||||
$featureDir = Get-FeatureDir -RepoRoot $repoRoot -Branch $currentBranch
|
||||
|
||||
[PSCustomObject]@{
|
||||
REPO_ROOT = $repoRoot
|
||||
CURRENT_BRANCH = $currentBranch
|
||||
HAS_GIT = $hasGit
|
||||
FEATURE_DIR = $featureDir
|
||||
FEATURE_SPEC = Join-Path $featureDir 'spec.md'
|
||||
IMPL_PLAN = Join-Path $featureDir 'plan.md'
|
||||
TASKS = Join-Path $featureDir 'tasks.md'
|
||||
RESEARCH = Join-Path $featureDir 'research.md'
|
||||
DATA_MODEL = Join-Path $featureDir 'data-model.md'
|
||||
QUICKSTART = Join-Path $featureDir 'quickstart.md'
|
||||
CONTRACTS_DIR = Join-Path $featureDir 'contracts'
|
||||
}
|
||||
}
|
||||
|
||||
function Test-FileExists {
|
||||
param([string]$Path, [string]$Description)
|
||||
if (Test-Path -Path $Path -PathType Leaf) {
|
||||
Write-Output " ✓ $Description"
|
||||
return $true
|
||||
} else {
|
||||
Write-Output " ✗ $Description"
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
function Test-DirHasFiles {
|
||||
param([string]$Path, [string]$Description)
|
||||
if ((Test-Path -Path $Path -PathType Container) -and (Get-ChildItem -Path $Path -ErrorAction SilentlyContinue | Where-Object { -not $_.PSIsContainer } | Select-Object -First 1)) {
|
||||
Write-Output " ✓ $Description"
|
||||
return $true
|
||||
} else {
|
||||
Write-Output " ✗ $Description"
|
||||
return $false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,327 @@
|
||||
#!/usr/bin/env pwsh
|
||||
# Create a new feature
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[switch]$Json,
|
||||
[string]$ShortName,
|
||||
[int]$Number = 0,
|
||||
[switch]$Help,
|
||||
[Parameter(ValueFromRemainingArguments = $true)]
|
||||
[string[]]$FeatureDescription
|
||||
)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# Show help if requested
|
||||
if ($Help) {
|
||||
Write-Host "Usage: ./create-new-feature.ps1 [-Json] [-ShortName <name>] [-Number N] <feature description>"
|
||||
Write-Host ""
|
||||
Write-Host "Options:"
|
||||
Write-Host " -Json Output in JSON format"
|
||||
Write-Host " -ShortName <name> Provide a custom short name (2-4 words) for the branch"
|
||||
Write-Host " -Number N Specify branch number manually (overrides auto-detection)"
|
||||
Write-Host " -Help Show this help message"
|
||||
Write-Host ""
|
||||
Write-Host "Examples:"
|
||||
Write-Host " ./create-new-feature.ps1 'Add user authentication system' -ShortName 'user-auth'"
|
||||
Write-Host " ./create-new-feature.ps1 'Implement OAuth2 integration for API'"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Check if feature description provided
|
||||
if (-not $FeatureDescription -or $FeatureDescription.Count -eq 0) {
|
||||
Write-Error "Usage: ./create-new-feature.ps1 [-Json] [-ShortName <name>] <feature description>"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$featureDesc = ($FeatureDescription -join ' ').Trim()
|
||||
|
||||
# Resolve repository root. Prefer git information when available, but fall back
|
||||
# to searching for repository markers so the workflow still functions in repositories that
|
||||
# were initialized with --no-git.
|
||||
function Find-RepositoryRoot {
|
||||
param(
|
||||
[string]$StartDir,
|
||||
[string[]]$Markers = @('.git', '.specify')
|
||||
)
|
||||
$current = Resolve-Path $StartDir
|
||||
while ($true) {
|
||||
foreach ($marker in $Markers) {
|
||||
if (Test-Path (Join-Path $current $marker)) {
|
||||
return $current
|
||||
}
|
||||
}
|
||||
$parent = Split-Path $current -Parent
|
||||
if ($parent -eq $current) {
|
||||
# Reached filesystem root without finding markers
|
||||
return $null
|
||||
}
|
||||
$current = $parent
|
||||
}
|
||||
}
|
||||
|
||||
function Get-HighestNumberFromSpecs {
|
||||
param([string]$SpecsDir)
|
||||
|
||||
$highest = 0
|
||||
if (Test-Path $SpecsDir) {
|
||||
Get-ChildItem -Path $SpecsDir -Directory | ForEach-Object {
|
||||
if ($_.Name -match '^(\d+)') {
|
||||
$num = [int]$matches[1]
|
||||
if ($num -gt $highest) { $highest = $num }
|
||||
}
|
||||
}
|
||||
}
|
||||
return $highest
|
||||
}
|
||||
|
||||
function Get-HighestNumberFromBranches {
|
||||
param()
|
||||
|
||||
$highest = 0
|
||||
try {
|
||||
$branches = git branch -a 2>$null
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
foreach ($branch in $branches) {
|
||||
# Clean branch name: remove leading markers and remote prefixes
|
||||
$cleanBranch = $branch.Trim() -replace '^\*?\s+', '' -replace '^remotes/[^/]+/', ''
|
||||
|
||||
# Extract feature number if branch matches pattern ###-*
|
||||
if ($cleanBranch -match '^(\d+)-') {
|
||||
$num = [int]$matches[1]
|
||||
if ($num -gt $highest) { $highest = $num }
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
# If git command fails, return 0
|
||||
Write-Verbose "Could not check Git branches: $_"
|
||||
}
|
||||
return $highest
|
||||
}
|
||||
|
||||
function Get-NextBranchNumber {
|
||||
param(
|
||||
[string]$ShortName,
|
||||
[string]$SpecsDir
|
||||
)
|
||||
|
||||
# Fetch all remotes to get latest branch info (suppress errors if no remotes)
|
||||
try {
|
||||
git fetch --all --prune 2>$null | Out-Null
|
||||
} catch {
|
||||
# Ignore fetch errors
|
||||
}
|
||||
|
||||
# Find remote branches matching the pattern using git ls-remote
|
||||
$remoteBranches = @()
|
||||
try {
|
||||
$remoteRefs = git ls-remote --heads origin 2>$null
|
||||
if ($remoteRefs) {
|
||||
$remoteBranches = $remoteRefs | Where-Object { $_ -match "refs/heads/(\d+)-$([regex]::Escape($ShortName))$" } | ForEach-Object {
|
||||
if ($_ -match "refs/heads/(\d+)-") {
|
||||
[int]$matches[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
# Ignore errors
|
||||
}
|
||||
|
||||
# Check local branches
|
||||
$localBranches = @()
|
||||
try {
|
||||
$allBranches = git branch 2>$null
|
||||
if ($allBranches) {
|
||||
$localBranches = $allBranches | Where-Object { $_ -match "^\*?\s*(\d+)-$([regex]::Escape($ShortName))$" } | ForEach-Object {
|
||||
if ($_ -match "(\d+)-") {
|
||||
[int]$matches[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
# Ignore errors
|
||||
}
|
||||
|
||||
# Check specs directory
|
||||
$specDirs = @()
|
||||
if (Test-Path $SpecsDir) {
|
||||
try {
|
||||
$specDirs = Get-ChildItem -Path $SpecsDir -Directory | Where-Object { $_.Name -match "^(\d+)-$([regex]::Escape($ShortName))$" } | ForEach-Object {
|
||||
if ($_.Name -match "^(\d+)-") {
|
||||
[int]$matches[1]
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
# Ignore errors
|
||||
}
|
||||
}
|
||||
|
||||
# Combine all sources and get the highest number
|
||||
$maxNum = 0
|
||||
foreach ($num in ($remoteBranches + $localBranches + $specDirs)) {
|
||||
if ($num -gt $maxNum) {
|
||||
$maxNum = $num
|
||||
}
|
||||
}
|
||||
|
||||
# Return next number
|
||||
return $maxNum + 1
|
||||
}
|
||||
|
||||
function ConvertTo-CleanBranchName {
|
||||
param([string]$Name)
|
||||
|
||||
return $Name.ToLower() -replace '[^a-z0-9]', '-' -replace '-{2,}', '-' -replace '^-', '' -replace '-$', ''
|
||||
}
|
||||
$fallbackRoot = (Find-RepositoryRoot -StartDir $PSScriptRoot)
|
||||
if (-not $fallbackRoot) {
|
||||
Write-Error "Error: Could not determine repository root. Please run this script from within the repository."
|
||||
exit 1
|
||||
}
|
||||
|
||||
try {
|
||||
$repoRoot = git rev-parse --show-toplevel 2>$null
|
||||
if ($LASTEXITCODE -eq 0) {
|
||||
$hasGit = $true
|
||||
} else {
|
||||
throw "Git not available"
|
||||
}
|
||||
} catch {
|
||||
$repoRoot = $fallbackRoot
|
||||
$hasGit = $false
|
||||
}
|
||||
|
||||
Set-Location $repoRoot
|
||||
|
||||
$specsDir = Join-Path $repoRoot 'specs'
|
||||
New-Item -ItemType Directory -Path $specsDir -Force | Out-Null
|
||||
|
||||
# Function to generate branch name with stop word filtering and length filtering
|
||||
function Get-BranchName {
|
||||
param([string]$Description)
|
||||
|
||||
# Common stop words to filter out
|
||||
$stopWords = @(
|
||||
'i', 'a', 'an', 'the', 'to', 'for', 'of', 'in', 'on', 'at', 'by', 'with', 'from',
|
||||
'is', 'are', 'was', 'were', 'be', 'been', 'being', 'have', 'has', 'had',
|
||||
'do', 'does', 'did', 'will', 'would', 'should', 'could', 'can', 'may', 'might', 'must', 'shall',
|
||||
'this', 'that', 'these', 'those', 'my', 'your', 'our', 'their',
|
||||
'want', 'need', 'add', 'get', 'set'
|
||||
)
|
||||
|
||||
# Convert to lowercase and extract words (alphanumeric only)
|
||||
$cleanName = $Description.ToLower() -replace '[^a-z0-9\s]', ' '
|
||||
$words = $cleanName -split '\s+' | Where-Object { $_ }
|
||||
|
||||
# Filter words: remove stop words and words shorter than 3 chars (unless they're uppercase acronyms in original)
|
||||
$meaningfulWords = @()
|
||||
foreach ($word in $words) {
|
||||
# Skip stop words
|
||||
if ($stopWords -contains $word) { continue }
|
||||
|
||||
# Keep words that are length >= 3 OR appear as uppercase in original (likely acronyms)
|
||||
if ($word.Length -ge 3) {
|
||||
$meaningfulWords += $word
|
||||
} elseif ($Description -match "\b$($word.ToUpper())\b") {
|
||||
# Keep short words if they appear as uppercase in original (likely acronyms)
|
||||
$meaningfulWords += $word
|
||||
}
|
||||
}
|
||||
|
||||
# If we have meaningful words, use first 3-4 of them
|
||||
if ($meaningfulWords.Count -gt 0) {
|
||||
$maxWords = if ($meaningfulWords.Count -eq 4) { 4 } else { 3 }
|
||||
$result = ($meaningfulWords | Select-Object -First $maxWords) -join '-'
|
||||
return $result
|
||||
} else {
|
||||
# Fallback to original logic if no meaningful words found
|
||||
$result = ConvertTo-CleanBranchName -Name $Description
|
||||
$fallbackWords = ($result -split '-') | Where-Object { $_ } | Select-Object -First 3
|
||||
return [string]::Join('-', $fallbackWords)
|
||||
}
|
||||
}
|
||||
|
||||
# Generate branch name
|
||||
if ($ShortName) {
|
||||
# Use provided short name, just clean it up
|
||||
$branchSuffix = ConvertTo-CleanBranchName -Name $ShortName
|
||||
} else {
|
||||
# Generate from description with smart filtering
|
||||
$branchSuffix = Get-BranchName -Description $featureDesc
|
||||
}
|
||||
|
||||
# Determine branch number
|
||||
if ($Number -eq 0) {
|
||||
if ($hasGit) {
|
||||
# Check existing branches on remotes
|
||||
$Number = Get-NextBranchNumber -ShortName $branchSuffix -SpecsDir $specsDir
|
||||
} else {
|
||||
# Fall back to local directory check
|
||||
$Number = (Get-HighestNumberFromSpecs -SpecsDir $specsDir) + 1
|
||||
}
|
||||
}
|
||||
|
||||
$featureNum = ('{0:000}' -f $Number)
|
||||
$branchName = "$featureNum-$branchSuffix"
|
||||
|
||||
# GitHub enforces a 244-byte limit on branch names
|
||||
# Validate and truncate if necessary
|
||||
$maxBranchLength = 244
|
||||
if ($branchName.Length -gt $maxBranchLength) {
|
||||
# Calculate how much we need to trim from suffix
|
||||
# Account for: feature number (3) + hyphen (1) = 4 chars
|
||||
$maxSuffixLength = $maxBranchLength - 4
|
||||
|
||||
# Truncate suffix
|
||||
$truncatedSuffix = $branchSuffix.Substring(0, [Math]::Min($branchSuffix.Length, $maxSuffixLength))
|
||||
# Remove trailing hyphen if truncation created one
|
||||
$truncatedSuffix = $truncatedSuffix -replace '-$', ''
|
||||
|
||||
$originalBranchName = $branchName
|
||||
$branchName = "$featureNum-$truncatedSuffix"
|
||||
|
||||
Write-Warning "[specify] Branch name exceeded GitHub's 244-byte limit"
|
||||
Write-Warning "[specify] Original: $originalBranchName ($($originalBranchName.Length) bytes)"
|
||||
Write-Warning "[specify] Truncated to: $branchName ($($branchName.Length) bytes)"
|
||||
}
|
||||
|
||||
if ($hasGit) {
|
||||
try {
|
||||
git checkout -b $branchName | Out-Null
|
||||
} catch {
|
||||
Write-Warning "Failed to create git branch: $branchName"
|
||||
}
|
||||
} else {
|
||||
Write-Warning "[specify] Warning: Git repository not detected; skipped branch creation for $branchName"
|
||||
}
|
||||
|
||||
$featureDir = Join-Path $specsDir $branchName
|
||||
New-Item -ItemType Directory -Path $featureDir -Force | Out-Null
|
||||
|
||||
$template = Join-Path $repoRoot '.specify/templates/spec-template.md'
|
||||
$specFile = Join-Path $featureDir 'spec.md'
|
||||
if (Test-Path $template) {
|
||||
Copy-Item $template $specFile -Force
|
||||
} else {
|
||||
New-Item -ItemType File -Path $specFile | Out-Null
|
||||
}
|
||||
|
||||
# Set the SPECIFY_FEATURE environment variable for the current session
|
||||
$env:SPECIFY_FEATURE = $branchName
|
||||
|
||||
if ($Json) {
|
||||
$obj = [PSCustomObject]@{
|
||||
BRANCH_NAME = $branchName
|
||||
SPEC_FILE = $specFile
|
||||
FEATURE_NUM = $featureNum
|
||||
HAS_GIT = $hasGit
|
||||
}
|
||||
$obj | ConvertTo-Json -Compress
|
||||
} else {
|
||||
Write-Output "BRANCH_NAME: $branchName"
|
||||
Write-Output "SPEC_FILE: $specFile"
|
||||
Write-Output "FEATURE_NUM: $featureNum"
|
||||
Write-Output "HAS_GIT: $hasGit"
|
||||
Write-Output "SPECIFY_FEATURE environment variable set to: $branchName"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env pwsh
|
||||
# Setup implementation plan for a feature
|
||||
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[switch]$Json,
|
||||
[switch]$Help
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# Show help if requested
|
||||
if ($Help) {
|
||||
Write-Output "Usage: ./setup-plan.ps1 [-Json] [-Help]"
|
||||
Write-Output " -Json Output results in JSON format"
|
||||
Write-Output " -Help Show this help message"
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Load common functions
|
||||
. "$PSScriptRoot/common.ps1"
|
||||
|
||||
# Get all paths and variables from common functions
|
||||
$paths = Get-FeaturePathsEnv
|
||||
|
||||
# Check if we're on a proper feature branch (only for git repos)
|
||||
if (-not (Test-FeatureBranch -Branch $paths.CURRENT_BRANCH -HasGit $paths.HAS_GIT)) {
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Ensure the feature directory exists
|
||||
New-Item -ItemType Directory -Path $paths.FEATURE_DIR -Force | Out-Null
|
||||
|
||||
# Copy plan template if it exists, otherwise note it or create empty file
|
||||
$template = Join-Path $paths.REPO_ROOT '.specify/templates/plan-template.md'
|
||||
if (Test-Path $template) {
|
||||
Copy-Item $template $paths.IMPL_PLAN -Force
|
||||
Write-Output "Copied plan template to $($paths.IMPL_PLAN)"
|
||||
} else {
|
||||
Write-Warning "Plan template not found at $template"
|
||||
# Create a basic plan file if template doesn't exist
|
||||
New-Item -ItemType File -Path $paths.IMPL_PLAN -Force | Out-Null
|
||||
}
|
||||
|
||||
# Output results
|
||||
if ($Json) {
|
||||
$result = [PSCustomObject]@{
|
||||
FEATURE_SPEC = $paths.FEATURE_SPEC
|
||||
IMPL_PLAN = $paths.IMPL_PLAN
|
||||
SPECS_DIR = $paths.FEATURE_DIR
|
||||
BRANCH = $paths.CURRENT_BRANCH
|
||||
HAS_GIT = $paths.HAS_GIT
|
||||
}
|
||||
$result | ConvertTo-Json -Compress
|
||||
} else {
|
||||
Write-Output "FEATURE_SPEC: $($paths.FEATURE_SPEC)"
|
||||
Write-Output "IMPL_PLAN: $($paths.IMPL_PLAN)"
|
||||
Write-Output "SPECS_DIR: $($paths.FEATURE_DIR)"
|
||||
Write-Output "BRANCH: $($paths.CURRENT_BRANCH)"
|
||||
Write-Output "HAS_GIT: $($paths.HAS_GIT)"
|
||||
}
|
||||
@@ -0,0 +1,442 @@
|
||||
#!/usr/bin/env pwsh
|
||||
<#!
|
||||
.SYNOPSIS
|
||||
Update agent context files with information from plan.md (PowerShell version)
|
||||
|
||||
.DESCRIPTION
|
||||
Mirrors the behavior of scripts/bash/update-agent-context.sh:
|
||||
1. Environment Validation
|
||||
2. Plan Data Extraction
|
||||
3. Agent File Management (create from template or update existing)
|
||||
4. Content Generation (technology stack, recent changes, timestamp)
|
||||
5. Multi-Agent Support (claude, gemini, copilot, cursor-agent, qwen, opencode, codex, windsurf, kilocode, auggie, roo, codebuddy, amp, shai, q)
|
||||
|
||||
.PARAMETER AgentType
|
||||
Optional agent key to update a single agent. If omitted, updates all existing agent files (creating a default Claude file if none exist).
|
||||
|
||||
.EXAMPLE
|
||||
./update-agent-context.ps1 -AgentType claude
|
||||
|
||||
.EXAMPLE
|
||||
./update-agent-context.ps1 # Updates all existing agent files
|
||||
|
||||
.NOTES
|
||||
Relies on common helper functions in common.ps1
|
||||
#>
|
||||
param(
|
||||
[Parameter(Position=0)]
|
||||
[ValidateSet('claude','gemini','copilot','cursor-agent','qwen','opencode','codex','windsurf','kilocode','auggie','roo','codebuddy','amp','shai','q')]
|
||||
[string]$AgentType
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# Import common helpers
|
||||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
. (Join-Path $ScriptDir 'common.ps1')
|
||||
|
||||
# Acquire environment paths
|
||||
$envData = Get-FeaturePathsEnv
|
||||
$REPO_ROOT = $envData.REPO_ROOT
|
||||
$CURRENT_BRANCH = $envData.CURRENT_BRANCH
|
||||
$HAS_GIT = $envData.HAS_GIT
|
||||
$IMPL_PLAN = $envData.IMPL_PLAN
|
||||
$NEW_PLAN = $IMPL_PLAN
|
||||
|
||||
# Agent file paths
|
||||
$CLAUDE_FILE = Join-Path $REPO_ROOT 'CLAUDE.md'
|
||||
$GEMINI_FILE = Join-Path $REPO_ROOT 'GEMINI.md'
|
||||
$COPILOT_FILE = Join-Path $REPO_ROOT '.github/agents/copilot-instructions.md'
|
||||
$CURSOR_FILE = Join-Path $REPO_ROOT '.cursor/rules/specify-rules.mdc'
|
||||
$QWEN_FILE = Join-Path $REPO_ROOT 'QWEN.md'
|
||||
$AGENTS_FILE = Join-Path $REPO_ROOT 'AGENTS.md'
|
||||
$WINDSURF_FILE = Join-Path $REPO_ROOT '.windsurf/rules/specify-rules.md'
|
||||
$KILOCODE_FILE = Join-Path $REPO_ROOT '.kilocode/rules/specify-rules.md'
|
||||
$AUGGIE_FILE = Join-Path $REPO_ROOT '.augment/rules/specify-rules.md'
|
||||
$ROO_FILE = Join-Path $REPO_ROOT '.roo/rules/specify-rules.md'
|
||||
$CODEBUDDY_FILE = Join-Path $REPO_ROOT 'CODEBUDDY.md'
|
||||
$AMP_FILE = Join-Path $REPO_ROOT 'AGENTS.md'
|
||||
$SHAI_FILE = Join-Path $REPO_ROOT 'SHAI.md'
|
||||
$Q_FILE = Join-Path $REPO_ROOT 'AGENTS.md'
|
||||
|
||||
$TEMPLATE_FILE = Join-Path $REPO_ROOT '.specify/templates/agent-file-template.md'
|
||||
|
||||
# Parsed plan data placeholders
|
||||
$script:NEW_LANG = ''
|
||||
$script:NEW_FRAMEWORK = ''
|
||||
$script:NEW_DB = ''
|
||||
$script:NEW_PROJECT_TYPE = ''
|
||||
|
||||
function Write-Info {
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$Message
|
||||
)
|
||||
Write-Host "INFO: $Message"
|
||||
}
|
||||
|
||||
function Write-Success {
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$Message
|
||||
)
|
||||
Write-Host "$([char]0x2713) $Message"
|
||||
}
|
||||
|
||||
function Write-WarningMsg {
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$Message
|
||||
)
|
||||
Write-Warning $Message
|
||||
}
|
||||
|
||||
function Write-Err {
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$Message
|
||||
)
|
||||
Write-Host "ERROR: $Message" -ForegroundColor Red
|
||||
}
|
||||
|
||||
function Validate-Environment {
|
||||
if (-not $CURRENT_BRANCH) {
|
||||
Write-Err 'Unable to determine current feature'
|
||||
if ($HAS_GIT) { Write-Info "Make sure you're on a feature branch" } else { Write-Info 'Set SPECIFY_FEATURE environment variable or create a feature first' }
|
||||
exit 1
|
||||
}
|
||||
if (-not (Test-Path $NEW_PLAN)) {
|
||||
Write-Err "No plan.md found at $NEW_PLAN"
|
||||
Write-Info 'Ensure you are working on a feature with a corresponding spec directory'
|
||||
if (-not $HAS_GIT) { Write-Info 'Use: $env:SPECIFY_FEATURE=your-feature-name or create a new feature first' }
|
||||
exit 1
|
||||
}
|
||||
if (-not (Test-Path $TEMPLATE_FILE)) {
|
||||
Write-Err "Template file not found at $TEMPLATE_FILE"
|
||||
Write-Info 'Run specify init to scaffold .specify/templates, or add agent-file-template.md there.'
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
function Extract-PlanField {
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$FieldPattern,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$PlanFile
|
||||
)
|
||||
if (-not (Test-Path $PlanFile)) { return '' }
|
||||
# Lines like **Language/Version**: Python 3.12
|
||||
$regex = "^\*\*$([Regex]::Escape($FieldPattern))\*\*: (.+)$"
|
||||
Get-Content -LiteralPath $PlanFile -Encoding utf8 | ForEach-Object {
|
||||
if ($_ -match $regex) {
|
||||
$val = $Matches[1].Trim()
|
||||
if ($val -notin @('NEEDS CLARIFICATION','N/A')) { return $val }
|
||||
}
|
||||
} | Select-Object -First 1
|
||||
}
|
||||
|
||||
function Parse-PlanData {
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$PlanFile
|
||||
)
|
||||
if (-not (Test-Path $PlanFile)) { Write-Err "Plan file not found: $PlanFile"; return $false }
|
||||
Write-Info "Parsing plan data from $PlanFile"
|
||||
$script:NEW_LANG = Extract-PlanField -FieldPattern 'Language/Version' -PlanFile $PlanFile
|
||||
$script:NEW_FRAMEWORK = Extract-PlanField -FieldPattern 'Primary Dependencies' -PlanFile $PlanFile
|
||||
$script:NEW_DB = Extract-PlanField -FieldPattern 'Storage' -PlanFile $PlanFile
|
||||
$script:NEW_PROJECT_TYPE = Extract-PlanField -FieldPattern 'Project Type' -PlanFile $PlanFile
|
||||
|
||||
if ($NEW_LANG) { Write-Info "Found language: $NEW_LANG" } else { Write-WarningMsg 'No language information found in plan' }
|
||||
if ($NEW_FRAMEWORK) { Write-Info "Found framework: $NEW_FRAMEWORK" }
|
||||
if ($NEW_DB -and $NEW_DB -ne 'N/A') { Write-Info "Found database: $NEW_DB" }
|
||||
if ($NEW_PROJECT_TYPE) { Write-Info "Found project type: $NEW_PROJECT_TYPE" }
|
||||
return $true
|
||||
}
|
||||
|
||||
function Format-TechnologyStack {
|
||||
param(
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$Lang,
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$Framework
|
||||
)
|
||||
$parts = @()
|
||||
if ($Lang -and $Lang -ne 'NEEDS CLARIFICATION') { $parts += $Lang }
|
||||
if ($Framework -and $Framework -notin @('NEEDS CLARIFICATION','N/A')) { $parts += $Framework }
|
||||
if (-not $parts) { return '' }
|
||||
return ($parts -join ' + ')
|
||||
}
|
||||
|
||||
function Get-ProjectStructure {
|
||||
param(
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$ProjectType
|
||||
)
|
||||
if ($ProjectType -match 'web') { return "backend/`nfrontend/`ntests/" } else { return "src/`ntests/" }
|
||||
}
|
||||
|
||||
function Get-CommandsForLanguage {
|
||||
param(
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$Lang
|
||||
)
|
||||
switch -Regex ($Lang) {
|
||||
'Python' { return "cd src; pytest; ruff check ." }
|
||||
'Rust' { return "cargo test; cargo clippy" }
|
||||
'JavaScript|TypeScript' { return "npm test; npm run lint" }
|
||||
default { return "# Add commands for $Lang" }
|
||||
}
|
||||
}
|
||||
|
||||
function Get-LanguageConventions {
|
||||
param(
|
||||
[Parameter(Mandatory=$false)]
|
||||
[string]$Lang
|
||||
)
|
||||
if ($Lang) { "${Lang}: Follow standard conventions" } else { 'General: Follow standard conventions' }
|
||||
}
|
||||
|
||||
function New-AgentFile {
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$TargetFile,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$ProjectName,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[datetime]$Date
|
||||
)
|
||||
if (-not (Test-Path $TEMPLATE_FILE)) { Write-Err "Template not found at $TEMPLATE_FILE"; return $false }
|
||||
$temp = New-TemporaryFile
|
||||
Copy-Item -LiteralPath $TEMPLATE_FILE -Destination $temp -Force
|
||||
|
||||
$projectStructure = Get-ProjectStructure -ProjectType $NEW_PROJECT_TYPE
|
||||
$commands = Get-CommandsForLanguage -Lang $NEW_LANG
|
||||
$languageConventions = Get-LanguageConventions -Lang $NEW_LANG
|
||||
|
||||
$escaped_lang = $NEW_LANG
|
||||
$escaped_framework = $NEW_FRAMEWORK
|
||||
$escaped_branch = $CURRENT_BRANCH
|
||||
|
||||
$content = Get-Content -LiteralPath $temp -Raw -Encoding utf8
|
||||
$content = $content -replace '\[PROJECT NAME\]',$ProjectName
|
||||
$content = $content -replace '\[DATE\]',$Date.ToString('yyyy-MM-dd')
|
||||
|
||||
# Build the technology stack string safely
|
||||
$techStackForTemplate = ""
|
||||
if ($escaped_lang -and $escaped_framework) {
|
||||
$techStackForTemplate = "- $escaped_lang + $escaped_framework ($escaped_branch)"
|
||||
} elseif ($escaped_lang) {
|
||||
$techStackForTemplate = "- $escaped_lang ($escaped_branch)"
|
||||
} elseif ($escaped_framework) {
|
||||
$techStackForTemplate = "- $escaped_framework ($escaped_branch)"
|
||||
}
|
||||
|
||||
$content = $content -replace '\[EXTRACTED FROM ALL PLAN.MD FILES\]',$techStackForTemplate
|
||||
# For project structure we manually embed (keep newlines)
|
||||
$escapedStructure = [Regex]::Escape($projectStructure)
|
||||
$content = $content -replace '\[ACTUAL STRUCTURE FROM PLANS\]',$escapedStructure
|
||||
# Replace escaped newlines placeholder after all replacements
|
||||
$content = $content -replace '\[ONLY COMMANDS FOR ACTIVE TECHNOLOGIES\]',$commands
|
||||
$content = $content -replace '\[LANGUAGE-SPECIFIC, ONLY FOR LANGUAGES IN USE\]',$languageConventions
|
||||
|
||||
# Build the recent changes string safely
|
||||
$recentChangesForTemplate = ""
|
||||
if ($escaped_lang -and $escaped_framework) {
|
||||
$recentChangesForTemplate = "- ${escaped_branch}: Added ${escaped_lang} + ${escaped_framework}"
|
||||
} elseif ($escaped_lang) {
|
||||
$recentChangesForTemplate = "- ${escaped_branch}: Added ${escaped_lang}"
|
||||
} elseif ($escaped_framework) {
|
||||
$recentChangesForTemplate = "- ${escaped_branch}: Added ${escaped_framework}"
|
||||
}
|
||||
|
||||
$content = $content -replace '\[LAST 3 FEATURES AND WHAT THEY ADDED\]',$recentChangesForTemplate
|
||||
# Convert literal \n sequences introduced by Escape to real newlines
|
||||
$content = $content -replace '\\n',[Environment]::NewLine
|
||||
|
||||
$parent = Split-Path -Parent $TargetFile
|
||||
if (-not (Test-Path $parent)) { New-Item -ItemType Directory -Path $parent | Out-Null }
|
||||
Set-Content -LiteralPath $TargetFile -Value $content -NoNewline -Encoding utf8
|
||||
Remove-Item $temp -Force
|
||||
return $true
|
||||
}
|
||||
|
||||
function Update-ExistingAgentFile {
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$TargetFile,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[datetime]$Date
|
||||
)
|
||||
if (-not (Test-Path $TargetFile)) { return (New-AgentFile -TargetFile $TargetFile -ProjectName (Split-Path $REPO_ROOT -Leaf) -Date $Date) }
|
||||
|
||||
$techStack = Format-TechnologyStack -Lang $NEW_LANG -Framework $NEW_FRAMEWORK
|
||||
$newTechEntries = @()
|
||||
if ($techStack) {
|
||||
$escapedTechStack = [Regex]::Escape($techStack)
|
||||
if (-not (Select-String -Pattern $escapedTechStack -Path $TargetFile -Quiet)) {
|
||||
$newTechEntries += "- $techStack ($CURRENT_BRANCH)"
|
||||
}
|
||||
}
|
||||
if ($NEW_DB -and $NEW_DB -notin @('N/A','NEEDS CLARIFICATION')) {
|
||||
$escapedDB = [Regex]::Escape($NEW_DB)
|
||||
if (-not (Select-String -Pattern $escapedDB -Path $TargetFile -Quiet)) {
|
||||
$newTechEntries += "- $NEW_DB ($CURRENT_BRANCH)"
|
||||
}
|
||||
}
|
||||
$newChangeEntry = ''
|
||||
if ($techStack) { $newChangeEntry = "- ${CURRENT_BRANCH}: Added ${techStack}" }
|
||||
elseif ($NEW_DB -and $NEW_DB -notin @('N/A','NEEDS CLARIFICATION')) { $newChangeEntry = "- ${CURRENT_BRANCH}: Added ${NEW_DB}" }
|
||||
|
||||
$lines = Get-Content -LiteralPath $TargetFile -Encoding utf8
|
||||
$output = New-Object System.Collections.Generic.List[string]
|
||||
$inTech = $false; $inChanges = $false; $techAdded = $false; $changeAdded = $false; $existingChanges = 0
|
||||
|
||||
for ($i=0; $i -lt $lines.Count; $i++) {
|
||||
$line = $lines[$i]
|
||||
if ($line -eq '## Active Technologies') {
|
||||
$output.Add($line)
|
||||
$inTech = $true
|
||||
continue
|
||||
}
|
||||
if ($inTech -and $line -match '^##\s') {
|
||||
if (-not $techAdded -and $newTechEntries.Count -gt 0) { $newTechEntries | ForEach-Object { $output.Add($_) }; $techAdded = $true }
|
||||
$output.Add($line); $inTech = $false; continue
|
||||
}
|
||||
if ($inTech -and [string]::IsNullOrWhiteSpace($line)) {
|
||||
if (-not $techAdded -and $newTechEntries.Count -gt 0) { $newTechEntries | ForEach-Object { $output.Add($_) }; $techAdded = $true }
|
||||
$output.Add($line); continue
|
||||
}
|
||||
if ($line -eq '## Recent Changes') {
|
||||
$output.Add($line)
|
||||
if ($newChangeEntry) { $output.Add($newChangeEntry); $changeAdded = $true }
|
||||
$inChanges = $true
|
||||
continue
|
||||
}
|
||||
if ($inChanges -and $line -match '^##\s') { $output.Add($line); $inChanges = $false; continue }
|
||||
if ($inChanges -and $line -match '^- ') {
|
||||
if ($existingChanges -lt 2) { $output.Add($line); $existingChanges++ }
|
||||
continue
|
||||
}
|
||||
if ($line -match '\*\*Last updated\*\*: .*\d{4}-\d{2}-\d{2}') {
|
||||
$output.Add(($line -replace '\d{4}-\d{2}-\d{2}',$Date.ToString('yyyy-MM-dd')))
|
||||
continue
|
||||
}
|
||||
$output.Add($line)
|
||||
}
|
||||
|
||||
# Post-loop check: if we're still in the Active Technologies section and haven't added new entries
|
||||
if ($inTech -and -not $techAdded -and $newTechEntries.Count -gt 0) {
|
||||
$newTechEntries | ForEach-Object { $output.Add($_) }
|
||||
}
|
||||
|
||||
Set-Content -LiteralPath $TargetFile -Value ($output -join [Environment]::NewLine) -Encoding utf8
|
||||
return $true
|
||||
}
|
||||
|
||||
function Update-AgentFile {
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$TargetFile,
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$AgentName
|
||||
)
|
||||
if (-not $TargetFile -or -not $AgentName) { Write-Err 'Update-AgentFile requires TargetFile and AgentName'; return $false }
|
||||
Write-Info "Updating $AgentName context file: $TargetFile"
|
||||
$projectName = Split-Path $REPO_ROOT -Leaf
|
||||
$date = Get-Date
|
||||
|
||||
$dir = Split-Path -Parent $TargetFile
|
||||
if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir | Out-Null }
|
||||
|
||||
if (-not (Test-Path $TargetFile)) {
|
||||
if (New-AgentFile -TargetFile $TargetFile -ProjectName $projectName -Date $date) { Write-Success "Created new $AgentName context file" } else { Write-Err 'Failed to create new agent file'; return $false }
|
||||
} else {
|
||||
try {
|
||||
if (Update-ExistingAgentFile -TargetFile $TargetFile -Date $date) { Write-Success "Updated existing $AgentName context file" } else { Write-Err 'Failed to update agent file'; return $false }
|
||||
} catch {
|
||||
Write-Err "Cannot access or update existing file: $TargetFile. $_"
|
||||
return $false
|
||||
}
|
||||
}
|
||||
return $true
|
||||
}
|
||||
|
||||
function Update-SpecificAgent {
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$Type
|
||||
)
|
||||
switch ($Type) {
|
||||
'claude' { Update-AgentFile -TargetFile $CLAUDE_FILE -AgentName 'Claude Code' }
|
||||
'gemini' { Update-AgentFile -TargetFile $GEMINI_FILE -AgentName 'Gemini CLI' }
|
||||
'copilot' { Update-AgentFile -TargetFile $COPILOT_FILE -AgentName 'GitHub Copilot' }
|
||||
'cursor-agent' { Update-AgentFile -TargetFile $CURSOR_FILE -AgentName 'Cursor IDE' }
|
||||
'qwen' { Update-AgentFile -TargetFile $QWEN_FILE -AgentName 'Qwen Code' }
|
||||
'opencode' { Update-AgentFile -TargetFile $AGENTS_FILE -AgentName 'opencode' }
|
||||
'codex' { Update-AgentFile -TargetFile $AGENTS_FILE -AgentName 'Codex CLI' }
|
||||
'windsurf' { Update-AgentFile -TargetFile $WINDSURF_FILE -AgentName 'Windsurf' }
|
||||
'kilocode' { Update-AgentFile -TargetFile $KILOCODE_FILE -AgentName 'Kilo Code' }
|
||||
'auggie' { Update-AgentFile -TargetFile $AUGGIE_FILE -AgentName 'Auggie CLI' }
|
||||
'roo' { Update-AgentFile -TargetFile $ROO_FILE -AgentName 'Roo Code' }
|
||||
'codebuddy' { Update-AgentFile -TargetFile $CODEBUDDY_FILE -AgentName 'CodeBuddy CLI' }
|
||||
'amp' { Update-AgentFile -TargetFile $AMP_FILE -AgentName 'Amp' }
|
||||
'shai' { Update-AgentFile -TargetFile $SHAI_FILE -AgentName 'SHAI' }
|
||||
'q' { Update-AgentFile -TargetFile $Q_FILE -AgentName 'Amazon Q Developer CLI' }
|
||||
default { Write-Err "Unknown agent type '$Type'"; Write-Err 'Expected: claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|q'; return $false }
|
||||
}
|
||||
}
|
||||
|
||||
function Update-AllExistingAgents {
|
||||
$found = $false
|
||||
$ok = $true
|
||||
if (Test-Path $CLAUDE_FILE) { if (-not (Update-AgentFile -TargetFile $CLAUDE_FILE -AgentName 'Claude Code')) { $ok = $false }; $found = $true }
|
||||
if (Test-Path $GEMINI_FILE) { if (-not (Update-AgentFile -TargetFile $GEMINI_FILE -AgentName 'Gemini CLI')) { $ok = $false }; $found = $true }
|
||||
if (Test-Path $COPILOT_FILE) { if (-not (Update-AgentFile -TargetFile $COPILOT_FILE -AgentName 'GitHub Copilot')) { $ok = $false }; $found = $true }
|
||||
if (Test-Path $CURSOR_FILE) { if (-not (Update-AgentFile -TargetFile $CURSOR_FILE -AgentName 'Cursor IDE')) { $ok = $false }; $found = $true }
|
||||
if (Test-Path $QWEN_FILE) { if (-not (Update-AgentFile -TargetFile $QWEN_FILE -AgentName 'Qwen Code')) { $ok = $false }; $found = $true }
|
||||
if (Test-Path $AGENTS_FILE) { if (-not (Update-AgentFile -TargetFile $AGENTS_FILE -AgentName 'Codex/opencode')) { $ok = $false }; $found = $true }
|
||||
if (Test-Path $WINDSURF_FILE) { if (-not (Update-AgentFile -TargetFile $WINDSURF_FILE -AgentName 'Windsurf')) { $ok = $false }; $found = $true }
|
||||
if (Test-Path $KILOCODE_FILE) { if (-not (Update-AgentFile -TargetFile $KILOCODE_FILE -AgentName 'Kilo Code')) { $ok = $false }; $found = $true }
|
||||
if (Test-Path $AUGGIE_FILE) { if (-not (Update-AgentFile -TargetFile $AUGGIE_FILE -AgentName 'Auggie CLI')) { $ok = $false }; $found = $true }
|
||||
if (Test-Path $ROO_FILE) { if (-not (Update-AgentFile -TargetFile $ROO_FILE -AgentName 'Roo Code')) { $ok = $false }; $found = $true }
|
||||
if (Test-Path $CODEBUDDY_FILE) { if (-not (Update-AgentFile -TargetFile $CODEBUDDY_FILE -AgentName 'CodeBuddy CLI')) { $ok = $false }; $found = $true }
|
||||
if (Test-Path $SHAI_FILE) { if (-not (Update-AgentFile -TargetFile $SHAI_FILE -AgentName 'SHAI')) { $ok = $false }; $found = $true }
|
||||
if (Test-Path $Q_FILE) { if (-not (Update-AgentFile -TargetFile $Q_FILE -AgentName 'Amazon Q Developer CLI')) { $ok = $false }; $found = $true }
|
||||
if (-not $found) {
|
||||
Write-Info 'No existing agent files found, creating default Claude file...'
|
||||
if (-not (Update-AgentFile -TargetFile $CLAUDE_FILE -AgentName 'Claude Code')) { $ok = $false }
|
||||
}
|
||||
return $ok
|
||||
}
|
||||
|
||||
function Print-Summary {
|
||||
Write-Host ''
|
||||
Write-Info 'Summary of changes:'
|
||||
if ($NEW_LANG) { Write-Host " - Added language: $NEW_LANG" }
|
||||
if ($NEW_FRAMEWORK) { Write-Host " - Added framework: $NEW_FRAMEWORK" }
|
||||
if ($NEW_DB -and $NEW_DB -ne 'N/A') { Write-Host " - Added database: $NEW_DB" }
|
||||
Write-Host ''
|
||||
Write-Info 'Usage: ./update-agent-context.ps1 [-AgentType claude|gemini|copilot|cursor-agent|qwen|opencode|codex|windsurf|kilocode|auggie|roo|codebuddy|amp|shai|q]'
|
||||
}
|
||||
|
||||
function Main {
|
||||
Validate-Environment
|
||||
Write-Info "=== Updating agent context files for feature $CURRENT_BRANCH ==="
|
||||
if (-not (Parse-PlanData -PlanFile $NEW_PLAN)) { Write-Err 'Failed to parse plan data'; exit 1 }
|
||||
$success = $true
|
||||
if ($AgentType) {
|
||||
Write-Info "Updating specific agent: $AgentType"
|
||||
if (-not (Update-SpecificAgent -Type $AgentType)) { $success = $false }
|
||||
}
|
||||
else {
|
||||
Write-Info 'No agent specified, updating all existing agent files...'
|
||||
if (-not (Update-AllExistingAgents)) { $success = $false }
|
||||
}
|
||||
Print-Summary
|
||||
if ($success) { Write-Success 'Agent context update completed successfully'; exit 0 } else { Write-Err 'Agent context update completed with errors'; exit 1 }
|
||||
}
|
||||
|
||||
Main
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# [PROJECT NAME] 开发指南
|
||||
|
||||
基于所有功能计划自动生成. 最后更新时间: [DATE]
|
||||
|
||||
## 活跃技术
|
||||
[EXTRACTED FROM ALL PLAN.MD FILES]
|
||||
|
||||
## 项目结构
|
||||
```
|
||||
[ACTUAL STRUCTURE FROM PLANS]
|
||||
```
|
||||
|
||||
## 命令
|
||||
[ONLY COMMANDS FOR ACTIVE TECHNOLOGIES]
|
||||
|
||||
## 代码风格
|
||||
[LANGUAGE-SPECIFIC, ONLY FOR LANGUAGES IN USE]
|
||||
|
||||
## 最近变更
|
||||
[LAST 3 FEATURES AND WHAT THEY ADDED]
|
||||
|
||||
<!-- 手动添加内容开始 -->
|
||||
<!-- 手动添加内容结束 -->
|
||||
@@ -0,0 +1,40 @@
|
||||
# [检查清单类型] 检查清单: [功能名称]
|
||||
|
||||
**目的**: [此检查清单涵盖内容的简要描述]
|
||||
**创建时间**: [日期]
|
||||
**功能**: [链接到 spec.md 或相关文档]
|
||||
|
||||
**注意**: 此检查清单由 `/speckit.checklist` 命令基于功能上下文和需求生成.
|
||||
|
||||
<!--
|
||||
============================================================================
|
||||
重要说明: 以下检查清单项目仅为示例项目, 仅供说明用途.
|
||||
|
||||
/speckit.checklist 命令必须根据以下内容替换为实际项目:
|
||||
- 用户的具体检查清单请求
|
||||
- 来自 spec.md 的功能需求
|
||||
- 来自 plan.md 的技术上下文
|
||||
- 来自 tasks.md 的实施细节
|
||||
|
||||
请勿在生成的检查清单文件中保留这些示例项目.
|
||||
============================================================================
|
||||
-->
|
||||
|
||||
## [类别 1]
|
||||
|
||||
- [ ] CHK001 第一个检查清单项目, 具有明确的行动
|
||||
- [ ] CHK002 第二个检查清单项目
|
||||
- [ ] CHK003 第三个检查清单项目
|
||||
|
||||
## [类别 2]
|
||||
|
||||
- [ ] CHK004 另一个类别项目
|
||||
- [ ] CHK005 具有特定标准的项目
|
||||
- [ ] CHK006 此类别中的最后一个项目
|
||||
|
||||
## 备注
|
||||
|
||||
- 完成项目时勾选: `[x]`
|
||||
- 内联添加评论或发现
|
||||
- 链接到相关资源或文档
|
||||
- 项目按顺序编号, 便于参考
|
||||
@@ -0,0 +1,101 @@
|
||||
# 实施计划: [FEATURE]
|
||||
|
||||
**分支**: `[###-feature-name]` | **日期**: [DATE] | **规范**: [link]
|
||||
**输入**: 来自 `/specs/[###-feature-name]/spec.md` 的功能规范
|
||||
|
||||
**注意**: 此模板由 `/speckit.plan` 命令填充. 执行工作流程请参见 `.specify/templates/commands/plan.md`.
|
||||
|
||||
## 摘要
|
||||
|
||||
[从功能规范中提取: 主要需求 + 研究得出的技术方法]
|
||||
|
||||
## 技术背景
|
||||
|
||||
<!--
|
||||
需要操作: 将此部分内容替换为项目的技术细节.
|
||||
此处的结构以咨询性质呈现, 用于指导迭代过程.
|
||||
-->
|
||||
|
||||
**语言/版本**: [例如: Python 3.11、Swift 5.9、Rust 1.75 或 NEEDS CLARIFICATION]
|
||||
**主要依赖**: [例如: FastAPI、UIKit、LLVM 或 NEEDS CLARIFICATION]
|
||||
**存储**: [如适用, 例如: PostgreSQL、CoreData、文件 或 N/A]
|
||||
**测试**: [例如: pytest、XCTest、cargo test 或 NEEDS CLARIFICATION]
|
||||
**目标平台**: [例如: Linux 服务器、iOS 15+、WASM 或 NEEDS CLARIFICATION]
|
||||
**项目类型**: [单一/网页/移动 - 决定源代码结构]
|
||||
**性能目标**: [领域特定, 例如: 1000 请求/秒、10k 行/秒、60 fps 或 NEEDS CLARIFICATION]
|
||||
**约束条件**: [领域特定, 例如: <200ms p95、<100MB 内存、离线可用 或 NEEDS CLARIFICATION]
|
||||
**规模/范围**: [领域特定, 例如: 10k 用户、1M 行代码、50 个屏幕 或 NEEDS CLARIFICATION]
|
||||
|
||||
## 章程检查
|
||||
|
||||
*门控: 必须在阶段 0 研究前通过. 阶段 1 设计后重新检查. *
|
||||
|
||||
[基于章程文件确定的门控条件]
|
||||
|
||||
## 项目结构
|
||||
|
||||
### 文档(此功能)
|
||||
|
||||
```
|
||||
specs/[###-feature]/
|
||||
├── plan.md # 此文件 (/speckit.plan 命令输出)
|
||||
├── research.md # 阶段 0 输出 (/speckit.plan 命令)
|
||||
├── data-model.md # 阶段 1 输出 (/speckit.plan 命令)
|
||||
├── quickstart.md # 阶段 1 输出 (/speckit.plan 命令)
|
||||
├── contracts/ # 阶段 1 输出 (/speckit.plan 命令)
|
||||
└── tasks.md # 阶段 2 输出 (/speckit.tasks 命令 - 非 /speckit.plan 创建)
|
||||
```
|
||||
|
||||
### 源代码(仓库根目录)
|
||||
<!--
|
||||
需要操作: 将下面的占位符树结构替换为此功能的具体布局.
|
||||
删除未使用的选项, 并使用真实路径(例如: apps/admin、packages/something)扩展所选结构.
|
||||
交付的计划不得包含选项标签.
|
||||
-->
|
||||
|
||||
```
|
||||
# [如未使用请删除] 选项 1: 单一项目(默认)
|
||||
src/
|
||||
├── models/
|
||||
├── services/
|
||||
├── cli/
|
||||
└── lib/
|
||||
|
||||
tests/
|
||||
├── contract/
|
||||
├── integration/
|
||||
└── unit/
|
||||
|
||||
# [如未使用请删除] 选项 2: Web 应用程序(检测到"前端" + "后端"时)
|
||||
backend/
|
||||
├── src/
|
||||
│ ├── models/
|
||||
│ ├── services/
|
||||
│ └── api/
|
||||
└── tests/
|
||||
|
||||
frontend/
|
||||
├── src/
|
||||
│ ├── components/
|
||||
│ ├── pages/
|
||||
│ └── services/
|
||||
└── tests/
|
||||
|
||||
# [如未使用请删除] 选项 3: 移动端 + API(检测到 "iOS/Android" 时)
|
||||
api/
|
||||
└── [同上后端结构]
|
||||
|
||||
ios/ 或 android/
|
||||
└── [平台特定结构: 功能模块、UI 流程、平台测试]
|
||||
```
|
||||
|
||||
**结构决策**: [记录所选结构并引用上面捕获的真实目录]
|
||||
|
||||
## 复杂度跟踪
|
||||
|
||||
*仅在章程检查有必须证明的违规时填写*
|
||||
|
||||
| 违规 | 为什么需要 | 拒绝更简单替代方案的原因 |
|
||||
|-----------|------------|-------------------------------------|
|
||||
| [例如: 第 4 个项目] | [当前需求] | [为什么 3 个项目不够] |
|
||||
| [例如: 仓储模式] | [特定问题] | [为什么直接数据库访问不够] |
|
||||
@@ -0,0 +1,115 @@
|
||||
# 功能规范: [FEATURE NAME]
|
||||
|
||||
**功能分支**: `[###-feature-name]`
|
||||
**创建时间**: [DATE]
|
||||
**状态**: 草稿
|
||||
**输入**: 用户描述: "$ARGUMENTS"
|
||||
|
||||
## 用户场景与测试 *(必填)*
|
||||
|
||||
<!--
|
||||
重要说明: 用户故事应按重要性排序, 作为用户旅程进行优先级划分.
|
||||
每个用户故事/旅程必须能够独立测试——这意味着即使只实现其中一个,
|
||||
你仍然应该有一个可行的 MVP(最小可行产品)来交付价值.
|
||||
|
||||
为每个故事分配优先级(P1、P2、P3 等), 其中 P1 是最关键的.
|
||||
将每个故事视为独立的功能切片, 可以:
|
||||
- 独立开发
|
||||
- 独立测试
|
||||
- 独立部署
|
||||
- 独立向用户演示
|
||||
-->
|
||||
|
||||
### 用户故事 1 - [简要标题] (优先级: P1)
|
||||
|
||||
[用通俗语言描述这个用户旅程]
|
||||
|
||||
**优先级原因**: [解释价值以及为什么具有此优先级]
|
||||
|
||||
**独立测试**: [描述如何独立测试 - 例如: "可以通过 [具体操作] 完全测试并交付 [具体价值]"]
|
||||
|
||||
**验收场景**:
|
||||
|
||||
1. **给定** [初始状态], **当** [操作时], **那么** [预期结果]
|
||||
2. **给定** [初始状态], **当** [操作时], **那么** [预期结果]
|
||||
|
||||
---
|
||||
|
||||
### 用户故事 2 - [简要标题] (优先级: P2)
|
||||
|
||||
[用通俗语言描述这个用户旅程]
|
||||
|
||||
**优先级原因**: [解释价值以及为什么具有此优先级]
|
||||
|
||||
**独立测试**: [描述如何独立测试]
|
||||
|
||||
**验收场景**:
|
||||
|
||||
1. **给定** [初始状态], **当** [操作时], **那么** [预期结果]
|
||||
|
||||
---
|
||||
|
||||
### 用户故事 3 - [简要标题] (优先级: P3)
|
||||
|
||||
[用通俗语言描述这个用户旅程]
|
||||
|
||||
**优先级原因**: [解释价值以及为什么具有此优先级]
|
||||
|
||||
**独立测试**: [描述如何独立测试]
|
||||
|
||||
**验收场景**:
|
||||
|
||||
1. **给定** [初始状态], **当** [操作时], **那么** [预期结果]
|
||||
|
||||
---
|
||||
|
||||
[根据需要添加更多用户故事, 每个都分配优先级]
|
||||
|
||||
### 边界情况
|
||||
|
||||
<!--
|
||||
需要操作: 本节内容表示占位符.
|
||||
请用正确的边界情况填写.
|
||||
-->
|
||||
|
||||
- 当 [边界条件] 时会发生什么?
|
||||
- 系统如何处理 [错误场景]?
|
||||
|
||||
## 需求 *(必填)*
|
||||
|
||||
<!--
|
||||
需要操作: 本节内容表示占位符.
|
||||
请用正确的功能需求填写.
|
||||
-->
|
||||
|
||||
### 功能需求
|
||||
|
||||
- **FR-001**: 系统必须 [具体能力, 例如: "允许用户创建账户"]
|
||||
- **FR-002**: 系统必须 [具体能力, 例如: "验证电子邮件地址"]
|
||||
- **FR-003**: 用户必须能够 [关键交互, 例如: "重置密码"]
|
||||
- **FR-004**: 系统必须 [数据需求, 例如: "持久化用户偏好设置"]
|
||||
- **FR-005**: 系统必须 [行为, 例如: "记录所有安全事件"]
|
||||
|
||||
*标记不明确需求的示例: *
|
||||
|
||||
- **FR-006**: 系统必须通过 [NEEDS CLARIFICATION: 未指定认证方法 - 电子邮件/密码、SSO、OAuth?] 认证用户
|
||||
- **FR-007**: 系统必须保留用户数据 [NEEDS CLARIFICATION: 未指定保留期限]
|
||||
|
||||
### 关键实体 *(如果功能涉及数据则包含)*
|
||||
|
||||
- **[实体 1]**: [它代表什么, 关键属性(不含实现细节)]
|
||||
- **[实体 2]**: [它代表什么, 与其他实体的关系]
|
||||
|
||||
## 成功标准 *(必填)*
|
||||
|
||||
<!--
|
||||
需要操作: 定义可衡量的成功标准.
|
||||
这些标准必须与技术无关且可衡量.
|
||||
-->
|
||||
|
||||
### 可衡量的结果
|
||||
|
||||
- **SC-001**: [可衡量的指标, 例如: "用户可以在 2 分钟内完成账户创建"]
|
||||
- **SC-002**: [可衡量的指标, 例如: "系统处理 1000 个并发用户而不降低性能"]
|
||||
- **SC-003**: [用户满意度指标, 例如: "90% 的用户在首次尝试时成功完成主要任务"]
|
||||
- **SC-004**: [业务指标, 例如: "将与 [X] 相关的支持工单减少 50%"]
|
||||
@@ -0,0 +1,249 @@
|
||||
---
|
||||
description: "功能实现任务列表模板"
|
||||
---
|
||||
|
||||
# 任务: [FEATURE NAME]
|
||||
|
||||
**输入**: 来自 `/specs/[###-feature-name]/` 的设计文档
|
||||
**前置条件**: plan.md(必需)、spec.md(用户故事必需)、research.md、data-model.md、contracts/
|
||||
|
||||
**测试**: 以下示例包含测试任务. 测试是可选的 - 仅在功能规范中明确要求时才包含.
|
||||
|
||||
**组织结构**: 任务按用户故事分组, 以便每个故事能够独立实施和测试.
|
||||
|
||||
## 格式: `[ID] [P] [Story] 描述`
|
||||
- **[P]**: 可以并行运行(不同文件, 无依赖关系)
|
||||
- **[Story]**: 此任务属于哪个用户故事(例如: US1、US2、US3)
|
||||
- 在描述中包含确切的文件路径
|
||||
|
||||
## 路径约定
|
||||
- **单一项目**: 仓库根目录下的 `src/`、`tests/`
|
||||
- **Web 应用**: `backend/src/`、`frontend/src/`
|
||||
- **移动应用**: `api/src/`、`ios/src/` 或 `android/src/`
|
||||
- 以下显示的路径假设为单一项目 - 根据 plan.md 结构进行调整
|
||||
|
||||
<!--
|
||||
============================================================================
|
||||
重要说明: 以下任务仅为说明目的的示例任务.
|
||||
|
||||
/speckit.tasks 命令必须根据以下内容替换为实际任务:
|
||||
- 来自 spec.md 的用户故事(及其优先级 P1、P2、P3...)
|
||||
- 来自 plan.md 的功能需求
|
||||
- 来自 data-model.md 的实体
|
||||
- 来自 contracts/ 的端点
|
||||
|
||||
任务必须按用户故事组织, 以便每个故事能够:
|
||||
- 独立实施
|
||||
- 独立测试
|
||||
- 作为 MVP 增量交付
|
||||
|
||||
不要在生成的 tasks.md 文件中保留这些示例任务.
|
||||
============================================================================
|
||||
-->
|
||||
|
||||
## 阶段 1: 设置(共享基础设施)
|
||||
|
||||
**目的**: 项目初始化和基本结构
|
||||
|
||||
- [ ] T001 根据实施计划创建项目结构
|
||||
- [ ] T002 使用 [framework] 依赖项初始化 [language] 项目
|
||||
- [ ] T003 [P] 配置代码检查和格式化工具
|
||||
|
||||
---
|
||||
|
||||
## 阶段 2: 基础(阻塞前置条件)
|
||||
|
||||
**目的**: 在任何用户故事可以实施之前必须完成的核心基础设施
|
||||
|
||||
**⚠️ 关键**: 在此阶段完成之前, 无法开始任何用户故事工作
|
||||
|
||||
基础任务示例(根据你的项目调整):
|
||||
|
||||
- [ ] T004 设置数据库架构和迁移框架
|
||||
- [ ] T005 [P] 实施身份验证/授权框架
|
||||
- [ ] T006 [P] 设置 API 路由和中间件结构
|
||||
- [ ] T007 创建所有故事依赖的基础模型/实体
|
||||
- [ ] T008 配置错误处理和日志记录基础设施
|
||||
- [ ] T009 设置环境配置管理
|
||||
|
||||
**检查点**: 基础就绪 - 现在可以开始并行实施用户故事
|
||||
|
||||
---
|
||||
|
||||
## 阶段 3: 用户故事 1 - [Title](优先级: P1)🎯 MVP
|
||||
|
||||
**目标**: [此故事交付内容的简要描述]
|
||||
|
||||
**独立测试**: [如何验证此故事独立运行]
|
||||
|
||||
### 用户故事 1 的测试(可选 - 仅在要求测试时)⚠️
|
||||
|
||||
**注意: 先编写这些测试, 确保在实施前它们失败**
|
||||
|
||||
- [ ] T010 [P] [US1] 在 tests/contract/test_[name].py 中为 [endpoint] 编写合约测试
|
||||
- [ ] T011 [P] [US1] 在 tests/integration/test_[name].py 中为 [user journey] 编写集成测试
|
||||
|
||||
### 用户故事 1 的实施
|
||||
|
||||
- [ ] T012 [P] [US1] 在 src/models/[entity1].py 中创建 [Entity1] 模型
|
||||
- [ ] T013 [P] [US1] 在 src/models/[entity2].py 中创建 [Entity2] 模型
|
||||
- [ ] T014 [US1] 在 src/services/[service].py 中实施 [Service](依赖于 T012、T013)
|
||||
- [ ] T015 [US1] 在 src/[location]/[file].py 中实施 [endpoint/feature]
|
||||
- [ ] T016 [US1] 添加验证和错误处理
|
||||
- [ ] T017 [US1] 为用户故事 1 操作添加日志记录
|
||||
|
||||
**检查点**: 此时, 用户故事 1 应该完全功能化且可独立测试
|
||||
|
||||
---
|
||||
|
||||
## 阶段 4: 用户故事 2 - [Title](优先级: P2)
|
||||
|
||||
**目标**: [此故事交付内容的简要描述]
|
||||
|
||||
**独立测试**: [如何验证此故事独立运行]
|
||||
|
||||
### 用户故事 2 的测试(可选 - 仅在要求测试时)⚠️
|
||||
|
||||
- [ ] T018 [P] [US2] 在 tests/contract/test_[name].py 中为 [endpoint] 编写合约测试
|
||||
- [ ] T019 [P] [US2] 在 tests/integration/test_[name].py 中为 [user journey] 编写集成测试
|
||||
|
||||
### 用户故事 2 的实施
|
||||
|
||||
- [ ] T020 [P] [US2] 在 src/models/[entity].py 中创建 [Entity] 模型
|
||||
- [ ] T021 [US2] 在 src/services/[service].py 中实施 [Service]
|
||||
- [ ] T022 [US2] 在 src/[location]/[file].py 中实施 [endpoint/feature]
|
||||
- [ ] T023 [US2] 与用户故事 1 组件集成(如需要)
|
||||
|
||||
**检查点**: 此时, 用户故事 1 和 2 都应该独立运行
|
||||
|
||||
---
|
||||
|
||||
## 阶段 5: 用户故事 3 - [Title](优先级: P3)
|
||||
|
||||
**目标**: [此故事交付内容的简要描述]
|
||||
|
||||
**独立测试**: [如何验证此故事独立运行]
|
||||
|
||||
### 用户故事 3 的测试(可选 - 仅在要求测试时)⚠️
|
||||
|
||||
- [ ] T024 [P] [US3] 在 tests/contract/test_[name].py 中为 [endpoint] 编写合约测试
|
||||
- [ ] T025 [P] [US3] 在 tests/integration/test_[name].py 中为 [user journey] 编写集成测试
|
||||
|
||||
### 用户故事 3 的实施
|
||||
|
||||
- [ ] T026 [P] [US3] 在 src/models/[entity].py 中创建 [Entity] 模型
|
||||
- [ ] T027 [US3] 在 src/services/[service].py 中实施 [Service]
|
||||
- [ ] T028 [US3] 在 src/[location]/[file].py 中实施 [endpoint/feature]
|
||||
|
||||
**检查点**: 所有用户故事现在应该独立功能化
|
||||
|
||||
---
|
||||
|
||||
[根据需要添加更多用户故事阶段, 遵循相同模式]
|
||||
|
||||
---
|
||||
|
||||
## 阶段 N: 完善与横切关注点
|
||||
|
||||
**目的**: 影响多个用户故事的改进
|
||||
|
||||
- [ ] TXXX [P] 在 docs/ 中更新文档
|
||||
- [ ] TXXX 代码清理和重构
|
||||
- [ ] TXXX 跨所有故事的性能优化
|
||||
- [ ] TXXX [P] 在 tests/unit/ 中添加额外的单元测试(如要求)
|
||||
- [ ] TXXX 安全加固
|
||||
- [ ] TXXX 运行 quickstart.md 验证
|
||||
|
||||
---
|
||||
|
||||
## 依赖关系与执行顺序
|
||||
|
||||
### 阶段依赖关系
|
||||
|
||||
- **设置(阶段 1)**: 无依赖关系 - 可立即开始
|
||||
- **基础(阶段 2)**: 依赖于设置完成 - 阻塞所有用户故事
|
||||
- **用户故事(阶段 3+)**: 都依赖于基础阶段完成
|
||||
- 然后用户故事可以并行进行(如果有人员)
|
||||
- 或按优先级顺序进行(P1 → P2 → P3)
|
||||
- **完善(最终阶段)**: 依赖于所有期望的用户故事完成
|
||||
|
||||
### 用户故事依赖关系
|
||||
|
||||
- **用户故事 1(P1)**: 可在基础(阶段 2)后开始 - 无其他故事依赖
|
||||
- **用户故事 2(P2)**: 可在基础(阶段 2)后开始 - 可与 US1 集成但应独立可测试
|
||||
- **用户故事 3(P3)**: 可在基础(阶段 2)后开始 - 可与 US1/US2 集成但应独立可测试
|
||||
|
||||
### 每个用户故事内部
|
||||
|
||||
- 测试(如包含)必须在实施前编写并失败
|
||||
- 模型在服务之前
|
||||
- 服务在端点之前
|
||||
- 核心实施在集成之前
|
||||
- 故事完成后才移至下一个优先级
|
||||
|
||||
### 并行机会
|
||||
|
||||
- 所有标记为 [P] 的设置任务可以并行运行
|
||||
- 所有标记为 [P] 的基础任务可以并行运行(在阶段 2 内)
|
||||
- 基础阶段完成后, 所有用户故事可以并行开始(如果团队容量允许)
|
||||
- 用户故事中所有标记为 [P] 的测试可以并行运行
|
||||
- 故事中标记为 [P] 的模型可以并行运行
|
||||
- 不同用户故事可以由不同团队成员并行处理
|
||||
|
||||
---
|
||||
|
||||
## 并行示例: 用户故事 1
|
||||
|
||||
```bash
|
||||
# 一起启动用户故事 1 的所有测试(如要求测试):
|
||||
任务: "在 tests/contract/test_[name].py 中为 [endpoint] 编写合约测试"
|
||||
任务: "在 tests/integration/test_[name].py 中为 [user journey] 编写集成测试"
|
||||
|
||||
# 一起启动用户故事 1 的所有模型:
|
||||
任务: "在 src/models/[entity1].py 中创建 [Entity1] 模型"
|
||||
任务: "在 src/models/[entity2].py 中创建 [Entity2] 模型"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 实施策略
|
||||
|
||||
### 仅 MVP(仅用户故事 1)
|
||||
|
||||
1. 完成阶段 1: 设置
|
||||
2. 完成阶段 2: 基础(关键 - 阻塞所有故事)
|
||||
3. 完成阶段 3: 用户故事 1
|
||||
4. **停止并验证**: 独立测试用户故事 1
|
||||
5. 如准备好则部署/演示
|
||||
|
||||
### 增量交付
|
||||
|
||||
1. 完成设置 + 基础 → 基础就绪
|
||||
2. 添加用户故事 1 → 独立测试 → 部署/演示(MVP! )
|
||||
3. 添加用户故事 2 → 独立测试 → 部署/演示
|
||||
4. 添加用户故事 3 → 独立测试 → 部署/演示
|
||||
5. 每个故事在不破坏先前故事的情况下增加价值
|
||||
|
||||
### 并行团队策略
|
||||
|
||||
有多个开发人员时:
|
||||
|
||||
1. 团队一起完成设置 + 基础
|
||||
2. 基础完成后:
|
||||
- 开发人员 A: 用户故事 1
|
||||
- 开发人员 B: 用户故事 2
|
||||
- 开发人员 C: 用户故事 3
|
||||
3. 故事独立完成和集成
|
||||
|
||||
---
|
||||
|
||||
## 注意事项
|
||||
|
||||
- [P] 任务 = 不同文件, 无依赖关系
|
||||
- [Story] 标签将任务映射到特定用户故事以实现可追溯性
|
||||
- 每个用户故事应该独立可完成和可测试
|
||||
- 在实施前验证测试失败
|
||||
- 在每个任务或逻辑组后提交
|
||||
- 在任何检查点停止以独立验证故事
|
||||
- 避免: 模糊任务、相同文件冲突、破坏独立性的跨故事依赖
|
||||
|
||||
Reference in New Issue
Block a user