kortext 2.2.0 → 3.0.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 (209) hide show
  1. package/AGENTS.md +7 -11
  2. package/CHANGELOG.md +81 -0
  3. package/LICENSE +21 -0
  4. package/README.md +144 -47
  5. package/USER-GUIDE.md +505 -0
  6. package/bin/kortext.js +23 -0
  7. package/bin/kortext.ts +377 -0
  8. package/dist/bin/kortext.js +346 -0
  9. package/dist/bin/kortext.js.map +1 -0
  10. package/dist/mcp/index.js +4 -0
  11. package/dist/mcp/index.js.map +1 -0
  12. package/dist/mcp/server.js +553 -0
  13. package/dist/mcp/server.js.map +1 -0
  14. package/dist/mcp/sse.js +38 -0
  15. package/dist/mcp/sse.js.map +1 -0
  16. package/dist/mcp/stdio.js +44 -0
  17. package/dist/mcp/stdio.js.map +1 -0
  18. package/dist/server/cli/cleanup.js +73 -0
  19. package/dist/server/cli/cleanup.js.map +1 -0
  20. package/dist/server/cli/commands.js +73 -0
  21. package/dist/server/cli/commands.js.map +1 -0
  22. package/dist/server/cli/doctor.js +118 -0
  23. package/dist/server/cli/doctor.js.map +1 -0
  24. package/dist/server/cli/executor-factory.js +39 -0
  25. package/dist/server/cli/executor-factory.js.map +1 -0
  26. package/dist/server/cli/init.js +121 -0
  27. package/dist/server/cli/init.js.map +1 -0
  28. package/dist/server/cli/logs.js +28 -0
  29. package/dist/server/cli/logs.js.map +1 -0
  30. package/dist/server/cli/serve.js +72 -0
  31. package/dist/server/cli/serve.js.map +1 -0
  32. package/dist/server/config/env.js +12 -0
  33. package/dist/server/config/env.js.map +1 -0
  34. package/dist/server/db/client.js +32 -0
  35. package/dist/server/db/client.js.map +1 -0
  36. package/dist/server/db/json.js +21 -0
  37. package/dist/server/db/json.js.map +1 -0
  38. package/dist/server/db/migrate.js +70 -0
  39. package/dist/server/db/migrate.js.map +1 -0
  40. package/dist/server/db/migrations/001_init.sql +243 -0
  41. package/dist/server/db/repositories/audit-log.js +58 -0
  42. package/dist/server/db/repositories/audit-log.js.map +1 -0
  43. package/dist/server/db/repositories/backlog.js +96 -0
  44. package/dist/server/db/repositories/backlog.js.map +1 -0
  45. package/dist/server/db/repositories/contexts.js +54 -0
  46. package/dist/server/db/repositories/contexts.js.map +1 -0
  47. package/dist/server/db/repositories/decisions.js +71 -0
  48. package/dist/server/db/repositories/decisions.js.map +1 -0
  49. package/dist/server/db/repositories/handovers.js +53 -0
  50. package/dist/server/db/repositories/handovers.js.map +1 -0
  51. package/dist/server/db/repositories/index.js +30 -0
  52. package/dist/server/db/repositories/index.js.map +1 -0
  53. package/dist/server/db/repositories/locks.js +59 -0
  54. package/dist/server/db/repositories/locks.js.map +1 -0
  55. package/dist/server/db/repositories/notifications.js +63 -0
  56. package/dist/server/db/repositories/notifications.js.map +1 -0
  57. package/dist/server/db/repositories/pending-questions.js +63 -0
  58. package/dist/server/db/repositories/pending-questions.js.map +1 -0
  59. package/dist/server/db/repositories/runs.js +138 -0
  60. package/dist/server/db/repositories/runs.js.map +1 -0
  61. package/dist/server/db/repositories/runtime-artifacts.js +39 -0
  62. package/dist/server/db/repositories/runtime-artifacts.js.map +1 -0
  63. package/dist/server/db/repositories/secrets.js +65 -0
  64. package/dist/server/db/repositories/secrets.js.map +1 -0
  65. package/dist/server/db/repositories/sessions.js +48 -0
  66. package/dist/server/db/repositories/sessions.js.map +1 -0
  67. package/dist/server/db/schemas.js +308 -0
  68. package/dist/server/db/schemas.js.map +1 -0
  69. package/dist/server/engine/consistency.js +25 -0
  70. package/dist/server/engine/consistency.js.map +1 -0
  71. package/dist/server/engine/dag.js +86 -0
  72. package/dist/server/engine/dag.js.map +1 -0
  73. package/dist/server/engine/executor.js +2 -0
  74. package/dist/server/engine/executor.js.map +1 -0
  75. package/dist/server/engine/executors/claude-cli-executor.js +83 -0
  76. package/dist/server/engine/executors/claude-cli-executor.js.map +1 -0
  77. package/dist/server/engine/executors/cli-spawn.js +127 -0
  78. package/dist/server/engine/executors/cli-spawn.js.map +1 -0
  79. package/dist/server/engine/executors/codex-cli-executor.js +69 -0
  80. package/dist/server/engine/executors/codex-cli-executor.js.map +1 -0
  81. package/dist/server/engine/executors/gemini-cli-executor.js +69 -0
  82. package/dist/server/engine/executors/gemini-cli-executor.js.map +1 -0
  83. package/dist/server/engine/executors/mock-executor.js +52 -0
  84. package/dist/server/engine/executors/mock-executor.js.map +1 -0
  85. package/dist/server/engine/executors/persona-routed-executor.js +17 -0
  86. package/dist/server/engine/executors/persona-routed-executor.js.map +1 -0
  87. package/dist/server/engine/gate-enforcer.js +75 -0
  88. package/dist/server/engine/gate-enforcer.js.map +1 -0
  89. package/dist/server/engine/git-commit.js +42 -0
  90. package/dist/server/engine/git-commit.js.map +1 -0
  91. package/dist/server/engine/handover.js +120 -0
  92. package/dist/server/engine/handover.js.map +1 -0
  93. package/dist/server/engine/item-lifecycle.js +74 -0
  94. package/dist/server/engine/item-lifecycle.js.map +1 -0
  95. package/dist/server/engine/persona-registry.js +108 -0
  96. package/dist/server/engine/persona-registry.js.map +1 -0
  97. package/dist/server/engine/worker-pool.js +324 -0
  98. package/dist/server/engine/worker-pool.js.map +1 -0
  99. package/dist/server/engine/workflow-loader.js +55 -0
  100. package/dist/server/engine/workflow-loader.js.map +1 -0
  101. package/dist/server/engine/workflow-parser.js +158 -0
  102. package/dist/server/engine/workflow-parser.js.map +1 -0
  103. package/dist/server/engine/worktree.js +176 -0
  104. package/dist/server/engine/worktree.js.map +1 -0
  105. package/dist/server/index.js +99 -0
  106. package/dist/server/index.js.map +1 -0
  107. package/dist/server/notifications/dispatcher.js +60 -0
  108. package/dist/server/notifications/dispatcher.js.map +1 -0
  109. package/dist/server/notifications/slack.js +37 -0
  110. package/dist/server/notifications/slack.js.map +1 -0
  111. package/dist/server/notifications/telegram.js +33 -0
  112. package/dist/server/notifications/telegram.js.map +1 -0
  113. package/dist/server/orchestrator/approval-queue.js +83 -0
  114. package/dist/server/orchestrator/approval-queue.js.map +1 -0
  115. package/dist/server/orchestrator/blueprint-watcher.js +94 -0
  116. package/dist/server/orchestrator/blueprint-watcher.js.map +1 -0
  117. package/dist/server/orchestrator/orchestrator.js +283 -0
  118. package/dist/server/orchestrator/orchestrator.js.map +1 -0
  119. package/dist/server/orchestrator/pipeline-chainer.js +96 -0
  120. package/dist/server/orchestrator/pipeline-chainer.js.map +1 -0
  121. package/dist/server/orchestrator/resume.js +36 -0
  122. package/dist/server/orchestrator/resume.js.map +1 -0
  123. package/dist/server/routes/approvals.js +52 -0
  124. package/dist/server/routes/approvals.js.map +1 -0
  125. package/dist/server/routes/backlog.js +44 -0
  126. package/dist/server/routes/backlog.js.map +1 -0
  127. package/dist/server/routes/db-info.js +21 -0
  128. package/dist/server/routes/db-info.js.map +1 -0
  129. package/dist/server/routes/docs.js +70 -0
  130. package/dist/server/routes/docs.js.map +1 -0
  131. package/dist/server/routes/doctor.js +19 -0
  132. package/dist/server/routes/doctor.js.map +1 -0
  133. package/dist/server/routes/handovers.js +25 -0
  134. package/dist/server/routes/handovers.js.map +1 -0
  135. package/dist/server/routes/health.js +11 -0
  136. package/dist/server/routes/health.js.map +1 -0
  137. package/dist/server/routes/personas.js +96 -0
  138. package/dist/server/routes/personas.js.map +1 -0
  139. package/dist/server/routes/runs.js +41 -0
  140. package/dist/server/routes/runs.js.map +1 -0
  141. package/dist/server/routes/workflows.js +38 -0
  142. package/dist/server/routes/workflows.js.map +1 -0
  143. package/dist/server/safety/harmful-output-filter.js +40 -0
  144. package/dist/server/safety/harmful-output-filter.js.map +1 -0
  145. package/dist/server/safety/secret-scanner.js +169 -0
  146. package/dist/server/safety/secret-scanner.js.map +1 -0
  147. package/dist/server/services/markdown-sync.js +101 -0
  148. package/dist/server/services/markdown-sync.js.map +1 -0
  149. package/dist/web/assets/index-B80d5ZPZ.js +75 -0
  150. package/dist/web/assets/index-B80d5ZPZ.js.map +1 -0
  151. package/dist/web/assets/index-Bge5Gzqv.css +1 -0
  152. package/dist/web/index.html +13 -0
  153. package/docs/architecture.md +413 -0
  154. package/package.json +83 -11
  155. package/rules/behavior.md +2 -2
  156. package/scripts/copy-migrations.mjs +29 -0
  157. package/workspace/.locks/workspace_handover.md.lock +3 -0
  158. package/hooks/audit-logger.sh +0 -25
  159. package/hooks/auto-locker.sh +0 -74
  160. package/hooks/auto-unlocker.sh +0 -17
  161. package/hooks/backlog-sync-guard.sh +0 -12
  162. package/hooks/branch-guard.sh +0 -32
  163. package/hooks/commit-msg-guard.sh +0 -43
  164. package/hooks/git-pre-commit.sh +0 -76
  165. package/hooks/git-pre-push.sh +0 -17
  166. package/hooks/handover-guard.sh +0 -33
  167. package/hooks/kortext-init.sh +0 -194
  168. package/hooks/kortext-lib.sh +0 -141
  169. package/hooks/lint-guard.sh +0 -50
  170. package/hooks/secret-scanner.sh +0 -89
  171. package/hooks/size-guard.sh +0 -48
  172. package/hooks/snapshot-guard.sh +0 -39
  173. package/hooks/write-guard.sh +0 -77
  174. package/scripts/kortext-backlog-add.py +0 -123
  175. package/scripts/kortext-backlog-health.py +0 -112
  176. package/scripts/kortext-backlog-sync.py +0 -117
  177. package/scripts/kortext-bulk-plan.py +0 -63
  178. package/scripts/kortext-cli.py +0 -295
  179. package/scripts/kortext-consistency-check.py +0 -74
  180. package/scripts/kortext-context-check.py +0 -146
  181. package/scripts/kortext-handover.py +0 -107
  182. package/scripts/kortext-item-check.py +0 -61
  183. package/scripts/kortext-item-start.py +0 -70
  184. package/scripts/kortext-item-transition.py +0 -78
  185. package/scripts/kortext-lock.py +0 -174
  186. package/scripts/kortext-session-start.py +0 -127
  187. package/scripts/lock_kortext.sh +0 -34
  188. package/settings/.claude-settings.template.json +0 -48
  189. package/settings/CHANGELOG.md +0 -176
  190. package/settings/INTEGRATION-MAP.md +0 -276
  191. package/settings/README.md +0 -255
  192. package/settings/USER-GUIDE.md +0 -502
  193. package/settings/VERSION +0 -1
  194. package/settings/config.md +0 -8
  195. package/settings/runtime-adapters.md +0 -104
  196. package/skills/backend-developer/.gitkeep +0 -0
  197. package/skills/compliance-expert/.gitkeep +0 -0
  198. package/skills/copywriter/.gitkeep +0 -0
  199. package/skills/db-admin/.gitkeep +0 -0
  200. package/skills/delivery-manager/.gitkeep +0 -0
  201. package/skills/designer/.gitkeep +0 -0
  202. package/skills/devops-engineer/.gitkeep +0 -0
  203. package/skills/engineering-manager/.gitkeep +0 -0
  204. package/skills/frontend-developer/.gitkeep +0 -0
  205. package/skills/growth-expert/.gitkeep +0 -0
  206. package/skills/operation-manager/.gitkeep +0 -0
  207. package/skills/product-manager/.gitkeep +0 -0
  208. package/skills/qa-engineer/.gitkeep +0 -0
  209. package/skills/security-engineer/.gitkeep +0 -0
@@ -1,50 +0,0 @@
1
- #!/bin/bash
2
- # KORTEXT MANAGED HOOK — generated/edited by kortext framework
3
- # [KORTEXT] Kod Hatası Denetleyicisi (Lint-Guard)
4
-
5
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
- # shellcheck source=kortext-lib.sh
7
- source "$SCRIPT_DIR/kortext-lib.sh"
8
-
9
- FILE_PATH="${KORTEXT_FILE_PATH:-${CLAUDE_FILE_PATH:-${GEMINI_FILE_PATH:-${OPENAI_FILE_PATH:-}}}}"
10
-
11
- if [ -z "$FILE_PATH" ] || [ ! -f "$FILE_PATH" ]; then exit 0; fi
12
-
13
- EXTENSION="${FILE_PATH##*.}"
14
-
15
- echo "🔍 [KORTEXT LINT] Denetleniyor: $FILE_PATH"
16
-
17
- case "$EXTENSION" in
18
- sh)
19
- # Shell script syntax kontrolü
20
- bash -n "$FILE_PATH"
21
- ;;
22
- js)
23
- # JavaScript syntax kontrolü (Node.js varsa)
24
- if command -v node > /dev/null 2>&1; then
25
- node -c "$FILE_PATH"
26
- fi
27
- ;;
28
- json)
29
- # JSON format kontrolü (Python varsa)
30
- if command -v python3 > /dev/null 2>&1; then
31
- python3 -m json.tool "$FILE_PATH" > /dev/null
32
- fi
33
- ;;
34
- *)
35
- # Diğer dosyalar için şimdilik pas geç
36
- exit 0
37
- ;;
38
- esac
39
-
40
- # Eğer yukarıdaki komutlardan biri hata verirse ($? 1 olursa) durdur
41
- if [ $? -ne 0 ]; then
42
- echo "---"
43
- echo "❌ KORTEXT LINT HATASI"
44
- echo "Dosya içinde yazım veya sözdizimi (syntax) hatası tespit edildi."
45
- echo "Lütfen kodu düzeltip tekrar deneyin."
46
- echo "---"
47
- exit 1
48
- fi
49
-
50
- exit 0
@@ -1,89 +0,0 @@
1
- #!/bin/bash
2
- # KORTEXT MANAGED HOOK — generated/edited by kortext framework
3
- # [KORTEXT] Gizli Bilgi ve Sızıntı Tarayıcı
4
-
5
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
- # shellcheck source=kortext-lib.sh
7
- source "$SCRIPT_DIR/kortext-lib.sh"
8
-
9
- kortext_load_config
10
- KORTEXT_HOOK_MODE="${KORTEXT_HOOK_MODE:-permissive}"
11
-
12
- # ---- Pattern Grubu 1: Tırnaklı Atama (api_key = "...") ----
13
- P1="(api[_-]?key|secret[_-]?key|password|token|bearer|credential|private[_-]key|access[_-]?key|auth[_-]?token)\s*[:=]\s*['\"][^'\"]{8,}['\"]"
14
-
15
- # ---- Pattern Grubu 2: Tırnaksız Atama (API_KEY=sk-abc123) ----
16
- P2="(API_KEY|SECRET_KEY|ACCESS_KEY|AUTH_TOKEN|DB_PASSWORD|DATABASE_URL)=[^'\"\s]{8,}"
17
-
18
- # ---- Pattern Grubu 3: Servis Spesifik Formatlar ----
19
- # OpenAI: sk-proj-..., Anthropic: sk-ant-..., AWS: AKIA..., GitHub: ghp_..., Slack: xox*
20
- P3="(sk-[a-zA-Z0-9]{20,}|AKIA[0-9A-Z]{16}|ghp_[a-zA-Z0-9]{36,}|ghs_[a-zA-Z0-9]{36,}|xox[baprs]-[0-9\-a-zA-Z]{20,})"
21
-
22
- # ---- Pattern Grubu 4: Authorization Header Değerleri ----
23
- P4="Authorization:\s*Bearer\s+[a-zA-Z0-9._\-]{20,}"
24
-
25
- # ---- İstisna: Env okuma ve placeholder değerler ----
26
- EXCLUSIONS="process\.env|import\.meta\.env|os\.environ|getenv|YOUR_|<YOUR|PLACEHOLDER|example|EXAMPLE|\[VALUE\]|\[fill\]"
27
-
28
- scan_file() {
29
- local source_path="$1"
30
- local display_path="${2:-$source_path}"
31
- local pattern
32
-
33
- # Behavior kuralı: ".env versiyon kontrolüne dahil edilmez, gizli bilgiler orada saklanır."
34
- # Bu yüzden gerçek .env dosyalarını tarama dışı bırakıyoruz.
35
- if [[ "$display_path" == *".env"* ]] && [[ "$display_path" != *".env.example"* ]]; then
36
- return 0
37
- fi
38
-
39
- [ -f "$source_path" ] || return 0
40
-
41
- for pattern in "$P1" "$P2" "$P3" "$P4"; do
42
- if grep -Ei "$pattern" "$source_path" 2>/dev/null | grep -vEi "$EXCLUSIONS" > /dev/null; then
43
- echo "---"
44
- echo "⚠️ KORTEXT GÜVENLİK İHLALİ: SIZINTI TESPİT EDİLDİ"
45
- echo "Hata: Dosya içinde açık bir şifre, anahtar (key) veya token tespit edildi."
46
- echo "Kortext Behavior Kuralları gereği (Madde 38-39):"
47
- echo "1. Gizli bilgiler asla kod içine hardcoded yazılmaz."
48
- echo "2. Sadece .env dosyası kullanılmalı ve değerler tırnak içinde oraya taşınmalıdır."
49
- echo ""
50
- echo "Dosya: $display_path"
51
- echo "---"
52
- return 1
53
- fi
54
- done
55
-
56
- return 0
57
- }
58
-
59
- if [ "${1:-}" = "--stdin" ]; then
60
- DISPLAY_PATH="${2:-STDIN}"
61
- TMP_FILE="$(mktemp)"
62
- cat > "$TMP_FILE"
63
- scan_file "$TMP_FILE" "$DISPLAY_PATH"
64
- STATUS=$?
65
- rm -f "$TMP_FILE"
66
- exit "$STATUS"
67
- fi
68
-
69
- if [ "$#" -gt 0 ]; then
70
- STATUS=0
71
- for FILE_PATH in "$@"; do
72
- if ! scan_file "$FILE_PATH"; then
73
- STATUS=1
74
- fi
75
- done
76
- exit "$STATUS"
77
- fi
78
-
79
- FILE_PATH="${KORTEXT_FILE_PATH:-${CLAUDE_FILE_PATH:-${GEMINI_FILE_PATH:-${OPENAI_FILE_PATH:-}}}}"
80
-
81
- if [ -z "$FILE_PATH" ]; then
82
- if [ "$KORTEXT_HOOK_MODE" = "strict" ]; then
83
- echo "⚠️ [KORTEXT] KORTEXT_FILE_PATH tanımsız. strict modda çıkılıyor."
84
- exit 1
85
- fi
86
- exit 0
87
- fi
88
-
89
- scan_file "$FILE_PATH"
@@ -1,48 +0,0 @@
1
- #!/bin/bash
2
- # KORTEXT MANAGED HOOK — generated/edited by kortext framework
3
- # [KORTEXT] Dosya Boyutu ve Arşivleme Muhafixı
4
-
5
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
- # shellcheck source=kortext-lib.sh
7
- source "$SCRIPT_DIR/kortext-lib.sh"
8
-
9
- kortext_load_config
10
- KORTEXT_HOOK_MODE="${KORTEXT_HOOK_MODE:-permissive}"
11
- MAX_LINES="${KORTEXT_SIZE_LIMIT:-500}"
12
-
13
- FILE_PATH="${KORTEXT_FILE_PATH:-${CLAUDE_FILE_PATH:-${GEMINI_FILE_PATH:-${OPENAI_FILE_PATH:-}}}}"
14
-
15
- # Eğer dosya yolu boşsa veya dosya mevcut değilse çık
16
- if [ -z "$FILE_PATH" ] || [ ! -f "$FILE_PATH" ]; then
17
- if [ -z "$FILE_PATH" ] && [ "$KORTEXT_HOOK_MODE" = "strict" ]; then
18
- echo "⚠️ [KORTEXT] KORTEXT_FILE_PATH tanımsız. strict modda çıkılıyor."
19
- exit 1
20
- fi
21
- exit 0
22
- fi
23
-
24
- # ÖZEL İSTİSNA: backlog/ dizini her zaman tam kapsamlı kalmalıdır, arşivlenmez.
25
- if [[ "$FILE_PATH" == *"backlog/"* ]]; then
26
- exit 0
27
- fi
28
-
29
- LINE_COUNT=$(wc -l < "$FILE_PATH")
30
-
31
- if [ "$LINE_COUNT" -gt "$MAX_LINES" ]; then
32
- echo "---"
33
- echo "🛑 KORTEXT BOYUT SINIRI AŞILDI"
34
- echo "Dosya: $FILE_PATH ($LINE_COUNT satır)"
35
- echo "Limit: $MAX_LINES satır"
36
- echo ""
37
- echo "⚠️ ARCHIVING PROTOCOL GEREĞİ:"
38
- echo "1. Dosyadaki eski veya tamamlanmış verileri tespit et."
39
- echo "2. Bu verileri '$KORTEXT_REL/workspace/archive/' altına '[dosya-adi]_[YYYY-MM-DD_HHMMSS].md' formatıyla taşı."
40
- echo "3. Ana dosyada arşivlenen bölüme bir link/not bırak."
41
- echo "4. Ana dosyayı hafifletip işlemi tekrar dene."
42
- echo ""
43
- echo "Not: 'backlog/' dizinindeki dosyalar bu kuraldan muaf tutulmuştur."
44
- echo "---"
45
- exit 1
46
- fi
47
-
48
- exit 0
@@ -1,39 +0,0 @@
1
- #!/bin/bash
2
- # KORTEXT MANAGED HOOK — generated/edited by kortext framework
3
- # [KORTEXT] Anlık Yedekleme Muhafızı (Snapshot-Guard)
4
-
5
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
6
- # shellcheck source=kortext-lib.sh
7
- source "$SCRIPT_DIR/kortext-lib.sh"
8
-
9
- kortext_load_config
10
- KORTEXT_HOOK_MODE="${KORTEXT_HOOK_MODE:-permissive}"
11
- BACKUP_KEEP="${KORTEXT_BACKUP_KEEP:-5}"
12
-
13
- FILE_PATH="${KORTEXT_FILE_PATH:-${CLAUDE_FILE_PATH:-${GEMINI_FILE_PATH:-${OPENAI_FILE_PATH:-}}}}"
14
- BACKUP_DIR="$KORTEXT_WORKSPACE_DIR/backups"
15
-
16
- # Dosya yolu yoksa veya mevcut değilse çık
17
- if [ -z "$FILE_PATH" ] || [ ! -f "$FILE_PATH" ]; then
18
- if [ -z "$FILE_PATH" ] && [ "$KORTEXT_HOOK_MODE" = "strict" ]; then
19
- echo "⚠️ [KORTEXT] KORTEXT_FILE_PATH tanımsız. strict modda çıkılıyor."
20
- exit 1
21
- fi
22
- exit 0
23
- fi
24
-
25
- # Yedekleme dizinini oluştur
26
- mkdir -p "$BACKUP_DIR"
27
-
28
- FILENAME=$(basename "$FILE_PATH")
29
- TIMESTAMP=$(date "+%Y-%m-%d_%H%M%S") # Tarih-Saat-Dakika-Saniye
30
- BACKUP_NAME="${BACKUP_DIR}/${FILENAME}_${TIMESTAMP}.bak"
31
-
32
- # 1. Yedeği al
33
- cp "$FILE_PATH" "$BACKUP_NAME"
34
-
35
- # 2. Temizlik: Aynı dosya için olan yedeklerden sadece en yeni 5 tanesini tut
36
- # (Diğerlerini silerek yer tasarrufu sağlar)
37
- ls -t "${BACKUP_DIR}/${FILENAME}"_* 2>/dev/null | tail -n +$((BACKUP_KEEP + 1)) | xargs rm -f 2>/dev/null
38
-
39
- exit 0
@@ -1,77 +0,0 @@
1
- #!/bin/bash
2
- # KORTEXT MANAGED HOOK — generated/edited by kortext framework
3
- # [KORTEXT] Yazma Muhafızı (Gelişmiş)
4
- # 1. Konum Kontrolü: Sadece izin verilen dizinlere yazılmasını sağlar.
5
- # 2. Kalite Kontrolü (Tamlık Kapısı): Yarım kalmış içeriklerin yazılmasını engeller.
6
-
7
- SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
- # shellcheck source=kortext-lib.sh
9
- source "$SCRIPT_DIR/kortext-lib.sh"
10
-
11
- kortext_load_config
12
- KORTEXT_HOOK_MODE="${KORTEXT_HOOK_MODE:-permissive}"
13
-
14
- # Girdiyi Oku (JSON formatında gelmesi beklenir)
15
- INPUT=$(cat)
16
- FILE_PATH="$(kortext_json_field "$INPUT" '.tool_input.file_path')"
17
-
18
- # Eğer JSON'dan gelmiyorsa çevresel değişkenleri dene
19
- if [ -z "$FILE_PATH" ]; then
20
- FILE_PATH="${KORTEXT_FILE_PATH:-${CLAUDE_FILE_PATH:-${GEMINI_FILE_PATH:-${OPENAI_FILE_PATH:-}}}}"
21
- fi
22
-
23
- if [ -z "$FILE_PATH" ]; then
24
- if [ "$KORTEXT_HOOK_MODE" = "strict" ]; then
25
- echo "⚠️ [KORTEXT] Dosya yolu tespit edilemedi. strict modda çıkılıyor."
26
- exit 1
27
- fi
28
- exit 0
29
- fi
30
-
31
- # 1. BÖLÜM: KONUM KONTROLÜ
32
- ALLOWED=false
33
- if kortext_is_workspace_path "$FILE_PATH" || kortext_is_env_path "$FILE_PATH"; then
34
- ALLOWED=true
35
- fi
36
-
37
- if [ "$ALLOWED" = false ]; then
38
- echo "---"
39
- echo "❌ KORTEXT ERİŞİM ENGELİ"
40
- echo "Hata: Kortext kuralları gereği Framework çekirdek dizinlerine yazma yetkiniz yoktur."
41
- echo "Lütfen çıktılarınızı '$KORTEXT_REL/workspace/' altındaki uygun klasörlere kaydedin."
42
- echo "Hedeflenen Dosya: $FILE_PATH"
43
- echo "---"
44
- exit 1
45
- fi
46
-
47
- # 2. BÖLÜM: TAMLIK KAPISI (KALİTE KONTROLÜ)
48
- # Yazılacak içeriği al (Write veya Edit/MultiEdit araçları için)
49
- CONTENT="$(kortext_json_field "$INPUT" '.tool_input.content // .tool_input.new_string')"
50
-
51
- if [ -n "$CONTENT" ]; then
52
- # Yarım bırakma işaretçileri (TBD, FIXME, PLACEHOLDER vb.)
53
- # Önemli İstisna: "// todo: [tech-debt]" formatındaki teknik borçlara izin verilir.
54
- if echo "$CONTENT" | grep -qiE '\bTBD\b|\bFIXME\b|\[PLACEHOLDER\]|\[INSERT ' || \
55
- (echo "$CONTENT" | grep -i '\bTODO\b' | grep -vi '\[tech-debt\]' | grep -q .); then
56
- echo "---"
57
- echo "⚠️ TAMLIK KAPISI: EKSİK İÇERİK TESPİT EDİLDİ"
58
- echo "Hata: Yazmaya çalıştığınız içerikte disiplinsiz (etiketsiz) yer tutucular var."
59
- echo "Kortext Politikası: Sıradan TODO/TBD kullanımı yasaktır."
60
- echo "İstisna: Eğer teknik borç bırakmanız gerekiyorsa '// todo: [tech-debt] açıklama' formatını kullanın."
61
- echo "Dosya: $FILE_PATH"
62
- echo "---"
63
- exit 1
64
- fi
65
-
66
- # Kararsızlık ifadeleri
67
- if echo "$CONTENT" | grep -qiE 'assess whether|decide later|need to determine|open question|to be decided|deferred decision'; then
68
- echo "---"
69
- echo "⚠️ TAMLIK KAPISI: BELİRSİZLİK TESPİT EDİLDİ"
70
- echo "Hata: İçerikte 'sonra karar verilecek' veya 'belirlenmesi gerekiyor' gibi ucu açık ifadeler var."
71
- echo "Kortext Politikası: Yazma işleminden önce tüm kararlar çözülmüş olmalıdır."
72
- echo "---"
73
- exit 1
74
- fi
75
- fi
76
-
77
- exit 0
@@ -1,123 +0,0 @@
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()
@@ -1,112 +0,0 @@
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()
@@ -1,117 +0,0 @@
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()