specline 1.4.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +132 -125
- package/adapters/claude/deploy.json +12 -0
- package/adapters/claude/hooks/hooks.json +12 -0
- package/adapters/claude/hooks.json +12 -0
- package/adapters/claude/orchestration.md +17 -0
- package/adapters/codex/agent.toml.hbs +7 -0
- package/adapters/codex/deploy.json +12 -0
- package/adapters/codex/hooks.json +12 -0
- package/adapters/codex/orchestration.md +18 -0
- package/adapters/cursor/deploy.json +12 -0
- package/adapters/cursor/hooks.json +9 -0
- package/adapters/cursor/orchestration.md +17 -0
- package/adapters/opencode/deploy.json +12 -0
- package/adapters/opencode/orchestration.md +18 -0
- package/adapters/opencode/plugin.js +10 -0
- package/cli.mjs +161 -558
- package/core/agents/specline-backend-dev.yaml +45 -0
- package/core/agents/specline-code-reviewer.yaml +67 -0
- package/core/agents/specline-config-dev.yaml +50 -0
- package/core/agents/specline-config-reviewer.yaml +70 -0
- package/core/agents/specline-explore-assistant.yaml +79 -0
- package/core/agents/specline-frontend-dev.yaml +45 -0
- package/core/agents/specline-spec-creator.yaml +58 -0
- package/core/agents/specline-spec-reviewer.yaml +58 -0
- package/core/agents/specline-test-runner.yaml +62 -0
- package/core/agents/specline-test-writer.yaml +67 -0
- package/core/bootstrap/using-specline.md +14 -0
- package/core/gates/pipeline-gate-checks/a1-covers-ref.sh +125 -0
- package/core/gates/pipeline-gate-checks/a2-a3-reverse.sh +171 -0
- package/core/gates/pipeline-gate-checks/c1-exception.sh +71 -0
- package/core/gates/pipeline-gate-checks/c2-vague.sh +60 -0
- package/core/gates/pipeline-gate-checks/common.sh +68 -0
- package/core/gates/pipeline-gate-checks/d1-cycle.sh +149 -0
- package/core/gates/pipeline-gate-checks/d3-type-file.sh +260 -0
- package/core/gates/pipeline-gate.sh +1456 -0
- package/core/hooks/session-start.sh +259 -0
- package/core/skills/specline-apply-change/SKILL.md +197 -0
- package/core/skills/specline-archive-change/SKILL.md +173 -0
- package/core/skills/specline-explore/SKILL.md +504 -0
- package/core/skills/specline-knowledge/SKILL.md +539 -0
- package/core/skills/specline-pipeline/SKILL.md +604 -0
- package/core/skills/specline-pipeline/references/error-recovery-details.md +49 -0
- package/core/skills/specline-pipeline/references/event-log-spec.md +59 -0
- package/core/skills/specline-pipeline/references/pipeline-state-schema.md +87 -0
- package/core/skills/specline-pipeline/templates/subagent-prompts.md +397 -0
- package/core/skills/specline-propose/SKILL.md +186 -0
- package/core/skills/specline-quickfix/SKILL.md +289 -0
- package/core/templates/AGENTS.md.hbs +5 -0
- package/core/templates/specline/config.yaml +15 -0
- package/lib/deploy-claude.mjs +80 -0
- package/lib/deploy-codex.mjs +77 -0
- package/lib/deploy-opencode.mjs +93 -0
- package/lib/deploy.mjs +668 -0
- package/lib/gate.mjs +103 -0
- package/lib/hash.mjs +13 -0
- package/lib/hook.mjs +105 -0
- package/lib/init.mjs +122 -0
- package/lib/lock.mjs +99 -0
- package/lib/merge.mjs +184 -0
- package/lib/paths.mjs +40 -0
- package/lib/platforms.mjs +74 -0
- package/lib/render-agents.mjs +88 -0
- package/lib/render.mjs +126 -0
- package/lib/sync.mjs +253 -0
- package/lib/tty-select.mjs +89 -0
- package/package.json +4 -1
- package/templates/.cursor/README.md +18 -0
- package/templates/.cursor/agents/specline-code-reviewer.md +18 -2
- package/templates/.cursor/agents/specline-spec-creator.md +51 -2
- package/templates/.cursor/agents/specline-test-runner.md +10 -1
- package/templates/.cursor/agents/specline-test-writer.md +58 -7
- package/templates/.cursor/hooks/specline-pipeline-gate-checks/a2-a3-reverse.sh +1 -1
- package/templates/.cursor/hooks/specline-pipeline-gate.sh +118 -0
- package/templates/.cursor/skills/specline-pipeline/SKILL.md +10 -4
- package/templates/.cursor/skills/specline-propose/SKILL.md +3 -3
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# specline-session-start.sh — sessionStart Hook (Pipeline Session Binding)
|
|
3
|
+
#
|
|
4
|
+
# 新会话启动时:
|
|
5
|
+
# 1. 清理过期绑定(7 天未更新)
|
|
6
|
+
# 2. 检查当前 session 是否已有绑定
|
|
7
|
+
# 3. 有绑定且 pipeline 仍活跃 → 使用已有绑定,注入上下文
|
|
8
|
+
# 4. 有绑定但 pipeline 已失效 → 清理脏数据,重新扫描
|
|
9
|
+
# 5. 无绑定 → 透明放行(echo '{}')——不自动绑定,避免跨窗口污染
|
|
10
|
+
#
|
|
11
|
+
# Input (stdin JSON):
|
|
12
|
+
# { "session_id": "...", "is_background_agent": bool, ... }
|
|
13
|
+
#
|
|
14
|
+
# Output (stdout JSON):
|
|
15
|
+
# { "additional_context": "<pipeline 上下文>" } 或 {}(无活跃 pipeline)
|
|
16
|
+
|
|
17
|
+
set -euo pipefail
|
|
18
|
+
|
|
19
|
+
# ============================================================================
|
|
20
|
+
# Input
|
|
21
|
+
# ============================================================================
|
|
22
|
+
|
|
23
|
+
input=$(cat)
|
|
24
|
+
|
|
25
|
+
# 跳过 background agent(子 Agent 不需要 pipeline 上下文)
|
|
26
|
+
is_bg=$(echo "$input" | jq -r '.is_background_agent // false')
|
|
27
|
+
if [ "$is_bg" = "true" ]; then
|
|
28
|
+
echo '{}'
|
|
29
|
+
exit 0
|
|
30
|
+
fi
|
|
31
|
+
|
|
32
|
+
session_id=$(echo "$input" | jq -r '.session_id // empty')
|
|
33
|
+
if [ -z "$session_id" ]; then
|
|
34
|
+
echo '{}'
|
|
35
|
+
exit 0
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
# ============================================================================
|
|
39
|
+
# Paths
|
|
40
|
+
# ============================================================================
|
|
41
|
+
|
|
42
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
43
|
+
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
44
|
+
BINDINGS_FILE="$PROJECT_ROOT/specline/.pipeline-sessions.json"
|
|
45
|
+
CHANGES_DIR="$PROJECT_ROOT/specline/changes"
|
|
46
|
+
|
|
47
|
+
# ============================================================================
|
|
48
|
+
# Helper Functions
|
|
49
|
+
# ============================================================================
|
|
50
|
+
|
|
51
|
+
# init_bindings_file — ensure bindings file exists with a valid JSON object
|
|
52
|
+
init_bindings_file() {
|
|
53
|
+
if [ ! -f "$BINDINGS_FILE" ]; then
|
|
54
|
+
mkdir -p "$(dirname "$BINDINGS_FILE")"
|
|
55
|
+
echo '{}' > "$BINDINGS_FILE"
|
|
56
|
+
fi
|
|
57
|
+
|
|
58
|
+
# Validate it's readable JSON; reset if corrupted
|
|
59
|
+
if ! jq empty "$BINDINGS_FILE" 2>/dev/null; then
|
|
60
|
+
echo '{}' > "$BINDINGS_FILE"
|
|
61
|
+
fi
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
# clean_expired_bindings — remove bindings where bound_at > 7 days ago
|
|
65
|
+
# Uses ISO-8601 lexical comparison: works on both macOS and Linux
|
|
66
|
+
clean_expired_bindings() {
|
|
67
|
+
[ -f "$BINDINGS_FILE" ] || return 0
|
|
68
|
+
|
|
69
|
+
local cutoff_date
|
|
70
|
+
# macOS date, fallback to Linux date
|
|
71
|
+
cutoff_date=$(date -u -v-7d +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || \
|
|
72
|
+
date -u -d '7 days ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null)
|
|
73
|
+
|
|
74
|
+
if [ -z "$cutoff_date" ]; then
|
|
75
|
+
return 0 # Cannot determine cutoff, skip cleanup
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
local tmp_file="${BINDINGS_FILE}.tmp"
|
|
79
|
+
# Keep only entries whose bound_at is >= cutoff (i.e. within the last 7 days)
|
|
80
|
+
jq --arg cutoff "$cutoff_date" \
|
|
81
|
+
'with_entries(select(.value.bound_at >= $cutoff))' \
|
|
82
|
+
"$BINDINGS_FILE" > "$tmp_file" 2>/dev/null && \
|
|
83
|
+
mv "$tmp_file" "$BINDINGS_FILE" 2>/dev/null || true
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
# is_pipeline_active — check if a pipeline's state file exists and is not archived
|
|
87
|
+
# Returns 0 (active) or 1 (inactive)
|
|
88
|
+
is_pipeline_active() {
|
|
89
|
+
local change_name="$1"
|
|
90
|
+
local state_file="$CHANGES_DIR/$change_name/.pipeline-state.json"
|
|
91
|
+
|
|
92
|
+
[ -f "$state_file" ] || return 1
|
|
93
|
+
|
|
94
|
+
local phase
|
|
95
|
+
phase=$(jq -r '.current_phase // "unknown"' "$state_file" 2>/dev/null)
|
|
96
|
+
[ "$phase" != "archive" ] || return 1
|
|
97
|
+
|
|
98
|
+
return 0
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
# scan_active_pipelines — scan changes/ (excluding archive/) for active pipelines
|
|
102
|
+
# Output: one line per pipeline: change_name|phase|state_file_path
|
|
103
|
+
scan_active_pipelines() {
|
|
104
|
+
if [ ! -d "$CHANGES_DIR" ]; then
|
|
105
|
+
return 0
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
for state_file in "$CHANGES_DIR"/*/.pipeline-state.json; do
|
|
109
|
+
[ -f "$state_file" ] || continue
|
|
110
|
+
|
|
111
|
+
# Exclude archive/
|
|
112
|
+
case "$state_file" in
|
|
113
|
+
*/archive/*) continue ;;
|
|
114
|
+
esac
|
|
115
|
+
|
|
116
|
+
local change_name phase
|
|
117
|
+
change_name=$(jq -r '.change_name // ""' "$state_file" 2>/dev/null)
|
|
118
|
+
phase=$(jq -r '.current_phase // ""' "$state_file" 2>/dev/null)
|
|
119
|
+
|
|
120
|
+
[ -n "$change_name" ] || continue
|
|
121
|
+
[ "$phase" != "archive" ] || continue
|
|
122
|
+
|
|
123
|
+
printf '%s|%s|%s\n' "$change_name" "$phase" "$state_file"
|
|
124
|
+
done
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
# phase_constraints — output constraint text for a given phase (to stdout)
|
|
128
|
+
phase_constraints() {
|
|
129
|
+
local phase="$1"
|
|
130
|
+
case "$phase" in
|
|
131
|
+
spec)
|
|
132
|
+
printf '%s\n' "- 只能通过 specline-spec-creator / specline-spec-reviewer 子 Agent 工作"
|
|
133
|
+
printf '%s\n' "- 禁止编辑任何应用代码文件(.ts/.tsx/.py/.go 等)"
|
|
134
|
+
printf '%s\n' "- 规划文件生成后需运行 Spec Gate"
|
|
135
|
+
;;
|
|
136
|
+
coding)
|
|
137
|
+
printf '%s\n' "- 编码必须通过子 Agent:specline-frontend-dev / specline-backend-dev / specline-config-dev"
|
|
138
|
+
printf '%s\n' "- 禁止直接编辑应用代码文件"
|
|
139
|
+
printf '%s\n' "- 每批次任务完成后运行 Build Gate"
|
|
140
|
+
printf '%s\n' "- 每个 Task 完成后更新 tasks.md 的 checkbox"
|
|
141
|
+
;;
|
|
142
|
+
code_review)
|
|
143
|
+
printf '%s\n' "- 只能运行 specline-code-reviewer + Lint Gate"
|
|
144
|
+
printf '%s\n' "- 如需修复代码,通过子 Agent 完成"
|
|
145
|
+
;;
|
|
146
|
+
test)
|
|
147
|
+
printf '%s\n' "- 运行测试 Gate 链:unit → integration → e2e"
|
|
148
|
+
printf '%s\n' "- 测试失败时通过 specline-test-runner 分析原因"
|
|
149
|
+
printf '%s\n' "- 代码修复通过子 Agent,测试修复通过 specline-test-writer"
|
|
150
|
+
;;
|
|
151
|
+
*)
|
|
152
|
+
printf '%s\n' "- 遵循 specline-pipeline SKILL 的当前阶段约束"
|
|
153
|
+
;;
|
|
154
|
+
esac
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
# build_context — generate a JSON-escaped additional_context string for a bound pipeline
|
|
158
|
+
build_context() {
|
|
159
|
+
local change_name="$1"
|
|
160
|
+
local phase="$2"
|
|
161
|
+
local state_file="$3"
|
|
162
|
+
|
|
163
|
+
{
|
|
164
|
+
printf '🚨 **Specline Pipeline 运行中**\n\n'
|
|
165
|
+
printf '**当前变更**: %s\n' "$change_name"
|
|
166
|
+
printf '**当前阶段**: %s\n' "$phase"
|
|
167
|
+
|
|
168
|
+
# Task progress for coding phase
|
|
169
|
+
if [ "$phase" = "coding" ] && [ -f "$state_file" ]; then
|
|
170
|
+
local completed total
|
|
171
|
+
completed=$(jq -r '[.phases.coding.tasks[]? | select(.status == "completed")] | length' "$state_file" 2>/dev/null || printf '0')
|
|
172
|
+
total=$(jq -r '[.phases.coding.tasks[]?] | length' "$state_file" 2>/dev/null || printf '0')
|
|
173
|
+
if [ "$total" != "0" ]; then
|
|
174
|
+
printf '**任务进度**: %s/%s 完成\n' "$completed" "$total"
|
|
175
|
+
fi
|
|
176
|
+
fi
|
|
177
|
+
|
|
178
|
+
printf '\n**阶段约束**:\n'
|
|
179
|
+
phase_constraints "$phase"
|
|
180
|
+
printf '\n'
|
|
181
|
+
printf '**重要**: 你是 Specline Pipeline 编排者。上述约束具有最高优先级,必须在每个操作前检查是否符合当前阶段要求。'
|
|
182
|
+
} | jq -Rs '.'
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
# phase_constraint_table — static phase constraint reference table (markdown)
|
|
186
|
+
phase_constraint_table() {
|
|
187
|
+
cat << 'TABLEEOF'
|
|
188
|
+
| 阶段 | 约束 |
|
|
189
|
+
|------|------|
|
|
190
|
+
| spec | 只能通过 specline-spec-creator/specline-spec-reviewer 子 Agent 工作,禁止编辑代码 |
|
|
191
|
+
| coding | 必须通过子 Agent 编码,批次完成后运行 Build Gate,更新 tasks.md |
|
|
192
|
+
| code_review | 只能运行 specline-code-reviewer + Lint Gate |
|
|
193
|
+
| test | 运行测试 Gate 链:unit → integration → e2e |
|
|
194
|
+
TABLEEOF
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
# write_binding — write a session_id → change_name binding to .pipeline-sessions.json
|
|
198
|
+
write_binding() {
|
|
199
|
+
local sid="$1"
|
|
200
|
+
local change="$2"
|
|
201
|
+
|
|
202
|
+
local now_iso
|
|
203
|
+
now_iso=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
204
|
+
|
|
205
|
+
local tmp_file="${BINDINGS_FILE}.tmp"
|
|
206
|
+
jq --arg sid "$sid" --arg change "$change" --arg now "$now_iso" \
|
|
207
|
+
'.[$sid] = {"change": $change, "bound_at": $now}' \
|
|
208
|
+
"$BINDINGS_FILE" > "$tmp_file" 2>/dev/null && \
|
|
209
|
+
mv "$tmp_file" "$BINDINGS_FILE" 2>/dev/null || true
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
# delete_binding — remove a session_id entry from .pipeline-sessions.json
|
|
213
|
+
delete_binding() {
|
|
214
|
+
local session_id="$1"
|
|
215
|
+
|
|
216
|
+
[ -f "$BINDINGS_FILE" ] || return 0
|
|
217
|
+
|
|
218
|
+
local tmp_file="${BINDINGS_FILE}.tmp"
|
|
219
|
+
jq --arg sid "$session_id" 'del(.[$sid])' "$BINDINGS_FILE" > "$tmp_file" 2>/dev/null && \
|
|
220
|
+
mv "$tmp_file" "$BINDINGS_FILE" 2>/dev/null || true
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
# ============================================================================
|
|
224
|
+
# Main Logic
|
|
225
|
+
# ============================================================================
|
|
226
|
+
|
|
227
|
+
init_bindings_file
|
|
228
|
+
|
|
229
|
+
# 1. Clean expired bindings (bound_at > 7 days ago)
|
|
230
|
+
clean_expired_bindings
|
|
231
|
+
|
|
232
|
+
# 2. Check existing binding for this session
|
|
233
|
+
existing_change=""
|
|
234
|
+
if [ -f "$BINDINGS_FILE" ]; then
|
|
235
|
+
existing_change=$(jq -r --arg sid "$session_id" '.[$sid].change // empty' "$BINDINGS_FILE" 2>/dev/null)
|
|
236
|
+
fi
|
|
237
|
+
|
|
238
|
+
if [ -n "$existing_change" ]; then
|
|
239
|
+
if is_pipeline_active "$existing_change"; then
|
|
240
|
+
# Binding is still valid — use it
|
|
241
|
+
state_file="$CHANGES_DIR/$existing_change/.pipeline-state.json"
|
|
242
|
+
phase=$(jq -r '.current_phase // "unknown"' "$state_file" 2>/dev/null)
|
|
243
|
+
|
|
244
|
+
ctx_json=$(build_context "$existing_change" "$phase" "$state_file")
|
|
245
|
+
|
|
246
|
+
printf '{\n "additional_context": %s\n}\n' "$ctx_json"
|
|
247
|
+
exit 0
|
|
248
|
+
else
|
|
249
|
+
# Dirty data: pipeline archived or deleted — clean up and rescan
|
|
250
|
+
delete_binding "$session_id"
|
|
251
|
+
fi
|
|
252
|
+
fi
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
# 3. No (valid) binding → transparent pass-through
|
|
256
|
+
# 不再自动绑定或注入任何 pipeline 上下文,避免跨窗口污染。
|
|
257
|
+
# 用户需通过 /specline-pipeline --change <name> 显式绑定。
|
|
258
|
+
echo '{}'
|
|
259
|
+
exit 0
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: specline-apply-change
|
|
3
|
+
description: Implement tasks from a Specline change. Use when the user wants to start implementing, continue implementation, or work through tasks.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: Compatible with specline.
|
|
6
|
+
metadata:
|
|
7
|
+
author: specline
|
|
8
|
+
version: "1.0"
|
|
9
|
+
generatedBy: "1.3.1"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
Implement tasks from a Specline change.
|
|
13
|
+
|
|
14
|
+
**Input**: Optionally specify a change name. If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
|
|
15
|
+
|
|
16
|
+
## 速览 (Layer 1)
|
|
17
|
+
|
|
18
|
+
> **一句话**:实现 Specline change 中的编码任务。
|
|
19
|
+
> **入口**:`/specline-apply-change [change-name]` 或直接说「继续实现」
|
|
20
|
+
> **流程**:选 change → 读上下文 → 逐任务实现 → 标记完成
|
|
21
|
+
|
|
22
|
+
> ⚠️ **人机门禁策略感知**:当调用方传递了 `HUMAN_GATE_POLICY=minimal` 或 `HUMAN_GATE_POLICY=none` 上下文时,本 Skill 内所有的 {{CONFIRM}} 交互应自动采用默认安全选项:
|
|
23
|
+
> - change 选择 → 若上下文中已有 change name,直接使用;否则取第一个活跃 change
|
|
24
|
+
> - 其他 {{CONFIRM}} 交互 → 自动采用默认安全选项继续,不暂停等待人工输入
|
|
25
|
+
|
|
26
|
+
**Fluid Workflow Integration**
|
|
27
|
+
|
|
28
|
+
This skill supports the "actions on a change" model:
|
|
29
|
+
- **Can be invoked anytime**: Before all artifacts are done (if tasks exist), after partial implementation, interleaved with other actions
|
|
30
|
+
- **Allows artifact updates**: If implementation reveals design issues, suggest updating artifacts - not phase-locked, work fluidly
|
|
31
|
+
|
|
32
|
+
**开始前请确认:**
|
|
33
|
+
- [ ] Change 已选中(`/specline-pipeline --change <name>`)
|
|
34
|
+
- [ ] 已读取 proposal.md(知道做什么)
|
|
35
|
+
- [ ] 已读取 spec.md(知道需求和场景)
|
|
36
|
+
- [ ] 已读取 design.md(知道技术决策)
|
|
37
|
+
- [ ] 已读取 tasks.md(知道实现清单)
|
|
38
|
+
|
|
39
|
+
## 详细步骤 — Happy Path (Layer 2)
|
|
40
|
+
|
|
41
|
+
**Steps**
|
|
42
|
+
|
|
43
|
+
1. **Select the change**
|
|
44
|
+
|
|
45
|
+
If a name is provided, use it. Otherwise:
|
|
46
|
+
- Infer from conversation context if the user mentioned a change
|
|
47
|
+
- Auto-select if only one active change exists
|
|
48
|
+
- If ambiguous, run `specline gate list --json` to get available changes and use {{CONFIRM}} to let the user select
|
|
49
|
+
|
|
50
|
+
Always announce: "Using change: <name>" and how to override (e.g., `/specline-pipeline --change <other>`).
|
|
51
|
+
|
|
52
|
+
2. **Check status to understand the schema**
|
|
53
|
+
```bash
|
|
54
|
+
specline gate artifacts --change "<name>" --json
|
|
55
|
+
```
|
|
56
|
+
Parse the JSON to understand:
|
|
57
|
+
- `schemaName`: The workflow being used (e.g., "spec-driven")
|
|
58
|
+
- Which artifact contains the tasks (typically "tasks" for spec-driven, check status for others)
|
|
59
|
+
|
|
60
|
+
3. **Read context files**
|
|
61
|
+
|
|
62
|
+
Read the planning files at `specline/changes/<name>/`:
|
|
63
|
+
- `proposal.md` — what & why
|
|
64
|
+
- `specs/<capability>/spec.md` — requirements & scenarios
|
|
65
|
+
- `design.md` — architecture & decisions
|
|
66
|
+
- `tasks.md` — implementation checklist
|
|
67
|
+
|
|
68
|
+
Check task completion: count `- [ ]` (incomplete) vs `- [x]` (complete).
|
|
69
|
+
|
|
70
|
+
4. **Show current progress**
|
|
71
|
+
|
|
72
|
+
Display:
|
|
73
|
+
- Progress: "N/M tasks complete"
|
|
74
|
+
- Remaining tasks overview
|
|
75
|
+
|
|
76
|
+
5. **Implement tasks (loop until done or blocked)**
|
|
77
|
+
|
|
78
|
+
For each pending task:
|
|
79
|
+
- Show which task is being worked on
|
|
80
|
+
- Make the code changes required
|
|
81
|
+
- Keep changes minimal and focused
|
|
82
|
+
- Mark task complete in the tasks file: `- [ ]` → `- [x]`
|
|
83
|
+
- Continue to next task
|
|
84
|
+
|
|
85
|
+
**Pause if:**
|
|
86
|
+
- Task is unclear → ask for clarification
|
|
87
|
+
- Implementation reveals a design issue → suggest updating artifacts
|
|
88
|
+
- Error or blocker encountered → report and wait for guidance
|
|
89
|
+
- User interrupts
|
|
90
|
+
|
|
91
|
+
6. **On completion or pause, show status**
|
|
92
|
+
|
|
93
|
+
Display:
|
|
94
|
+
- Tasks completed this session
|
|
95
|
+
- Overall progress: "N/M tasks complete"
|
|
96
|
+
- If all done: suggest archive
|
|
97
|
+
- If paused: explain why and wait for guidance
|
|
98
|
+
|
|
99
|
+
## 输出模板 & 高级话题 (Layer 3)
|
|
100
|
+
|
|
101
|
+
### 输出模板
|
|
102
|
+
|
|
103
|
+
**Output During Implementation**
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
## Implementing: <change-name> (schema: <schema-name>)
|
|
107
|
+
|
|
108
|
+
Working on task 3/7: <task description>
|
|
109
|
+
[...implementation happening...]
|
|
110
|
+
✓ Task complete
|
|
111
|
+
|
|
112
|
+
Working on task 4/7: <task description>
|
|
113
|
+
[...implementation happening...]
|
|
114
|
+
✓ Task complete
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Output On Completion**
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
## Implementation Complete
|
|
121
|
+
|
|
122
|
+
**Change:** <change-name>
|
|
123
|
+
**Schema:** <schema-name>
|
|
124
|
+
**Progress:** 7/7 tasks complete ✓
|
|
125
|
+
|
|
126
|
+
### Completed This Session
|
|
127
|
+
- [x] Task 1
|
|
128
|
+
- [x] Task 2
|
|
129
|
+
...
|
|
130
|
+
|
|
131
|
+
All tasks complete! Ready to archive this change.
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**Output On Pause (Issue Encountered)**
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
## Implementation Paused
|
|
138
|
+
|
|
139
|
+
**Change:** <change-name>
|
|
140
|
+
**Schema:** <schema-name>
|
|
141
|
+
**Progress:** 4/7 tasks complete
|
|
142
|
+
|
|
143
|
+
### Issue Encountered
|
|
144
|
+
<description of the issue>
|
|
145
|
+
|
|
146
|
+
**Options:**
|
|
147
|
+
1. <option 1>
|
|
148
|
+
2. <option 2>
|
|
149
|
+
3. Other approach
|
|
150
|
+
|
|
151
|
+
What would you like to do?
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Guardrails
|
|
155
|
+
- Keep going through tasks until done or blocked
|
|
156
|
+
- Always read context files before starting (from the apply instructions output)
|
|
157
|
+
- If task is ambiguous, pause and ask before implementing
|
|
158
|
+
- If implementation reveals issues, pause and suggest artifact updates
|
|
159
|
+
- Keep code changes minimal and scoped to each task
|
|
160
|
+
- Update task checkbox immediately after completing each task
|
|
161
|
+
- Pause on errors, blockers, or unclear requirements - don't guess
|
|
162
|
+
- Use contextFiles from CLI output, don't assume specific file names
|
|
163
|
+
- **Hook blocked → no silent fallback**: If this skill is invoked because a coding subagent (specline-frontend-dev / specline-backend-dev) was blocked by a hook, you MUST first notify the user of the blocking cause and attempt diagnosis. Do not silently execute tasks that should have been handled by the blocked subagent. Reference the Hook Blocking Resolution Protocol in the specline-pipeline skill.
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Anti-Rationalization 表格
|
|
168
|
+
|
|
169
|
+
逐任务实现时,Agent 容易偏离规范:
|
|
170
|
+
|
|
171
|
+
| 借口 | 现实 |
|
|
172
|
+
|------|------|
|
|
173
|
+
| "不用读 Spec/Design/Tasks,我理解需求" | 记忆不可靠。实现前读上下文文件是防止方向偏离的最便宜保险。 |
|
|
174
|
+
| "顺便把这个相邻函数也重构了" | Scope Discipline 是 Core Behaviors。越界修改让 Code Review 和回溯都变困难。 |
|
|
175
|
+
| "checkbox 我最后一起标记" | Checkbox 是断点续跑的唯一信号源。不及时标记意味着下次恢复时状态丢失。 |
|
|
176
|
+
| "这个任务没有测试也没关系,下一个任务会补" | 每个 Testable=true 的任务必须产出测试。推迟 = 不写。 |
|
|
177
|
+
| "tasks.md 的 Covers 追溯链我不用管,代码写对就行" | Covers 链是 Spec → Code 的可追溯纽带。不维护它,Code Review 和测试失败定位都失去锚点。 |
|
|
178
|
+
|
|
179
|
+
## Verification Checklist
|
|
180
|
+
|
|
181
|
+
每完成一个任务后自查,全部完成后终查:
|
|
182
|
+
|
|
183
|
+
- [ ] 开始前已读 proposal.md / spec.md / design.md / tasks.md
|
|
184
|
+
- [ ] 每个任务的实现范围未超出 Files 声明
|
|
185
|
+
- [ ] 每个 Testable=true 的任务产出了测试文件(在 tests/unit/ 或 tests/models/)
|
|
186
|
+
- [ ] tasks.md 中每个已完成任务的 `[ ]` 已改为 `[x]`
|
|
187
|
+
- [ ] task-{id}-result.json 已写入 .tmp/ 目录
|
|
188
|
+
- [ ] 本 session 修改的文件与 tasks.md 的 Files 声明一致
|
|
189
|
+
- [ ] 未修改其他任务负责的文件
|
|
190
|
+
|
|
191
|
+
### 暂停场景处理
|
|
192
|
+
|
|
193
|
+
当实现过程中出现以下情况时,暂停并等待用户指引:
|
|
194
|
+
- 任务描述不清晰 → 请求用户澄清
|
|
195
|
+
- 实现中暴露出设计问题 → 建议更新 Artifact(proposal / spec / design / tasks)
|
|
196
|
+
- 遇到错误或阻塞 → 报告具体问题并等待指导
|
|
197
|
+
- 用户主动中断 → 记录当前进度,下次可从断点继续
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: specline-archive-change
|
|
3
|
+
description: Archive a completed change in the experimental workflow. Use when the user wants to finalize and archive a change after implementation is complete.
|
|
4
|
+
license: MIT
|
|
5
|
+
compatibility: Compatible with specline.
|
|
6
|
+
metadata:
|
|
7
|
+
author: specline
|
|
8
|
+
version: "1.0"
|
|
9
|
+
generatedBy: "1.3.1"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## TL;DR (Layer 1)
|
|
13
|
+
|
|
14
|
+
> **一句话**:归档已完成的 Specline change。
|
|
15
|
+
> **入口**:`/specline-archive-change [change-name]`
|
|
16
|
+
> **流程**:选 change → 检查完成度 → Delta spec sync 决策 → 移动目录 → 完成
|
|
17
|
+
|
|
18
|
+
### 归档前后目录结构变化
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
归档前 (活跃、可修改) 归档后 (只读、可追溯)
|
|
22
|
+
|
|
23
|
+
specline/changes/ specline/changes/
|
|
24
|
+
├── my-change/ ──▶ ├── archive/
|
|
25
|
+
│ ├── proposal.md │ └── 2026-06-01-my-change/
|
|
26
|
+
│ ├── design.md │ ├── proposal.md
|
|
27
|
+
│ ├── tasks.md │ ├── design.md
|
|
28
|
+
│ └── specs/ │ ├── tasks.md
|
|
29
|
+
│ └── specs/
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Input**: Optionally specify a change name. If omitted, check if it can be inferred from conversation context. If vague or ambiguous you MUST prompt for available changes.
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## Steps (Layer 2 — Happy Path)
|
|
37
|
+
|
|
38
|
+
1. **If no change name provided, prompt for selection**
|
|
39
|
+
|
|
40
|
+
Run `specline gate list --json` to get available changes. Use {{CONFIRM}} to let the user select.
|
|
41
|
+
|
|
42
|
+
Show only active changes (not already archived).
|
|
43
|
+
Include the schema used for each change if available.
|
|
44
|
+
|
|
45
|
+
**IMPORTANT**: Do NOT guess or auto-select a change. Always let the user choose.
|
|
46
|
+
|
|
47
|
+
2. **Check artifact completion status**
|
|
48
|
+
|
|
49
|
+
Run `specline gate artifacts --change "<name>" --json` to check artifact completion.
|
|
50
|
+
|
|
51
|
+
Parse the JSON to understand:
|
|
52
|
+
- `schemaName`: The workflow being used
|
|
53
|
+
- `artifacts`: List of artifacts with their status (`done` or other)
|
|
54
|
+
|
|
55
|
+
**If any artifacts are not `done`:**
|
|
56
|
+
- Display warning listing incomplete artifacts
|
|
57
|
+
- Use {{CONFIRM}} to confirm user wants to proceed
|
|
58
|
+
- Proceed if user confirms
|
|
59
|
+
|
|
60
|
+
3. **Check task completion status**
|
|
61
|
+
|
|
62
|
+
Read the tasks file (typically `tasks.md`) to check for incomplete tasks.
|
|
63
|
+
|
|
64
|
+
Count tasks marked with `- [ ]` (incomplete) vs `- [x]` (complete).
|
|
65
|
+
|
|
66
|
+
**If incomplete tasks found:**
|
|
67
|
+
- Display warning showing count of incomplete tasks
|
|
68
|
+
- Use {{CONFIRM}} to confirm user wants to proceed
|
|
69
|
+
- Proceed if user confirms
|
|
70
|
+
|
|
71
|
+
**If no tasks file exists:** Proceed without task-related warning.
|
|
72
|
+
|
|
73
|
+
4. **Assess delta spec sync state**
|
|
74
|
+
|
|
75
|
+
**决策流程:**
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
Delta specs 存在?
|
|
79
|
+
├── 否 → 直接归档
|
|
80
|
+
└── 是 → 比较 delta spec 与 main spec
|
|
81
|
+
├── 无差异 → 「已同步」→ 直接归档
|
|
82
|
+
└── 有差异 → 展示变更摘要 → 询问用户
|
|
83
|
+
├── 同步 → 执行 sync → 归档
|
|
84
|
+
└── 跳过 → 归档
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Check for delta specs at `specline/changes/<name>/specs/`. If none exist, proceed without sync prompt.
|
|
88
|
+
|
|
89
|
+
**If delta specs exist:**
|
|
90
|
+
- Compare each delta spec with its corresponding main spec at `specline/specs/<capability>/spec.md`
|
|
91
|
+
- Determine what changes would be applied (adds, modifications, removals, renames)
|
|
92
|
+
- Show a combined summary before prompting
|
|
93
|
+
|
|
94
|
+
**Prompt options:**
|
|
95
|
+
- If changes needed: "Sync now (recommended)", "Archive without syncing"
|
|
96
|
+
- If already synced: "Archive now", "Sync anyway", "Cancel"
|
|
97
|
+
|
|
98
|
+
If user chooses sync, {{DISPATCH}},role="general-purpose",prompt: "Use Skill tool to invoke specline-sync-specs for change '<name>'. Delta spec analysis: <include the analyzed delta spec summary>". Proceed to archive regardless of choice.
|
|
99
|
+
|
|
100
|
+
5. **Perform the archive**
|
|
101
|
+
|
|
102
|
+
Create the archive directory if it doesn't exist:
|
|
103
|
+
```bash
|
|
104
|
+
mkdir -p specline/changes/archive
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Generate target name using current date: `YYYY-MM-DD-<change-name>`
|
|
108
|
+
|
|
109
|
+
**Check if target already exists:**
|
|
110
|
+
- If yes: Fail with error, suggest renaming existing archive or using different date
|
|
111
|
+
- If no: Move the change directory to archive
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
specline gate archive --execute --change <name>
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
6. **Display summary**
|
|
118
|
+
|
|
119
|
+
Show archive completion summary including:
|
|
120
|
+
- Change name
|
|
121
|
+
- Schema that was used
|
|
122
|
+
- Archive location
|
|
123
|
+
- Whether specs were synced (if applicable)
|
|
124
|
+
- Note about any warnings (incomplete artifacts/tasks)
|
|
125
|
+
|
|
126
|
+
### Output On Success
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
## Archive Complete
|
|
130
|
+
|
|
131
|
+
**Change:** <change-name>
|
|
132
|
+
**Schema:** <schema-name>
|
|
133
|
+
**Archived to:** specline/changes/archive/YYYY-MM-DD-<name>/
|
|
134
|
+
**Specs:** ✓ Synced to main specs (or "No delta specs" or "Sync skipped")
|
|
135
|
+
|
|
136
|
+
All artifacts complete. All tasks complete.
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Guardrails (Layer 3 — 高级话题)
|
|
142
|
+
|
|
143
|
+
- Always prompt for change selection if not provided
|
|
144
|
+
- Use artifact graph (specline gate artifacts --json) for completion checking
|
|
145
|
+
- Don't block archive on warnings - just inform and confirm
|
|
146
|
+
- Preserve .specline.yaml when moving to archive (it moves with the directory)
|
|
147
|
+
- Show clear summary of what happened
|
|
148
|
+
- If sync is requested, use specline-sync-specs approach (agent-driven)
|
|
149
|
+
- If delta specs exist, always run the sync assessment and show the combined summary before prompting
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Anti-Rationalization 表格
|
|
154
|
+
|
|
155
|
+
归档是流水线的最后一步,松懈的代价是污染长期记录:
|
|
156
|
+
|
|
157
|
+
| 借口 | 现实 |
|
|
158
|
+
|------|------|
|
|
159
|
+
| "不用检查完成度,反正用户说可以归档了" | 用户说可以不代表真的可以。Artifact 和 task 完成度检查是归档前的最后防线。 |
|
|
160
|
+
| "Delta spec 不用同步,下次再说" | 未同步的 Delta spec 意味着 spec 与代码脱节。归档后几乎不会再有人回来补。 |
|
|
161
|
+
| "归档就是移动目录,不需要通知用户" | 归档改变了 change 的可见性和可修改性。用户需要知道发生了什么。 |
|
|
162
|
+
| "警告不用管,自动继续就行" | 警告(artifact 不完整、task 未完成)是信号。归档时应确认而非忽略。 |
|
|
163
|
+
|
|
164
|
+
## Verification Checklist
|
|
165
|
+
|
|
166
|
+
归档前自查:
|
|
167
|
+
|
|
168
|
+
- [ ] Artifact 完成度已检查(`specline gate artifacts --json`)
|
|
169
|
+
- [ ] Task 完成度已检查(tasks.md checkbox 状态)
|
|
170
|
+
- [ ] 任何警告/不完整项已向用户确认
|
|
171
|
+
- [ ] Delta spec sync 决策已完成(存在则展示摘要→询问;不存在则跳过)
|
|
172
|
+
- [ ] 归档目录已创建(`specline/changes/archive/YYYY-MM-DD-<name>/`)
|
|
173
|
+
- [ ] 归档摘要已展示给用户
|