mindsystem-cc 3.17.1 → 3.18.1

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 (37) hide show
  1. package/agents/ms-consolidator.md +4 -4
  2. package/agents/ms-debugger.md +3 -3
  3. package/agents/ms-designer.md +33 -70
  4. package/agents/ms-executor.md +7 -6
  5. package/agents/ms-plan-writer.md +52 -26
  6. package/agents/ms-researcher.md +13 -13
  7. package/commands/ms/check-phase.md +1 -1
  8. package/commands/ms/complete-milestone.md +47 -54
  9. package/commands/ms/design-phase.md +33 -30
  10. package/commands/ms/review-design.md +106 -395
  11. package/mindsystem/references/principles.md +3 -3
  12. package/mindsystem/references/routing/next-phase-routing.md +1 -1
  13. package/mindsystem/references/scope-estimation.md +22 -35
  14. package/mindsystem/templates/design-iteration.md +13 -13
  15. package/mindsystem/templates/design.md +145 -327
  16. package/mindsystem/templates/knowledge.md +1 -1
  17. package/mindsystem/templates/milestone-archive.md +3 -3
  18. package/mindsystem/templates/phase-prompt.md +6 -7
  19. package/mindsystem/templates/research-subagent-prompt.md +2 -2
  20. package/mindsystem/templates/research.md +7 -7
  21. package/mindsystem/templates/roadmap.md +1 -1
  22. package/mindsystem/templates/verification-report.md +1 -1
  23. package/mindsystem/workflows/complete-milestone.md +52 -227
  24. package/mindsystem/workflows/discuss-phase.md +3 -3
  25. package/mindsystem/workflows/execute-plan.md +1 -1
  26. package/mindsystem/workflows/plan-phase.md +22 -50
  27. package/mindsystem/workflows/verify-phase.md +1 -1
  28. package/package.json +1 -1
  29. package/scripts/archive-milestone-files.sh +68 -0
  30. package/scripts/archive-milestone-phases.sh +138 -0
  31. package/scripts/gather-milestone-stats.sh +179 -0
  32. package/scripts/ms-lookup/ms_lookup/backends/context7.py +17 -5
  33. package/scripts/ms-lookup/ms_lookup/backends/perplexity.py +17 -3
  34. package/scripts/ms-lookup-wrapper.sh +1 -1
  35. package/scripts/scan-planning-context.py +186 -36
  36. package/scripts/validate-execution-order.sh +4 -5
  37. package/scripts/cleanup-phase-artifacts.sh +0 -68
