kin: KIN-ARCH-004 Добавить подсказку в форму о требовании ~/.ssh/config для ProxyJump
This commit is contained in:
parent
4188384f1b
commit
af554e15fa
7 changed files with 262 additions and 8 deletions
35
web/api.py
35
web/api.py
|
|
@ -16,7 +16,7 @@ from fastapi import FastAPI, HTTPException, Query
|
|||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import JSONResponse, FileResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from pydantic import BaseModel
|
||||
from pydantic import BaseModel, model_validator
|
||||
|
||||
from core.db import init_db
|
||||
from core import models
|
||||
|
|
@ -180,6 +180,12 @@ class ProjectCreate(BaseModel):
|
|||
ssh_key_path: str | None = None
|
||||
ssh_proxy_jump: str | None = None
|
||||
|
||||
@model_validator(mode="after")
|
||||
def validate_operations_ssh_host(self) -> "ProjectCreate":
|
||||
if self.project_type == "operations" and not self.ssh_host:
|
||||
raise ValueError("ssh_host is required for operations projects")
|
||||
return self
|
||||
|
||||
|
||||
class ProjectPatch(BaseModel):
|
||||
execution_mode: str | None = None
|
||||
|
|
@ -365,6 +371,9 @@ def approve_phase(phase_id: int, body: PhaseApprove | None = None):
|
|||
except ValueError as e:
|
||||
conn.close()
|
||||
raise HTTPException(400, str(e))
|
||||
# Mark the phase's task as done for consistency
|
||||
if phase.get("task_id"):
|
||||
models.update_task(conn, phase["task_id"], status="done")
|
||||
conn.close()
|
||||
return result
|
||||
|
||||
|
|
@ -644,6 +653,21 @@ def approve_task(task_id: str, body: TaskApprove | None = None):
|
|||
event="task_done", task_modules=task_modules)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Advance phase state machine if this task belongs to an active phase
|
||||
phase_result = None
|
||||
phase_row = conn.execute(
|
||||
"SELECT * FROM project_phases WHERE task_id = ?", (task_id,)
|
||||
).fetchone()
|
||||
if phase_row:
|
||||
phase = dict(phase_row)
|
||||
if phase.get("status") == "active":
|
||||
from core.phases import approve_phase as _approve_phase
|
||||
try:
|
||||
phase_result = _approve_phase(conn, phase["id"])
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
decision = None
|
||||
if body and body.decision_title:
|
||||
decision = models.add_decision(
|
||||
|
|
@ -664,6 +688,7 @@ def approve_task(task_id: str, body: TaskApprove | None = None):
|
|||
"followup_tasks": followup_tasks,
|
||||
"needs_decision": len(pending_actions) > 0,
|
||||
"pending_actions": pending_actions,
|
||||
"phase": phase_result,
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -954,9 +979,8 @@ def get_notifications(project_id: str | None = None):
|
|||
"""Return tasks with status='blocked' as escalation notifications.
|
||||
|
||||
Each item includes task details, the agent role that blocked it,
|
||||
the reason, and the pipeline step. Intended for GUI polling (5s interval).
|
||||
|
||||
TODO: Telegram — send notification on new escalation (telegram_sent: false placeholder).
|
||||
the reason, the pipeline step, and whether a Telegram alert was sent.
|
||||
Intended for GUI polling (5s interval).
|
||||
"""
|
||||
conn = get_conn()
|
||||
query = "SELECT * FROM tasks WHERE status = 'blocked'"
|
||||
|
|
@ -979,8 +1003,7 @@ def get_notifications(project_id: str | None = None):
|
|||
"reason": t.get("blocked_reason"),
|
||||
"pipeline_step": t.get("blocked_pipeline_step"),
|
||||
"blocked_at": t.get("blocked_at") or t.get("updated_at"),
|
||||
# TODO: Telegram — set to True once notification is sent via Telegram bot
|
||||
"telegram_sent": False,
|
||||
"telegram_sent": bool(t.get("telegram_sent")),
|
||||
})
|
||||
return notifications
|
||||
|
||||
|
|
|
|||
|
|
@ -269,8 +269,16 @@ async function createNewProject() {
|
|||
<input v-model="form.ssh_key_path" placeholder="Key path (e.g. ~/.ssh/id_rsa)"
|
||||
class="bg-gray-800 border border-gray-700 rounded px-3 py-2 text-sm text-gray-200 placeholder-gray-600" />
|
||||
</div>
|
||||
<input v-model="form.ssh_proxy_jump" placeholder="ProxyJump (optional, e.g. jumpt)"
|
||||
class="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-sm text-gray-200 placeholder-gray-600" />
|
||||
<div>
|
||||
<input v-model="form.ssh_proxy_jump" placeholder="ProxyJump (optional, e.g. jumpt)"
|
||||
class="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-sm text-gray-200 placeholder-gray-600" />
|
||||
<p class="mt-1 flex items-center gap-1 text-xs text-gray-500">
|
||||
<svg class="w-3 h-3 flex-shrink-0 text-gray-500" fill="currentColor" viewBox="0 0 20 20">
|
||||
<path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
Алиас из ~/.ssh/config на сервере Kin
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
<input v-model="form.tech_stack" placeholder="Tech stack (comma-separated)"
|
||||
class="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-sm text-gray-200 placeholder-gray-600" />
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue