ruby_reactor 0.5.4 → 0.6.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.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/skills/speckit-agent-context-update/SKILL.md +32 -0
  3. data/.claude/skills/speckit-analyze/SKILL.md +262 -0
  4. data/.claude/skills/speckit-checklist/SKILL.md +374 -0
  5. data/.claude/skills/speckit-clarify/SKILL.md +286 -0
  6. data/.claude/skills/speckit-constitution/SKILL.md +157 -0
  7. data/.claude/skills/speckit-converge/SKILL.md +277 -0
  8. data/.claude/skills/speckit-implement/SKILL.md +224 -0
  9. data/.claude/skills/speckit-plan/SKILL.md +171 -0
  10. data/.claude/skills/speckit-specify/SKILL.md +346 -0
  11. data/.claude/skills/speckit-tasks/SKILL.md +215 -0
  12. data/.claude/skills/speckit-taskstoissues/SKILL.md +110 -0
  13. data/.release-please-manifest.json +1 -1
  14. data/.specify/extensions/.registry +19 -0
  15. data/.specify/extensions/agent-context/README.md +66 -0
  16. data/.specify/extensions/agent-context/agent-context-config.yml +5 -0
  17. data/.specify/extensions/agent-context/commands/speckit.agent-context.update.md +27 -0
  18. data/.specify/extensions/agent-context/extension.yml +34 -0
  19. data/.specify/extensions/agent-context/scripts/bash/update-agent-context.sh +282 -0
  20. data/.specify/extensions/agent-context/scripts/powershell/update-agent-context.ps1 +353 -0
  21. data/.specify/extensions.yml +23 -0
  22. data/.specify/feature.json +3 -0
  23. data/.specify/init-options.json +9 -0
  24. data/.specify/integration.json +15 -0
  25. data/.specify/integrations/claude.manifest.json +17 -0
  26. data/.specify/integrations/speckit.manifest.json +17 -0
  27. data/.specify/memory/constitution.md +134 -0
  28. data/.specify/scripts/bash/check-prerequisites.sh +189 -0
  29. data/.specify/scripts/bash/common.sh +619 -0
  30. data/.specify/scripts/bash/create-new-feature.sh +299 -0
  31. data/.specify/scripts/bash/setup-plan.sh +84 -0
  32. data/.specify/scripts/bash/setup-tasks.sh +91 -0
  33. data/.specify/templates/checklist-template.md +40 -0
  34. data/.specify/templates/constitution-template.md +50 -0
  35. data/.specify/templates/plan-template.md +113 -0
  36. data/.specify/templates/spec-template.md +131 -0
  37. data/.specify/templates/tasks-template.md +252 -0
  38. data/.specify/workflows/speckit/workflow.yml +77 -0
  39. data/.specify/workflows/workflow-registry.json +13 -0
  40. data/CHANGELOG.md +7 -0
  41. data/README.md +51 -24
  42. data/lib/ruby_reactor/adapters/active_job/compat.rb +24 -0
  43. data/lib/ruby_reactor/adapters/active_job/map_collector_worker.rb +19 -0
  44. data/lib/ruby_reactor/adapters/active_job/map_element_worker.rb +19 -0
  45. data/lib/ruby_reactor/adapters/active_job/router.rb +91 -0
  46. data/lib/ruby_reactor/adapters/active_job/sweeper_worker.rb +16 -0
  47. data/lib/ruby_reactor/adapters/active_job/worker.rb +24 -0
  48. data/lib/ruby_reactor/adapters/sidekiq/map_collector_worker.rb +15 -0
  49. data/lib/ruby_reactor/adapters/sidekiq/map_element_worker.rb +15 -0
  50. data/lib/ruby_reactor/adapters/sidekiq/router.rb +91 -0
  51. data/lib/ruby_reactor/adapters/sidekiq/sweeper_worker.rb +19 -0
  52. data/lib/ruby_reactor/adapters/sidekiq/worker.rb +25 -0
  53. data/lib/ruby_reactor/configuration.rb +24 -4
  54. data/lib/ruby_reactor/map/element_executor.rb +1 -1
  55. data/lib/ruby_reactor/rspec/active_job_helpers.rb +52 -0
  56. data/lib/ruby_reactor/rspec/async_test_helpers.rb +41 -0
  57. data/lib/ruby_reactor/rspec/sidekiq_helpers.rb +3 -3
  58. data/lib/ruby_reactor/rspec/test_subject.rb +11 -7
  59. data/lib/ruby_reactor/rspec.rb +4 -0
  60. data/lib/ruby_reactor/sweeper_job.rb +70 -0
  61. data/lib/ruby_reactor/version.rb +1 -1
  62. data/lib/ruby_reactor/worker.rb +226 -0
  63. data/lib/ruby_reactor.rb +40 -1
  64. data/specs/active_job.md +259 -0
  65. metadata +54 -6
  66. data/lib/ruby_reactor/sidekiq_adapter.rb +0 -87
  67. data/lib/ruby_reactor/sidekiq_workers/map_collector_worker.rb +0 -13
  68. data/lib/ruby_reactor/sidekiq_workers/map_element_worker.rb +0 -13
  69. data/lib/ruby_reactor/sidekiq_workers/sweeper_worker.rb +0 -73
  70. data/lib/ruby_reactor/sidekiq_workers/worker.rb +0 -222
