93d1b21的任务收尾
This commit is contained in:
@@ -101,10 +101,10 @@ DEFAULT_CONFIG = """############################################################
|
||||
|
||||
[general]
|
||||
# 是否在 .gitignore 中忽略 .aide 目录
|
||||
# - true(默认):自动添加 .aide/ 到 .gitignore,不跟踪 aide 状态
|
||||
# - false:不修改 .gitignore,允许 git 跟踪 .aide 目录
|
||||
# 适用于需要在多设备同步 aide 状态的场景
|
||||
gitignore_aide = true
|
||||
# - true:自动添加 .aide/ 到 .gitignore,不跟踪 aide 状态
|
||||
# - false(默认):不修改 .gitignore,允许 git 跟踪 .aide 目录
|
||||
# 推荐使用此设置,便于多设备同步 aide 状态和任务历史
|
||||
gitignore_aide = false
|
||||
|
||||
################################################################################
|
||||
# [runtime] - Aide 运行时要求
|
||||
@@ -240,6 +240,30 @@ path = ".aide/project-docs"
|
||||
# 默认:.aide/project-docs/block-plan.md
|
||||
block_plan_path = ".aide/project-docs/block-plan.md"
|
||||
|
||||
################################################################################
|
||||
# [user_docs] - 面向用户的文档配置
|
||||
################################################################################
|
||||
# 配置面向用户的文档系统。
|
||||
# 包括 README、用户文档和流程图等。
|
||||
|
||||
[user_docs]
|
||||
# README 文件路径(相对于项目根目录)
|
||||
readme_path = "README.md"
|
||||
|
||||
# README 编写规范文件路径
|
||||
# 存放项目的 README 编写规范和模板选择
|
||||
rules_path = "make-readme-rules.md"
|
||||
|
||||
# 用户文档目录路径
|
||||
docs_path = "docs"
|
||||
|
||||
# 用户流程图目录路径
|
||||
graph_path = "docs/graph-guide"
|
||||
|
||||
# 流程图计划文件路径
|
||||
# 存放流程图编写计划和进度,用于分步执行和接续执行
|
||||
graph_plan_path = "docs/graph-guide/plan.md"
|
||||
|
||||
################################################################################
|
||||
# [flow] - 流程追踪配置
|
||||
################################################################################
|
||||
@@ -327,11 +351,11 @@ class ConfigManager:
|
||||
|
||||
def ensure_gitignore(self) -> None:
|
||||
"""根据配置决定是否在 .gitignore 中添加 .aide/ 忽略项。"""
|
||||
# 读取配置,默认为 True(忽略 .aide 目录)
|
||||
# 读取配置,默认为 False(不忽略 .aide 目录)
|
||||
config = self.load_config()
|
||||
gitignore_aide = self._walk_get(config, "general.gitignore_aide")
|
||||
if gitignore_aide is None:
|
||||
gitignore_aide = True # 默认值
|
||||
gitignore_aide = False # 默认值
|
||||
|
||||
if not gitignore_aide:
|
||||
# 配置为 False,不添加忽略项
|
||||
|
||||
@@ -4,13 +4,14 @@ from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import secrets
|
||||
import time
|
||||
from contextlib import contextmanager
|
||||
from pathlib import Path
|
||||
|
||||
from aide.flow.errors import FlowError
|
||||
from aide.flow.types import FlowStatus
|
||||
from aide.flow.utils import now_task_id
|
||||
from aide.flow.utils import now_iso, now_task_id
|
||||
|
||||
|
||||
class FlowStorage:
|
||||
@@ -21,6 +22,7 @@ class FlowStorage:
|
||||
self.lock_path = self.aide_dir / "flow-status.lock"
|
||||
self.tmp_path = self.aide_dir / "flow-status.json.tmp"
|
||||
self.logs_dir = self.aide_dir / "logs"
|
||||
self.back_confirm_path = self.aide_dir / "back-confirm-state.json"
|
||||
|
||||
def ensure_ready(self) -> None:
|
||||
if not self.aide_dir.exists():
|
||||
@@ -144,3 +146,45 @@ class FlowStorage:
|
||||
|
||||
return None
|
||||
|
||||
# === Back-confirm 状态管理 ===
|
||||
|
||||
def has_pending_back_confirm(self) -> bool:
|
||||
"""检查是否存在待确认的 back 请求。"""
|
||||
return self.back_confirm_path.exists()
|
||||
|
||||
def load_back_confirm_state(self) -> dict | None:
|
||||
"""加载 back-confirm 状态。"""
|
||||
if not self.back_confirm_path.exists():
|
||||
return None
|
||||
try:
|
||||
raw = self.back_confirm_path.read_text(encoding="utf-8")
|
||||
data = json.loads(raw)
|
||||
if not isinstance(data, dict):
|
||||
raise ValueError("back-confirm 状态文件格式错误")
|
||||
return data
|
||||
except Exception as exc:
|
||||
raise FlowError(f"读取 back-confirm 状态失败: {exc}")
|
||||
|
||||
def save_back_confirm_state(self, target_part: str, reason: str) -> str:
|
||||
"""保存 back-confirm 状态,返回生成的 key。"""
|
||||
key = secrets.token_hex(6) # 12 字符的随机 key
|
||||
data = {
|
||||
"pending_key": key,
|
||||
"target_part": target_part,
|
||||
"reason": reason,
|
||||
"created_at": now_iso(),
|
||||
}
|
||||
try:
|
||||
payload = json.dumps(data, ensure_ascii=False, indent=2) + "\n"
|
||||
self.back_confirm_path.write_text(payload, encoding="utf-8")
|
||||
except Exception as exc:
|
||||
raise FlowError(f"保存 back-confirm 状态失败: {exc}")
|
||||
return key
|
||||
|
||||
def clear_back_confirm_state(self) -> None:
|
||||
"""清除 back-confirm 状态文件。"""
|
||||
try:
|
||||
self.back_confirm_path.unlink(missing_ok=True)
|
||||
except Exception as exc:
|
||||
raise FlowError(f"清除 back-confirm 状态失败: {exc}")
|
||||
|
||||
|
||||
@@ -39,7 +39,64 @@ class FlowTracker:
|
||||
return self._run(action="next-part", to_phase=phase, text=summary)
|
||||
|
||||
def back_part(self, phase: str, reason: str) -> bool:
|
||||
return self._run(action="back-part", to_phase=phase, text=reason)
|
||||
"""返工请求:检测是否已确认,未确认则生成 key。"""
|
||||
try:
|
||||
self.storage.ensure_ready()
|
||||
|
||||
# 检查是否存在待确认的 back 请求
|
||||
if self.storage.has_pending_back_confirm():
|
||||
state = self.storage.load_back_confirm_state()
|
||||
if state:
|
||||
output.warn("已存在待确认的返工请求")
|
||||
output.info(f"目标环节: {state['target_part']}")
|
||||
output.info(f"原因: {state['reason']}")
|
||||
output.info(f"请执行: aide flow back-confirm --key {state['pending_key']}")
|
||||
return False
|
||||
|
||||
# 生成新的确认 key
|
||||
key = self.storage.save_back_confirm_state(phase, reason)
|
||||
output.warn("返工需要确认。请先完成准备工作,然后执行:")
|
||||
output.info(f"aide flow back-confirm --key {key}")
|
||||
return True
|
||||
|
||||
except FlowError as exc:
|
||||
output.err(str(exc))
|
||||
return False
|
||||
|
||||
def back_confirm(self, key: str) -> bool:
|
||||
"""确认返工请求并执行。"""
|
||||
try:
|
||||
self.storage.ensure_ready()
|
||||
|
||||
# 检查是否存在待确认的请求
|
||||
state = self.storage.load_back_confirm_state()
|
||||
if state is None:
|
||||
output.err("无待确认的返工请求")
|
||||
return False
|
||||
|
||||
# 验证 key
|
||||
if state.get("pending_key") != key:
|
||||
output.err("确认 key 不匹配")
|
||||
return False
|
||||
|
||||
# 获取目标阶段和原因
|
||||
target_part = state["target_part"]
|
||||
reason = state["reason"]
|
||||
|
||||
# 清除确认状态文件
|
||||
self.storage.clear_back_confirm_state()
|
||||
|
||||
# 执行实际的 back-part 操作
|
||||
result = self._run(action="back-part", to_phase=target_part, text=reason)
|
||||
|
||||
if result:
|
||||
output.warn("建议执行 /exit 重新开始对话")
|
||||
|
||||
return result
|
||||
|
||||
except FlowError as exc:
|
||||
output.err(str(exc))
|
||||
return False
|
||||
|
||||
def issue(self, description: str) -> bool:
|
||||
return self._run(action="issue", to_phase=None, text=description)
|
||||
|
||||
@@ -119,6 +119,10 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
flow_back_part.add_argument("reason", help="回退原因")
|
||||
flow_back_part.set_defaults(func=handle_flow_back_part)
|
||||
|
||||
flow_back_confirm = flow_sub.add_parser("back-confirm", help="确认返工请求")
|
||||
flow_back_confirm.add_argument("--key", required=True, help="确认 key")
|
||||
flow_back_confirm.set_defaults(func=handle_flow_back_confirm)
|
||||
|
||||
flow_issue = flow_sub.add_parser("issue", help="记录一般问题(不阻塞继续)")
|
||||
flow_issue.add_argument("description", help="问题描述")
|
||||
flow_issue.set_defaults(func=handle_flow_issue)
|
||||
@@ -166,7 +170,8 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
|
||||
|
||||
def handle_init(args: argparse.Namespace) -> bool:
|
||||
root = find_project_root()
|
||||
# 使用当前工作目录(原地初始化,类似 git init)
|
||||
root = Path.cwd()
|
||||
cfg = ConfigManager(root)
|
||||
cfg.ensure_config()
|
||||
cfg.ensure_gitignore()
|
||||
@@ -300,6 +305,13 @@ def handle_flow_back_part(args: argparse.Namespace) -> bool:
|
||||
return tracker.back_part(args.phase, args.reason)
|
||||
|
||||
|
||||
def handle_flow_back_confirm(args: argparse.Namespace) -> bool:
|
||||
root = find_project_root()
|
||||
cfg = ConfigManager(root)
|
||||
tracker = FlowTracker(root, cfg)
|
||||
return tracker.back_confirm(args.key)
|
||||
|
||||
|
||||
def handle_flow_issue(args: argparse.Namespace) -> bool:
|
||||
root = find_project_root()
|
||||
cfg = ConfigManager(root)
|
||||
|
||||
Reference in New Issue
Block a user