cc-devflow 2.4.6 → 4.1.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/.claude/CLAUDE.md +1065 -48
- package/.claude/agents/dev-implementer.md +195 -0
- package/.claude/commands/{flow-archive.md → flow/archive.md} +46 -11
- package/.claude/commands/flow/context.md +150 -0
- package/.claude/commands/flow/delta.md +245 -0
- package/.claude/commands/{flow-dev.md → flow/dev.md} +112 -11
- package/.claude/commands/flow/init.md +45 -0
- package/.claude/commands/flow/quality.md +159 -0
- package/.claude/commands/flow/spec.md +186 -0
- package/.claude/commands/flow/workspace.md +146 -0
- package/.claude/commands/{cancel-ralph.md → util/cancel-ralph.md} +1 -0
- package/.claude/config/quality-gates.yml +305 -0
- package/.claude/docs/guides/TEAM_MODE_GUIDE.md +313 -0
- package/.claude/docs/templates/DELTA_SPEC_TEMPLATE.md +91 -0
- package/.claude/docs/templates/DESIGN_DECISIONS_TEMPLATE.md +151 -0
- package/.claude/docs/templates/JOURNAL_TEMPLATE.md +75 -0
- package/.claude/docs/templates/_shared/CLAUDE.md +36 -0
- package/.claude/docs/templates/_shared/CONSTITUTION_CHECK.md +125 -0
- package/.claude/docs/templates/_shared/VALIDATION_CHECKLIST.md +187 -0
- package/.claude/docs/templates/_shared/YAML_FRONTMATTER.md +164 -0
- package/.claude/docs/templates/context/dev.jsonl.template +6 -0
- package/.claude/docs/templates/context/epic.jsonl.template +5 -0
- package/.claude/docs/templates/context/prd.jsonl.template +4 -0
- package/.claude/docs/templates/context/research.jsonl.template +4 -0
- package/.claude/docs/templates/context/review.jsonl.template +5 -0
- package/.claude/docs/templates/context/tech.jsonl.template +5 -0
- package/.claude/hooks/CLAUDE.md +342 -0
- package/.claude/hooks/inject-agent-context.ts +480 -0
- package/.claude/hooks/inject-skill-context.ts +359 -0
- package/.claude/hooks/ralph-loop.ts +931 -0
- package/.claude/hooks/task-completed-hook.ts +593 -0
- package/.claude/hooks/teammate-idle-hook.ts +690 -0
- package/.claude/hooks/types/team-types.d.ts +238 -0
- package/.claude/rules/devflow-conventions.md +82 -9
- package/.claude/scripts/archive-requirement.sh +44 -1
- package/.claude/scripts/common.sh +670 -3
- package/.claude/scripts/delta-parser.ts +527 -0
- package/.claude/scripts/detect-file-conflicts.sh +151 -0
- package/.claude/scripts/flow-context-add.sh +134 -0
- package/.claude/scripts/flow-context-init.sh +133 -0
- package/.claude/scripts/flow-context-validate.sh +144 -0
- package/.claude/scripts/flow-delta-apply.sh +297 -0
- package/.claude/scripts/flow-delta-archive.sh +71 -0
- package/.claude/scripts/flow-delta-create.sh +202 -0
- package/.claude/scripts/flow-delta-list.sh +142 -0
- package/.claude/scripts/flow-delta-status.sh +235 -0
- package/.claude/scripts/flow-quality-full.sh +184 -0
- package/.claude/scripts/flow-quality-quick.sh +64 -0
- package/.claude/scripts/flow-workspace-init.sh +117 -0
- package/.claude/scripts/flow-workspace-record.sh +164 -0
- package/.claude/scripts/flow-workspace-start.sh +88 -0
- package/.claude/scripts/get-workflow-status.sh +415 -0
- package/.claude/scripts/parse-task-dependencies.js +334 -0
- package/.claude/scripts/record-quality-error.sh +165 -0
- package/.claude/scripts/run-quality-gates.sh +242 -0
- package/.claude/scripts/team-dev-init.sh +319 -0
- package/.claude/scripts/team-state-recovery.sh +229 -0
- package/.claude/scripts/workflow-status.ts +433 -0
- package/.claude/settings.json +19 -0
- package/.claude/skills/cc-devflow-orchestrator/SKILL.md +85 -200
- package/.claude/skills/domain/using-git-worktrees/SKILL.md +252 -0
- package/.claude/skills/domain/using-git-worktrees/assets/SHELL_ALIASES.md +133 -0
- package/.claude/skills/domain/using-git-worktrees/context.jsonl +4 -0
- package/.claude/skills/domain/using-git-worktrees/scripts/worktree-cleanup.sh +218 -0
- package/.claude/skills/domain/using-git-worktrees/scripts/worktree-create.sh +232 -0
- package/.claude/skills/domain/using-git-worktrees/scripts/worktree-list.sh +130 -0
- package/.claude/skills/domain/using-git-worktrees/scripts/worktree-status.sh +140 -0
- package/.claude/skills/domain/using-git-worktrees/scripts/worktree-switch.sh +70 -0
- package/.claude/skills/skill-rules.json +72 -1
- package/.claude/skills/utility/journey-checker/SKILL.md +199 -0
- package/.claude/skills/utility/journey-checker/pressure-scenarios.md +164 -0
- package/.claude/skills/utility/skill-creator/LICENSE.txt +202 -0
- package/.claude/skills/utility/skill-creator/SKILL.md +356 -0
- package/.claude/skills/utility/skill-creator/references/output-patterns.md +82 -0
- package/.claude/skills/utility/skill-creator/references/workflows.md +28 -0
- package/.claude/skills/utility/skill-creator/scripts/init_skill.py +303 -0
- package/.claude/skills/utility/skill-creator/scripts/package_skill.py +110 -0
- package/.claude/skills/utility/skill-creator/scripts/quick_validate.py +95 -0
- package/.claude/skills/workflow/flow-dev/CLAUDE.md +78 -0
- package/.claude/skills/workflow/flow-dev/SKILL.md +96 -0
- package/.claude/skills/workflow/flow-dev/assets/IMPLEMENTATION_PLAN_TEMPLATE.md +71 -0
- package/.claude/skills/workflow/flow-dev/context.jsonl +8 -0
- package/.claude/skills/workflow/flow-dev/dev-implementer.jsonl +8 -0
- package/.claude/skills/workflow/flow-dev/scripts/entry-gate.sh +116 -0
- package/.claude/skills/workflow/flow-dev/scripts/exit-gate.sh +101 -0
- package/.claude/skills/workflow/flow-dev/scripts/task-orchestrator.sh +106 -0
- package/.claude/skills/workflow/flow-fix/SKILL.md +105 -0
- package/.claude/skills/workflow/flow-fix/context.jsonl +6 -0
- package/.claude/skills/workflow/flow-fix/references/bug-analyzer.md +381 -0
- package/.claude/skills/workflow/flow-init/SKILL.md +211 -0
- package/.claude/skills/workflow/flow-init/assets/BRAINSTORM_TEMPLATE.md +148 -0
- package/.claude/skills/workflow/flow-init/assets/INIT_FLOW_TEMPLATE.md +198 -0
- package/.claude/skills/workflow/flow-init/assets/RESEARCH_TEMPLATE.md +276 -0
- package/.claude/skills/workflow/flow-init/context.jsonl +5 -0
- package/.claude/skills/workflow/flow-init/references/flow-researcher.md +132 -0
- package/.claude/skills/workflow/flow-init/scripts/check-prerequisites.sh +232 -0
- package/.claude/skills/workflow/flow-init/scripts/consolidate-research.sh +182 -0
- package/.claude/skills/workflow/flow-init/scripts/create-requirement.sh +515 -0
- package/.claude/skills/workflow/flow-init/scripts/generate-research-tasks.sh +157 -0
- package/.claude/skills/workflow/flow-init/scripts/populate-research-tasks.sh +284 -0
- package/.claude/skills/workflow/flow-init/scripts/validate-research.sh +332 -0
- package/.claude/skills/workflow/flow-quality/SKILL.md +94 -0
- package/.claude/skills/workflow/flow-quality/context.jsonl +6 -0
- package/.claude/skills/workflow/flow-quality/references/code-quality-reviewer.md +205 -0
- package/.claude/skills/workflow/flow-quality/references/qa-tester.md +313 -0
- package/.claude/skills/workflow/flow-quality/references/security-reviewer.md +314 -0
- package/.claude/skills/workflow/flow-quality/references/spec-reviewer.md +221 -0
- package/.claude/skills/workflow/flow-release/SKILL.md +126 -0
- package/.claude/skills/workflow/flow-release/context.jsonl +7 -0
- package/.claude/skills/workflow/flow-release/references/release-manager.md +295 -0
- package/.claude/skills/workflow/flow-spec/CLAUDE.md +103 -0
- package/.claude/skills/workflow/flow-spec/SKILL.md +545 -0
- package/.claude/skills/workflow/flow-spec/context.jsonl +7 -0
- package/.claude/skills/workflow/flow-spec/scripts/entry-gate.sh +194 -0
- package/.claude/skills/workflow/flow-spec/scripts/exit-gate.sh +244 -0
- package/.claude/skills/workflow/flow-spec/scripts/parallel-orchestrator.sh +205 -0
- package/.claude/skills/workflow/flow-spec/scripts/team-communication.sh +353 -0
- package/.claude/skills/workflow/flow-spec/scripts/team-init.sh +195 -0
- package/.claude/skills/workflow/flow-spec/scripts/test-team-mode.sh +496 -0
- package/.claude/skills/workflow/flow-spec/team-config.json +165 -0
- package/.claude/skills/workflow.yaml +417 -0
- package/CHANGELOG.md +254 -0
- package/README.md +193 -33
- package/README.zh-CN.md +206 -46
- package/lib/compiler/CLAUDE.md +77 -46
- package/lib/compiler/__tests__/multi-module-emitters.test.js +508 -0
- package/lib/compiler/context-expander.js +179 -0
- package/lib/compiler/emitters/antigravity-emitter.js +195 -5
- package/lib/compiler/emitters/base-emitter.js +217 -2
- package/lib/compiler/emitters/codex-emitter.js +200 -4
- package/lib/compiler/emitters/cursor-emitter.js +307 -3
- package/lib/compiler/emitters/qwen-emitter.js +196 -4
- package/lib/compiler/index.js +197 -2
- package/lib/compiler/platforms.js +270 -21
- package/package.json +1 -1
- package/.claude/commands/flow-epic.md +0 -183
- package/.claude/commands/flow-init.md +0 -370
- package/.claude/commands/flow-prd.md +0 -144
- package/.claude/commands/flow-qa.md +0 -93
- package/.claude/commands/flow-review.md +0 -257
- package/.claude/commands/flow-tech.md +0 -142
- package/.claude/commands/flow-ui.md +0 -189
- package/.claude/skills/file-header-guardian/SKILL.md +0 -56
- package/.claude/skills/skill-developer/ADVANCED.md +0 -197
- package/.claude/skills/skill-developer/HOOK_MECHANISMS.md +0 -306
- package/.claude/skills/skill-developer/PATTERNS_LIBRARY.md +0 -152
- package/.claude/skills/skill-developer/SKILL.md +0 -426
- package/.claude/skills/skill-developer/SKILL_RULES_REFERENCE.md +0 -315
- package/.claude/skills/skill-developer/TRIGGER_TYPES.md +0 -305
- package/.claude/skills/skill-developer/TROUBLESHOOTING.md +0 -514
- package/.claude/skills/writing-skills/SKILL.md +0 -655
- package/.claude/skills/writing-skills/anthropic-best-practices.md +0 -1150
- package/.claude/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +0 -189
- package/.claude/skills/writing-skills/graphviz-conventions.dot +0 -172
- package/.claude/skills/writing-skills/persuasion-principles.md +0 -187
- package/.claude/skills/writing-skills/render-graphs.js +0 -168
- package/.claude/skills/writing-skills/testing-skills-with-subagents.md +0 -384
- package/.claude/tsc-cache/795ba6e3-b98a-423b-bab2-51aa62812569/affected-repos.txt +0 -1
- package/.claude/tsc-cache/ae335694-be5a-4ba4-a1a0-b676c09a7906/affected-repos.txt +0 -1
- /package/.claude/commands/{core-architecture.md → core/architecture.md} +0 -0
- /package/.claude/commands/{core-guidelines.md → core/guidelines.md} +0 -0
- /package/.claude/commands/{core-roadmap.md → core/roadmap.md} +0 -0
- /package/.claude/commands/{core-style.md → core/style.md} +0 -0
- /package/.claude/commands/{flow-checklist.md → flow/checklist.md} +0 -0
- /package/.claude/commands/{flow-clarify.md → flow/clarify.md} +0 -0
- /package/.claude/commands/{flow-constitution.md → flow/constitution.md} +0 -0
- /package/.claude/commands/{flow-fix.md → flow/fix.md} +0 -0
- /package/.claude/commands/{flow-ideate.md → flow/ideate.md} +0 -0
- /package/.claude/commands/{flow-new.md → flow/new.md} +0 -0
- /package/.claude/commands/{flow-release.md → flow/release.md} +0 -0
- /package/.claude/commands/{flow-restart.md → flow/restart.md} +0 -0
- /package/.claude/commands/{flow-status.md → flow/status.md} +0 -0
- /package/.claude/commands/{flow-update.md → flow/update.md} +0 -0
- /package/.claude/commands/{flow-upgrade.md → flow/upgrade.md} +0 -0
- /package/.claude/commands/{flow-verify.md → flow/verify.md} +0 -0
- /package/.claude/commands/{code-review-high.md → util/code-review.md} +0 -0
- /package/.claude/commands/{git-commit.md → util/git-commit.md} +0 -0
- /package/.claude/commands/{problem-analyzer.md → util/problem-analyzer.md} +0 -0
- /package/.claude/skills/{flow-attention-refresh → domain/attention-refresh}/SKILL.md +0 -0
- /package/.claude/skills/{flow-brainstorming → domain/brainstorming}/SKILL.md +0 -0
- /package/.claude/skills/{flow-debugging → domain/debugging}/SKILL.md +0 -0
- /package/.claude/skills/{flow-finishing-branch → domain/finishing-branch}/SKILL.md +0 -0
- /package/.claude/skills/{flow-receiving-review → domain/receiving-review}/SKILL.md +0 -0
- /package/.claude/skills/{flow-tdd → domain/tdd}/SKILL.md +0 -0
- /package/.claude/skills/{verification-before-completion → domain/verification}/SKILL.md +0 -0
- /package/.claude/skills/{constitution-guardian → guardrail/constitution-guardian}/SKILL.md +0 -0
- /package/.claude/skills/{devflow-tdd-enforcer → guardrail/tdd-enforcer}/SKILL.md +0 -0
- /package/.claude/skills/{devflow-constitution-quick-ref → utility/constitution-quick-ref}/SKILL.md +0 -0
- /package/.claude/skills/{devflow-file-standards → utility/file-standards}/SKILL.md +0 -0
- /package/.claude/skills/{fractal-docs-generator → utility/fractal-docs}/SKILL.md +0 -0
- /package/.claude/skills/{npm-release → utility/npm-release}/SKILL.md +0 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# [INPUT]: 依赖 context/*.jsonl 文件
|
|
3
|
+
# [OUTPUT]: 追加条目到指定的 jsonl 文件
|
|
4
|
+
# [POS]: scripts 的 context 添加脚本,被 /flow-context add 调用
|
|
5
|
+
# [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
|
|
6
|
+
|
|
7
|
+
set -e
|
|
8
|
+
|
|
9
|
+
# ============================================================================
|
|
10
|
+
# Usage
|
|
11
|
+
# ============================================================================
|
|
12
|
+
|
|
13
|
+
usage() {
|
|
14
|
+
cat << EOF
|
|
15
|
+
Usage: flow-context-add.sh <agent> <path> <purpose> [--optional] [--type <file|directory|spec>]
|
|
16
|
+
|
|
17
|
+
Add an entry to a context JSONL file.
|
|
18
|
+
|
|
19
|
+
Arguments:
|
|
20
|
+
agent Agent type (research, prd, tech, epic, dev, review)
|
|
21
|
+
path File or directory path
|
|
22
|
+
purpose Human-readable purpose
|
|
23
|
+
|
|
24
|
+
Options:
|
|
25
|
+
--optional Mark entry as optional
|
|
26
|
+
--type Entry type (default: file)
|
|
27
|
+
--depth Directory depth (only for directory type, default: 1)
|
|
28
|
+
|
|
29
|
+
Examples:
|
|
30
|
+
flow-context-add.sh dev "src/utils/auth.ts" "Authentication utilities"
|
|
31
|
+
flow-context-add.sh dev "contracts/" "API contracts" --type directory --depth 2
|
|
32
|
+
flow-context-add.sh dev "ERROR_LOG.md" "Previous errors" --optional
|
|
33
|
+
EOF
|
|
34
|
+
exit 1
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
# ============================================================================
|
|
38
|
+
# Parse Arguments
|
|
39
|
+
# ============================================================================
|
|
40
|
+
|
|
41
|
+
AGENT=""
|
|
42
|
+
PATH_ARG=""
|
|
43
|
+
PURPOSE=""
|
|
44
|
+
OPTIONAL="false"
|
|
45
|
+
ENTRY_TYPE="file"
|
|
46
|
+
DEPTH=1
|
|
47
|
+
|
|
48
|
+
while [[ $# -gt 0 ]]; do
|
|
49
|
+
case $1 in
|
|
50
|
+
--optional)
|
|
51
|
+
OPTIONAL="true"
|
|
52
|
+
shift
|
|
53
|
+
;;
|
|
54
|
+
--type)
|
|
55
|
+
ENTRY_TYPE="$2"
|
|
56
|
+
shift 2
|
|
57
|
+
;;
|
|
58
|
+
--depth)
|
|
59
|
+
DEPTH="$2"
|
|
60
|
+
shift 2
|
|
61
|
+
;;
|
|
62
|
+
--help|-h)
|
|
63
|
+
usage
|
|
64
|
+
;;
|
|
65
|
+
*)
|
|
66
|
+
if [[ -z "$AGENT" ]]; then
|
|
67
|
+
AGENT="$1"
|
|
68
|
+
elif [[ -z "$PATH_ARG" ]]; then
|
|
69
|
+
PATH_ARG="$1"
|
|
70
|
+
elif [[ -z "$PURPOSE" ]]; then
|
|
71
|
+
PURPOSE="$1"
|
|
72
|
+
fi
|
|
73
|
+
shift
|
|
74
|
+
;;
|
|
75
|
+
esac
|
|
76
|
+
done
|
|
77
|
+
|
|
78
|
+
if [[ -z "$AGENT" || -z "$PATH_ARG" || -z "$PURPOSE" ]]; then
|
|
79
|
+
echo "Error: agent, path, and purpose are required"
|
|
80
|
+
usage
|
|
81
|
+
fi
|
|
82
|
+
|
|
83
|
+
# ============================================================================
|
|
84
|
+
# Detect REQ-ID
|
|
85
|
+
# ============================================================================
|
|
86
|
+
|
|
87
|
+
# Try environment variable first
|
|
88
|
+
REQ_ID="${DEVFLOW_REQ_ID:-}"
|
|
89
|
+
|
|
90
|
+
# Try git branch
|
|
91
|
+
if [[ -z "$REQ_ID" ]]; then
|
|
92
|
+
BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
|
|
93
|
+
REQ_ID=$(echo "$BRANCH" | grep -oE 'REQ-[0-9]+' | head -1 || echo "")
|
|
94
|
+
fi
|
|
95
|
+
|
|
96
|
+
if [[ -z "$REQ_ID" ]]; then
|
|
97
|
+
echo "Error: Could not detect REQ-ID. Set DEVFLOW_REQ_ID or use a feature branch."
|
|
98
|
+
exit 1
|
|
99
|
+
fi
|
|
100
|
+
|
|
101
|
+
# ============================================================================
|
|
102
|
+
# Main Logic
|
|
103
|
+
# ============================================================================
|
|
104
|
+
|
|
105
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
106
|
+
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
107
|
+
CONTEXT_FILE="$PROJECT_ROOT/devflow/requirements/$REQ_ID/context/${AGENT}.jsonl"
|
|
108
|
+
|
|
109
|
+
if [[ ! -f "$CONTEXT_FILE" ]]; then
|
|
110
|
+
echo "Error: Context file not found: $CONTEXT_FILE"
|
|
111
|
+
echo "Run '/flow-context init $REQ_ID' first."
|
|
112
|
+
exit 1
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
# Build JSON entry
|
|
116
|
+
if [[ "$ENTRY_TYPE" == "directory" ]]; then
|
|
117
|
+
if [[ "$OPTIONAL" == "true" ]]; then
|
|
118
|
+
ENTRY="{\"type\": \"$ENTRY_TYPE\", \"path\": \"$PATH_ARG\", \"purpose\": \"$PURPOSE\", \"depth\": $DEPTH, \"optional\": true}"
|
|
119
|
+
else
|
|
120
|
+
ENTRY="{\"type\": \"$ENTRY_TYPE\", \"path\": \"$PATH_ARG\", \"purpose\": \"$PURPOSE\", \"depth\": $DEPTH}"
|
|
121
|
+
fi
|
|
122
|
+
else
|
|
123
|
+
if [[ "$OPTIONAL" == "true" ]]; then
|
|
124
|
+
ENTRY="{\"type\": \"$ENTRY_TYPE\", \"path\": \"$PATH_ARG\", \"purpose\": \"$PURPOSE\", \"optional\": true}"
|
|
125
|
+
else
|
|
126
|
+
ENTRY="{\"type\": \"$ENTRY_TYPE\", \"path\": \"$PATH_ARG\", \"purpose\": \"$PURPOSE\"}"
|
|
127
|
+
fi
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
# Append to file
|
|
131
|
+
echo "$ENTRY" >> "$CONTEXT_FILE"
|
|
132
|
+
|
|
133
|
+
echo "✅ Added entry to $CONTEXT_FILE:"
|
|
134
|
+
echo " $ENTRY"
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# [INPUT]: 依赖 .claude/docs/templates/context/*.jsonl.template
|
|
3
|
+
# [OUTPUT]: 创建 devflow/requirements/{REQ}/context/ 目录
|
|
4
|
+
# [POS]: scripts 的 context 初始化脚本,被 /flow-context init 调用
|
|
5
|
+
# [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
|
|
6
|
+
|
|
7
|
+
set -e
|
|
8
|
+
|
|
9
|
+
# ============================================================================
|
|
10
|
+
# Configuration
|
|
11
|
+
# ============================================================================
|
|
12
|
+
|
|
13
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
14
|
+
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
15
|
+
TEMPLATES_DIR="$PROJECT_ROOT/.claude/docs/templates/context"
|
|
16
|
+
|
|
17
|
+
# ============================================================================
|
|
18
|
+
# Usage
|
|
19
|
+
# ============================================================================
|
|
20
|
+
|
|
21
|
+
usage() {
|
|
22
|
+
cat << EOF
|
|
23
|
+
Usage: flow-context-init.sh <REQ-ID> [--type <backend|frontend|fullstack>]
|
|
24
|
+
|
|
25
|
+
Initialize context directory for a requirement.
|
|
26
|
+
|
|
27
|
+
Arguments:
|
|
28
|
+
REQ-ID Requirement ID (e.g., REQ-007)
|
|
29
|
+
|
|
30
|
+
Options:
|
|
31
|
+
--type Project type (default: fullstack)
|
|
32
|
+
- backend: Exclude frontend specs
|
|
33
|
+
- frontend: Exclude backend specs
|
|
34
|
+
- fullstack: Include all specs
|
|
35
|
+
|
|
36
|
+
Examples:
|
|
37
|
+
flow-context-init.sh REQ-007
|
|
38
|
+
flow-context-init.sh REQ-007 --type backend
|
|
39
|
+
EOF
|
|
40
|
+
exit 1
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
# ============================================================================
|
|
44
|
+
# Parse Arguments
|
|
45
|
+
# ============================================================================
|
|
46
|
+
|
|
47
|
+
REQ_ID=""
|
|
48
|
+
PROJECT_TYPE="fullstack"
|
|
49
|
+
|
|
50
|
+
while [[ $# -gt 0 ]]; do
|
|
51
|
+
case $1 in
|
|
52
|
+
--type)
|
|
53
|
+
PROJECT_TYPE="$2"
|
|
54
|
+
shift 2
|
|
55
|
+
;;
|
|
56
|
+
--help|-h)
|
|
57
|
+
usage
|
|
58
|
+
;;
|
|
59
|
+
*)
|
|
60
|
+
if [[ -z "$REQ_ID" ]]; then
|
|
61
|
+
REQ_ID="$1"
|
|
62
|
+
fi
|
|
63
|
+
shift
|
|
64
|
+
;;
|
|
65
|
+
esac
|
|
66
|
+
done
|
|
67
|
+
|
|
68
|
+
if [[ -z "$REQ_ID" ]]; then
|
|
69
|
+
echo "Error: REQ-ID is required"
|
|
70
|
+
usage
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
# Validate REQ-ID format
|
|
74
|
+
if [[ ! "$REQ_ID" =~ ^REQ-[0-9]+$ ]]; then
|
|
75
|
+
echo "Error: Invalid REQ-ID format. Expected REQ-XXX (e.g., REQ-007)"
|
|
76
|
+
exit 1
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
# ============================================================================
|
|
80
|
+
# Main Logic
|
|
81
|
+
# ============================================================================
|
|
82
|
+
|
|
83
|
+
REQ_DIR="$PROJECT_ROOT/devflow/requirements/$REQ_ID"
|
|
84
|
+
CONTEXT_DIR="$REQ_DIR/context"
|
|
85
|
+
|
|
86
|
+
# Check if requirement directory exists
|
|
87
|
+
if [[ ! -d "$REQ_DIR" ]]; then
|
|
88
|
+
echo "Error: Requirement directory not found: $REQ_DIR"
|
|
89
|
+
exit 1
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
# Create context directory
|
|
93
|
+
mkdir -p "$CONTEXT_DIR"
|
|
94
|
+
|
|
95
|
+
echo "Initializing context for $REQ_ID (type: $PROJECT_TYPE)..."
|
|
96
|
+
|
|
97
|
+
# Copy templates
|
|
98
|
+
for template in "$TEMPLATES_DIR"/*.jsonl.template; do
|
|
99
|
+
if [[ -f "$template" ]]; then
|
|
100
|
+
filename=$(basename "$template" .template)
|
|
101
|
+
target="$CONTEXT_DIR/$filename"
|
|
102
|
+
|
|
103
|
+
# Skip if already exists
|
|
104
|
+
if [[ -f "$target" ]]; then
|
|
105
|
+
echo " ⏭️ Skipping $filename (already exists)"
|
|
106
|
+
continue
|
|
107
|
+
fi
|
|
108
|
+
|
|
109
|
+
# Copy and filter based on project type
|
|
110
|
+
case $PROJECT_TYPE in
|
|
111
|
+
backend)
|
|
112
|
+
# Remove frontend spec entries
|
|
113
|
+
grep -v 'devflow/spec/frontend' "$template" > "$target" || cp "$template" "$target"
|
|
114
|
+
;;
|
|
115
|
+
frontend)
|
|
116
|
+
# Remove backend spec entries
|
|
117
|
+
grep -v 'devflow/spec/backend' "$template" > "$target" || cp "$template" "$target"
|
|
118
|
+
;;
|
|
119
|
+
*)
|
|
120
|
+
# Copy as-is
|
|
121
|
+
cp "$template" "$target"
|
|
122
|
+
;;
|
|
123
|
+
esac
|
|
124
|
+
|
|
125
|
+
echo " ✅ Created $filename"
|
|
126
|
+
fi
|
|
127
|
+
done
|
|
128
|
+
|
|
129
|
+
echo ""
|
|
130
|
+
echo "Context initialized at: $CONTEXT_DIR"
|
|
131
|
+
echo ""
|
|
132
|
+
echo "Files created:"
|
|
133
|
+
ls -la "$CONTEXT_DIR"
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# [INPUT]: 依赖 context/*.jsonl 文件
|
|
3
|
+
# [OUTPUT]: 验证结果输出到 stdout
|
|
4
|
+
# [POS]: scripts 的 context 验证脚本,被 /flow-context validate 调用
|
|
5
|
+
# [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
|
|
6
|
+
|
|
7
|
+
set -e
|
|
8
|
+
|
|
9
|
+
# ============================================================================
|
|
10
|
+
# Usage
|
|
11
|
+
# ============================================================================
|
|
12
|
+
|
|
13
|
+
usage() {
|
|
14
|
+
cat << EOF
|
|
15
|
+
Usage: flow-context-validate.sh [REQ-ID]
|
|
16
|
+
|
|
17
|
+
Validate all context paths exist for a requirement.
|
|
18
|
+
|
|
19
|
+
Arguments:
|
|
20
|
+
REQ-ID Requirement ID (optional, auto-detected from branch)
|
|
21
|
+
|
|
22
|
+
Examples:
|
|
23
|
+
flow-context-validate.sh REQ-007
|
|
24
|
+
flow-context-validate.sh
|
|
25
|
+
EOF
|
|
26
|
+
exit 1
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
# ============================================================================
|
|
30
|
+
# Parse Arguments
|
|
31
|
+
# ============================================================================
|
|
32
|
+
|
|
33
|
+
REQ_ID="$1"
|
|
34
|
+
|
|
35
|
+
# Auto-detect REQ-ID if not provided
|
|
36
|
+
if [[ -z "$REQ_ID" ]]; then
|
|
37
|
+
REQ_ID="${DEVFLOW_REQ_ID:-}"
|
|
38
|
+
|
|
39
|
+
if [[ -z "$REQ_ID" ]]; then
|
|
40
|
+
BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")
|
|
41
|
+
REQ_ID=$(echo "$BRANCH" | grep -oE 'REQ-[0-9]+' | head -1 || echo "")
|
|
42
|
+
fi
|
|
43
|
+
fi
|
|
44
|
+
|
|
45
|
+
if [[ -z "$REQ_ID" ]]; then
|
|
46
|
+
echo "Error: Could not detect REQ-ID. Provide it as argument or set DEVFLOW_REQ_ID."
|
|
47
|
+
usage
|
|
48
|
+
fi
|
|
49
|
+
|
|
50
|
+
# ============================================================================
|
|
51
|
+
# Main Logic
|
|
52
|
+
# ============================================================================
|
|
53
|
+
|
|
54
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
55
|
+
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
56
|
+
REQ_DIR="$PROJECT_ROOT/devflow/requirements/$REQ_ID"
|
|
57
|
+
CONTEXT_DIR="$REQ_DIR/context"
|
|
58
|
+
|
|
59
|
+
if [[ ! -d "$CONTEXT_DIR" ]]; then
|
|
60
|
+
echo "Error: Context directory not found: $CONTEXT_DIR"
|
|
61
|
+
echo "Run '/flow-context init $REQ_ID' first."
|
|
62
|
+
exit 1
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
echo "Validating context for $REQ_ID..."
|
|
66
|
+
echo ""
|
|
67
|
+
|
|
68
|
+
TOTAL_VALID=0
|
|
69
|
+
TOTAL_INVALID=0
|
|
70
|
+
TOTAL_OPTIONAL_MISSING=0
|
|
71
|
+
|
|
72
|
+
for jsonl_file in "$CONTEXT_DIR"/*.jsonl; do
|
|
73
|
+
if [[ ! -f "$jsonl_file" ]]; then
|
|
74
|
+
continue
|
|
75
|
+
fi
|
|
76
|
+
|
|
77
|
+
filename=$(basename "$jsonl_file")
|
|
78
|
+
valid=0
|
|
79
|
+
invalid=0
|
|
80
|
+
missing_paths=()
|
|
81
|
+
|
|
82
|
+
while IFS= read -r line || [[ -n "$line" ]]; do
|
|
83
|
+
# Skip empty lines and comments
|
|
84
|
+
[[ -z "$line" || "$line" =~ ^[[:space:]]*# || "$line" =~ ^[[:space:]]*// ]] && continue
|
|
85
|
+
|
|
86
|
+
# Parse JSON (basic extraction)
|
|
87
|
+
path=$(echo "$line" | grep -oP '"path"\s*:\s*"\K[^"]+' || echo "")
|
|
88
|
+
type=$(echo "$line" | grep -oP '"type"\s*:\s*"\K[^"]+' || echo "file")
|
|
89
|
+
optional=$(echo "$line" | grep -oP '"optional"\s*:\s*\K(true|false)' || echo "false")
|
|
90
|
+
|
|
91
|
+
if [[ -z "$path" ]]; then
|
|
92
|
+
continue
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
# Resolve path
|
|
96
|
+
if [[ "$type" == "spec" ]]; then
|
|
97
|
+
full_path="$PROJECT_ROOT/$path"
|
|
98
|
+
else
|
|
99
|
+
full_path="$REQ_DIR/$path"
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
# Check existence
|
|
103
|
+
if [[ -e "$full_path" ]]; then
|
|
104
|
+
((valid++))
|
|
105
|
+
else
|
|
106
|
+
if [[ "$optional" == "true" ]]; then
|
|
107
|
+
((TOTAL_OPTIONAL_MISSING++))
|
|
108
|
+
else
|
|
109
|
+
((invalid++))
|
|
110
|
+
missing_paths+=("$path")
|
|
111
|
+
fi
|
|
112
|
+
fi
|
|
113
|
+
done < "$jsonl_file"
|
|
114
|
+
|
|
115
|
+
TOTAL_VALID=$((TOTAL_VALID + valid))
|
|
116
|
+
TOTAL_INVALID=$((TOTAL_INVALID + invalid))
|
|
117
|
+
|
|
118
|
+
total=$((valid + invalid))
|
|
119
|
+
if [[ $invalid -eq 0 ]]; then
|
|
120
|
+
echo " ✓ $filename: $valid/$total paths valid"
|
|
121
|
+
else
|
|
122
|
+
echo " ✗ $filename: $valid/$total paths valid"
|
|
123
|
+
for mp in "${missing_paths[@]}"; do
|
|
124
|
+
echo " - Missing: $mp"
|
|
125
|
+
done
|
|
126
|
+
fi
|
|
127
|
+
done
|
|
128
|
+
|
|
129
|
+
echo ""
|
|
130
|
+
GRAND_TOTAL=$((TOTAL_VALID + TOTAL_INVALID))
|
|
131
|
+
if [[ $GRAND_TOTAL -gt 0 ]]; then
|
|
132
|
+
PERCENT=$((TOTAL_VALID * 100 / GRAND_TOTAL))
|
|
133
|
+
echo "Overall: $TOTAL_VALID/$GRAND_TOTAL paths valid ($PERCENT%)"
|
|
134
|
+
if [[ $TOTAL_OPTIONAL_MISSING -gt 0 ]]; then
|
|
135
|
+
echo "Optional missing: $TOTAL_OPTIONAL_MISSING (not counted in validation)"
|
|
136
|
+
fi
|
|
137
|
+
else
|
|
138
|
+
echo "No context entries found."
|
|
139
|
+
fi
|
|
140
|
+
|
|
141
|
+
# Exit with error if any required paths are missing
|
|
142
|
+
if [[ $TOTAL_INVALID -gt 0 ]]; then
|
|
143
|
+
exit 1
|
|
144
|
+
fi
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# [INPUT]: 依赖 deltas/{delta-id}/delta.md, delta-parser.ts
|
|
3
|
+
# [OUTPUT]: 应用 delta 到 PRD.md,移动到 archive/
|
|
4
|
+
# [POS]: scripts 的 delta spec 应用脚本,被 /flow:delta apply 调用
|
|
5
|
+
# [PROTOCOL]: 变更时更新此头部,然后检查 CLAUDE.md
|
|
6
|
+
|
|
7
|
+
set -e
|
|
8
|
+
|
|
9
|
+
# ============================================================================
|
|
10
|
+
# Configuration
|
|
11
|
+
# ============================================================================
|
|
12
|
+
|
|
13
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
14
|
+
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
|
|
15
|
+
PARSER_SCRIPT="$SCRIPT_DIR/delta-parser.ts"
|
|
16
|
+
ARCHIVE_DIR="$PROJECT_ROOT/devflow/archive"
|
|
17
|
+
|
|
18
|
+
# ============================================================================
|
|
19
|
+
# Usage
|
|
20
|
+
# ============================================================================
|
|
21
|
+
|
|
22
|
+
usage() {
|
|
23
|
+
cat << EOF
|
|
24
|
+
Usage: flow-delta-apply.sh <REQ-ID> <delta-slug> [--dry-run] [--force]
|
|
25
|
+
|
|
26
|
+
Apply a delta spec to the main PRD.md specification.
|
|
27
|
+
|
|
28
|
+
Arguments:
|
|
29
|
+
REQ-ID Requirement ID (e.g., REQ-123)
|
|
30
|
+
delta-slug Delta identifier (e.g., add-2fa or 2026-02-01-add-2fa)
|
|
31
|
+
|
|
32
|
+
Options:
|
|
33
|
+
--dry-run Show what would be done without making changes
|
|
34
|
+
--force Apply even if status is not 'approved'
|
|
35
|
+
--all Apply all approved deltas
|
|
36
|
+
|
|
37
|
+
Examples:
|
|
38
|
+
flow-delta-apply.sh REQ-123 add-2fa
|
|
39
|
+
flow-delta-apply.sh REQ-123 add-2fa --dry-run
|
|
40
|
+
flow-delta-apply.sh REQ-123 --all
|
|
41
|
+
EOF
|
|
42
|
+
exit 1
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
# ============================================================================
|
|
46
|
+
# Parse Arguments
|
|
47
|
+
# ============================================================================
|
|
48
|
+
|
|
49
|
+
REQ_ID=""
|
|
50
|
+
DELTA_SLUG=""
|
|
51
|
+
DRY_RUN=false
|
|
52
|
+
FORCE=false
|
|
53
|
+
APPLY_ALL=false
|
|
54
|
+
|
|
55
|
+
while [[ $# -gt 0 ]]; do
|
|
56
|
+
case $1 in
|
|
57
|
+
--dry-run)
|
|
58
|
+
DRY_RUN=true
|
|
59
|
+
shift
|
|
60
|
+
;;
|
|
61
|
+
--force)
|
|
62
|
+
FORCE=true
|
|
63
|
+
shift
|
|
64
|
+
;;
|
|
65
|
+
--all)
|
|
66
|
+
APPLY_ALL=true
|
|
67
|
+
shift
|
|
68
|
+
;;
|
|
69
|
+
--help|-h)
|
|
70
|
+
usage
|
|
71
|
+
;;
|
|
72
|
+
*)
|
|
73
|
+
if [[ -z "$REQ_ID" ]]; then
|
|
74
|
+
REQ_ID="$1"
|
|
75
|
+
elif [[ -z "$DELTA_SLUG" ]]; then
|
|
76
|
+
DELTA_SLUG="$1"
|
|
77
|
+
fi
|
|
78
|
+
shift
|
|
79
|
+
;;
|
|
80
|
+
esac
|
|
81
|
+
done
|
|
82
|
+
|
|
83
|
+
if [[ -z "$REQ_ID" ]]; then
|
|
84
|
+
echo "Error: REQ-ID is required"
|
|
85
|
+
usage
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
if [[ -z "$DELTA_SLUG" && "$APPLY_ALL" != "true" ]]; then
|
|
89
|
+
echo "Error: delta-slug is required (or use --all)"
|
|
90
|
+
usage
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
# Validate REQ-ID format
|
|
94
|
+
if [[ ! "$REQ_ID" =~ ^REQ-[0-9]+$ ]]; then
|
|
95
|
+
echo "Error: Invalid REQ-ID format. Expected: REQ-XXX"
|
|
96
|
+
exit 1
|
|
97
|
+
fi
|
|
98
|
+
|
|
99
|
+
# ============================================================================
|
|
100
|
+
# Helper Functions
|
|
101
|
+
# ============================================================================
|
|
102
|
+
|
|
103
|
+
find_delta_dir() {
|
|
104
|
+
local req_dir="$1"
|
|
105
|
+
local slug="$2"
|
|
106
|
+
local deltas_dir="$req_dir/deltas"
|
|
107
|
+
|
|
108
|
+
# Try exact match first
|
|
109
|
+
if [[ -d "$deltas_dir/$slug" ]]; then
|
|
110
|
+
echo "$deltas_dir/$slug"
|
|
111
|
+
return 0
|
|
112
|
+
fi
|
|
113
|
+
|
|
114
|
+
# Try to find by suffix (slug without date prefix)
|
|
115
|
+
for dir in "$deltas_dir"/*-"$slug"; do
|
|
116
|
+
if [[ -d "$dir" ]]; then
|
|
117
|
+
echo "$dir"
|
|
118
|
+
return 0
|
|
119
|
+
fi
|
|
120
|
+
done
|
|
121
|
+
|
|
122
|
+
return 1
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
get_delta_status() {
|
|
126
|
+
local delta_file="$1"
|
|
127
|
+
grep -E '^status:' "$delta_file" | head -1 | sed 's/status:[[:space:]]*"\?\([^"]*\)"\?/\1/'
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
update_delta_status() {
|
|
131
|
+
local delta_file="$1"
|
|
132
|
+
local new_status="$2"
|
|
133
|
+
|
|
134
|
+
if $DRY_RUN; then
|
|
135
|
+
echo " [DRY-RUN] Would update status to '$new_status'"
|
|
136
|
+
return 0
|
|
137
|
+
fi
|
|
138
|
+
|
|
139
|
+
# Use sed to update status in frontmatter
|
|
140
|
+
if [[ "$(uname)" == "Darwin" ]]; then
|
|
141
|
+
sed -i '' "s/^status:.*$/status: \"$new_status\"/" "$delta_file"
|
|
142
|
+
else
|
|
143
|
+
sed -i "s/^status:.*$/status: \"$new_status\"/" "$delta_file"
|
|
144
|
+
fi
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
apply_single_delta() {
|
|
148
|
+
local delta_dir="$1"
|
|
149
|
+
local delta_id=$(basename "$delta_dir")
|
|
150
|
+
local delta_file="$delta_dir/delta.md"
|
|
151
|
+
local prd_file="$REQ_DIR/PRD.md"
|
|
152
|
+
|
|
153
|
+
echo "Applying delta: $delta_id"
|
|
154
|
+
|
|
155
|
+
# Check delta file exists
|
|
156
|
+
if [[ ! -f "$delta_file" ]]; then
|
|
157
|
+
echo " Error: Delta file not found: $delta_file"
|
|
158
|
+
return 1
|
|
159
|
+
fi
|
|
160
|
+
|
|
161
|
+
# Check PRD.md exists
|
|
162
|
+
if [[ ! -f "$prd_file" ]]; then
|
|
163
|
+
echo " Error: PRD.md not found: $prd_file"
|
|
164
|
+
return 1
|
|
165
|
+
fi
|
|
166
|
+
|
|
167
|
+
# Check status
|
|
168
|
+
local status=$(get_delta_status "$delta_file")
|
|
169
|
+
if [[ "$status" != "approved" && "$FORCE" != "true" ]]; then
|
|
170
|
+
echo " Error: Delta status is '$status', expected 'approved'"
|
|
171
|
+
echo " Use --force to apply anyway"
|
|
172
|
+
return 1
|
|
173
|
+
fi
|
|
174
|
+
|
|
175
|
+
# Check if parser exists
|
|
176
|
+
if [[ ! -f "$PARSER_SCRIPT" ]]; then
|
|
177
|
+
echo " Error: Delta parser not found: $PARSER_SCRIPT"
|
|
178
|
+
echo " Falling back to simple copy..."
|
|
179
|
+
|
|
180
|
+
if $DRY_RUN; then
|
|
181
|
+
echo " [DRY-RUN] Would apply delta to PRD.md"
|
|
182
|
+
else
|
|
183
|
+
# Simple fallback: just log that we would apply
|
|
184
|
+
echo " Warning: Full delta parsing not available"
|
|
185
|
+
echo " Please manually review and apply changes from: $delta_file"
|
|
186
|
+
fi
|
|
187
|
+
return 0
|
|
188
|
+
fi
|
|
189
|
+
|
|
190
|
+
# Apply delta using TypeScript parser
|
|
191
|
+
if $DRY_RUN; then
|
|
192
|
+
echo " [DRY-RUN] Would apply delta to PRD.md"
|
|
193
|
+
echo " Parsing delta..."
|
|
194
|
+
npx ts-node "$PARSER_SCRIPT" parse "$delta_file" 2>/dev/null || {
|
|
195
|
+
echo " Warning: Could not parse delta (ts-node may not be available)"
|
|
196
|
+
}
|
|
197
|
+
else
|
|
198
|
+
echo " Applying changes to PRD.md..."
|
|
199
|
+
|
|
200
|
+
# Create backup
|
|
201
|
+
cp "$prd_file" "$prd_file.bak"
|
|
202
|
+
|
|
203
|
+
# Apply delta
|
|
204
|
+
if npx ts-node "$PARSER_SCRIPT" apply "$prd_file" "$delta_file" > "$prd_file.new" 2>/dev/null; then
|
|
205
|
+
mv "$prd_file.new" "$prd_file"
|
|
206
|
+
rm "$prd_file.bak"
|
|
207
|
+
echo " ✓ Changes applied to PRD.md"
|
|
208
|
+
else
|
|
209
|
+
echo " Warning: TypeScript parser failed, using fallback"
|
|
210
|
+
rm -f "$prd_file.new"
|
|
211
|
+
mv "$prd_file.bak" "$prd_file"
|
|
212
|
+
echo " Please manually review and apply changes from: $delta_file"
|
|
213
|
+
fi
|
|
214
|
+
|
|
215
|
+
# Update status
|
|
216
|
+
update_delta_status "$delta_file" "applied"
|
|
217
|
+
echo " ✓ Status updated to 'applied'"
|
|
218
|
+
|
|
219
|
+
# Archive delta
|
|
220
|
+
local date_prefix=$(date +"%Y-%m")
|
|
221
|
+
local archive_target="$ARCHIVE_DIR/$date_prefix/$REQ_ID/deltas/$delta_id"
|
|
222
|
+
|
|
223
|
+
mkdir -p "$archive_target"
|
|
224
|
+
cp -r "$delta_dir"/* "$archive_target/"
|
|
225
|
+
rm -rf "$delta_dir"
|
|
226
|
+
|
|
227
|
+
echo " ✓ Archived to: $archive_target"
|
|
228
|
+
fi
|
|
229
|
+
|
|
230
|
+
return 0
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
# ============================================================================
|
|
234
|
+
# Main Logic
|
|
235
|
+
# ============================================================================
|
|
236
|
+
|
|
237
|
+
REQ_DIR="$PROJECT_ROOT/devflow/requirements/$REQ_ID"
|
|
238
|
+
DELTAS_DIR="$REQ_DIR/deltas"
|
|
239
|
+
|
|
240
|
+
if [[ ! -d "$REQ_DIR" ]]; then
|
|
241
|
+
echo "Error: Requirement directory not found: $REQ_DIR"
|
|
242
|
+
exit 1
|
|
243
|
+
fi
|
|
244
|
+
|
|
245
|
+
if [[ ! -d "$DELTAS_DIR" ]]; then
|
|
246
|
+
echo "No deltas found for $REQ_ID"
|
|
247
|
+
exit 0
|
|
248
|
+
fi
|
|
249
|
+
|
|
250
|
+
if $APPLY_ALL; then
|
|
251
|
+
echo "Applying all approved deltas for $REQ_ID..."
|
|
252
|
+
echo ""
|
|
253
|
+
|
|
254
|
+
APPLIED=0
|
|
255
|
+
SKIPPED=0
|
|
256
|
+
|
|
257
|
+
for delta_dir in "$DELTAS_DIR"/*/; do
|
|
258
|
+
if [[ ! -d "$delta_dir" ]]; then
|
|
259
|
+
continue
|
|
260
|
+
fi
|
|
261
|
+
|
|
262
|
+
delta_file="$delta_dir/delta.md"
|
|
263
|
+
if [[ ! -f "$delta_file" ]]; then
|
|
264
|
+
continue
|
|
265
|
+
fi
|
|
266
|
+
|
|
267
|
+
status=$(get_delta_status "$delta_file")
|
|
268
|
+
if [[ "$status" == "approved" ]]; then
|
|
269
|
+
if apply_single_delta "$delta_dir"; then
|
|
270
|
+
((APPLIED++))
|
|
271
|
+
fi
|
|
272
|
+
else
|
|
273
|
+
((SKIPPED++))
|
|
274
|
+
fi
|
|
275
|
+
echo ""
|
|
276
|
+
done
|
|
277
|
+
|
|
278
|
+
echo "Summary: $APPLIED applied, $SKIPPED skipped (not approved)"
|
|
279
|
+
else
|
|
280
|
+
# Find the specific delta
|
|
281
|
+
DELTA_DIR=$(find_delta_dir "$REQ_DIR" "$DELTA_SLUG")
|
|
282
|
+
|
|
283
|
+
if [[ -z "$DELTA_DIR" || ! -d "$DELTA_DIR" ]]; then
|
|
284
|
+
echo "Error: Delta not found: $DELTA_SLUG"
|
|
285
|
+
echo "Available deltas:"
|
|
286
|
+
ls -1 "$DELTAS_DIR" 2>/dev/null || echo " (none)"
|
|
287
|
+
exit 1
|
|
288
|
+
fi
|
|
289
|
+
|
|
290
|
+
apply_single_delta "$DELTA_DIR"
|
|
291
|
+
fi
|
|
292
|
+
|
|
293
|
+
echo ""
|
|
294
|
+
if $DRY_RUN; then
|
|
295
|
+
echo "This was a dry run. No changes were made."
|
|
296
|
+
echo "Run without --dry-run to apply changes."
|
|
297
|
+
fi
|