@@ -343,6 +343,7 @@ def scan_debug_docs(
343
343
  results.append(
344
344
  {
345
345
  "path": str(path),
346
+ "slug": path.stem,
346
347
  "subsystem": fm.get("subsystem", ""),
347
348
  "root_cause": fm.get("root_cause", ""),
348
349
  "resolution": fm.get("resolution", ""),
@@ -552,6 +553,145 @@ def aggregate_from_summaries(
552
553
  }
553
554
 
554
555
 
556
+ # ---------------------------------------------------------------------------
557
+ # Markdown formatting
558
+ # ---------------------------------------------------------------------------
559
+
560
+
561
+ def format_markdown(output: dict[str, Any]) -> str:
562
+ """Format scanner output as readable markdown for LLM consumption."""
563
+ sections: list[str] = []
564
+ agg = output.get("aggregated", {})
565
+
566
+ # --- Established Patterns ---
567
+ patterns = agg.get("patterns_established", [])
568
+ if patterns:
569
+ lines = ["### Established Patterns"]
570
+ lines.extend(f"- {p}" for p in patterns)
571
+ sections.append("\n".join(lines))
572
+
573
+ # --- Tech Stack ---
574
+ tech = agg.get("tech_stack_added", [])
575
+ if tech:
576
+ sections.append(f"### Tech Stack\n{', '.join(tech)}")
577
+
578
+ # --- Key Decisions ---
579
+ decisions = agg.get("key_decisions", [])
580
+ if decisions:
581
+ lines = ["### Key Decisions"]
582
+ lines.extend(f"- {d}" for d in decisions)
583
+ sections.append("\n".join(lines))
584
+
585
+ # --- Key Files ---
586
+ created = agg.get("key_files_created", [])
587
+ modified = agg.get("key_files_modified", [])
588
+ if created or modified:
589
+ lines = ["### Key Files"]
590
+ if created:
591
+ lines.append("**Created:**")
592
+ lines.extend(f"- `{f}`" for f in created)
593
+ if modified:
594
+ lines.append("**Modified:**")
595
+ lines.extend(f"- `{f}`" for f in modified)
596
+ sections.append("\n".join(lines))
597
+
598
+ # --- Debug Learnings ---
599
+ debug = output.get("debug_learnings", [])
600
+ if debug:
601
+ lines = ["### Debug Learnings"]
602
+ for d in debug:
603
+ slug = d.get("slug", "unknown")
604
+ sub = d.get("subsystem", "")
605
+ rc = d.get("root_cause", "")
606
+ res = d.get("resolution", "")
607
+ lines.append(f"- **{slug}** ({sub}): {rc} — Fix: {res}")
608
+ sections.append("\n".join(lines))
609
+
610
+ # --- Adhoc Learnings ---
611
+ adhoc_entries = [
612
+ a for a in output.get("adhoc_learnings", []) if a.get("learnings")
613
+ ]
614
+ if adhoc_entries:
615
+ lines = ["### Adhoc Learnings"]
616
+ for a in adhoc_entries:
617
+ sub = a.get("subsystem", "")
618
+ path = a.get("path", "")
619
+ label = sub or Path(path).stem if path else "unknown"
620
+ lines.append(f"- **{label}**")
621
+ for learning in a["learnings"]:
622
+ lines.append(f" - {learning}")
623
+ sections.append("\n".join(lines))
624
+
625
+ # --- Summaries ---
626
+ summaries = output.get("summaries", [])
627
+ needs_read = [
628
+ s
629
+ for s in summaries
630
+ if s.get("relevance") == "HIGH" and s.get("has_readiness_warnings")
631
+ ]
632
+ other_relevant = [
633
+ s
634
+ for s in summaries
635
+ if s.get("relevance") in ("HIGH", "MEDIUM")
636
+ and not s.get("has_readiness_warnings")
637
+ ]
638
+
639
+ if needs_read:
640
+ lines = ["### Summaries Needing Full Read"]
641
+ for s in needs_read:
642
+ lines.append(f"- `{s['path']}`")
643
+ sections.append("\n".join(lines))
644
+
645
+ if other_relevant:
646
+ lines = ["### Other Relevant Summaries"]
647
+ for s in other_relevant:
648
+ lines.append(f"- `{s['path']}` [{s.get('relevance', '')}]")
649
+ sections.append("\n".join(lines))
650
+
651
+ # --- Knowledge Files ---
652
+ matched_knowledge = [
653
+ k for k in output.get("knowledge_files", []) if k.get("matched")
654
+ ]
655
+ if matched_knowledge:
656
+ lines = ["### Knowledge Files to Read"]
657
+ for k in matched_knowledge:
658
+ lines.append(f"- `{k['path']}`")
659
+ sections.append("\n".join(lines))
660
+
661
+ # --- Pending Todos ---
662
+ todos = output.get("pending_todos", [])
663
+ if todos:
664
+ lines = ["### Pending Todos"]
665
+ for t in todos:
666
+ title = t.get("title", "untitled")
667
+ priority = t.get("priority", "")
668
+ sub = t.get("subsystem", "")
669
+ path = t.get("path", "")
670
+ lines.append(f"- **{title}** [{priority}] ({sub}) — `{path}`")
671
+ sections.append("\n".join(lines))
672
+
673
+ # --- Scanner Info ---
674
+ sources = output.get("sources", {})
675
+ parse_errors = sources.get("parse_errors", [])
676
+ info_lines = ["### Scanner Info"]
677
+ for name, src in sources.items():
678
+ if name == "parse_errors" or not isinstance(src, dict):
679
+ continue
680
+ scanned = src.get("scanned", 0)
681
+ skipped = src.get("skipped")
682
+ if skipped:
683
+ info_lines.append(f"- {name}: skipped ({skipped})")
684
+ else:
685
+ info_lines.append(f"- {name}: {scanned} scanned")
686
+ if parse_errors:
687
+ info_lines.append("**Parse errors:**")
688
+ for err in parse_errors:
689
+ info_lines.append(f"- `{err.get('path', '')}`: {err.get('error', '')}")
690
+ sections.append("\n".join(info_lines))
691
+
692
+ return "\n\n".join(sections)
693
+
694
+
555
695
  # ---------------------------------------------------------------------------
556
696
  # Main
557
697
  # ---------------------------------------------------------------------------
@@ -583,6 +723,11 @@ def build_parser() -> argparse.ArgumentParser:
583
723
  default="",
584
724
  help="Comma-separated keywords for tag matching",
585
725
  )
726
+ parser.add_argument(
727
+ "--json",
728
+ action="store_true",
729
+ help="Output raw JSON (default: formatted markdown)",
730
+ )
586
731
  return parser
587
732
 
588
733
 
@@ -604,40 +749,42 @@ def main() -> None:
604
749
 
605
750
  planning = find_planning_dir()
606
751
  if planning is None:
607
- # No .planning/ directory — output valid JSON with all sources skipped
608
- output: dict[str, Any] = {
609
- "success": True,
610
- "target": {
611
- "phase": phase,
612
- "phase_name": phase_name,
613
- "subsystems": subsystems,
614
- "keywords": keywords,
615
- },
616
- "sources": {
617
- "summaries": {"dir": "", "scanned": 0, "skipped": ".planning/ not found"},
618
- "debug_docs": {"dir": "", "scanned": 0, "skipped": ".planning/ not found"},
619
- "adhoc_summaries": {"dir": "", "scanned": 0, "skipped": ".planning/ not found"},
620
- "completed_todos": {"dir": "", "scanned": 0, "skipped": ".planning/ not found"},
621
- "pending_todos": {"dir": "", "scanned": 0, "skipped": ".planning/ not found"},
622
- "knowledge_files": {"dir": "", "scanned": 0, "skipped": ".planning/ not found"},
623
- "parse_errors": [],
624
- },
625
- "summaries": [],
626
- "debug_learnings": [],
627
- "adhoc_learnings": [],
628
- "completed_todos": [],
629
- "pending_todos": [],
630
- "knowledge_files": [],
631
- "aggregated": {
632
- "tech_stack_added": [],
633
- "patterns_established": [],
634
- "key_files_created": [],
635
- "key_files_modified": [],
636
- "key_decisions": [],
637
- },
638
- }
639
- json.dump(output, sys.stdout, indent=2, cls=_SafeEncoder)
640
- sys.stdout.write("\n")
752
+ if args.json:
753
+ output: dict[str, Any] = {
754
+ "success": True,
755
+ "target": {
756
+ "phase": phase,
757
+ "phase_name": phase_name,
758
+ "subsystems": subsystems,
759
+ "keywords": keywords,
760
+ },
761
+ "sources": {
762
+ "summaries": {"dir": "", "scanned": 0, "skipped": ".planning/ not found"},
763
+ "debug_docs": {"dir": "", "scanned": 0, "skipped": ".planning/ not found"},
764
+ "adhoc_summaries": {"dir": "", "scanned": 0, "skipped": ".planning/ not found"},
765
+ "completed_todos": {"dir": "", "scanned": 0, "skipped": ".planning/ not found"},
766
+ "pending_todos": {"dir": "", "scanned": 0, "skipped": ".planning/ not found"},
767
+ "knowledge_files": {"dir": "", "scanned": 0, "skipped": ".planning/ not found"},
768
+ "parse_errors": [],
769
+ },
770
+ "summaries": [],
771
+ "debug_learnings": [],
772
+ "adhoc_learnings": [],
773
+ "completed_todos": [],
774
+ "pending_todos": [],
775
+ "knowledge_files": [],
776
+ "aggregated": {
777
+ "tech_stack_added": [],
778
+ "patterns_established": [],
779
+ "key_files_created": [],
780
+ "key_files_modified": [],
781
+ "key_decisions": [],
782
+ },
783
+ }
784
+ json.dump(output, sys.stdout, indent=2, cls=_SafeEncoder)
785
+ sys.stdout.write("\n")
786
+ else:
787
+ print("No .planning/ directory found. No prior context available.")
641
788
  return
642
789
 
643
790
  parse_errors: list[dict[str, str]] = []
@@ -681,8 +828,11 @@ def main() -> None:
681
828
  "aggregated": aggregated,
682
829
  }
683
830
 
684
- json.dump(output, sys.stdout, indent=2, cls=_SafeEncoder)
685
- sys.stdout.write("\n")
831
+ if args.json:
832
+ json.dump(output, sys.stdout, indent=2, cls=_SafeEncoder)
833
+ sys.stdout.write("\n")
834
+ else:
835
+ print(format_markdown(output))
686
836
 
687
837
 
688
838
  if __name__ == "__main__":
@@ -70,13 +70,13 @@ fi
70
70
  # --- Check 3 (warning): File conflicts within waves ---
71
71
  CURRENT_WAVE=""
72
72
  WAVE_COUNT=0
73
- declare -A WAVE_FILES
73
+ CURRENT_WAVE_FILES=""
74
74
 
75
75
  while IFS= read -r line; do
76
76
  if echo "$line" | grep -qE '^## Wave [0-9]+'; then
77
77
  CURRENT_WAVE=$(echo "$line" | grep -oE '[0-9]+')
78
78
  WAVE_COUNT=$((WAVE_COUNT + 1))
79
- WAVE_FILES[$CURRENT_WAVE]=""
79
+ CURRENT_WAVE_FILES=""
80
80
  elif [ -n "$CURRENT_WAVE" ]; then
81
81
  PLAN_FILE=$(echo "$line" | grep -oE '[0-9][0-9.]*-[0-9]+-PLAN\.md' || true)
82
82
  if [ -n "$PLAN_FILE" ] && [ -f "$PHASE_DIR/$PLAN_FILE" ]; then
@@ -84,11 +84,10 @@ while IFS= read -r line; do
84
84
  FILE_PATHS=$(grep -E '^\*\*Files:\*\*' "$PHASE_DIR/$PLAN_FILE" | sed 's/\*\*Files:\*\*//g' | tr ',' '\n' | sed 's/`//g; s/^[[:space:]]*//; s/[[:space:]]*$//' | grep -v '^$' || true)
85
85
  while IFS= read -r fpath; do
86
86
  [ -z "$fpath" ] && continue
87
- EXISTING="${WAVE_FILES[$CURRENT_WAVE]}"
88
- if echo "$EXISTING" | grep -qF "|$fpath|"; then
87
+ if echo "$CURRENT_WAVE_FILES" | grep -qF "|$fpath|"; then
89
88
  echo "WARNING: File '$fpath' appears in multiple plans within Wave $CURRENT_WAVE"
90
89
  else
91
- WAVE_FILES[$CURRENT_WAVE]="${EXISTING}|$fpath|"
90
+ CURRENT_WAVE_FILES="${CURRENT_WAVE_FILES}|$fpath|"
92
91
  fi
93
92
  done <<< "$FILE_PATHS"
94
93
  fi
@@ -1,68 +0,0 @@
1
- #!/bin/bash
2
- #
3
- # cleanup-phase-artifacts.sh
4
- # Deletes raw phase artifacts (CONTEXT, DESIGN, RESEARCH, SUMMARY, UAT,
5
- # VERIFICATION, EXECUTION-ORDER) from all phases in a milestone range.
6
- # Knowledge files in .planning/knowledge/ are not touched.
7
- #
8
- # Usage: ./scripts/cleanup-phase-artifacts.sh <start_phase> <end_phase>
9
- # Example: ./scripts/cleanup-phase-artifacts.sh 1 6
10
-
11
- set -e
12
-
13
- # --- Validation ---
14
- if [ -z "$1" ] || [ -z "$2" ]; then
15
- echo "Error: Two arguments required"
16
- echo "Usage: $0 <start_phase> <end_phase>"
17
- exit 1
18
- fi
19
-
20
- START="$1"
21
- END="$2"
22
-
23
- if ! [[ "$START" =~ ^[0-9]+$ ]] || ! [[ "$END" =~ ^[0-9]+$ ]]; then
24
- echo "Error: Both arguments must be numeric"
25
- echo "Usage: $0 <start_phase> <end_phase>"
26
- exit 1
27
- fi
28
-
29
- if [ "$START" -gt "$END" ]; then
30
- echo "Error: Start phase ($START) cannot exceed end phase ($END)"
31
- exit 1
32
- fi
33
-
34
- # --- Find .planning from git root ---
35
- GIT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
36
- if [ -z "$GIT_ROOT" ]; then
37
- echo "Error: Not in a git repository"
38
- exit 1
39
- fi
40
-
41
- PHASES_DIR="$GIT_ROOT/.planning/phases"
42
- if [ ! -d "$PHASES_DIR" ]; then
43
- echo "Error: Phases directory not found at $PHASES_DIR"
44
- exit 1
45
- fi
46
-
47
- # --- Delete artifacts from each phase in range ---
48
- DELETED=0
49
- for dir in "$PHASES_DIR"/*/; do
50
- [ -d "$dir" ] || continue
51
- dirname=$(basename "$dir")
52
- phase_num="${dirname%%-*}"
53
- # Strip leading zeros for numeric comparison
54
- phase_int=$((10#$phase_num))
55
- if [ "$phase_int" -ge "$START" ] && [ "$phase_int" -le "$END" ]; then
56
- for f in "$dir"/*-CONTEXT.md "$dir"/*-DESIGN.md "$dir"/*-RESEARCH.md \
57
- "$dir"/*-SUMMARY.md "$dir"/*-UAT.md "$dir"/*-VERIFICATION.md \
58
- "$dir"/*-EXECUTION-ORDER.md; do
59
- if [ -f "$f" ]; then
60
- rm -f "$f"
61
- DELETED=$((DELETED + 1))
62
- fi
63
- done
64
- fi
65
- done
66
-
67
- echo "Cleaned $DELETED artifact files from phases $START-$END"
68
- exit 0