kortext 1.0.0 → 2.2.3

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 (140) hide show
  1. package/AGENTS.md +28 -0
  2. package/README.md +98 -0
  3. package/agents/backend-developer.md +132 -0
  4. package/agents/compliance-expert.md +106 -0
  5. package/agents/copywriter.md +122 -0
  6. package/agents/db-admin.md +117 -0
  7. package/agents/delivery-manager.md +121 -0
  8. package/agents/designer.md +108 -0
  9. package/agents/devops-engineer.md +141 -0
  10. package/agents/engineering-manager.md +208 -0
  11. package/agents/frontend-developer.md +174 -0
  12. package/agents/growth-expert.md +115 -0
  13. package/agents/operation-manager.md +122 -0
  14. package/agents/product-manager.md +114 -0
  15. package/agents/qa-engineer.md +126 -0
  16. package/agents/security-engineer.md +119 -0
  17. package/hooks/audit-logger.sh +25 -0
  18. package/hooks/auto-locker.sh +74 -0
  19. package/hooks/auto-unlocker.sh +17 -0
  20. package/hooks/backlog-sync-guard.sh +12 -0
  21. package/hooks/branch-guard.sh +32 -0
  22. package/hooks/commit-msg-guard.sh +43 -0
  23. package/hooks/git-pre-commit.sh +76 -0
  24. package/hooks/git-pre-push.sh +17 -0
  25. package/hooks/handover-guard.sh +33 -0
  26. package/hooks/kortext-init.sh +194 -0
  27. package/hooks/kortext-lib.sh +151 -0
  28. package/hooks/lint-guard.sh +50 -0
  29. package/hooks/secret-scanner.sh +89 -0
  30. package/hooks/size-guard.sh +48 -0
  31. package/hooks/snapshot-guard.sh +39 -0
  32. package/hooks/write-guard.sh +77 -0
  33. package/package.json +23 -6
  34. package/rules/behavior.md +252 -0
  35. package/rules/branching.md +82 -0
  36. package/rules/commands.md +112 -0
  37. package/rules/emergency.md +160 -0
  38. package/rules/mcp.md +47 -0
  39. package/rules/models.md +93 -0
  40. package/scripts/kortext-backlog-add.py +123 -0
  41. package/scripts/kortext-backlog-health.py +112 -0
  42. package/scripts/kortext-backlog-sync.py +117 -0
  43. package/scripts/kortext-bulk-plan.py +63 -0
  44. package/scripts/kortext-cli.py +376 -0
  45. package/scripts/kortext-consistency-check.py +74 -0
  46. package/scripts/kortext-context-check.py +146 -0
  47. package/scripts/kortext-handover.py +107 -0
  48. package/scripts/kortext-item-check.py +61 -0
  49. package/scripts/kortext-item-start.py +70 -0
  50. package/scripts/kortext-item-transition.py +78 -0
  51. package/scripts/kortext-lock.py +174 -0
  52. package/scripts/kortext-session-start.py +127 -0
  53. package/scripts/lock_kortext.sh +34 -0
  54. package/settings/.claude-settings.template.json +48 -0
  55. package/settings/CHANGELOG.md +176 -0
  56. package/settings/INTEGRATION-MAP.md +276 -0
  57. package/settings/README.md +255 -0
  58. package/settings/USER-GUIDE.md +502 -0
  59. package/settings/VERSION +1 -0
  60. package/settings/config.md +8 -0
  61. package/settings/runtime-adapters.md +104 -0
  62. package/skills/backend-developer/.gitkeep +0 -0
  63. package/skills/compliance-expert/.gitkeep +0 -0
  64. package/skills/copywriter/.gitkeep +0 -0
  65. package/skills/db-admin/.gitkeep +0 -0
  66. package/skills/delivery-manager/.gitkeep +0 -0
  67. package/skills/designer/.gitkeep +0 -0
  68. package/skills/devops-engineer/.gitkeep +0 -0
  69. package/skills/engineering-manager/.gitkeep +0 -0
  70. package/skills/frontend-developer/.gitkeep +0 -0
  71. package/skills/growth-expert/.gitkeep +0 -0
  72. package/skills/operation-manager/.gitkeep +0 -0
  73. package/skills/product-manager/.gitkeep +0 -0
  74. package/skills/qa-engineer/.gitkeep +0 -0
  75. package/skills/security-engineer/.gitkeep +0 -0
  76. package/workflows/00-kortext-setup.md +53 -0
  77. package/workflows/01a-analysis-pipeline.md +117 -0
  78. package/workflows/01b-onboarding-pipeline.md +110 -0
  79. package/workflows/02-planning-pipeline.md +146 -0
  80. package/workflows/02b-spike-workflow.md +120 -0
  81. package/workflows/03-environment-setup.md +99 -0
  82. package/workflows/04-development-cycle.md +203 -0
  83. package/workflows/05-test-cycle.md +123 -0
  84. package/workflows/06-deployment-cycle.md +224 -0
  85. package/workflows/07-rollback-pipeline.md +203 -0
  86. package/workflows/08-hotfix-pipeline.md +196 -0
  87. package/workflows/09-maintenance-cycle.md +133 -0
  88. package/workspace/archive/.gitkeep +0 -0
  89. package/workspace/backups/.gitkeep +0 -0
  90. package/workspace/memory/backlog/.gitkeep +0 -0
  91. package/workspace/memory/backlog/BXX-[bug-name].md +2 -0
  92. package/workspace/memory/backlog/DXX-[debt-name].md +2 -0
  93. package/workspace/memory/backlog/README.md +31 -0
  94. package/workspace/memory/backlog/TXX-[task-name].md +2 -0
  95. package/workspace/memory/backlog/debt-dashboard.md +3 -0
  96. package/workspace/memory/backlog/epic-dashboard.md +10 -0
  97. package/workspace/memory/backlog/version-dashboard.md +7 -0
  98. package/workspace/memory/context/.gitkeep +0 -0
  99. package/workspace/memory/context/README.md +35 -0
  100. package/workspace/memory/context/[agent-name]-active.md +2 -0
  101. package/workspace/memory/decisions.md +17 -0
  102. package/workspace/memory/handover.md +40 -0
  103. package/workspace/memory/learned.md +21 -0
  104. package/workspace/references/access.md +47 -0
  105. package/workspace/references/api-reference.md +59 -0
  106. package/workspace/references/blueprint.md +29 -0
  107. package/workspace/references/content-strategy.md +39 -0
  108. package/workspace/references/db-schema.md +51 -0
  109. package/workspace/references/design-system.md +107 -0
  110. package/workspace/references/dictionary.md +42 -0
  111. package/workspace/references/file-system.md +42 -0
  112. package/workspace/references/growth-strategy.md +46 -0
  113. package/workspace/references/legal-strategy.md +35 -0
  114. package/workspace/references/required-skills.md +11 -0
  115. package/workspace/references/security-rules.md +34 -0
  116. package/workspace/references/tech-stack.md +49 -0
  117. package/workspace/references/test-strategy.md +48 -0
  118. package/workspace/reports/analysis-reports.md +40 -0
  119. package/workspace/reports/content-reports.md +29 -0
  120. package/workspace/reports/delivery-reports.md +26 -0
  121. package/workspace/reports/growth-reports.md +9 -0
  122. package/workspace/reports/legal-reports.md +29 -0
  123. package/workspace/reports/product-requirements.md +28 -0
  124. package/workspace/reports/release-notes.md +20 -0
  125. package/workspace/reports/security-reports.md +27 -0
  126. package/workspace/reports/status-reports.md +48 -0
  127. package/workspace/reports/tech-requirements.md +30 -0
  128. package/workspace/reports/test-reports.md +61 -0
  129. package/workspace/templates/BXX-[bug-name].md +34 -0
  130. package/workspace/templates/DXX-[debt-name].md +35 -0
  131. package/workspace/templates/EXX-[epic-name].md +48 -0
  132. package/workspace/templates/HXX-[hotfix-name].md +73 -0
  133. package/workspace/templates/SXX-[spike-name].md +51 -0
  134. package/workspace/templates/TXX-[task-name].md +34 -0
  135. package/workspace/templates/[agent-name]-active.md +4 -0
  136. package/workspace/templates/[original-name]_[YYYY-MM-DD_HHMMSS].md +5 -0
  137. package/workspace/templates/adr-XXX.md +66 -0
  138. package/workspace/templates/debt-dashboard.md +10 -0
  139. package/workspace/templates/epic-dashboard.md +10 -0
  140. package/workspace/templates/version-dashboard.md +10 -0
