kin: KIN-091 Улучшения из исследования рынка: (1) Revise button с feedback loop, (2) auto-test before review — агент сам прогоняет тесты и фиксит до review, (3) spec-driven workflow для новых проектов — constitution → spec → plan → tasks, (4) git worktrees для параллельных агентов без конфликтов, (5) auto-trigger pipeline при создании задачи с label auto

This commit is contained in:
Gros Frumos 2026-03-16 22:35:31 +02:00
parent 0cc063d47a
commit 0ccd451b4b
14 changed files with 1660 additions and 18 deletions

View file

@ -42,9 +42,9 @@ def build_context(
}
# Attachments — all roles get them so debugger sees screenshots, UX sees mockups, etc.
# Initialize before conditional to guarantee key presence in ctx (#213)
attachments = models.list_attachments(conn, task_id)
if attachments:
ctx["attachments"] = attachments
ctx["attachments"] = attachments
# If task has a revise comment, fetch the last agent output for context
if task and task.get("revise_comment"):
@ -97,6 +97,15 @@ def build_context(
# Minimal context — just the task spec
pass
elif role in ("constitution", "spec"):
ctx["modules"] = models.get_modules(conn, project_id)
ctx["decisions"] = models.get_decisions(conn, project_id)
elif role == "task_decomposer":
ctx["modules"] = models.get_modules(conn, project_id)
ctx["decisions"] = models.get_decisions(conn, project_id)
ctx["active_tasks"] = models.list_tasks(conn, project_id=project_id, status="in_progress")
elif role == "security":
ctx["decisions"] = models.get_decisions(
conn, project_id, category="security",
@ -279,7 +288,22 @@ def format_prompt(context: dict, role: str, prompt_template: str | None = None)
if attachments:
sections.append(f"## Attachments ({len(attachments)}):")
for a in attachments:
sections.append(f"- {a['filename']}: {a['path']}")
mime = a.get("mime_type", "")
size = a.get("size", 0)
sections.append(f"- {a['filename']} ({mime}, {size} bytes): {a['path']}")
# Inline content for small text-readable files (<= 32 KB) so PM can use them immediately
_TEXT_TYPES = {"text/", "application/json", "application/xml", "application/yaml"}
_TEXT_EXTS = {".txt", ".md", ".json", ".yaml", ".yml", ".csv", ".log", ".xml", ".toml", ".ini", ".env"}
is_text = (
any(mime.startswith(t) if t.endswith("/") else mime == t for t in _TEXT_TYPES)
or Path(a["filename"]).suffix.lower() in _TEXT_EXTS
)
if is_text and 0 < size <= 32 * 1024:
try:
content = Path(a["path"]).read_text(encoding="utf-8", errors="replace")
sections.append(f"```\n{content}\n```")
except Exception:
pass
sections.append("")
# Previous step output (pipeline chaining)