sdd-agent-pack 1.3.4 → 1.3.5

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.
@@ -61,7 +61,16 @@ TASKS_FILE = "specs/tasks.md"
61
61
 
62
62
 
63
63
  def parse_epics(file_path: str) -> list[dict]:
64
- """Parse incomplete epics from tasks.md frontmatter."""
64
+ """Parse incomplete epics from tasks.md.
65
+
66
+ Detects epic headings like:
67
+ ## Epic EPIC-001 — Title
68
+ ## Epic TDS.1: Title
69
+ ### Epic Something
70
+
71
+ An epic is "incomplete" if any checkbox (- [ ]) is unchecked under it.
72
+ An epic is "complete" if all its checkboxes are checked or there are none.
73
+ """
65
74
  if not os.path.exists(file_path):
66
75
  print(f"✗ tasks.md not found at {file_path}")
67
76
  print(" Run this from your repository root.")
@@ -71,43 +80,35 @@ def parse_epics(file_path: str) -> list[dict]:
71
80
  content = f.read()
72
81
 
73
82
  epics = []
74
-
75
- # Try YAML frontmatter format first
76
- # Look for: status: pending or status: in-progress under an epic entry
77
- frontmatter_match = re.search(
78
- r"autopilot:\s*\n\s+epics:\s*\n(.+?)(?=\n\S|\Z)",
79
- content,
80
- re.DOTALL,
81
- )
82
-
83
- if frontmatter_match:
84
- # Parse structured frontmatter
85
- epic_pattern = re.compile(
86
- r"- id:\s*(\S+)\s*\n\s+title:\s*(.+?)\s*\n\s+status:\s*(.+?)(?:\n|$)"
87
- )
88
- for match in epic_pattern.finditer(frontmatter_match.group(1)):
89
- epic_id = match.group(1)
90
- title = match.group(2).strip()
91
- status = match.group(3).strip()
92
- if status in ("pending", "in-progress"):
93
- epics.append({"id": epic_id, "title": title, "status": status})
94
- else:
95
- # Fallback: parse markdown headings and status lines
96
- lines = content.split("\n")
97
- current_epic = None
98
- for i, line in enumerate(lines):
99
- heading_match = re.match(r"^#{2,4}\s+(.+)$", line)
100
- if heading_match:
101
- current_epic = heading_match.group(1).strip()
102
- elif current_epic and re.search(
103
- r"status:\s*(pending|in-progress)", line
104
- ):
105
- epics.append(
106
- {"id": current_epic, "title": current_epic, "status": "pending"}
107
- )
108
- current_epic = None
109
- elif current_epic and re.search(r"status:\s*complete", line):
110
- current_epic = None
83
+ lines = content.split("\n")
84
+
85
+ epic_heading_re = re.compile(r"^#{2,4}\s+Epic\s+(.+)$", re.IGNORECASE)
86
+
87
+ current_epic = None
88
+ has_unchecked = False
89
+
90
+ for line in lines:
91
+ heading_match = epic_heading_re.match(line)
92
+ if heading_match:
93
+ # Save previous epic if it has unchecked tasks
94
+ if current_epic and has_unchecked:
95
+ epics.append({
96
+ "id": current_epic,
97
+ "title": current_epic,
98
+ "status": "incomplete",
99
+ })
100
+ current_epic = heading_match.group(1).strip()
101
+ has_unchecked = False
102
+ elif current_epic and re.match(r"^\s*-\s+\[\s*\]", line):
103
+ has_unchecked = True
104
+
105
+ # Don't forget the last epic
106
+ if current_epic and has_unchecked:
107
+ epics.append({
108
+ "id": current_epic,
109
+ "title": current_epic,
110
+ "status": "incomplete",
111
+ })
111
112
 
112
113
  return epics
113
114
 
@@ -68,24 +68,36 @@ echo "━━━ SDD Agent Pack — Epic Orchestrator ━━━"
68
68
  echo ""
69
69
 
70
70
  # Parse incomplete epics from tasks.md
71
- # Looks for lines like: "### EPIC-001: Title" followed by "- [ ] ..."
71
+ # Looks for epic headings (## Epic XXX Title) and checks if any
72
+ # of their tasks or requirements have unchecked boxes (- [ ]).
73
+ # An epic is "incomplete" if any checkbox under it is unchecked.
72
74
  echo "Scanning $TASKS_FILE for incomplete epics..."
73
75
 
74
76
  epics=()
75
77
  current_epic=""
78
+ has_unchecked=false
76
79
 
77
80
  while IFS= read -r line; do
78
- if [[ "$line" =~ ^###[[:space:]]+(EPIC-[^:]+):(.+)$ ]] || [[ "$line" =~ ^###[[:space:]]+(T[^:]+):(.+)$ ]] || [[ "$line" =~ ^###[[:space:]]+([^:]+):(.+)$ ]]; then
79
- current_epic="${BASH_REMATCH[1]}:${BASH_REMATCH[2]}"
80
- current_epic="$(echo "$current_epic" | xargs)"
81
- elif [[ "$line" =~ status:[[:space:]]*(pending|in-progress) ]] && [ -n "$current_epic" ]; then
82
- epics+=("$current_epic")
83
- current_epic=""
84
- elif [[ "$line" =~ status:[[:space:]]*complete ]] || [[ "$line" =~ status:[[:space:]]*completed ]]; then
85
- current_epic=""
81
+ # Detect epic heading: ## Epic XXX Title or ## Epic XXX: Title
82
+ if [[ "$line" =~ ^[#]+\ +Epic\ +(.+)$ ]]; then
83
+ # Save previous epic if it has unchecked tasks
84
+ if [ -n "$current_epic" ] && [ "$has_unchecked" = true ]; then
85
+ epics+=("$current_epic")
86
+ fi
87
+ current_epic="${BASH_REMATCH[1]}"
88
+ current_epic="$(echo "$current_epic" | sed 's/^[#[:space:]]*//' | xargs)"
89
+ has_unchecked=false
90
+ # Detect unchecked checkbox
91
+ elif [[ "$line" =~ ^[[:space:]]*-\ +\[\ \] ]] && [ -n "$current_epic" ]; then
92
+ has_unchecked=true
86
93
  fi
87
94
  done < "$TASKS_FILE"
88
95
 
96
+ # Don't forget the last epic
97
+ if [ -n "$current_epic" ] && [ "$has_unchecked" = true ]; then
98
+ epics+=("$current_epic")
99
+ fi
100
+
89
101
  if [ ${#epics[@]} -eq 0 ]; then
90
102
  echo "✓ All epics are complete! Nothing to do."
91
103
  exit 0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sdd-agent-pack",
3
- "version": "1.3.4",
3
+ "version": "1.3.5",
4
4
  "description": "Lightweight installer for SDD workflow assets into application repositories",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",