@@ -0,0 +1,93 @@
1
+ # Model Konfigürasyonu
2
+
3
+ Bu dosya, personanın görev türüne göre hangi model profilini kullanacağını merkezi olarak tanımlar. Persona dosyalarında doğrudan model adı yazılmaz; persona dosyaları yalnızca görev kategorisini belirtir.
4
+
5
+ ## Görev Kategorileri
6
+
7
+ | Kategori | Kullanım Alanı | Varsayılan Profil | Fallback Profil |
8
+ | :--- | :--- | :--- | :--- |
9
+ | `deep-research` | Araştırma, analiz, mimari tasarım, strateji, karmaşık kod üretimi, güvenlik değerlendirmesi | `high-reasoning` | `standard-reasoning` |
10
+ | `routine` | Format düzenleme, standart güncelleme, raporlama, basit denetim, düşük riskli rutin işler | `fast-reasoning` | `standard-reasoning` |
11
+
12
+ ## Model Profilleri
13
+
14
+ | Profil | Beklenen Özellik | Kullanım |
15
+ | :--- | :--- | :--- |
16
+ | `high-reasoning` | En güçlü muhakeme, uzun bağlam, karmaşık analiz | Kritik teknik kararlar ve çok adımlı üretim işleri |
17
+ | `standard-reasoning` | Dengeli muhakeme ve hız | Fallback veya orta karmaşıklıktaki işler |
18
+ | `fast-reasoning` | Hızlı cevap, düşük maliyet | Rutin raporlama ve basit kontrol işleri |
19
+
20
+ ## Rol → Kategori Ataması
21
+
22
+ | Persona | Varsayılan Kategori | Not |
23
+ | :--- | :--- | :--- |
24
+ | `+operation-manager` | `routine` | Orkestrasyon, durum takibi, raporlama |
25
+ | `+product-manager` | `deep-research` | Ürün gereksinimi, kapsam ve önceliklendirme |
26
+ | `+engineering-manager` | `deep-research` | Mimari, teknik karar, code review |
27
+ | `+delivery-manager` | `routine` | Release koordinasyonu ve teslimat raporları |
28
+ | `+backend-developer` | `deep-research` | Backend uygulama ve servis mantığı |
29
+ | `+frontend-developer` | `deep-research` | UI uygulama ve frontend mimarisi |
30
+ | `+db-admin` | `deep-research` | Veri modeli, migration, performans |
31
+ | `+devops-engineer` | `routine` | CI/CD, ortam, deployment operasyonları |
32
+ | `+qa-engineer` | `routine` | Test yürütme, doğrulama, raporlama |
33
+ | `+security-engineer` | `deep-research` | Güvenlik analizi, risk ve zafiyet değerlendirmesi |
34
+ | `+designer` | `deep-research` | Tasarım sistemi, UX/UI değerlendirmesi |
35
+ | `+copywriter` | `deep-research` | İçerik stratejisi, marka dili, mikro metin |
36
+ | `+growth-expert` | `deep-research` | SEO/GEO, analitik, büyüme stratejisi |
37
+ | `+compliance-expert` | `deep-research` | KVKK/GDPR ve yasal değerlendirme |
38
+
39
+ ## Sağlayıcı Seçimi
40
+
41
+ Gerçek model ID'leri sağlayıcıya ve kurulu ortama göre değişebilir. Bu nedenle model ID'leri persona dosyalarına yazılmaz.
42
+
43
+ ## Resmi Model Kaynakları
44
+
45
+ Model seçimi veya model güncellemesi yapılmadan önce sağlayıcının resmi model dokümantasyonu kontrol edilir.
46
+
47
+ | Sağlayıcı | Resmi Kaynak |
48
+ | :--- | :--- |
49
+ | Anthropic / Claude | https://docs.anthropic.com/en/docs/about-claude/models/overview |
50
+ | Google / Gemini | https://ai.google.dev/gemini-api/docs/models |
51
+ | OpenAI | https://developers.openai.com/api/docs/models |
52
+
53
+ ## Güncellik Kuralı
54
+
55
+ - +prime "en güncel", "latest" veya belirli bir sağlayıcıdaki yeni model ailesini isterse ajan resmi model dokümanını kontrol etmeden model önermemelidir.
56
+ - Varsayılan tercih +prime aksi yönde belirtmedikçe en güncel uygun modeldir.
57
+ - Production kullanımında model ID sabitlenmesi gerekiyorsa ilgili snapshot/stable ID `workspace/references/access.md` veya `workspace/references/tech-stack.md` içinde ayrıca belgelenir.
58
+ - Bir sağlayıcının "latest" alias'ı ile sabit snapshot ID'si farklı amaçlara hizmet ediyorsa bu fark raporda açıkça belirtilir.
59
+
60
+ Model seçimi yapılırken:
61
+
62
+ 1. Önce görevin kategorisi belirlenir.
63
+ 2. Resmi model kaynağı kontrol edilir.
64
+ 3. Kategoriye karşılık gelen varsayılan profil seçilir.
65
+ 4. Mevcut ortamda bu profile karşılık gelen en güncel uygun model kullanılır.
66
+ 5. Model erişilemezse fallback profil kullanılır.
67
+ 6. Fallback kullanımı `workspace/reports/status-reports.md` veya ilgili görev raporuna not edilir.
68
+
69
+ ## Fallback Politikası
70
+
71
+ - Fallback modeli aynı görevi tamamlamak için yeterliyse işlem devam eder.
72
+ - Fallback kalite riski oluşturuyorsa görev `Blocked` yapılır ve +operation-manager'a eskale edilir.
73
+ - `deep-research` görevlerinde fallback kullanıldıysa sonuç kalitesi özellikle belirtilir.
74
+ - API/LLM kesintilerinde retry ve fallback sırası `rules/emergency.md` içindeki Self-Healing Protocol'e göre yürütülür.
75
+
76
+ ## Persona Dosyalarında Kullanım
77
+
78
+ Persona dosyalarının `instructions` bölümünde her görev adımında model adı yerine kategori referansı kullanılır:
79
+
80
+ ```markdown
81
+ ### 1. Araştırma Protokolü
82
+ **Kategori:** `deep-research`
83
+
84
+ ### 2. Rutin Güncelleme
85
+ **Kategori:** `routine`
86
+ ```
87
+
88
+ ## Güncelleme Politikası
89
+
90
+ - Model profili veya kategori değişikliklerinde yalnızca bu dosya güncellenir.
91
+ - Gerçek sağlayıcı/model ID eşleşmeleri proje ortamına göre `workspace/references/tech-stack.md` veya `workspace/references/access.md` içinde belgelenir.
92
+ - Model değişikliği önerisi +operation-manager tarafından yapılır.
93
+ - Stratejik model değişikliği +prime onayı gerektirir.
@@ -0,0 +1,123 @@
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import argparse
5
+ import shutil
6
+ import subprocess
7
+ from datetime import datetime
8
+ from pathlib import Path
9
+
10
+
11
+ BACKLOG_ROOT = Path("workspace/memory/backlog")
12
+
13
+
14
+ def _atomic_commit(message: str, paths: list[str]) -> None:
15
+ # Kortext atomic operation: dosyaları add edip commit'ler.
16
+ if not shutil.which("git"):
17
+ return
18
+ try:
19
+ subprocess.run(["git", "add", "--", *paths], check=True, capture_output=True)
20
+ subprocess.run(
21
+ ["git", "commit", "-m", message, "--", *paths],
22
+ check=True,
23
+ capture_output=True,
24
+ )
25
+ except subprocess.CalledProcessError:
26
+ return
27
+
28
+
29
+ def slugify(title: str) -> str:
30
+ return "-".join(title.lower().split())
31
+
32
+
33
+ def dashboard_path(kind: str) -> Path:
34
+ mapping = {
35
+ "version": BACKLOG_ROOT / "version-dashboard.md",
36
+ "epic": BACKLOG_ROOT / "epic-dashboard.md",
37
+ "debt": BACKLOG_ROOT / "debt-dashboard.md",
38
+ }
39
+ return mapping[kind]
40
+
41
+
42
+ def append_row(path: Path, row: str) -> None:
43
+ content = path.read_text() if path.exists() else ""
44
+ if row not in content:
45
+ if content and not content.endswith("\n"):
46
+ content += "\n"
47
+ content += row + "\n"
48
+ path.write_text(content)
49
+
50
+
51
+ def build_item_content(item_type: str, item_id: str, title: str, persona: str, epic: str | None) -> str:
52
+ date_str = datetime.now().strftime("%Y.%m.%d-%H:%M")
53
+ epic_line = f"> **Epic:** {epic}\n" if epic else ""
54
+ return f"""# {item_id}: {title}
55
+ {epic_line}> **Assignee:** [{persona}]
56
+ > **Model:** [selected-ai-model]
57
+ > **Status:** To Do
58
+
59
+ ---
60
+
61
+ ## Description
62
+ {title} açıklaması.
63
+
64
+ ## Acceptance Criteria
65
+ - [ ] Code review
66
+ - [ ] Quality control
67
+ - [ ] Security check
68
+
69
+ ## Dependencies
70
+ - [task-id] - [task-name]
71
+
72
+ ## Work Log
73
+ - **[{date_str}] ({persona}):** {item_type.capitalize()} oluşturuldu.
74
+
75
+ ## Decisions
76
+ - [alınan karar]
77
+
78
+ ## Notes
79
+ - [notlar]
80
+ """
81
+
82
+
83
+ def main() -> None:
84
+ parser = argparse.ArgumentParser(description="Kortext Backlog Add Tool")
85
+ parser.add_argument("--type", choices=["task", "bug", "debt"], required=True)
86
+ parser.add_argument("--id", required=True, help="e.g. T01, B01, D01")
87
+ parser.add_argument("--title", required=True)
88
+ parser.add_argument("--persona", default="+persona")
89
+ parser.add_argument("--epic", help="e.g. E01-auth (required for task and bug)")
90
+ parser.add_argument("--no-commit", action="store_true", help="Atomic git commit'i atla")
91
+ args = parser.parse_args()
92
+
93
+ if args.type in {"task", "bug"} and not args.epic:
94
+ raise SystemExit("Hata: task ve bug türleri için --epic zorunludur.")
95
+
96
+ BACKLOG_ROOT.mkdir(parents=True, exist_ok=True)
97
+ file_path = BACKLOG_ROOT / f"{args.id}-{slugify(args.title)}.md"
98
+ file_path.write_text(build_item_content(args.type, args.id, args.title, args.persona, args.epic))
99
+
100
+ if args.type in {"task", "bug"}:
101
+ dashboard = dashboard_path("epic")
102
+ append_row(
103
+ dashboard,
104
+ f"| {args.id} | [{args.title}](./{file_path.name}) | {args.epic} | {args.persona} | To Do |",
105
+ )
106
+ else:
107
+ dashboard = dashboard_path("debt")
108
+ append_row(
109
+ dashboard,
110
+ f"| {args.id} | [{args.title}](./{file_path.name}) | {args.persona} | To Do |",
111
+ )
112
+
113
+ print(f"✅ {args.type.capitalize()} oluşturuldu: {file_path}")
114
+
115
+ if not args.no_commit:
116
+ _atomic_commit(
117
+ f"chore(kortext): add {args.type} {args.id} [skip ci]",
118
+ [str(file_path), str(dashboard)],
119
+ )
120
+
121
+
122
+ if __name__ == "__main__":
123
+ main()
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Kortext Backlog Health
4
+ ----------------------
5
+ Backlog'un genel sağlık durumunu raporlar. Blocker itemlar, stale In Progress'ler,
6
+ review bekleyenler ve hazır (başlanabilir) itemlar özetlenir.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import os
11
+ import re
12
+ from datetime import datetime
13
+ from pathlib import Path
14
+
15
+
16
+ ROOT = Path(__file__).resolve().parents[1]
17
+ BACKLOG_DIR = ROOT / "workspace/memory/backlog"
18
+ # In Progress backlog item'larının stale eşiği. Env var ile override edilebilir.
19
+ STALE_HOURS = int(os.environ.get("KORTEXT_STALE_HOURS_BACKLOG", "48"))
20
+
21
+ STATUS_PATTERN = re.compile(r"\*\*Status:\*\*\s*(.+)")
22
+ BLOCKED_BY_PATTERN = re.compile(r"\*\*Blocked By:\*\*\s*(.+)")
23
+ RISK_PATTERN = re.compile(r"\*\*Risk:\*\*\s*(Blocker|High|Critical)", re.IGNORECASE)
24
+
25
+
26
+ def parse_items() -> list[dict]:
27
+ items = []
28
+ if not BACKLOG_DIR.exists():
29
+ return items
30
+ for f in sorted(BACKLOG_DIR.glob("[TBD]*.md")):
31
+ text = f.read_text(errors="ignore")
32
+ status_m = STATUS_PATTERN.search(text)
33
+ blocked_m = BLOCKED_BY_PATTERN.search(text)
34
+ risk_m = RISK_PATTERN.search(text)
35
+
36
+ status = status_m.group(1).strip() if status_m else "?"
37
+ has_blocker = blocked_m is not None and blocked_m.group(1).strip() not in ("", "-", "Yok")
38
+ is_high_risk = risk_m is not None
39
+ mtime = datetime.fromtimestamp(f.stat().st_mtime)
40
+ age_hours = (datetime.now() - mtime).total_seconds() / 3600
41
+
42
+ items.append({
43
+ "id": f.stem,
44
+ "status": status,
45
+ "has_blocker": has_blocker,
46
+ "is_high_risk": is_high_risk,
47
+ "age_hours": round(age_hours, 1),
48
+ "stale": status == "In Progress" and age_hours > STALE_HOURS,
49
+ })
50
+ return items
51
+
52
+
53
+ def compute_score(items: list[dict]) -> tuple[int, int]:
54
+ """Basit sağlık skoru: toplam item sayısı üzerinden sorunlu itemları düşür."""
55
+ total = len(items)
56
+ if total == 0:
57
+ return 100, 100
58
+ problems = sum(1 for i in items if i["stale"] or i["has_blocker"])
59
+ score = max(0, round((1 - problems / total) * 100))
60
+ return score, 100
61
+
62
+
63
+ def main() -> None:
64
+ items = parse_items()
65
+ now = datetime.now().strftime("%d.%m.%Y %H:%M")
66
+
67
+ # Grupla
68
+ todo = [i for i in items if i["status"] == "To Do" and not i["has_blocker"]]
69
+ in_progress = [i for i in items if i["status"] == "In Progress"]
70
+ review = [i for i in items if i["status"] == "Review"]
71
+ blocked = [i for i in items if i["has_blocker"] or i["status"] == "Blocked"]
72
+ stale = [i for i in items if i["stale"]]
73
+ done = [i for i in items if i["status"] == "Done"]
74
+ score, max_score = compute_score(items)
75
+
76
+ print("=" * 60)
77
+ print(f" KORTEXT BACKLOG HEALTH — {now}")
78
+ print("=" * 60)
79
+ print(f"\n Toplam item : {len(items)}")
80
+ print(f" ✅ Başlanabilir : {len(todo)}")
81
+ print(f" 🔄 In Progress : {len(in_progress)}")
82
+ print(f" 👀 Review bekliyor : {len(review)}")
83
+ print(f" 🚫 Bloklu : {len(blocked)}")
84
+ print(f" ⚠️ Stale ({STALE_HOURS}s+) : {len(stale)}")
85
+ print(f" ✔️ Done : {len(done)}")
86
+
87
+ if blocked:
88
+ print(f"\n 🚫 BLOKLANAN İTEMLAR:")
89
+ for i in blocked:
90
+ print(f" • {i['id']} ({i['status']})")
91
+
92
+ if stale:
93
+ print(f"\n ⚠️ STALE İTEMLAR:")
94
+ for i in stale:
95
+ print(f" • {i['id']} — {i['age_hours']} saat önce güncellendi")
96
+
97
+ if review:
98
+ print(f"\n 👀 REVIEW BEKLEYENLER (+prime aksiyonu gerekebilir):")
99
+ for i in review:
100
+ print(f" • {i['id']}")
101
+
102
+ bar_filled = int(score / 5)
103
+ bar = "█" * bar_filled + "░" * (20 - bar_filled)
104
+ print(f"\n Sağlık Skoru: {score}/{max_score} [{bar}]")
105
+ print("=" * 60)
106
+
107
+ if score < 50:
108
+ raise SystemExit(1)
109
+
110
+
111
+ if __name__ == "__main__":
112
+ main()
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import re
5
+ from dataclasses import dataclass
6
+ from pathlib import Path
7
+
8
+
9
+ BACKLOG_ROOT = Path("workspace/memory/backlog")
10
+
11
+
12
+ @dataclass
13
+ class Item:
14
+ item_id: str
15
+ title: str
16
+ status: str
17
+ path: Path
18
+ epic: str | None
19
+
20
+
21
+ def parse_item(path: Path) -> Item:
22
+ content = path.read_text()
23
+ header = re.search(r"^# ([TBD]\d+): (.+)$", content, re.M)
24
+ status = re.search(r"> \*\*Status:\*\* (.+)", content)
25
+ epic = re.search(r"> \*\*Epic:\*\* (.+)", content)
26
+ if not header or not status:
27
+ raise ValueError(f"Geçersiz item şablonu: {path}")
28
+ return Item(
29
+ item_id=header.group(1),
30
+ title=header.group(2),
31
+ status=status.group(1).strip(),
32
+ path=path,
33
+ epic=epic.group(1).strip() if epic else None,
34
+ )
35
+
36
+
37
+ def actual_items() -> list[Item]:
38
+ items: list[Item] = []
39
+ for path in BACKLOG_ROOT.glob("*.md"):
40
+ if path.name.endswith("dashboard.md"):
41
+ continue
42
+ if re.match(r"^[TBD]\d+-", path.name):
43
+ items.append(parse_item(path))
44
+ return items
45
+
46
+
47
+ def expected_epic_rows(items: list[Item]) -> set[str]:
48
+ return {
49
+ f"| {item.item_id} | [{item.title}](./{item.path.name}) | {item.epic} | "
50
+ f"{read_assignee(item.path)} | {item.status} |"
51
+ for item in items
52
+ if item.item_id.startswith(("T", "B"))
53
+ }
54
+
55
+
56
+ def expected_debt_rows(items: list[Item]) -> set[str]:
57
+ return {
58
+ f"| {item.item_id} | [{item.title}](./{item.path.name}) | "
59
+ f"{read_assignee(item.path)} | {item.status} |"
60
+ for item in items
61
+ if item.item_id.startswith("D")
62
+ }
63
+
64
+
65
+ def read_assignee(path: Path) -> str:
66
+ match = re.search(r"> \*\*Assignee:\*\* \[(.+)\]", path.read_text())
67
+ return match.group(1) if match else "+persona"
68
+
69
+
70
+ def actual_rows(path: Path) -> set[str]:
71
+ if not path.exists():
72
+ return set()
73
+ return {
74
+ line
75
+ for line in path.read_text().splitlines()
76
+ if re.match(r"^\| [TBD]\d+ \|", line)
77
+ }
78
+
79
+
80
+ def compare(label: str, expected: set[str], actual: set[str]) -> list[str]:
81
+ failures: list[str] = []
82
+ for row in sorted(expected - actual):
83
+ failures.append(f"{label}: eksik satır -> {row}")
84
+ for row in sorted(actual - expected):
85
+ failures.append(f"{label}: beklenmeyen satır -> {row}")
86
+ return failures
87
+
88
+
89
+ def main() -> None:
90
+ items = actual_items()
91
+ failures: list[str] = []
92
+ failures.extend(
93
+ compare(
94
+ "epic-dashboard.md",
95
+ expected_epic_rows(items),
96
+ actual_rows(BACKLOG_ROOT / "epic-dashboard.md"),
97
+ )
98
+ )
99
+ failures.extend(
100
+ compare(
101
+ "debt-dashboard.md",
102
+ expected_debt_rows(items),
103
+ actual_rows(BACKLOG_ROOT / "debt-dashboard.md"),
104
+ )
105
+ )
106
+
107
+ if failures:
108
+ print("❌ Backlog dashboard drift tespit edildi:")
109
+ for failure in failures:
110
+ print(f"- {failure}")
111
+ raise SystemExit(1)
112
+
113
+ print("✅ Backlog dashboard'ları item dosyalarıyla uyumlu.")
114
+
115
+
116
+ if __name__ == "__main__":
117
+ main()
@@ -0,0 +1,63 @@
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import json
5
+ import subprocess
6
+ import sys
7
+ from pathlib import Path
8
+
9
+
10
+ SCRIPT_ADD = Path(__file__).with_name("kortext-backlog-add.py")
11
+
12
+
13
+ def run_add_task(item_type: str, epic: str | None, item_id: str, title: str, persona: str) -> None:
14
+ cmd = [
15
+ sys.executable,
16
+ str(SCRIPT_ADD),
17
+ "--type",
18
+ item_type,
19
+ "--id",
20
+ item_id,
21
+ "--title",
22
+ title,
23
+ "--persona",
24
+ persona,
25
+ ]
26
+ if epic:
27
+ cmd.extend(["--epic", epic])
28
+ subprocess.run(cmd, check=True)
29
+
30
+
31
+ def main() -> None:
32
+ if len(sys.argv) < 2:
33
+ raise SystemExit("Kullanım: kortext-bulk-plan.py <plan.json>")
34
+
35
+ data = json.loads(Path(sys.argv[1]).read_text())
36
+
37
+ for epic in data.get("epics", []):
38
+ epic_id = epic.get("id")
39
+ for item in epic.get("tasks", []):
40
+ print(f"⌛ Oluşturuluyor: {item.get('id')}...")
41
+ run_add_task(
42
+ item.get("type", "task"),
43
+ epic_id,
44
+ item.get("id"),
45
+ item.get("title"),
46
+ item.get("persona", "+persona"),
47
+ )
48
+
49
+ for debt in data.get("debts", []):
50
+ print(f"⌛ Oluşturuluyor: {debt.get('id')}...")
51
+ run_add_task(
52
+ "debt",
53
+ None,
54
+ debt.get("id"),
55
+ debt.get("title"),
56
+ debt.get("persona", "+persona"),
57
+ )
58
+
59
+ print("\n🚀 Toplu planlama başarıyla tamamlandı!")
60
+
61
+
62
+ if __name__ == "__main__":
63
+ main()