@@ -0,0 +1,299 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ JSON_MODE=false
6
+ DRY_RUN=false
7
+ ALLOW_EXISTING=false
8
+ SHORT_NAME=""
9
+ BRANCH_NUMBER=""
10
+ USE_TIMESTAMP=false
11
+ ARGS=()
12
+ i=1
13
+ while [ $i -le $# ]; do
14
+ arg="${!i}"
15
+ case "$arg" in
16
+ --json)
17
+ JSON_MODE=true
18
+ ;;
19
+ --dry-run)
20
+ DRY_RUN=true
21
+ ;;
22
+ --allow-existing-branch)
23
+ ALLOW_EXISTING=true
24
+ ;;
25
+ --short-name)
26
+ if [ $((i + 1)) -gt $# ]; then
27
+ echo 'Error: --short-name requires a value' >&2
28
+ exit 1
29
+ fi
30
+ i=$((i + 1))
31
+ next_arg="${!i}"
32
+ # Check if the next argument is another option (starts with --)
33
+ if [[ "$next_arg" == --* ]]; then
34
+ echo 'Error: --short-name requires a value' >&2
35
+ exit 1
36
+ fi
37
+ SHORT_NAME="$next_arg"
38
+ ;;
39
+ --number)
40
+ if [ $((i + 1)) -gt $# ]; then
41
+ echo 'Error: --number requires a value' >&2
42
+ exit 1
43
+ fi
44
+ i=$((i + 1))
45
+ next_arg="${!i}"
46
+ if [[ "$next_arg" == --* ]]; then
47
+ echo 'Error: --number requires a value' >&2
48
+ exit 1
49
+ fi
50
+ BRANCH_NUMBER="$next_arg"
51
+ ;;
52
+ --timestamp)
53
+ USE_TIMESTAMP=true
54
+ ;;
55
+ --help|-h)
56
+ echo "Usage: $0 [--json] [--dry-run] [--allow-existing-branch] [--short-name <name>] [--number N] [--timestamp] <feature_description>"
57
+ echo ""
58
+ echo "Options:"
59
+ echo " --json Output in JSON format"
60
+ echo " --dry-run Compute feature name and paths without creating directories or files"
61
+ echo " --allow-existing-branch Reuse an existing feature directory if it already exists"
62
+ echo " --short-name <name> Provide a custom short name (2-4 words) for the feature"
63
+ echo " --number N Specify branch number manually (overrides auto-detection)"
64
+ echo " --timestamp Use timestamp prefix (YYYYMMDD-HHMMSS) instead of sequential numbering"
65
+ echo " --help, -h Show this help message"
66
+ echo ""
67
+ echo "Examples:"
68
+ echo " $0 'Add user authentication system' --short-name 'user-auth'"
69
+ echo " $0 'Implement OAuth2 integration for API' --number 5"
70
+ echo " $0 --timestamp --short-name 'user-auth' 'Add user authentication'"
71
+ exit 0
72
+ ;;
73
+ *)
74
+ ARGS+=("$arg")
75
+ ;;
76
+ esac
77
+ i=$((i + 1))
78
+ done
79
+
80
+ FEATURE_DESCRIPTION="${ARGS[*]}"
81
+ if [ -z "$FEATURE_DESCRIPTION" ]; then
82
+ echo "Usage: $0 [--json] [--dry-run] [--allow-existing-branch] [--short-name <name>] [--number N] [--timestamp] <feature_description>" >&2
83
+ exit 1
84
+ fi
85
+
86
+ # Trim whitespace and validate description is not empty (e.g., user passed only whitespace)
87
+ FEATURE_DESCRIPTION=$(echo "$FEATURE_DESCRIPTION" | sed -E 's/^[[:space:]]+|[[:space:]]+$//g')
88
+ if [ -z "$FEATURE_DESCRIPTION" ]; then
89
+ echo "Error: Feature description cannot be empty or contain only whitespace" >&2
90
+ exit 1
91
+ fi
92
+
93
+ # Function to get highest number from specs directory
94
+ get_highest_from_specs() {
95
+ local specs_dir="$1"
96
+ local highest=0
97
+
98
+ if [ -d "$specs_dir" ]; then
99
+ for dir in "$specs_dir"/*; do
100
+ [ -d "$dir" ] || continue
101
+ dirname=$(basename "$dir")
102
+ # Match sequential prefixes (>=3 digits), but skip timestamp dirs.
103
+ if echo "$dirname" | grep -Eq '^[0-9]{3,}-' && ! echo "$dirname" | grep -Eq '^[0-9]{8}-[0-9]{6}-'; then
104
+ number=$(echo "$dirname" | grep -Eo '^[0-9]+')
105
+ number=$((10#$number))
106
+ if [ "$number" -gt "$highest" ]; then
107
+ highest=$number
108
+ fi
109
+ fi
110
+ done
111
+ fi
112
+
113
+ echo "$highest"
114
+ }
115
+
116
+ # Function to clean and format a branch name
117
+ clean_branch_name() {
118
+ local name="$1"
119
+ echo "$name" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/-\+/-/g' | sed 's/^-//' | sed 's/-$//'
120
+ }
121
+
122
+ # Resolve repository root using common.sh functions which prioritize .specify
123
+ SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
124
+ source "$SCRIPT_DIR/common.sh"
125
+
126
+ REPO_ROOT=$(get_repo_root) || exit 1
127
+
128
+ cd "$REPO_ROOT"
129
+
130
+ SPECS_DIR="$REPO_ROOT/specs"
131
+ if [ "$DRY_RUN" != true ]; then
132
+ mkdir -p "$SPECS_DIR"
133
+ fi
134
+
135
+ # Function to generate branch name with stop word filtering and length filtering
136
+ generate_branch_name() {
137
+ local description="$1"
138
+
139
+ # Common stop words to filter out
140
+ local stop_words="^(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)$"
141
+
142
+ # Convert to lowercase and split into words
143
+ local clean_name=$(echo "$description" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/ /g')
144
+
145
+ # Filter words: remove stop words and words shorter than 3 chars (unless they're uppercase acronyms in original)
146
+ local meaningful_words=()
147
+ for word in $clean_name; do
148
+ # Skip empty words
149
+ [ -z "$word" ] && continue
150
+
151
+ # Keep words that are NOT stop words AND (length >= 3 OR are potential acronyms)
152
+ if ! echo "$word" | grep -qiE "$stop_words"; then
153
+ if [ ${#word} -ge 3 ]; then
154
+ meaningful_words+=("$word")
155
+ elif echo "$description" | grep -q "\b${word^^}\b"; then
156
+ # Keep short words if they appear as uppercase in original (likely acronyms)
157
+ meaningful_words+=("$word")
158
+ fi
159
+ fi
160
+ done
161
+
162
+ # If we have meaningful words, use first 3-4 of them
163
+ if [ ${#meaningful_words[@]} -gt 0 ]; then
164
+ local max_words=3
165
+ if [ ${#meaningful_words[@]} -eq 4 ]; then max_words=4; fi
166
+
167
+ local result=""
168
+ local count=0
169
+ for word in "${meaningful_words[@]}"; do
170
+ if [ $count -ge $max_words ]; then break; fi
171
+ if [ -n "$result" ]; then result="$result-"; fi
172
+ result="$result$word"
173
+ count=$((count + 1))
174
+ done
175
+ echo "$result"
176
+ else
177
+ # Fallback to original logic if no meaningful words found
178
+ local cleaned=$(clean_branch_name "$description")
179
+ echo "$cleaned" | tr '-' '\n' | grep -v '^$' | head -3 | tr '\n' '-' | sed 's/-$//'
180
+ fi
181
+ }
182
+
183
+ # Generate branch name
184
+ if [ -n "$SHORT_NAME" ]; then
185
+ # Use provided short name, just clean it up
186
+ BRANCH_SUFFIX=$(clean_branch_name "$SHORT_NAME")
187
+ else
188
+ # Generate from description with smart filtering
189
+ BRANCH_SUFFIX=$(generate_branch_name "$FEATURE_DESCRIPTION")
190
+ fi
191
+
192
+ # Warn if --number and --timestamp are both specified
193
+ if [ "$USE_TIMESTAMP" = true ] && [ -n "$BRANCH_NUMBER" ]; then
194
+ >&2 echo "[specify] Warning: --number is ignored when --timestamp is used"
195
+ BRANCH_NUMBER=""
196
+ fi
197
+
198
+ # Determine branch prefix
199
+ if [ "$USE_TIMESTAMP" = true ]; then
200
+ FEATURE_NUM=$(date +%Y%m%d-%H%M%S)
201
+ BRANCH_NAME="${FEATURE_NUM}-${BRANCH_SUFFIX}"
202
+ else
203
+ # Determine branch number from existing feature directories
204
+ if [ -z "$BRANCH_NUMBER" ]; then
205
+ HIGHEST=$(get_highest_from_specs "$SPECS_DIR")
206
+ BRANCH_NUMBER=$((HIGHEST + 1))
207
+ fi
208
+
209
+ # Force base-10 interpretation to prevent octal conversion (e.g., 010 → 8 in octal, but should be 10 in decimal)
210
+ FEATURE_NUM=$(printf "%03d" "$((10#$BRANCH_NUMBER))")
211
+ BRANCH_NAME="${FEATURE_NUM}-${BRANCH_SUFFIX}"
212
+ fi
213
+
214
+ # GitHub enforces a 244-byte limit on branch names
215
+ # Validate and truncate if necessary
216
+ MAX_BRANCH_LENGTH=244
217
+ if [ ${#BRANCH_NAME} -gt $MAX_BRANCH_LENGTH ]; then
218
+ # Calculate how much we need to trim from suffix
219
+ # Account for prefix length: timestamp (15) + hyphen (1) = 16, or sequential (3) + hyphen (1) = 4
220
+ PREFIX_LENGTH=$(( ${#FEATURE_NUM} + 1 ))
221
+ MAX_SUFFIX_LENGTH=$((MAX_BRANCH_LENGTH - PREFIX_LENGTH))
222
+
223
+ # Truncate suffix at word boundary if possible
224
+ TRUNCATED_SUFFIX=$(echo "$BRANCH_SUFFIX" | cut -c1-$MAX_SUFFIX_LENGTH)
225
+ # Remove trailing hyphen if truncation created one
226
+ TRUNCATED_SUFFIX=$(echo "$TRUNCATED_SUFFIX" | sed 's/-$//')
227
+
228
+ ORIGINAL_BRANCH_NAME="$BRANCH_NAME"
229
+ BRANCH_NAME="${FEATURE_NUM}-${TRUNCATED_SUFFIX}"
230
+
231
+ >&2 echo "[specify] Warning: Branch name exceeded GitHub's 244-byte limit"
232
+ >&2 echo "[specify] Original: $ORIGINAL_BRANCH_NAME (${#ORIGINAL_BRANCH_NAME} bytes)"
233
+ >&2 echo "[specify] Truncated to: $BRANCH_NAME (${#BRANCH_NAME} bytes)"
234
+ fi
235
+
236
+ FEATURE_DIR="$SPECS_DIR/$BRANCH_NAME"
237
+ SPEC_FILE="$FEATURE_DIR/spec.md"
238
+
239
+ if [ "$DRY_RUN" != true ]; then
240
+ if [ -d "$FEATURE_DIR" ] && [ "$ALLOW_EXISTING" != true ]; then
241
+ if [ "$USE_TIMESTAMP" = true ]; then
242
+ >&2 echo "Error: Feature directory '$FEATURE_DIR' already exists. Rerun to get a new timestamp or use a different --short-name."
243
+ else
244
+ >&2 echo "Error: Feature directory '$FEATURE_DIR' already exists. Please use a different feature name or specify a different number with --number."
245
+ fi
246
+ exit 1
247
+ fi
248
+
249
+ mkdir -p "$FEATURE_DIR"
250
+
251
+ if [ ! -f "$SPEC_FILE" ]; then
252
+ TEMPLATE=$(resolve_template "spec-template" "$REPO_ROOT") || true
253
+ if [ -n "$TEMPLATE" ] && [ -f "$TEMPLATE" ]; then
254
+ cp "$TEMPLATE" "$SPEC_FILE"
255
+ else
256
+ echo "Warning: Spec template not found; created empty spec file" >&2
257
+ touch "$SPEC_FILE"
258
+ fi
259
+ fi
260
+
261
+ # Persist to .specify/feature.json so downstream commands can find the feature
262
+ _persist_feature_json "$REPO_ROOT" "$FEATURE_DIR"
263
+
264
+ # Inform the user how to set feature state in their own shell
265
+ printf '# To persist: export SPECIFY_FEATURE=%q\n' "$BRANCH_NAME" >&2
266
+ printf '# export SPECIFY_FEATURE_DIRECTORY=%q\n' "$FEATURE_DIR" >&2
267
+ fi
268
+
269
+ if $JSON_MODE; then
270
+ if command -v jq >/dev/null 2>&1; then
271
+ if [ "$DRY_RUN" = true ]; then
272
+ jq -cn \
273
+ --arg branch_name "$BRANCH_NAME" \
274
+ --arg spec_file "$SPEC_FILE" \
275
+ --arg feature_num "$FEATURE_NUM" \
276
+ '{BRANCH_NAME:$branch_name,SPEC_FILE:$spec_file,FEATURE_NUM:$feature_num,DRY_RUN:true}'
277
+ else
278
+ jq -cn \
279
+ --arg branch_name "$BRANCH_NAME" \
280
+ --arg spec_file "$SPEC_FILE" \
281
+ --arg feature_num "$FEATURE_NUM" \
282
+ '{BRANCH_NAME:$branch_name,SPEC_FILE:$spec_file,FEATURE_NUM:$feature_num}'
283
+ fi
284
+ else
285
+ if [ "$DRY_RUN" = true ]; then
286
+ printf '{"BRANCH_NAME":"%s","SPEC_FILE":"%s","FEATURE_NUM":"%s","DRY_RUN":true}\n' "$(json_escape "$BRANCH_NAME")" "$(json_escape "$SPEC_FILE")" "$(json_escape "$FEATURE_NUM")"
287
+ else
288
+ printf '{"BRANCH_NAME":"%s","SPEC_FILE":"%s","FEATURE_NUM":"%s"}\n' "$(json_escape "$BRANCH_NAME")" "$(json_escape "$SPEC_FILE")" "$(json_escape "$FEATURE_NUM")"
289
+ fi
290
+ fi
291
+ else
292
+ echo "BRANCH_NAME: $BRANCH_NAME"
293
+ echo "SPEC_FILE: $SPEC_FILE"
294
+ echo "FEATURE_NUM: $FEATURE_NUM"
295
+ if [ "$DRY_RUN" != true ]; then
296
+ printf '# To persist in your shell: export SPECIFY_FEATURE=%q\n' "$BRANCH_NAME"
297
+ printf '# export SPECIFY_FEATURE_DIRECTORY=%q\n' "$FEATURE_DIR"
298
+ fi
299
+ fi
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ # Parse command line arguments
6
+ JSON_MODE=false
7
+ ARGS=()
8
+
9
+ for arg in "$@"; do
10
+ case "$arg" in
11
+ --json)
12
+ JSON_MODE=true
13
+ ;;
14
+ --help|-h)
15
+ echo "Usage: $0 [--json]"
16
+ echo " --json Output results in JSON format"
17
+ echo " --help Show this help message"
18
+ exit 0
19
+ ;;
20
+ *)
21
+ ARGS+=("$arg")
22
+ ;;
23
+ esac
24
+ done
25
+
26
+ # Get script directory and load common functions
27
+ SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
28
+ source "$SCRIPT_DIR/common.sh"
29
+
30
+ # Get all paths and variables from common functions
31
+ _paths_output=$(get_feature_paths) || { echo "ERROR: Failed to resolve feature paths" >&2; exit 1; }
32
+ eval "$_paths_output"
33
+ unset _paths_output
34
+
35
+ # Ensure the feature directory exists
36
+ mkdir -p "$FEATURE_DIR"
37
+
38
+ # Copy plan template if plan doesn't already exist
39
+ if [[ -f "$IMPL_PLAN" ]]; then
40
+ if $JSON_MODE; then
41
+ echo "Plan already exists at $IMPL_PLAN, skipping template copy" >&2
42
+ else
43
+ echo "Plan already exists at $IMPL_PLAN, skipping template copy"
44
+ fi
45
+ else
46
+ TEMPLATE=$(resolve_template "plan-template" "$REPO_ROOT") || true
47
+ if [[ -n "$TEMPLATE" ]] && [[ -f "$TEMPLATE" ]]; then
48
+ cp "$TEMPLATE" "$IMPL_PLAN"
49
+ if $JSON_MODE; then
50
+ echo "Copied plan template to $IMPL_PLAN" >&2
51
+ else
52
+ echo "Copied plan template to $IMPL_PLAN"
53
+ fi
54
+ else
55
+ if $JSON_MODE; then
56
+ echo "Warning: Plan template not found" >&2
57
+ else
58
+ echo "Warning: Plan template not found"
59
+ fi
60
+ # Create a basic plan file if template doesn't exist
61
+ touch "$IMPL_PLAN"
62
+ fi
63
+ fi
64
+
65
+ # Output results
66
+ if $JSON_MODE; then
67
+ if has_jq; then
68
+ jq -cn \
69
+ --arg feature_spec "$FEATURE_SPEC" \
70
+ --arg impl_plan "$IMPL_PLAN" \
71
+ --arg specs_dir "$FEATURE_DIR" \
72
+ --arg branch "$CURRENT_BRANCH" \
73
+ '{FEATURE_SPEC:$feature_spec,IMPL_PLAN:$impl_plan,SPECS_DIR:$specs_dir,BRANCH:$branch}'
74
+ else
75
+ printf '{"FEATURE_SPEC":"%s","IMPL_PLAN":"%s","SPECS_DIR":"%s","BRANCH":"%s"}\n' \
76
+ "$(json_escape "$FEATURE_SPEC")" "$(json_escape "$IMPL_PLAN")" "$(json_escape "$FEATURE_DIR")" "$(json_escape "$CURRENT_BRANCH")"
77
+ fi
78
+ else
79
+ echo "FEATURE_SPEC: $FEATURE_SPEC"
80
+ echo "IMPL_PLAN: $IMPL_PLAN"
81
+ echo "SPECS_DIR: $FEATURE_DIR"
82
+ echo "BRANCH: $CURRENT_BRANCH"
83
+ fi
84
+
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ # Parse command line arguments
6
+ JSON_MODE=false
7
+
8
+ for arg in "$@"; do
9
+ case "$arg" in
10
+ --json) JSON_MODE=true ;;
11
+ --help|-h)
12
+ echo "Usage: $0 [--json]"
13
+ echo " --json Output results in JSON format"
14
+ echo " --help Show this help message"
15
+ exit 0
16
+ ;;
17
+ *) echo "ERROR: Unknown option '$arg'" >&2; exit 1 ;;
18
+ esac
19
+ done
20
+
21
+ # Source common functions
22
+ SCRIPT_DIR="$(CDPATH="" cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
23
+ source "$SCRIPT_DIR/common.sh"
24
+
25
+ # Get feature paths
26
+ _paths_output=$(get_feature_paths) || { echo "ERROR: Failed to resolve feature paths" >&2; exit 1; }
27
+ eval "$_paths_output"
28
+ unset _paths_output
29
+
30
+ # Validate required files
31
+ if [[ ! -f "$IMPL_PLAN" ]]; then
32
+ echo "ERROR: plan.md not found in $FEATURE_DIR" >&2
33
+ echo "Run /speckit-plan first to create the implementation plan." >&2
34
+ exit 1
35
+ fi
36
+
37
+ if [[ ! -f "$FEATURE_SPEC" ]]; then
38
+ echo "ERROR: spec.md not found in $FEATURE_DIR" >&2
39
+ echo "Run /speckit-specify first to create the feature structure." >&2
40
+ exit 1
41
+ fi
42
+
43
+ # Build available docs list
44
+ docs=()
45
+ [[ -f "$RESEARCH" ]] && docs+=("research.md")
46
+ [[ -f "$DATA_MODEL" ]] && docs+=("data-model.md")
47
+ if [[ -d "$CONTRACTS_DIR" ]] && [[ -n "$(ls -A "$CONTRACTS_DIR" 2>/dev/null)" ]]; then
48
+ docs+=("contracts/")
49
+ fi
50
+ [[ -f "$QUICKSTART" ]] && docs+=("quickstart.md")
51
+
52
+ # Resolve tasks template through override stack
53
+ TASKS_TEMPLATE=$(resolve_template "tasks-template" "$REPO_ROOT") || true
54
+ if [[ -z "$TASKS_TEMPLATE" ]] || [[ ! -f "$TASKS_TEMPLATE" ]]; then
55
+ echo "ERROR: Could not resolve required tasks-template from the template override stack for $REPO_ROOT" >&2
56
+ echo "Template 'tasks-template' was not found in any supported location (overrides, presets, extensions, or shared core). Add an override at .specify/templates/overrides/tasks-template.md, or run 'specify init' / reinstall shared infra to restore the core .specify/templates/tasks-template.md template." >&2
57
+ exit 1
58
+ fi
59
+
60
+ # Output results
61
+ if $JSON_MODE; then
62
+ if has_jq; then
63
+ if [[ ${#docs[@]} -eq 0 ]]; then
64
+ json_docs="[]"
65
+ else
66
+ json_docs=$(printf '%s\n' "${docs[@]}" | jq -R . | jq -s .)
67
+ fi
68
+ jq -cn \
69
+ --arg feature_dir "$FEATURE_DIR" \
70
+ --argjson docs "$json_docs" \
71
+ --arg tasks_template "${TASKS_TEMPLATE:-}" \
72
+ '{FEATURE_DIR:$feature_dir,AVAILABLE_DOCS:$docs,TASKS_TEMPLATE:$tasks_template}'
73
+ else
74
+ if [[ ${#docs[@]} -eq 0 ]]; then
75
+ json_docs="[]"
76
+ else
77
+ json_docs=$(for d in "${docs[@]}"; do printf '"%s",' "$(json_escape "$d")"; done)
78
+ json_docs="[${json_docs%,}]"
79
+ fi
80
+ printf '{"FEATURE_DIR":"%s","AVAILABLE_DOCS":%s,"TASKS_TEMPLATE":"%s"}\n' \
81
+ "$(json_escape "$FEATURE_DIR")" "$json_docs" "$(json_escape "${TASKS_TEMPLATE:-}")"
82
+ fi
83
+ else
84
+ echo "FEATURE_DIR: $FEATURE_DIR"
85
+ echo "TASKS_TEMPLATE: ${TASKS_TEMPLATE:-not found}"
86
+ echo "AVAILABLE_DOCS:"
87
+ check_file "$RESEARCH" "research.md"
88
+ check_file "$DATA_MODEL" "data-model.md"
89
+ check_dir "$CONTRACTS_DIR" "contracts/"
90
+ check_file "$QUICKSTART" "quickstart.md"
91
+ fi
@@ -0,0 +1,40 @@
1
+ # [CHECKLIST TYPE] Checklist: [FEATURE NAME]
2
+
3
+ **Purpose**: [Brief description of what this checklist covers]
4
+ **Created**: [DATE]
5
+ **Feature**: [Link to spec.md or relevant documentation]
6
+
7
+ **Note**: This checklist is generated by the `/speckit-checklist` command based on feature context and requirements.
8
+
9
+ <!--
10
+ ============================================================================
11
+ IMPORTANT: The checklist items below are SAMPLE ITEMS for illustration only.
12
+
13
+ The /speckit-checklist command MUST replace these with actual items based on:
14
+ - User's specific checklist request
15
+ - Feature requirements from spec.md
16
+ - Technical context from plan.md
17
+ - Implementation details from tasks.md
18
+
19
+ DO NOT keep these sample items in the generated checklist file.
20
+ ============================================================================
21
+ -->
22
+
23
+ ## [Category 1]
24
+
25
+ - [ ] CHK001 First checklist item with clear action
26
+ - [ ] CHK002 Second checklist item
27
+ - [ ] CHK003 Third checklist item
28
+
29
+ ## [Category 2]
30
+
31
+ - [ ] CHK004 Another category item
32
+ - [ ] CHK005 Item with specific criteria
33
+ - [ ] CHK006 Final item in this category
34
+
35
+ ## Notes
36
+
37
+ - Check items off as completed: `[x]`
38
+ - Add comments or findings inline
39
+ - Link to relevant resources or documentation
40
+ - Items are numbered sequentially for easy reference
@@ -0,0 +1,50 @@
1
+ # [PROJECT_NAME] Constitution
2
+ <!-- Example: Spec Constitution, TaskFlow Constitution, etc. -->
3
+
4
+ ## Core Principles
5
+
6
+ ### [PRINCIPLE_1_NAME]
7
+ <!-- Example: I. Library-First -->
8
+ [PRINCIPLE_1_DESCRIPTION]
9
+ <!-- Example: Every feature starts as a standalone library; Libraries must be self-contained, independently testable, documented; Clear purpose required - no organizational-only libraries -->
10
+
11
+ ### [PRINCIPLE_2_NAME]
12
+ <!-- Example: II. CLI Interface -->
13
+ [PRINCIPLE_2_DESCRIPTION]
14
+ <!-- Example: Every library exposes functionality via CLI; Text in/out protocol: stdin/args → stdout, errors → stderr; Support JSON + human-readable formats -->
15
+
16
+ ### [PRINCIPLE_3_NAME]
17
+ <!-- Example: III. Test-First (NON-NEGOTIABLE) -->
18
+ [PRINCIPLE_3_DESCRIPTION]
19
+ <!-- Example: TDD mandatory: Tests written → User approved → Tests fail → Then implement; Red-Green-Refactor cycle strictly enforced -->
20
+
21
+ ### [PRINCIPLE_4_NAME]
22
+ <!-- Example: IV. Integration Testing -->
23
+ [PRINCIPLE_4_DESCRIPTION]
24
+ <!-- Example: Focus areas requiring integration tests: New library contract tests, Contract changes, Inter-service communication, Shared schemas -->
25
+
26
+ ### [PRINCIPLE_5_NAME]
27
+ <!-- Example: V. Observability, VI. Versioning & Breaking Changes, VII. Simplicity -->
28
+ [PRINCIPLE_5_DESCRIPTION]
29
+ <!-- Example: Text I/O ensures debuggability; Structured logging required; Or: MAJOR.MINOR.BUILD format; Or: Start simple, YAGNI principles -->
30
+
31
+ ## [SECTION_2_NAME]
32
+ <!-- Example: Additional Constraints, Security Requirements, Performance Standards, etc. -->
33
+
34
+ [SECTION_2_CONTENT]
35
+ <!-- Example: Technology stack requirements, compliance standards, deployment policies, etc. -->
36
+
37
+ ## [SECTION_3_NAME]
38
+ <!-- Example: Development Workflow, Review Process, Quality Gates, etc. -->
39
+
40
+ [SECTION_3_CONTENT]
41
+ <!-- Example: Code review requirements, testing gates, deployment approval process, etc. -->
42
+
43
+ ## Governance
44
+ <!-- Example: Constitution supersedes all other practices; Amendments require documentation, approval, migration plan -->
45
+
46
+ [GOVERNANCE_RULES]
47
+ <!-- Example: All PRs/reviews must verify compliance; Complexity must be justified; Use [GUIDANCE_FILE] for runtime development guidance -->
48
+
49
+ **Version**: [CONSTITUTION_VERSION] | **Ratified**: [RATIFICATION_DATE] | **Last Amended**: [LAST_AMENDED_DATE]
50
+ <!-- Example: Version: 2.1.1 | Ratified: 2025-06-13 | Last Amended: 2025-07-16 -->
@@ -0,0 +1,113 @@
1
+ # Implementation Plan: [FEATURE]
2
+
3
+ **Branch**: `[###-feature-name]` | **Date**: [DATE] | **Spec**: [link]
4
+
5
+ **Input**: Feature specification from `/specs/[###-feature-name]/spec.md`
6
+
7
+ **Note**: This template is filled in by the `/speckit-plan` command. See `.specify/templates/plan-template.md` for the execution workflow.
8
+
9
+ ## Summary
10
+
11
+ [Extract from feature spec: primary requirement + technical approach from research]
12
+
13
+ ## Technical Context
14
+
15
+ <!--
16
+ ACTION REQUIRED: Replace the content in this section with the technical details
17
+ for the project. The structure here is presented in advisory capacity to guide
18
+ the iteration process.
19
+ -->
20
+
21
+ **Language/Version**: [e.g., Python 3.11, Swift 5.9, Rust 1.75 or NEEDS CLARIFICATION]
22
+
23
+ **Primary Dependencies**: [e.g., FastAPI, UIKit, LLVM or NEEDS CLARIFICATION]
24
+
25
+ **Storage**: [if applicable, e.g., PostgreSQL, CoreData, files or N/A]
26
+
27
+ **Testing**: [e.g., pytest, XCTest, cargo test or NEEDS CLARIFICATION]
28
+
29
+ **Target Platform**: [e.g., Linux server, iOS 15+, WASM or NEEDS CLARIFICATION]
30
+
31
+ **Project Type**: [e.g., library/cli/web-service/mobile-app/compiler/desktop-app or NEEDS CLARIFICATION]
32
+
33
+ **Performance Goals**: [domain-specific, e.g., 1000 req/s, 10k lines/sec, 60 fps or NEEDS CLARIFICATION]
34
+
35
+ **Constraints**: [domain-specific, e.g., <200ms p95, <100MB memory, offline-capable or NEEDS CLARIFICATION]
36
+
37
+ **Scale/Scope**: [domain-specific, e.g., 10k users, 1M LOC, 50 screens or NEEDS CLARIFICATION]
38
+
39
+ ## Constitution Check
40
+
41
+ *GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.*
42
+
43
+ [Gates determined based on constitution file]
44
+
45
+ ## Project Structure
46
+
47
+ ### Documentation (this feature)
48
+
49
+ ```text
50
+ specs/[###-feature]/
51
+ ├── plan.md # This file (/speckit-plan command output)
52
+ ├── research.md # Phase 0 output (/speckit-plan command)
53
+ ├── data-model.md # Phase 1 output (/speckit-plan command)
54
+ ├── quickstart.md # Phase 1 output (/speckit-plan command)
55
+ ├── contracts/ # Phase 1 output (/speckit-plan command)
56
+ └── tasks.md # Phase 2 output (/speckit-tasks command - NOT created by /speckit-plan)
57
+ ```
58
+
59
+ ### Source Code (repository root)
60
+ <!--
61
+ ACTION REQUIRED: Replace the placeholder tree below with the concrete layout
62
+ for this feature. Delete unused options and expand the chosen structure with
63
+ real paths (e.g., apps/admin, packages/something). The delivered plan must
64
+ not include Option labels.
65
+ -->
66
+
67
+ ```text
68
+ # [REMOVE IF UNUSED] Option 1: Single project (DEFAULT)
69
+ src/
70
+ ├── models/
71
+ ├── services/
72
+ ├── cli/
73
+ └── lib/
74
+
75
+ tests/
76
+ ├── contract/
77
+ ├── integration/
78
+ └── unit/
79
+
80
+ # [REMOVE IF UNUSED] Option 2: Web application (when "frontend" + "backend" detected)
81
+ backend/
82
+ ├── src/
83
+ │ ├── models/
84
+ │ ├── services/
85
+ │ └── api/
86
+ └── tests/
87
+
88
+ frontend/
89
+ ├── src/
90
+ │ ├── components/
91
+ │ ├── pages/
92
+ │ └── services/
93
+ └── tests/
94
+
95
+ # [REMOVE IF UNUSED] Option 3: Mobile + API (when "iOS/Android" detected)
96
+ api/
97
+ └── [same as backend above]
98
+
99
+ ios/ or android/
100
+ └── [platform-specific structure: feature modules, UI flows, platform tests]
101
+ ```
102
+
103
+ **Structure Decision**: [Document the selected structure and reference the real
104
+ directories captured above]
105
+
106
+ ## Complexity Tracking
107
+
108
+ > **Fill ONLY if Constitution Check has violations that must be justified**
109
+
110
+ | Violation | Why Needed | Simpler Alternative Rejected Because |
111
+ |-----------|------------|-------------------------------------|
112
+ | [e.g., 4th project] | [current need] | [why 3 projects insufficient] |
113
+ | [e.g., Repository pattern] | [specific problem] | [why direct DB access insufficient] |