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.
- package/AGENTS.md +7 -11
- package/CHANGELOG.md +81 -0
- package/LICENSE +21 -0
- package/README.md +144 -47
- package/USER-GUIDE.md +505 -0
- package/bin/kortext.js +23 -0
- package/bin/kortext.ts +377 -0
- package/dist/bin/kortext.js +346 -0
- package/dist/bin/kortext.js.map +1 -0
- package/dist/mcp/index.js +4 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/server.js +553 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/sse.js +38 -0
- package/dist/mcp/sse.js.map +1 -0
- package/dist/mcp/stdio.js +44 -0
- package/dist/mcp/stdio.js.map +1 -0
- package/dist/server/cli/cleanup.js +73 -0
- package/dist/server/cli/cleanup.js.map +1 -0
- package/dist/server/cli/commands.js +73 -0
- package/dist/server/cli/commands.js.map +1 -0
- package/dist/server/cli/doctor.js +118 -0
- package/dist/server/cli/doctor.js.map +1 -0
- package/dist/server/cli/executor-factory.js +39 -0
- package/dist/server/cli/executor-factory.js.map +1 -0
- package/dist/server/cli/init.js +121 -0
- package/dist/server/cli/init.js.map +1 -0
- package/dist/server/cli/logs.js +28 -0
- package/dist/server/cli/logs.js.map +1 -0
- package/dist/server/cli/serve.js +72 -0
- package/dist/server/cli/serve.js.map +1 -0
- package/dist/server/config/env.js +12 -0
- package/dist/server/config/env.js.map +1 -0
- package/dist/server/db/client.js +32 -0
- package/dist/server/db/client.js.map +1 -0
- package/dist/server/db/json.js +21 -0
- package/dist/server/db/json.js.map +1 -0
- package/dist/server/db/migrate.js +70 -0
- package/dist/server/db/migrate.js.map +1 -0
- package/dist/server/db/migrations/001_init.sql +243 -0
- package/dist/server/db/repositories/audit-log.js +58 -0
- package/dist/server/db/repositories/audit-log.js.map +1 -0
- package/dist/server/db/repositories/backlog.js +96 -0
- package/dist/server/db/repositories/backlog.js.map +1 -0
- package/dist/server/db/repositories/contexts.js +54 -0
- package/dist/server/db/repositories/contexts.js.map +1 -0
- package/dist/server/db/repositories/decisions.js +71 -0
- package/dist/server/db/repositories/decisions.js.map +1 -0
- package/dist/server/db/repositories/handovers.js +53 -0
- package/dist/server/db/repositories/handovers.js.map +1 -0
- package/dist/server/db/repositories/index.js +30 -0
- package/dist/server/db/repositories/index.js.map +1 -0
- package/dist/server/db/repositories/locks.js +59 -0
- package/dist/server/db/repositories/locks.js.map +1 -0
- package/dist/server/db/repositories/notifications.js +63 -0
- package/dist/server/db/repositories/notifications.js.map +1 -0
- package/dist/server/db/repositories/pending-questions.js +63 -0
- package/dist/server/db/repositories/pending-questions.js.map +1 -0
- package/dist/server/db/repositories/runs.js +138 -0
- package/dist/server/db/repositories/runs.js.map +1 -0
- package/dist/server/db/repositories/runtime-artifacts.js +39 -0
- package/dist/server/db/repositories/runtime-artifacts.js.map +1 -0
- package/dist/server/db/repositories/secrets.js +65 -0
- package/dist/server/db/repositories/secrets.js.map +1 -0
- package/dist/server/db/repositories/sessions.js +48 -0
- package/dist/server/db/repositories/sessions.js.map +1 -0
- package/dist/server/db/schemas.js +308 -0
- package/dist/server/db/schemas.js.map +1 -0
- package/dist/server/engine/consistency.js +25 -0
- package/dist/server/engine/consistency.js.map +1 -0
- package/dist/server/engine/dag.js +86 -0
- package/dist/server/engine/dag.js.map +1 -0
- package/dist/server/engine/executor.js +2 -0
- package/dist/server/engine/executor.js.map +1 -0
- package/dist/server/engine/executors/claude-cli-executor.js +83 -0
- package/dist/server/engine/executors/claude-cli-executor.js.map +1 -0
- package/dist/server/engine/executors/cli-spawn.js +127 -0
- package/dist/server/engine/executors/cli-spawn.js.map +1 -0
- package/dist/server/engine/executors/codex-cli-executor.js +69 -0
- package/dist/server/engine/executors/codex-cli-executor.js.map +1 -0
- package/dist/server/engine/executors/gemini-cli-executor.js +69 -0
- package/dist/server/engine/executors/gemini-cli-executor.js.map +1 -0
- package/dist/server/engine/executors/mock-executor.js +52 -0
- package/dist/server/engine/executors/mock-executor.js.map +1 -0
- package/dist/server/engine/executors/persona-routed-executor.js +17 -0
- package/dist/server/engine/executors/persona-routed-executor.js.map +1 -0
- package/dist/server/engine/gate-enforcer.js +75 -0
- package/dist/server/engine/gate-enforcer.js.map +1 -0
- package/dist/server/engine/git-commit.js +42 -0
- package/dist/server/engine/git-commit.js.map +1 -0
- package/dist/server/engine/handover.js +120 -0
- package/dist/server/engine/handover.js.map +1 -0
- package/dist/server/engine/item-lifecycle.js +74 -0
- package/dist/server/engine/item-lifecycle.js.map +1 -0
- package/dist/server/engine/persona-registry.js +108 -0
- package/dist/server/engine/persona-registry.js.map +1 -0
- package/dist/server/engine/worker-pool.js +324 -0
- package/dist/server/engine/worker-pool.js.map +1 -0
- package/dist/server/engine/workflow-loader.js +55 -0
- package/dist/server/engine/workflow-loader.js.map +1 -0
- package/dist/server/engine/workflow-parser.js +158 -0
- package/dist/server/engine/workflow-parser.js.map +1 -0
- package/dist/server/engine/worktree.js +176 -0
- package/dist/server/engine/worktree.js.map +1 -0
- package/dist/server/index.js +99 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/notifications/dispatcher.js +60 -0
- package/dist/server/notifications/dispatcher.js.map +1 -0
- package/dist/server/notifications/slack.js +37 -0
- package/dist/server/notifications/slack.js.map +1 -0
- package/dist/server/notifications/telegram.js +33 -0
- package/dist/server/notifications/telegram.js.map +1 -0
- package/dist/server/orchestrator/approval-queue.js +83 -0
- package/dist/server/orchestrator/approval-queue.js.map +1 -0
- package/dist/server/orchestrator/blueprint-watcher.js +94 -0
- package/dist/server/orchestrator/blueprint-watcher.js.map +1 -0
- package/dist/server/orchestrator/orchestrator.js +283 -0
- package/dist/server/orchestrator/orchestrator.js.map +1 -0
- package/dist/server/orchestrator/pipeline-chainer.js +96 -0
- package/dist/server/orchestrator/pipeline-chainer.js.map +1 -0
- package/dist/server/orchestrator/resume.js +36 -0
- package/dist/server/orchestrator/resume.js.map +1 -0
- package/dist/server/routes/approvals.js +52 -0
- package/dist/server/routes/approvals.js.map +1 -0
- package/dist/server/routes/backlog.js +44 -0
- package/dist/server/routes/backlog.js.map +1 -0
- package/dist/server/routes/db-info.js +21 -0
- package/dist/server/routes/db-info.js.map +1 -0
- package/dist/server/routes/docs.js +70 -0
- package/dist/server/routes/docs.js.map +1 -0
- package/dist/server/routes/doctor.js +19 -0
- package/dist/server/routes/doctor.js.map +1 -0
- package/dist/server/routes/handovers.js +25 -0
- package/dist/server/routes/handovers.js.map +1 -0
- package/dist/server/routes/health.js +11 -0
- package/dist/server/routes/health.js.map +1 -0
- package/dist/server/routes/personas.js +96 -0
- package/dist/server/routes/personas.js.map +1 -0
- package/dist/server/routes/runs.js +41 -0
- package/dist/server/routes/runs.js.map +1 -0
- package/dist/server/routes/workflows.js +38 -0
- package/dist/server/routes/workflows.js.map +1 -0
- package/dist/server/safety/harmful-output-filter.js +40 -0
- package/dist/server/safety/harmful-output-filter.js.map +1 -0
- package/dist/server/safety/secret-scanner.js +169 -0
- package/dist/server/safety/secret-scanner.js.map +1 -0
- package/dist/server/services/markdown-sync.js +101 -0
- package/dist/server/services/markdown-sync.js.map +1 -0
- package/dist/web/assets/index-B80d5ZPZ.js +75 -0
- package/dist/web/assets/index-B80d5ZPZ.js.map +1 -0
- package/dist/web/assets/index-Bge5Gzqv.css +1 -0
- package/dist/web/index.html +13 -0
- package/docs/architecture.md +413 -0
- package/package.json +83 -11
- package/rules/behavior.md +2 -2
- package/scripts/copy-migrations.mjs +29 -0
- package/workspace/.locks/workspace_handover.md.lock +3 -0
- package/hooks/audit-logger.sh +0 -25
- package/hooks/auto-locker.sh +0 -74
- package/hooks/auto-unlocker.sh +0 -17
- package/hooks/backlog-sync-guard.sh +0 -12
- package/hooks/branch-guard.sh +0 -32
- package/hooks/commit-msg-guard.sh +0 -43
- package/hooks/git-pre-commit.sh +0 -76
- package/hooks/git-pre-push.sh +0 -17
- package/hooks/handover-guard.sh +0 -33
- package/hooks/kortext-init.sh +0 -194
- package/hooks/kortext-lib.sh +0 -141
- package/hooks/lint-guard.sh +0 -50
- package/hooks/secret-scanner.sh +0 -89
- package/hooks/size-guard.sh +0 -48
- package/hooks/snapshot-guard.sh +0 -39
- package/hooks/write-guard.sh +0 -77
- package/scripts/kortext-backlog-add.py +0 -123
- package/scripts/kortext-backlog-health.py +0 -112
- package/scripts/kortext-backlog-sync.py +0 -117
- package/scripts/kortext-bulk-plan.py +0 -63
- package/scripts/kortext-cli.py +0 -295
- package/scripts/kortext-consistency-check.py +0 -74
- package/scripts/kortext-context-check.py +0 -146
- package/scripts/kortext-handover.py +0 -107
- package/scripts/kortext-item-check.py +0 -61
- package/scripts/kortext-item-start.py +0 -70
- package/scripts/kortext-item-transition.py +0 -78
- package/scripts/kortext-lock.py +0 -174
- package/scripts/kortext-session-start.py +0 -127
- package/scripts/lock_kortext.sh +0 -34
- package/settings/.claude-settings.template.json +0 -48
- package/settings/CHANGELOG.md +0 -176
- package/settings/INTEGRATION-MAP.md +0 -276
- package/settings/README.md +0 -255
- package/settings/USER-GUIDE.md +0 -502
- package/settings/VERSION +0 -1
- package/settings/config.md +0 -8
- package/settings/runtime-adapters.md +0 -104
- package/skills/backend-developer/.gitkeep +0 -0
- package/skills/compliance-expert/.gitkeep +0 -0
- package/skills/copywriter/.gitkeep +0 -0
- package/skills/db-admin/.gitkeep +0 -0
- package/skills/delivery-manager/.gitkeep +0 -0
- package/skills/designer/.gitkeep +0 -0
- package/skills/devops-engineer/.gitkeep +0 -0
- package/skills/engineering-manager/.gitkeep +0 -0
- package/skills/frontend-developer/.gitkeep +0 -0
- package/skills/growth-expert/.gitkeep +0 -0
- package/skills/operation-manager/.gitkeep +0 -0
- package/skills/product-manager/.gitkeep +0 -0
- package/skills/qa-engineer/.gitkeep +0 -0
- package/skills/security-engineer/.gitkeep +0 -0
|
@@ -1,63 +0,0 @@
|
|
|
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()
|
package/scripts/kortext-cli.py
DELETED
|
@@ -1,295 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Kortext CLI — Ana Komut Dağıtıcı
|
|
4
|
-
---------------------------------
|
|
5
|
-
npm install sonrası `kortext` binary'si bu dosyayı çağırır. Tüm alt komutlar
|
|
6
|
-
buradan yönlendirilir. Yazılım bilmeyen kullanıcı için Türkçe açıklamalı
|
|
7
|
-
komut tablosu içerir.
|
|
8
|
-
|
|
9
|
-
Standart kütüphane dışında bağımlılığı yoktur. Python 3.10+ gereklidir.
|
|
10
|
-
"""
|
|
11
|
-
from __future__ import annotations
|
|
12
|
-
|
|
13
|
-
import argparse
|
|
14
|
-
import os
|
|
15
|
-
import subprocess
|
|
16
|
-
import sys
|
|
17
|
-
from pathlib import Path
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
# Kortext kurulumunun kök dizini. Bu dosya scripts/ altında olduğu için
|
|
21
|
-
# bir üst klasör root sayılır.
|
|
22
|
-
ROOT = Path(__file__).resolve().parents[1]
|
|
23
|
-
SCRIPTS = ROOT / "scripts"
|
|
24
|
-
HOOKS = ROOT / "hooks"
|
|
25
|
-
WORKFLOWS = ROOT / "workflows"
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
# Komut → Türkçe açıklama eşlemesi. `kortext help` çıktısında kullanılır.
|
|
29
|
-
COMMAND_HELP: list[tuple[str, str]] = [
|
|
30
|
-
("init", "Kortext'i mevcut çalışma dizinine kur (git hook + lock)."),
|
|
31
|
-
("start <workflow>", "Workflow dosyasının başlığını ve özetini ekrana bas."),
|
|
32
|
-
("status", "Aktif ajanları, son handover'ı ve oturum özetini göster."),
|
|
33
|
-
("check", "Tutarlılık + context + backlog sağlık kontrollerini sırayla çalıştır."),
|
|
34
|
-
("lock <file>", "Paylaşımlı dosyaya kilit al (eşzamanlı yazma çakışmasını önler)."),
|
|
35
|
-
("unlock <file>", "Daha önce alınmış kilidi serbest bırak."),
|
|
36
|
-
("list-locks", "Aktif tüm kilitleri listele."),
|
|
37
|
-
("handover ...", "Görev devir kaydı oluştur (handover.md'ye satır ekler)."),
|
|
38
|
-
("add ...", "Backlog'a yeni task/bug/debt item'ı ekle."),
|
|
39
|
-
("transition ...", "Item status geçişi yap (To Do → In Progress → ...)."),
|
|
40
|
-
("health", "Backlog sağlık raporunu üret (stale/blocked/review)."),
|
|
41
|
-
("help", "Bu yardım listesini göster."),
|
|
42
|
-
]
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
def _run_python_script(script_name: str, args: list[str], env_overrides: dict[str, str] | None = None) -> int:
|
|
46
|
-
"""Bir Python scriptini subprocess olarak çalıştırır ve exit code'unu döndürür."""
|
|
47
|
-
script_path = SCRIPTS / script_name
|
|
48
|
-
if not script_path.exists():
|
|
49
|
-
print(f"❌ Script bulunamadı: {script_path}", file=sys.stderr)
|
|
50
|
-
return 127
|
|
51
|
-
|
|
52
|
-
cmd = [sys.executable, str(script_path), *args]
|
|
53
|
-
env = os.environ.copy()
|
|
54
|
-
if env_overrides:
|
|
55
|
-
env.update(env_overrides)
|
|
56
|
-
|
|
57
|
-
# Subprocess çıktısı doğrudan terminale aksın; hata kodunu koruyalım.
|
|
58
|
-
result = subprocess.run(cmd, env=env)
|
|
59
|
-
return result.returncode
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
def _run_shell_script(script_path: Path, args: list[str], env_overrides: dict[str, str] | None = None) -> int:
|
|
63
|
-
"""Bir shell scriptini çalıştırır."""
|
|
64
|
-
if not script_path.exists():
|
|
65
|
-
print(f"❌ Shell script bulunamadı: {script_path}", file=sys.stderr)
|
|
66
|
-
return 127
|
|
67
|
-
|
|
68
|
-
cmd = ["bash", str(script_path), *args]
|
|
69
|
-
env = os.environ.copy()
|
|
70
|
-
if env_overrides:
|
|
71
|
-
env.update(env_overrides)
|
|
72
|
-
|
|
73
|
-
result = subprocess.run(cmd, env=env)
|
|
74
|
-
return result.returncode
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def cmd_init(args: argparse.Namespace) -> int:
|
|
78
|
-
"""`kortext init` — kortext-init.sh'i tetikler. Runtime bilgisi env ile geçer."""
|
|
79
|
-
env: dict[str, str] = {}
|
|
80
|
-
if args.runtime:
|
|
81
|
-
env["KORTEXT_RUNTIME"] = args.runtime
|
|
82
|
-
# kortext-init.sh git hook kurulumunu da yapar.
|
|
83
|
-
return _run_shell_script(HOOKS / "kortext-init.sh", ["--install-hooks"], env)
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
def cmd_start(args: argparse.Namespace) -> int:
|
|
87
|
-
"""`kortext start <workflow>` — workflow dosyasının ilk başlığını basar.
|
|
88
|
-
|
|
89
|
-
Tam dosya adı bilinmiyorsa numara/anahtar kelimeyle eşleştirir
|
|
90
|
-
(ör. `analysis` → `01a-analysis-pipeline.md`).
|
|
91
|
-
"""
|
|
92
|
-
workflow_arg = args.workflow.lower().strip()
|
|
93
|
-
if not WORKFLOWS.exists():
|
|
94
|
-
print(f"❌ workflows klasörü bulunamadı: {WORKFLOWS}", file=sys.stderr)
|
|
95
|
-
return 1
|
|
96
|
-
|
|
97
|
-
# En iyi eşleşmeyi bul: dosya adı içinde anahtar kelime geçen ilk dosya.
|
|
98
|
-
candidates = sorted(WORKFLOWS.glob("*.md"))
|
|
99
|
-
matches = [p for p in candidates if workflow_arg in p.stem.lower()]
|
|
100
|
-
if not matches:
|
|
101
|
-
print(f"❌ Eşleşen workflow bulunamadı: '{workflow_arg}'", file=sys.stderr)
|
|
102
|
-
print("\nMevcut workflow'lar:", file=sys.stderr)
|
|
103
|
-
for p in candidates:
|
|
104
|
-
print(f" • {p.stem}", file=sys.stderr)
|
|
105
|
-
return 1
|
|
106
|
-
|
|
107
|
-
target = matches[0]
|
|
108
|
-
text = target.read_text(errors="ignore")
|
|
109
|
-
lines = text.splitlines()
|
|
110
|
-
title_line = next((l for l in lines if l.startswith("# ")), target.stem)
|
|
111
|
-
|
|
112
|
-
print("=" * 60)
|
|
113
|
-
print(f" KORTEXT WORKFLOW BAŞLADI")
|
|
114
|
-
print("=" * 60)
|
|
115
|
-
print(f"\nDosya : {target.relative_to(ROOT)}")
|
|
116
|
-
print(f"Başlık : {title_line}")
|
|
117
|
-
# Workflow özeti olarak ilk paragrafı yazdır.
|
|
118
|
-
summary_lines: list[str] = []
|
|
119
|
-
in_summary = False
|
|
120
|
-
for line in lines:
|
|
121
|
-
if line.startswith("# "):
|
|
122
|
-
in_summary = True
|
|
123
|
-
continue
|
|
124
|
-
if in_summary:
|
|
125
|
-
if line.startswith("#"):
|
|
126
|
-
break
|
|
127
|
-
if line.strip():
|
|
128
|
-
summary_lines.append(line.strip())
|
|
129
|
-
if summary_lines:
|
|
130
|
-
print(f"\nÖzet :\n {summary_lines[0]}")
|
|
131
|
-
print("\n→ Akışı yürütmek için dosyayı oku ve adımları sırayla uygula.")
|
|
132
|
-
return 0
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
def cmd_status(_args: argparse.Namespace) -> int:
|
|
136
|
-
"""`kortext status` — oturum özetini gösterir."""
|
|
137
|
-
return _run_python_script("kortext-session-start.py", [])
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
def cmd_check(_args: argparse.Namespace) -> int:
|
|
141
|
-
"""`kortext check` — üç ardışık sağlık kontrolü çalıştırır."""
|
|
142
|
-
print("🔍 1/3 Tutarlılık kontrolü...")
|
|
143
|
-
rc1 = _run_python_script("kortext-consistency-check.py", [])
|
|
144
|
-
print("\n🔍 2/3 Context kontrolü...")
|
|
145
|
-
rc2 = _run_python_script("kortext-context-check.py", [])
|
|
146
|
-
print("\n🔍 3/3 Backlog sağlık kontrolü...")
|
|
147
|
-
rc3 = _run_python_script("kortext-backlog-health.py", [])
|
|
148
|
-
|
|
149
|
-
# Herhangi biri fail ederse non-zero döndür.
|
|
150
|
-
final = rc1 or rc2 or rc3
|
|
151
|
-
print("\n" + ("✅ Tüm kontroller geçti." if final == 0 else "❌ Bir veya daha fazla kontrol başarısız."))
|
|
152
|
-
return final
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
def cmd_lock(args: argparse.Namespace) -> int:
|
|
156
|
-
"""`kortext lock` — kortext-lock.py acquire delegasyonu."""
|
|
157
|
-
return _run_python_script(
|
|
158
|
-
"kortext-lock.py",
|
|
159
|
-
["acquire", "--file", args.file, "--agent", args.agent],
|
|
160
|
-
)
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
def cmd_unlock(args: argparse.Namespace) -> int:
|
|
164
|
-
"""`kortext unlock` — kortext-lock.py release delegasyonu."""
|
|
165
|
-
return _run_python_script("kortext-lock.py", ["release", "--file", args.file])
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
def cmd_list_locks(_args: argparse.Namespace) -> int:
|
|
169
|
-
"""`kortext list-locks` — kortext-lock.py list delegasyonu."""
|
|
170
|
-
return _run_python_script("kortext-lock.py", ["list"])
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
def cmd_handover(args: argparse.Namespace) -> int:
|
|
174
|
-
"""`kortext handover ...` — kortext-handover.py'ye argümanları aynen aktarır."""
|
|
175
|
-
return _run_python_script("kortext-handover.py", args.passthrough)
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
def cmd_add(args: argparse.Namespace) -> int:
|
|
179
|
-
"""`kortext add ...` — kortext-backlog-add.py'ye argümanları aynen aktarır."""
|
|
180
|
-
return _run_python_script("kortext-backlog-add.py", args.passthrough)
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
def cmd_transition(args: argparse.Namespace) -> int:
|
|
184
|
-
"""`kortext transition ...` — kortext-item-transition.py delegasyonu."""
|
|
185
|
-
return _run_python_script("kortext-item-transition.py", args.passthrough)
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
def cmd_health(_args: argparse.Namespace) -> int:
|
|
189
|
-
"""`kortext health` — kortext-backlog-health.py delegasyonu."""
|
|
190
|
-
return _run_python_script("kortext-backlog-health.py", [])
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
def cmd_help(_args: argparse.Namespace) -> int:
|
|
194
|
-
"""`kortext help` — tüm komutları Türkçe açıklamalı tabloda göster."""
|
|
195
|
-
print("=" * 70)
|
|
196
|
-
print(" KORTEXT KOMUT REFERANSI")
|
|
197
|
-
print("=" * 70)
|
|
198
|
-
print("\nKullanım: kortext <komut> [seçenekler]\n")
|
|
199
|
-
name_width = max(len(name) for name, _ in COMMAND_HELP) + 2
|
|
200
|
-
for name, desc in COMMAND_HELP:
|
|
201
|
-
print(f" {name.ljust(name_width)} {desc}")
|
|
202
|
-
print("\nDetay için: kortext <komut> --help")
|
|
203
|
-
print("=" * 70)
|
|
204
|
-
return 0
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
def build_parser() -> argparse.ArgumentParser:
|
|
208
|
-
"""Subparser yapısını kurar."""
|
|
209
|
-
parser = argparse.ArgumentParser(
|
|
210
|
-
prog="kortext",
|
|
211
|
-
description="Kortext AI Agent Framework — komut satırı arayüzü.",
|
|
212
|
-
add_help=False, # `--help` yerine `kortext help` tablosunu tercih ediyoruz.
|
|
213
|
-
)
|
|
214
|
-
parser.add_argument("-h", "--help", action="store_true", help="Yardım göster")
|
|
215
|
-
sub = parser.add_subparsers(dest="command")
|
|
216
|
-
|
|
217
|
-
# init
|
|
218
|
-
p_init = sub.add_parser("init", help="Kortext'i mevcut dizine kur")
|
|
219
|
-
p_init.add_argument(
|
|
220
|
-
"--runtime",
|
|
221
|
-
choices=["claude_code", "gemini_cli", "codex"],
|
|
222
|
-
help="Tercih edilen AI runtime (env var olarak iletilir).",
|
|
223
|
-
)
|
|
224
|
-
p_init.set_defaults(func=cmd_init)
|
|
225
|
-
|
|
226
|
-
# start
|
|
227
|
-
p_start = sub.add_parser("start", help="Bir workflow başlat")
|
|
228
|
-
p_start.add_argument("workflow", help="Workflow adı veya numarası (ör. analysis, 02b)")
|
|
229
|
-
p_start.set_defaults(func=cmd_start)
|
|
230
|
-
|
|
231
|
-
# status
|
|
232
|
-
p_status = sub.add_parser("status", help="Oturum özetini göster")
|
|
233
|
-
p_status.set_defaults(func=cmd_status)
|
|
234
|
-
|
|
235
|
-
# check
|
|
236
|
-
p_check = sub.add_parser("check", help="Üç sağlık kontrolünü sırayla çalıştır")
|
|
237
|
-
p_check.set_defaults(func=cmd_check)
|
|
238
|
-
|
|
239
|
-
# lock
|
|
240
|
-
p_lock = sub.add_parser("lock", help="Dosya kilidi al")
|
|
241
|
-
p_lock.add_argument("--file", required=True)
|
|
242
|
-
p_lock.add_argument("--agent", required=True)
|
|
243
|
-
p_lock.set_defaults(func=cmd_lock)
|
|
244
|
-
|
|
245
|
-
# unlock
|
|
246
|
-
p_unlock = sub.add_parser("unlock", help="Dosya kilidini kaldır")
|
|
247
|
-
p_unlock.add_argument("--file", required=True)
|
|
248
|
-
p_unlock.set_defaults(func=cmd_unlock)
|
|
249
|
-
|
|
250
|
-
# list-locks
|
|
251
|
-
p_locks = sub.add_parser("list-locks", help="Aktif kilitleri listele")
|
|
252
|
-
p_locks.set_defaults(func=cmd_list_locks)
|
|
253
|
-
|
|
254
|
-
# handover (passthrough)
|
|
255
|
-
p_handover = sub.add_parser("handover", help="Handover kaydı ekle")
|
|
256
|
-
p_handover.add_argument("passthrough", nargs=argparse.REMAINDER)
|
|
257
|
-
p_handover.set_defaults(func=cmd_handover)
|
|
258
|
-
|
|
259
|
-
# add (passthrough)
|
|
260
|
-
p_add = sub.add_parser("add", help="Backlog'a item ekle")
|
|
261
|
-
p_add.add_argument("passthrough", nargs=argparse.REMAINDER)
|
|
262
|
-
p_add.set_defaults(func=cmd_add)
|
|
263
|
-
|
|
264
|
-
# transition (passthrough)
|
|
265
|
-
p_trans = sub.add_parser("transition", help="Item status'u değiştir")
|
|
266
|
-
p_trans.add_argument("passthrough", nargs=argparse.REMAINDER)
|
|
267
|
-
p_trans.set_defaults(func=cmd_transition)
|
|
268
|
-
|
|
269
|
-
# health
|
|
270
|
-
p_health = sub.add_parser("health", help="Backlog sağlık raporu")
|
|
271
|
-
p_health.set_defaults(func=cmd_health)
|
|
272
|
-
|
|
273
|
-
# help
|
|
274
|
-
p_help = sub.add_parser("help", help="Yardım tablosu")
|
|
275
|
-
p_help.set_defaults(func=cmd_help)
|
|
276
|
-
|
|
277
|
-
return parser
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
def main() -> int:
|
|
281
|
-
parser = build_parser()
|
|
282
|
-
args = parser.parse_args()
|
|
283
|
-
|
|
284
|
-
# Komut yoksa veya --help geldiyse yardım göster.
|
|
285
|
-
if getattr(args, "help", False) or not getattr(args, "command", None):
|
|
286
|
-
return cmd_help(args)
|
|
287
|
-
|
|
288
|
-
func = getattr(args, "func", None)
|
|
289
|
-
if func is None:
|
|
290
|
-
return cmd_help(args)
|
|
291
|
-
return func(args)
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
if __name__ == "__main__":
|
|
295
|
-
sys.exit(main())
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
from __future__ import annotations
|
|
3
|
-
|
|
4
|
-
from pathlib import Path
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
ROOT = Path(__file__).resolve().parents[1]
|
|
8
|
-
SCAN_ROOTS = ["agents", "rules", "workflows", "scripts", "settings", "workspace"]
|
|
9
|
-
FORBIDDEN_PATTERNS = {
|
|
10
|
-
"active-agents": "Eski aktif bağlam klasörü",
|
|
11
|
-
"backlog/v[": "Eski hiyerarşik backlog modeli",
|
|
12
|
-
"workspace/memory/backlog.md": "Eski monolitik backlog referansı",
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
def iter_text_files() -> list[Path]:
|
|
17
|
-
files: list[Path] = []
|
|
18
|
-
for rel in SCAN_ROOTS:
|
|
19
|
-
for path in (ROOT / rel).rglob("*"):
|
|
20
|
-
if path.is_file() and path.suffix in {".md", ".py", ".sh"}:
|
|
21
|
-
if path == Path(__file__).resolve():
|
|
22
|
-
continue
|
|
23
|
-
files.append(path)
|
|
24
|
-
return files
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def main() -> None:
|
|
28
|
-
failures: list[str] = []
|
|
29
|
-
for path in iter_text_files():
|
|
30
|
-
text = path.read_text(errors="ignore")
|
|
31
|
-
for pattern, label in FORBIDDEN_PATTERNS.items():
|
|
32
|
-
if pattern in text:
|
|
33
|
-
failures.append(f"{path.relative_to(ROOT)}: {label} bulundu ({pattern})")
|
|
34
|
-
|
|
35
|
-
required_paths = [
|
|
36
|
-
ROOT / "workspace/memory/context",
|
|
37
|
-
ROOT / "workspace/memory/handover.md",
|
|
38
|
-
ROOT / "workspace/memory/decisions.md",
|
|
39
|
-
ROOT / "workspace/memory/learned.md",
|
|
40
|
-
ROOT / "workspace/memory/backlog/version-dashboard.md",
|
|
41
|
-
ROOT / "workspace/memory/backlog/epic-dashboard.md",
|
|
42
|
-
ROOT / "workspace/memory/backlog/debt-dashboard.md",
|
|
43
|
-
ROOT / "workspace/backups",
|
|
44
|
-
# v2.2.0 — yeni scriptler
|
|
45
|
-
ROOT / "scripts/kortext-session-start.py",
|
|
46
|
-
ROOT / "scripts/kortext-context-check.py",
|
|
47
|
-
ROOT / "scripts/kortext-backlog-health.py",
|
|
48
|
-
ROOT / "scripts/kortext-lock.py",
|
|
49
|
-
# v2.2.0 — yeni workflow'lar
|
|
50
|
-
ROOT / "workflows/02b-spike-workflow.md",
|
|
51
|
-
ROOT / "workflows/09-maintenance-cycle.md",
|
|
52
|
-
ROOT / "settings/CHANGELOG.md",
|
|
53
|
-
# v2.3.0 — şablon merkezi
|
|
54
|
-
ROOT / "workspace/templates",
|
|
55
|
-
ROOT / "workspace/templates/TXX-[task-name].md",
|
|
56
|
-
ROOT / "workspace/templates/BXX-[bug-name].md",
|
|
57
|
-
ROOT / "workspace/templates/DXX-[debt-name].md",
|
|
58
|
-
ROOT / "workspace/templates/[agent-name]-active.md",
|
|
59
|
-
]
|
|
60
|
-
for path in required_paths:
|
|
61
|
-
if not path.exists():
|
|
62
|
-
failures.append(f"{path.relative_to(ROOT)} eksik")
|
|
63
|
-
|
|
64
|
-
if failures:
|
|
65
|
-
print("❌ Tutarlılık kontrolü başarısız:")
|
|
66
|
-
for failure in failures:
|
|
67
|
-
print(f"- {failure}")
|
|
68
|
-
raise SystemExit(1)
|
|
69
|
-
|
|
70
|
-
print("✅ Kortext çekirdeği tutarlı görünüyor.")
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
if __name__ == "__main__":
|
|
74
|
-
main()
|
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Kortext Context Check
|
|
4
|
-
---------------------
|
|
5
|
-
Context bütünlüğünü ölçer. Stale aktif dosyalar, çakışan görevler,
|
|
6
|
-
handover uyumsuzlukları ve backlog dashboard tutarsızlıklarını raporlar.
|
|
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
|
-
CONTEXT_DIR = ROOT / "workspace/memory/context"
|
|
18
|
-
HANDOVER_PATH = ROOT / "workspace/memory/handover.md"
|
|
19
|
-
BACKLOG_DIR = ROOT / "workspace/memory/backlog"
|
|
20
|
-
EPIC_DASHBOARD = BACKLOG_DIR / "epic-dashboard.md"
|
|
21
|
-
|
|
22
|
-
# Stale eşikleri env var ile override edilebilir.
|
|
23
|
-
STALE_HOURS_CONTEXT = int(os.environ.get("KORTEXT_STALE_HOURS_CONTEXT", "24"))
|
|
24
|
-
STALE_HOURS_BACKLOG = int(os.environ.get("KORTEXT_STALE_HOURS_BACKLOG", "48"))
|
|
25
|
-
WARNINGS: list[str] = []
|
|
26
|
-
ERRORS: list[str] = []
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
def check_stale_context() -> None:
|
|
30
|
-
"""24 saatten eski In Progress context dosyalarını tespit eder."""
|
|
31
|
-
if not CONTEXT_DIR.exists():
|
|
32
|
-
return
|
|
33
|
-
for f in CONTEXT_DIR.glob("*-active.md"):
|
|
34
|
-
mtime = datetime.fromtimestamp(f.stat().st_mtime)
|
|
35
|
-
age_hours = (datetime.now() - mtime).total_seconds() / 3600
|
|
36
|
-
if age_hours > STALE_HOURS_CONTEXT:
|
|
37
|
-
WARNINGS.append(
|
|
38
|
-
f"⚠️ STALE: {f.name} — {round(age_hours, 1)} saat önce güncellendi. "
|
|
39
|
-
f"Görev hala açık mı kontrol et."
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
def check_context_vs_backlog() -> None:
|
|
44
|
-
"""Context dosyalarında belirtilen item ID'lerinin backlog'da gerçekten var ve In Progress olup olmadığını kontrol eder."""
|
|
45
|
-
if not CONTEXT_DIR.exists() or not BACKLOG_DIR.exists():
|
|
46
|
-
return
|
|
47
|
-
for ctx_file in CONTEXT_DIR.glob("*-active.md"):
|
|
48
|
-
content = ctx_file.read_text(errors="ignore")
|
|
49
|
-
# ### +persona | T01 | In Progress | ... formatını parse et
|
|
50
|
-
match = re.search(r"\|\s*([TB D]\d+)\s*\|", content)
|
|
51
|
-
if not match:
|
|
52
|
-
WARNINGS.append(
|
|
53
|
-
f"⚠️ FORMAT: {ctx_file.name} içinde item ID parse edilemedi. "
|
|
54
|
-
f"Standart format: `### +persona | TXX | Status | HH:MM | özet`"
|
|
55
|
-
)
|
|
56
|
-
continue
|
|
57
|
-
item_id = match.group(1).strip()
|
|
58
|
-
# Backlog'da bu ID'yi ara
|
|
59
|
-
found = list(BACKLOG_DIR.glob(f"{item_id}-*.md"))
|
|
60
|
-
if not found:
|
|
61
|
-
ERRORS.append(
|
|
62
|
-
f"❌ EXİSTS: {ctx_file.name} içindeki {item_id} backlog'da bulunamadı."
|
|
63
|
-
)
|
|
64
|
-
continue
|
|
65
|
-
item_text = found[0].read_text(errors="ignore")
|
|
66
|
-
if "**Status:** In Progress" not in item_text:
|
|
67
|
-
WARNINGS.append(
|
|
68
|
-
f"⚠️ STATUS UYUŞMAZLIĞI: {ctx_file.name} aktif gösteriyor ama "
|
|
69
|
-
f"{found[0].name} In Progress değil."
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def check_handover_freshness() -> None:
|
|
74
|
-
"""handover.md'nin son 48 saatte güncellenip güncellenmediğini kontrol eder."""
|
|
75
|
-
if not HANDOVER_PATH.exists():
|
|
76
|
-
WARNINGS.append("⚠️ HANDOVER: handover.md bulunamadı. Dosya oluşturulmalı.")
|
|
77
|
-
return
|
|
78
|
-
mtime = datetime.fromtimestamp(HANDOVER_PATH.stat().st_mtime)
|
|
79
|
-
age_hours = (datetime.now() - mtime).total_seconds() / 3600
|
|
80
|
-
if age_hours > STALE_HOURS_BACKLOG:
|
|
81
|
-
WARNINGS.append(
|
|
82
|
-
f"⚠️ HANDOVER: handover.md {round(age_hours, 1)} saat önce güncellendi. "
|
|
83
|
-
f"Son tamamlanan görevin devir kaydı yapıldı mı?"
|
|
84
|
-
)
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
def check_duplicate_context() -> None:
|
|
88
|
-
"""Aynı ajan için birden fazla aktif context dosyası var mı kontrol eder."""
|
|
89
|
-
if not CONTEXT_DIR.exists():
|
|
90
|
-
return
|
|
91
|
-
seen: dict[str, list[str]] = {}
|
|
92
|
-
for f in CONTEXT_DIR.glob("*-active.md"):
|
|
93
|
-
# agent-name-active.md → agent-name
|
|
94
|
-
agent = f.stem.replace("-active", "")
|
|
95
|
-
seen.setdefault(agent, []).append(f.name)
|
|
96
|
-
for agent, files in seen.items():
|
|
97
|
-
if len(files) > 1:
|
|
98
|
-
ERRORS.append(
|
|
99
|
-
f"❌ DUPLICATE CONTEXT: {agent} için birden fazla aktif dosya var: {files}"
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
def print_report(score: int, total_checks: int) -> None:
|
|
104
|
-
now = datetime.now().strftime("%d.%m.%Y %H:%M")
|
|
105
|
-
print("=" * 60)
|
|
106
|
-
print(f" KORTEXT CONTEXT CHECK — {now}")
|
|
107
|
-
print("=" * 60)
|
|
108
|
-
|
|
109
|
-
if ERRORS:
|
|
110
|
-
print(f"\n❌ HATALAR ({len(ERRORS)} adet):")
|
|
111
|
-
for e in ERRORS:
|
|
112
|
-
print(f" {e}")
|
|
113
|
-
|
|
114
|
-
if WARNINGS:
|
|
115
|
-
print(f"\n⚠️ UYARILAR ({len(WARNINGS)} adet):")
|
|
116
|
-
for w in WARNINGS:
|
|
117
|
-
print(f" {w}")
|
|
118
|
-
|
|
119
|
-
if not ERRORS and not WARNINGS:
|
|
120
|
-
print("\n✅ Tüm kontroller geçti. Context sağlıklı görünüyor.")
|
|
121
|
-
|
|
122
|
-
print(f"\n Sağlık Skoru: {score}/{total_checks}")
|
|
123
|
-
print("=" * 60)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
def main() -> None:
|
|
127
|
-
checks = [
|
|
128
|
-
check_stale_context,
|
|
129
|
-
check_context_vs_backlog,
|
|
130
|
-
check_handover_freshness,
|
|
131
|
-
check_duplicate_context,
|
|
132
|
-
]
|
|
133
|
-
for check in checks:
|
|
134
|
-
check()
|
|
135
|
-
|
|
136
|
-
total = len(checks)
|
|
137
|
-
failed = len([e for e in ERRORS]) + len([w for w in WARNINGS])
|
|
138
|
-
score = max(0, total - failed)
|
|
139
|
-
print_report(score, total)
|
|
140
|
-
|
|
141
|
-
if ERRORS:
|
|
142
|
-
raise SystemExit(1)
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
if __name__ == "__main__":
|
|
146
|
-
main()
|
|
@@ -1,107 +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
|
-
HANDOVER_PATH = Path("workspace/memory/handover.md")
|
|
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 main() -> None:
|
|
30
|
-
parser = argparse.ArgumentParser(description="Append a Kortext handover entry")
|
|
31
|
-
parser.add_argument("--item", required=True, help="e.g. T01-login-form")
|
|
32
|
-
parser.add_argument("--title", required=True)
|
|
33
|
-
parser.add_argument("--author", required=True)
|
|
34
|
-
parser.add_argument("--to", required=True, help="Devralan ajan veya 'none' (görev Done)")
|
|
35
|
-
parser.add_argument(
|
|
36
|
-
"--status",
|
|
37
|
-
required=True,
|
|
38
|
-
choices=["completed", "blocked", "partial"],
|
|
39
|
-
help="Görev durumu: completed | blocked | partial",
|
|
40
|
-
)
|
|
41
|
-
parser.add_argument("--completed", required=True)
|
|
42
|
-
parser.add_argument("--context", required=True, help="Bir sonraki ajanın mutlaka bilmesi gereken kritik bağlam")
|
|
43
|
-
parser.add_argument("--changed-file", action="append", default=[])
|
|
44
|
-
parser.add_argument("--watch-out", action="append", default=[])
|
|
45
|
-
parser.add_argument("--last-commit", required=True)
|
|
46
|
-
parser.add_argument("--next-step", required=True)
|
|
47
|
-
parser.add_argument("--no-commit", action="store_true", help="Atomic git commit'i atla")
|
|
48
|
-
args = parser.parse_args()
|
|
49
|
-
|
|
50
|
-
STATUS_LABELS = {
|
|
51
|
-
"completed": "Tamamlandı",
|
|
52
|
-
"blocked": "Bloklandı",
|
|
53
|
-
"partial": "Kısmen tamamlandı",
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
existing = HANDOVER_PATH.read_text() if HANDOVER_PATH.exists() else "# Handover Reports\n"
|
|
57
|
-
date = datetime.now().strftime("%d.%m.%y-%H:%M")
|
|
58
|
-
to_label = "Yok — görev Done" if args.to.lower() == "none" else f"+{args.to}"
|
|
59
|
-
changed_files = "\n".join(f"- {entry}" for entry in args.changed_file) or "- Yok"
|
|
60
|
-
watch_outs = "\n".join(f"- {entry}" for entry in args.watch_out) or "- Yok"
|
|
61
|
-
|
|
62
|
-
block = f"""## Handover: {args.item} — {args.title}
|
|
63
|
-
|
|
64
|
-
> [!INFO]
|
|
65
|
-
> - **Author:** +{args.author}
|
|
66
|
-
> - **To:** {to_label}
|
|
67
|
-
> - **Date:** {date}
|
|
68
|
-
> - **Status:** {STATUS_LABELS[args.status]}
|
|
69
|
-
|
|
70
|
-
### ✅ Completed
|
|
71
|
-
|
|
72
|
-
- {args.completed}
|
|
73
|
-
|
|
74
|
-
### Changed Files
|
|
75
|
-
|
|
76
|
-
{changed_files}
|
|
77
|
-
|
|
78
|
-
### Kritik Bağlam
|
|
79
|
-
|
|
80
|
-
- {args.context}
|
|
81
|
-
|
|
82
|
-
### Watch-outs & Decisions
|
|
83
|
-
|
|
84
|
-
{watch_outs}
|
|
85
|
-
|
|
86
|
-
### Last Commit
|
|
87
|
-
|
|
88
|
-
- {args.last_commit}
|
|
89
|
-
|
|
90
|
-
### Next Steps
|
|
91
|
-
|
|
92
|
-
- {args.next_step}
|
|
93
|
-
|
|
94
|
-
"""
|
|
95
|
-
HANDOVER_PATH.write_text(block + existing)
|
|
96
|
-
print(f"✅ Handover eklendi: {args.item} [{STATUS_LABELS[args.status]}]")
|
|
97
|
-
|
|
98
|
-
if not args.no_commit:
|
|
99
|
-
_atomic_commit(
|
|
100
|
-
f"chore(kortext): handover {args.item} ({args.status}) [skip ci]",
|
|
101
|
-
[str(HANDOVER_PATH)],
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
if __name__ == "__main__":
|
|
106
|
-
main()
|
|
107
|
-
|