@huajiwuyan/hello 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/README.md +68 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +448 -0
- package/package.json +38 -0
- package/templates/claude/commands/hello.md +760 -0
- package/templates/claude/skills/SKILL.md +90 -0
- package/templates/claude/skills/SKILL.toml +7 -0
- package/templates/claude/skills/assets/icon-large.svg +12 -0
- package/templates/claude/skills/assets/icon-small-400px.svg +12 -0
- package/templates/claude/skills/assets/templates/CHANGELOG.md +24 -0
- package/templates/claude/skills/assets/templates/CHANGELOG_{YYYY}.md +25 -0
- package/templates/claude/skills/assets/templates/INDEX.md +36 -0
- package/templates/claude/skills/assets/templates/archive/_index.md +22 -0
- package/templates/claude/skills/assets/templates/context.md +82 -0
- package/templates/claude/skills/assets/templates/modules/_index.md +22 -0
- package/templates/claude/skills/assets/templates/modules/module.md +35 -0
- package/templates/claude/skills/assets/templates/plan/proposal.md +104 -0
- package/templates/claude/skills/assets/templates/plan/tasks.md +49 -0
- package/templates/claude/skills/references/functions/auto.md +217 -0
- package/templates/claude/skills/references/functions/clean.md +167 -0
- package/templates/claude/skills/references/functions/commit.md +374 -0
- package/templates/claude/skills/references/functions/exec.md +178 -0
- package/templates/claude/skills/references/functions/help.md +105 -0
- package/templates/claude/skills/references/functions/init.md +228 -0
- package/templates/claude/skills/references/functions/plan.md +219 -0
- package/templates/claude/skills/references/functions/review.md +146 -0
- package/templates/claude/skills/references/functions/rollback.md +208 -0
- package/templates/claude/skills/references/functions/test.md +153 -0
- package/templates/claude/skills/references/functions/upgrade.md +371 -0
- package/templates/claude/skills/references/functions/validate.md +147 -0
- package/templates/claude/skills/references/rules/package.md +212 -0
- package/templates/claude/skills/references/rules/scaling.md +150 -0
- package/templates/claude/skills/references/rules/state.md +318 -0
- package/templates/claude/skills/references/rules/tools.md +371 -0
- package/templates/claude/skills/references/services/knowledge.md +408 -0
- package/templates/claude/skills/references/services/templates.md +344 -0
- package/templates/claude/skills/references/stages/analyze.md +201 -0
- package/templates/claude/skills/references/stages/design.md +379 -0
- package/templates/claude/skills/references/stages/develop.md +497 -0
- package/templates/claude/skills/references/stages/evaluate.md +286 -0
- package/templates/claude/skills/references/stages/tweak.md +244 -0
- package/templates/claude/skills/scripts/create_package.py +260 -0
- package/templates/claude/skills/scripts/list_packages.py +145 -0
- package/templates/claude/skills/scripts/migrate_package.py +399 -0
- package/templates/claude/skills/scripts/project_stats.py +438 -0
- package/templates/claude/skills/scripts/upgradewiki.py +321 -0
- package/templates/claude/skills/scripts/utils.py +596 -0
- package/templates/claude/skills/scripts/validate_package.py +309 -0
- package/templates/codex/prompts/hello.md +757 -0
- package/templates/codex/skills/SKILL.md +74 -0
- package/templates/codex/skills/SKILL.toml +7 -0
- package/templates/codex/skills/assets/icon-large.svg +12 -0
- package/templates/codex/skills/assets/icon-small-400px.svg +12 -0
- package/templates/codex/skills/assets/templates/CHANGELOG.md +24 -0
- package/templates/codex/skills/assets/templates/CHANGELOG_{YYYY}.md +25 -0
- package/templates/codex/skills/assets/templates/INDEX.md +36 -0
- package/templates/codex/skills/assets/templates/archive/_index.md +22 -0
- package/templates/codex/skills/assets/templates/context.md +82 -0
- package/templates/codex/skills/assets/templates/modules/_index.md +22 -0
- package/templates/codex/skills/assets/templates/modules/module.md +35 -0
- package/templates/codex/skills/assets/templates/plan/proposal.md +104 -0
- package/templates/codex/skills/assets/templates/plan/tasks.md +29 -0
- package/templates/codex/skills/references/functions/auto.md +181 -0
- package/templates/codex/skills/references/functions/brain.md +275 -0
- package/templates/codex/skills/references/functions/clean.md +154 -0
- package/templates/codex/skills/references/functions/commit.md +265 -0
- package/templates/codex/skills/references/functions/debug/condition-based-waiting.md +151 -0
- package/templates/codex/skills/references/functions/debug/defense-in-depth.md +147 -0
- package/templates/codex/skills/references/functions/debug/root-cause-tracing.md +168 -0
- package/templates/codex/skills/references/functions/debug.md +389 -0
- package/templates/codex/skills/references/functions/exec.md +153 -0
- package/templates/codex/skills/references/functions/help.md +101 -0
- package/templates/codex/skills/references/functions/init.md +221 -0
- package/templates/codex/skills/references/functions/plan.md +178 -0
- package/templates/codex/skills/references/functions/review.md +135 -0
- package/templates/codex/skills/references/functions/rlm.md +864 -0
- package/templates/codex/skills/references/functions/rollback.md +190 -0
- package/templates/codex/skills/references/functions/test.md +140 -0
- package/templates/codex/skills/references/functions/upgrade.md +363 -0
- package/templates/codex/skills/references/functions/validate.md +135 -0
- package/templates/codex/skills/references/rules/cache.md +136 -0
- package/templates/codex/skills/references/rules/scaling.md +124 -0
- package/templates/codex/skills/references/rules/state.md +201 -0
- package/templates/codex/skills/references/rules/tools.md +301 -0
- package/templates/codex/skills/references/services/attention.md +53 -0
- package/templates/codex/skills/references/services/knowledge.md +559 -0
- package/templates/codex/skills/references/services/package.md +383 -0
- package/templates/codex/skills/references/services/templates.md +390 -0
- package/templates/codex/skills/references/stages/analyze.md +191 -0
- package/templates/codex/skills/references/stages/design.md +355 -0
- package/templates/codex/skills/references/stages/develop.md +520 -0
- package/templates/codex/skills/references/stages/tweak.md +239 -0
- package/templates/codex/skills/rlm/__init__.py +39 -0
- package/templates/codex/skills/rlm/agent_orchestrator.py +422 -0
- package/templates/codex/skills/rlm/context_manager.py +366 -0
- package/templates/codex/skills/rlm/engine.py +915 -0
- package/templates/codex/skills/rlm/folding.py +391 -0
- package/templates/codex/skills/rlm/repl.py +452 -0
- package/templates/codex/skills/rlm/roles/analyzer.md +66 -0
- package/templates/codex/skills/rlm/roles/designer.md +94 -0
- package/templates/codex/skills/rlm/roles/explorer.md +43 -0
- package/templates/codex/skills/rlm/roles/implementer.md +62 -0
- package/templates/codex/skills/rlm/roles/kb_keeper.md +138 -0
- package/templates/codex/skills/rlm/roles/pkg_keeper.md +163 -0
- package/templates/codex/skills/rlm/roles/reviewer.md +74 -0
- package/templates/codex/skills/rlm/roles/synthesizer.md +90 -0
- package/templates/codex/skills/rlm/roles/tester.md +83 -0
- package/templates/codex/skills/rlm/schemas/agent_result.json +174 -0
- package/templates/codex/skills/rlm/session.py +376 -0
- package/templates/codex/skills/rlm/shared_tasks.py +370 -0
- package/templates/codex/skills/scripts/create_package.py +260 -0
- package/templates/codex/skills/scripts/list_packages.py +145 -0
- package/templates/codex/skills/scripts/migrate_package.py +399 -0
- package/templates/codex/skills/scripts/project_stats.py +438 -0
- package/templates/codex/skills/scripts/upgradewiki.py +321 -0
- package/templates/codex/skills/scripts/utils.py +596 -0
- package/templates/codex/skills/scripts/validate_package.py +309 -0
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
HelloAGENTS-RLM Shared Tasks Manager
|
|
5
|
+
多终端协作任务管理器
|
|
6
|
+
|
|
7
|
+
核心设计:
|
|
8
|
+
- 默认隔离模式: 每个终端独立任务列表
|
|
9
|
+
- 协作模式: 通过环境变量指定共享任务列表 ID
|
|
10
|
+
- 支持任务依赖: blocks/blocked_by 自动管理
|
|
11
|
+
- 文件锁保护并发写入
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import fcntl
|
|
15
|
+
import json
|
|
16
|
+
import os
|
|
17
|
+
import platform
|
|
18
|
+
import sys
|
|
19
|
+
from datetime import datetime
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
from typing import Any, Dict, List, Optional
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class SharedTasksManager:
|
|
25
|
+
"""
|
|
26
|
+
多终端协作任务管理器
|
|
27
|
+
|
|
28
|
+
使用方式:
|
|
29
|
+
隔离模式(默认): 直接运行 AI CLI
|
|
30
|
+
协作模式: hellotasks=<任务列表ID> <AI CLI 命令>
|
|
31
|
+
|
|
32
|
+
支持的 AI CLI:
|
|
33
|
+
- Codex CLI: hellotasks=auth-migration codex
|
|
34
|
+
- Claude Code: hellotasks=auth-migration claude
|
|
35
|
+
|
|
36
|
+
任务存储位置:
|
|
37
|
+
协作模式: {项目目录}/helloagents/tasks/{list_id}.json
|
|
38
|
+
隔离模式: 由 session.py 管理
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
def __init__(self, project_root: Optional[Path] = None):
|
|
42
|
+
"""
|
|
43
|
+
初始化任务管理器
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
project_root: 项目根目录,默认为当前工作目录
|
|
47
|
+
"""
|
|
48
|
+
self.project_root = project_root or Path.cwd()
|
|
49
|
+
self.tasks_dir = self.project_root / "helloagents" / "tasks"
|
|
50
|
+
|
|
51
|
+
# 从环境变量获取任务列表 ID
|
|
52
|
+
self.list_id = os.environ.get("hellotasks")
|
|
53
|
+
self.is_collaborative = bool(self.list_id)
|
|
54
|
+
|
|
55
|
+
if self.is_collaborative:
|
|
56
|
+
self.tasks_dir.mkdir(parents=True, exist_ok=True)
|
|
57
|
+
self.tasks_file = self.tasks_dir / f"{self.list_id}.json"
|
|
58
|
+
self._init_task_list()
|
|
59
|
+
|
|
60
|
+
def _init_task_list(self):
|
|
61
|
+
"""初始化任务列表文件"""
|
|
62
|
+
if not self.tasks_file.exists():
|
|
63
|
+
initial_data = {
|
|
64
|
+
"list_id": self.list_id,
|
|
65
|
+
"created_at": datetime.now().isoformat(),
|
|
66
|
+
"last_updated": datetime.now().isoformat(),
|
|
67
|
+
"tasks": [],
|
|
68
|
+
}
|
|
69
|
+
self._write_tasks(initial_data)
|
|
70
|
+
|
|
71
|
+
# ==================== 文件锁操作 ====================
|
|
72
|
+
|
|
73
|
+
def _read_tasks(self) -> Dict[str, Any]:
|
|
74
|
+
"""读取任务列表(带共享锁)"""
|
|
75
|
+
if not self.is_collaborative:
|
|
76
|
+
return {"tasks": []}
|
|
77
|
+
|
|
78
|
+
if not self.tasks_file.exists():
|
|
79
|
+
return {"list_id": self.list_id, "tasks": []}
|
|
80
|
+
|
|
81
|
+
try:
|
|
82
|
+
with open(self.tasks_file, 'r', encoding='utf-8') as f:
|
|
83
|
+
# Windows 不支持 fcntl,使用替代方案
|
|
84
|
+
if platform.system() != 'Windows':
|
|
85
|
+
fcntl.flock(f.fileno(), fcntl.LOCK_SH)
|
|
86
|
+
try:
|
|
87
|
+
return json.load(f)
|
|
88
|
+
finally:
|
|
89
|
+
if platform.system() != 'Windows':
|
|
90
|
+
fcntl.flock(f.fileno(), fcntl.LOCK_UN)
|
|
91
|
+
except Exception:
|
|
92
|
+
return {"list_id": self.list_id, "tasks": []}
|
|
93
|
+
|
|
94
|
+
def _write_tasks(self, data: Dict[str, Any]) -> bool:
|
|
95
|
+
"""写入任务列表(带排他锁)"""
|
|
96
|
+
if not self.is_collaborative:
|
|
97
|
+
return False
|
|
98
|
+
|
|
99
|
+
data["last_updated"] = datetime.now().isoformat()
|
|
100
|
+
|
|
101
|
+
try:
|
|
102
|
+
with open(self.tasks_file, 'w', encoding='utf-8') as f:
|
|
103
|
+
# Windows 使用简单的文件写入
|
|
104
|
+
if platform.system() != 'Windows':
|
|
105
|
+
fcntl.flock(f.fileno(), fcntl.LOCK_EX)
|
|
106
|
+
try:
|
|
107
|
+
json.dump(data, f, ensure_ascii=False, indent=2)
|
|
108
|
+
return True
|
|
109
|
+
finally:
|
|
110
|
+
if platform.system() != 'Windows':
|
|
111
|
+
fcntl.flock(f.fileno(), fcntl.LOCK_UN)
|
|
112
|
+
except Exception:
|
|
113
|
+
return False
|
|
114
|
+
|
|
115
|
+
# ==================== 任务 CRUD ====================
|
|
116
|
+
|
|
117
|
+
def add_task(
|
|
118
|
+
self,
|
|
119
|
+
subject: str,
|
|
120
|
+
description: str = "",
|
|
121
|
+
blocks: Optional[List[str]] = None,
|
|
122
|
+
blocked_by: Optional[List[str]] = None,
|
|
123
|
+
) -> Optional[str]:
|
|
124
|
+
"""
|
|
125
|
+
添加任务
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
subject: 任务标题
|
|
129
|
+
description: 任务描述
|
|
130
|
+
blocks: 此任务完成后解锁的任务 ID 列表
|
|
131
|
+
blocked_by: 阻塞此任务的任务 ID 列表
|
|
132
|
+
|
|
133
|
+
Returns:
|
|
134
|
+
任务 ID,失败返回 None
|
|
135
|
+
"""
|
|
136
|
+
if not self.is_collaborative:
|
|
137
|
+
return None
|
|
138
|
+
|
|
139
|
+
data = self._read_tasks()
|
|
140
|
+
task_id = f"t{len(data['tasks']) + 1}_{datetime.now().strftime('%H%M%S')}"
|
|
141
|
+
|
|
142
|
+
task = {
|
|
143
|
+
"id": task_id,
|
|
144
|
+
"subject": subject,
|
|
145
|
+
"description": description,
|
|
146
|
+
"status": "pending",
|
|
147
|
+
"owner": None,
|
|
148
|
+
"blocks": blocks or [],
|
|
149
|
+
"blocked_by": blocked_by or [],
|
|
150
|
+
"created_at": datetime.now().isoformat(),
|
|
151
|
+
"updated_at": datetime.now().isoformat(),
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
data["tasks"].append(task)
|
|
155
|
+
if self._write_tasks(data):
|
|
156
|
+
return task_id
|
|
157
|
+
return None
|
|
158
|
+
|
|
159
|
+
def update_task(
|
|
160
|
+
self,
|
|
161
|
+
task_id: str,
|
|
162
|
+
status: Optional[str] = None,
|
|
163
|
+
owner: Optional[str] = None,
|
|
164
|
+
) -> bool:
|
|
165
|
+
"""
|
|
166
|
+
更新任务状态
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
task_id: 任务 ID
|
|
170
|
+
status: 新状态 (pending/in_progress/completed)
|
|
171
|
+
owner: 任务负责人(终端标识)
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
是否成功
|
|
175
|
+
"""
|
|
176
|
+
if not self.is_collaborative:
|
|
177
|
+
return False
|
|
178
|
+
|
|
179
|
+
data = self._read_tasks()
|
|
180
|
+
|
|
181
|
+
for task in data["tasks"]:
|
|
182
|
+
if task["id"] == task_id:
|
|
183
|
+
if status:
|
|
184
|
+
task["status"] = status
|
|
185
|
+
if owner is not None:
|
|
186
|
+
task["owner"] = owner
|
|
187
|
+
task["updated_at"] = datetime.now().isoformat()
|
|
188
|
+
|
|
189
|
+
# 如果任务完成,自动更新依赖关系
|
|
190
|
+
if status == "completed":
|
|
191
|
+
self._resolve_dependencies(data, task_id)
|
|
192
|
+
|
|
193
|
+
return self._write_tasks(data)
|
|
194
|
+
|
|
195
|
+
return False
|
|
196
|
+
|
|
197
|
+
def _resolve_dependencies(self, data: Dict[str, Any], completed_task_id: str):
|
|
198
|
+
"""解除依赖:将 completed_task_id 从其他任务的 blocked_by 中移除"""
|
|
199
|
+
for task in data["tasks"]:
|
|
200
|
+
if completed_task_id in task.get("blocked_by", []):
|
|
201
|
+
task["blocked_by"].remove(completed_task_id)
|
|
202
|
+
task["updated_at"] = datetime.now().isoformat()
|
|
203
|
+
|
|
204
|
+
def claim_task(self, task_id: str, owner: str) -> bool:
|
|
205
|
+
"""
|
|
206
|
+
认领任务
|
|
207
|
+
|
|
208
|
+
Args:
|
|
209
|
+
task_id: 任务 ID
|
|
210
|
+
owner: 认领者标识
|
|
211
|
+
|
|
212
|
+
Returns:
|
|
213
|
+
是否成功(已被他人认领则失败)
|
|
214
|
+
"""
|
|
215
|
+
if not self.is_collaborative:
|
|
216
|
+
return False
|
|
217
|
+
|
|
218
|
+
data = self._read_tasks()
|
|
219
|
+
|
|
220
|
+
for task in data["tasks"]:
|
|
221
|
+
if task["id"] == task_id:
|
|
222
|
+
# 检查是否已被认领
|
|
223
|
+
if task["owner"] and task["owner"] != owner:
|
|
224
|
+
return False # 已被他人认领
|
|
225
|
+
|
|
226
|
+
# 检查是否被阻塞
|
|
227
|
+
if task.get("blocked_by"):
|
|
228
|
+
return False # 还有未完成的依赖
|
|
229
|
+
|
|
230
|
+
task["owner"] = owner
|
|
231
|
+
task["status"] = "in_progress"
|
|
232
|
+
task["updated_at"] = datetime.now().isoformat()
|
|
233
|
+
return self._write_tasks(data)
|
|
234
|
+
|
|
235
|
+
return False
|
|
236
|
+
|
|
237
|
+
def get_available_tasks(self) -> List[Dict[str, Any]]:
|
|
238
|
+
"""获取可认领的任务(无阻塞、未被认领)"""
|
|
239
|
+
if not self.is_collaborative:
|
|
240
|
+
return []
|
|
241
|
+
|
|
242
|
+
data = self._read_tasks()
|
|
243
|
+
available = []
|
|
244
|
+
|
|
245
|
+
for task in data["tasks"]:
|
|
246
|
+
if (task["status"] == "pending" and
|
|
247
|
+
not task.get("owner") and
|
|
248
|
+
not task.get("blocked_by")):
|
|
249
|
+
available.append(task)
|
|
250
|
+
|
|
251
|
+
return available
|
|
252
|
+
|
|
253
|
+
def get_task_list(self) -> List[Dict[str, Any]]:
|
|
254
|
+
"""获取完整任务列表"""
|
|
255
|
+
if not self.is_collaborative:
|
|
256
|
+
return []
|
|
257
|
+
|
|
258
|
+
data = self._read_tasks()
|
|
259
|
+
return data.get("tasks", [])
|
|
260
|
+
|
|
261
|
+
def get_task(self, task_id: str) -> Optional[Dict[str, Any]]:
|
|
262
|
+
"""获取单个任务详情"""
|
|
263
|
+
if not self.is_collaborative:
|
|
264
|
+
return None
|
|
265
|
+
|
|
266
|
+
data = self._read_tasks()
|
|
267
|
+
for task in data["tasks"]:
|
|
268
|
+
if task["id"] == task_id:
|
|
269
|
+
return task
|
|
270
|
+
return None
|
|
271
|
+
|
|
272
|
+
# ==================== 状态查询 ====================
|
|
273
|
+
|
|
274
|
+
def get_status(self) -> Dict[str, Any]:
|
|
275
|
+
"""获取任务列表状态"""
|
|
276
|
+
if not self.is_collaborative:
|
|
277
|
+
return {
|
|
278
|
+
"mode": "isolated",
|
|
279
|
+
"message": "未指定共享任务列表,使用隔离模式",
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
data = self._read_tasks()
|
|
283
|
+
tasks = data.get("tasks", [])
|
|
284
|
+
|
|
285
|
+
pending = sum(1 for t in tasks if t["status"] == "pending")
|
|
286
|
+
in_progress = sum(1 for t in tasks if t["status"] == "in_progress")
|
|
287
|
+
completed = sum(1 for t in tasks if t["status"] == "completed")
|
|
288
|
+
blocked = sum(1 for t in tasks if t.get("blocked_by"))
|
|
289
|
+
|
|
290
|
+
return {
|
|
291
|
+
"mode": "collaborative",
|
|
292
|
+
"list_id": self.list_id,
|
|
293
|
+
"tasks_file": str(self.tasks_file),
|
|
294
|
+
"total": len(tasks),
|
|
295
|
+
"pending": pending,
|
|
296
|
+
"in_progress": in_progress,
|
|
297
|
+
"completed": completed,
|
|
298
|
+
"blocked": blocked,
|
|
299
|
+
"last_updated": data.get("last_updated"),
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
def refresh(self) -> List[Dict[str, Any]]:
|
|
303
|
+
"""
|
|
304
|
+
强制刷新任务列表(从文件重新读取)
|
|
305
|
+
|
|
306
|
+
用于检查其他终端的更新
|
|
307
|
+
"""
|
|
308
|
+
return self.get_task_list()
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
# ==================== 便捷函数 ====================
|
|
312
|
+
|
|
313
|
+
def get_task_manager(project_root: Optional[str] = None) -> SharedTasksManager:
|
|
314
|
+
"""获取任务管理器实例"""
|
|
315
|
+
return SharedTasksManager(
|
|
316
|
+
project_root=Path(project_root) if project_root else None
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
def is_collaborative_mode() -> bool:
|
|
321
|
+
"""检查是否为协作模式"""
|
|
322
|
+
return bool(os.environ.get("hellotasks"))
|
|
323
|
+
|
|
324
|
+
|
|
325
|
+
# ==================== CLI 入口 ====================
|
|
326
|
+
|
|
327
|
+
if __name__ == "__main__":
|
|
328
|
+
import argparse
|
|
329
|
+
|
|
330
|
+
parser = argparse.ArgumentParser(description="HelloAGENTS Shared Tasks Manager")
|
|
331
|
+
parser.add_argument("--status", action="store_true", help="显示任务列表状态")
|
|
332
|
+
parser.add_argument("--list", action="store_true", help="列出所有任务")
|
|
333
|
+
parser.add_argument("--available", action="store_true", help="列出可认领的任务")
|
|
334
|
+
parser.add_argument("--add", type=str, help="添加任务 (subject)")
|
|
335
|
+
parser.add_argument("--complete", type=str, help="标记任务完成 (task_id)")
|
|
336
|
+
parser.add_argument("--claim", type=str, help="认领任务 (task_id)")
|
|
337
|
+
parser.add_argument("--owner", type=str, default="cli", help="认领者标识")
|
|
338
|
+
|
|
339
|
+
args = parser.parse_args()
|
|
340
|
+
manager = SharedTasksManager()
|
|
341
|
+
|
|
342
|
+
if args.status:
|
|
343
|
+
print(json.dumps(manager.get_status(), ensure_ascii=False, indent=2))
|
|
344
|
+
|
|
345
|
+
elif args.list:
|
|
346
|
+
tasks = manager.get_task_list()
|
|
347
|
+
print(json.dumps(tasks, ensure_ascii=False, indent=2))
|
|
348
|
+
|
|
349
|
+
elif args.available:
|
|
350
|
+
tasks = manager.get_available_tasks()
|
|
351
|
+
print(json.dumps(tasks, ensure_ascii=False, indent=2))
|
|
352
|
+
|
|
353
|
+
elif args.add:
|
|
354
|
+
task_id = manager.add_task(subject=args.add)
|
|
355
|
+
if task_id:
|
|
356
|
+
print(json.dumps({"success": True, "task_id": task_id}, ensure_ascii=False))
|
|
357
|
+
else:
|
|
358
|
+
print(json.dumps({"success": False, "error": "添加失败或非协作模式"}, ensure_ascii=False))
|
|
359
|
+
|
|
360
|
+
elif args.complete:
|
|
361
|
+
success = manager.update_task(args.complete, status="completed")
|
|
362
|
+
print(json.dumps({"success": success}, ensure_ascii=False))
|
|
363
|
+
|
|
364
|
+
elif args.claim:
|
|
365
|
+
success = manager.claim_task(args.claim, owner=args.owner)
|
|
366
|
+
print(json.dumps({"success": success}, ensure_ascii=False))
|
|
367
|
+
|
|
368
|
+
else:
|
|
369
|
+
# 默认显示状态
|
|
370
|
+
print(json.dumps(manager.get_status(), ensure_ascii=False, indent=2))
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
创建 HelloAGENTS 方案包
|
|
5
|
+
|
|
6
|
+
Usage:
|
|
7
|
+
python create_package.py <feature-name> [--path <base-path>] [--type <implementation|overview>]
|
|
8
|
+
|
|
9
|
+
Examples:
|
|
10
|
+
python create_package.py user-login
|
|
11
|
+
python create_package.py api-refactor --type overview
|
|
12
|
+
python create_package.py auth-system --path /path/to/project
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import argparse
|
|
16
|
+
import re
|
|
17
|
+
import sys
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from datetime import datetime
|
|
20
|
+
|
|
21
|
+
# 确保能找到同目录下的 utils 模块
|
|
22
|
+
sys.path.insert(0, str(Path(__file__).parent))
|
|
23
|
+
from utils import (
|
|
24
|
+
setup_encoding,
|
|
25
|
+
get_plan_path,
|
|
26
|
+
generate_package_name,
|
|
27
|
+
print_error,
|
|
28
|
+
print_success,
|
|
29
|
+
validate_base_path,
|
|
30
|
+
get_template_loader,
|
|
31
|
+
ExecutionReport
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
# 模板路径常量
|
|
36
|
+
TEMPLATE_PROPOSAL = "plan/proposal.md"
|
|
37
|
+
TEMPLATE_TASKS = "plan/tasks.md"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def create_package(feature: str, base_path: str = None, pkg_type: str = "implementation") -> ExecutionReport:
|
|
41
|
+
"""
|
|
42
|
+
创建方案包(并发安全,支持 AI 降级接手)
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
feature: 功能名称
|
|
46
|
+
base_path: 项目根目录
|
|
47
|
+
pkg_type: 方案包类型 (implementation/overview)
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
ExecutionReport: 执行报告,包含完成状态和上下文
|
|
51
|
+
"""
|
|
52
|
+
report = ExecutionReport("create_package")
|
|
53
|
+
report.set_context(feature=feature, pkg_type=pkg_type, base_path=base_path or "cwd")
|
|
54
|
+
|
|
55
|
+
plan_path = get_plan_path(base_path)
|
|
56
|
+
original_name = generate_package_name(feature)
|
|
57
|
+
|
|
58
|
+
# 步骤1: 确保父目录存在
|
|
59
|
+
try:
|
|
60
|
+
plan_path.mkdir(parents=True, exist_ok=True)
|
|
61
|
+
report.mark_completed(
|
|
62
|
+
"创建 plan/ 目录",
|
|
63
|
+
str(plan_path),
|
|
64
|
+
"检查目录是否存在: ls 或 Read 工具"
|
|
65
|
+
)
|
|
66
|
+
except PermissionError as e:
|
|
67
|
+
report.mark_failed(
|
|
68
|
+
"创建 plan/ 目录",
|
|
69
|
+
["创建 plan/ 目录", "创建方案包目录", "创建 proposal.md", "创建 tasks.md"],
|
|
70
|
+
f"权限不足: {e}"
|
|
71
|
+
)
|
|
72
|
+
return report
|
|
73
|
+
|
|
74
|
+
# 步骤2: 并发安全的目录创建(原子操作 + 重试)
|
|
75
|
+
max_retries = 100
|
|
76
|
+
package_path = None
|
|
77
|
+
package_name = None
|
|
78
|
+
|
|
79
|
+
for version in range(1, max_retries + 1):
|
|
80
|
+
package_name = original_name if version == 1 else f"{original_name}_v{version}"
|
|
81
|
+
package_path = plan_path / package_name
|
|
82
|
+
|
|
83
|
+
try:
|
|
84
|
+
package_path.mkdir(exist_ok=False)
|
|
85
|
+
report.mark_completed(
|
|
86
|
+
"创建方案包目录",
|
|
87
|
+
str(package_path),
|
|
88
|
+
"检查目录是否存在且为空目录"
|
|
89
|
+
)
|
|
90
|
+
report.set_context(package_path=str(package_path), package_name=package_name)
|
|
91
|
+
break
|
|
92
|
+
except FileExistsError:
|
|
93
|
+
continue
|
|
94
|
+
except PermissionError as e:
|
|
95
|
+
report.mark_failed(
|
|
96
|
+
"创建方案包目录",
|
|
97
|
+
["创建方案包目录", "创建 proposal.md", "创建 tasks.md"],
|
|
98
|
+
f"权限不足: {package_path}"
|
|
99
|
+
)
|
|
100
|
+
return report
|
|
101
|
+
else:
|
|
102
|
+
report.mark_failed(
|
|
103
|
+
"创建方案包目录",
|
|
104
|
+
["创建方案包目录", "创建 proposal.md", "创建 tasks.md"],
|
|
105
|
+
f"超过最大重试次数 ({max_retries}),存在大量同名方案包"
|
|
106
|
+
)
|
|
107
|
+
return report
|
|
108
|
+
|
|
109
|
+
# 步骤3: 加载并填充模板
|
|
110
|
+
current_date = datetime.now().strftime("%Y-%m-%d")
|
|
111
|
+
loader = get_template_loader()
|
|
112
|
+
|
|
113
|
+
# 定义占位符替换映射
|
|
114
|
+
replacements = {
|
|
115
|
+
"{feature}": feature,
|
|
116
|
+
"{YYYY-MM-DD}": current_date,
|
|
117
|
+
"{pkg_type}": pkg_type,
|
|
118
|
+
"{package_name}": package_name,
|
|
119
|
+
"{YYYYMMDDHHMM}_{feature}": package_name
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
# 步骤4: proposal.md - 检查模板存在性
|
|
123
|
+
proposal_content = loader.fill(TEMPLATE_PROPOSAL, replacements)
|
|
124
|
+
if proposal_content is None:
|
|
125
|
+
report.mark_failed(
|
|
126
|
+
f"加载模板 {TEMPLATE_PROPOSAL}",
|
|
127
|
+
["创建 proposal.md(需包含:元信息、需求、方案章节)", "创建 tasks.md"],
|
|
128
|
+
f"模板文件不存在: {TEMPLATE_PROPOSAL}"
|
|
129
|
+
)
|
|
130
|
+
return report
|
|
131
|
+
|
|
132
|
+
# 步骤5: tasks.md - 检查模板存在性
|
|
133
|
+
tasks_content = loader.fill(TEMPLATE_TASKS, replacements)
|
|
134
|
+
if tasks_content is None:
|
|
135
|
+
report.mark_failed(
|
|
136
|
+
f"加载模板 {TEMPLATE_TASKS}",
|
|
137
|
+
["创建 tasks.md(需包含:执行状态、任务列表、执行备注章节)"],
|
|
138
|
+
f"模板文件不存在: {TEMPLATE_TASKS}"
|
|
139
|
+
)
|
|
140
|
+
# 仍需标记 proposal 模板加载成功
|
|
141
|
+
report.mark_completed(
|
|
142
|
+
"加载 proposal.md 模板",
|
|
143
|
+
"模板内容已加载",
|
|
144
|
+
"N/A - 模板加载成功但未写入文件"
|
|
145
|
+
)
|
|
146
|
+
return report
|
|
147
|
+
|
|
148
|
+
# overview 类型:替换任务列表为"无执行任务"
|
|
149
|
+
if pkg_type == "overview":
|
|
150
|
+
# 替换执行状态中的完成率
|
|
151
|
+
tasks_content = re.sub(r'完成率:\s*\d+%', '完成率: N/A', tasks_content)
|
|
152
|
+
tasks_content = re.sub(r'总任务:\s*\w+', '总任务: 0', tasks_content)
|
|
153
|
+
# 替换任务列表部分
|
|
154
|
+
tasks_content = re.sub(
|
|
155
|
+
r'## 任务列表\s*\n.*?(?=\n---)',
|
|
156
|
+
'## 任务列表\n\n> 无执行任务(概述文档)\n',
|
|
157
|
+
tasks_content,
|
|
158
|
+
flags=re.DOTALL
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
# 步骤6: 写入 proposal.md
|
|
162
|
+
proposal_path = package_path / "proposal.md"
|
|
163
|
+
try:
|
|
164
|
+
proposal_path.write_text(proposal_content, encoding='utf-8')
|
|
165
|
+
report.mark_completed(
|
|
166
|
+
"创建 proposal.md",
|
|
167
|
+
str(proposal_path),
|
|
168
|
+
"检查文件存在且包含必需章节(元信息、需求、方案)"
|
|
169
|
+
)
|
|
170
|
+
except Exception as e:
|
|
171
|
+
report.mark_failed(
|
|
172
|
+
"写入 proposal.md",
|
|
173
|
+
["创建 proposal.md", "创建 tasks.md"],
|
|
174
|
+
str(e)
|
|
175
|
+
)
|
|
176
|
+
return report
|
|
177
|
+
|
|
178
|
+
# 步骤7: 写入 tasks.md
|
|
179
|
+
tasks_path = package_path / "tasks.md"
|
|
180
|
+
try:
|
|
181
|
+
tasks_path.write_text(tasks_content, encoding='utf-8')
|
|
182
|
+
report.mark_completed(
|
|
183
|
+
"创建 tasks.md",
|
|
184
|
+
str(tasks_path),
|
|
185
|
+
"检查文件存在且包含必需章节(执行状态、任务列表)"
|
|
186
|
+
)
|
|
187
|
+
except Exception as e:
|
|
188
|
+
report.mark_failed(
|
|
189
|
+
"写入 tasks.md",
|
|
190
|
+
["创建 tasks.md"],
|
|
191
|
+
str(e)
|
|
192
|
+
)
|
|
193
|
+
return report
|
|
194
|
+
|
|
195
|
+
# 全部完成
|
|
196
|
+
report.mark_success(str(package_path))
|
|
197
|
+
return report
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def main():
|
|
201
|
+
setup_encoding()
|
|
202
|
+
parser = argparse.ArgumentParser(
|
|
203
|
+
description="创建 HelloAGENTS 方案包"
|
|
204
|
+
)
|
|
205
|
+
parser.add_argument(
|
|
206
|
+
"feature",
|
|
207
|
+
help="功能名称 (如: user-login, api-refactor)"
|
|
208
|
+
)
|
|
209
|
+
parser.add_argument(
|
|
210
|
+
"--path",
|
|
211
|
+
default=None,
|
|
212
|
+
help="项目根目录 (默认: 当前目录)"
|
|
213
|
+
)
|
|
214
|
+
parser.add_argument(
|
|
215
|
+
"--type",
|
|
216
|
+
choices=["implementation", "overview"],
|
|
217
|
+
default="implementation",
|
|
218
|
+
help="方案包类型: implementation(实施计划) 或 overview(概述文档)"
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
args = parser.parse_args()
|
|
222
|
+
|
|
223
|
+
# 验证基础路径
|
|
224
|
+
try:
|
|
225
|
+
validate_base_path(args.path)
|
|
226
|
+
except ValueError as e:
|
|
227
|
+
report = ExecutionReport("create_package")
|
|
228
|
+
report.mark_failed("验证基础路径", ["验证路径", "创建方案包"], str(e))
|
|
229
|
+
report.print_report()
|
|
230
|
+
sys.exit(1)
|
|
231
|
+
|
|
232
|
+
# 验证 feature 名称
|
|
233
|
+
feature = args.feature.strip()
|
|
234
|
+
if not feature:
|
|
235
|
+
report = ExecutionReport("create_package")
|
|
236
|
+
report.mark_failed("验证功能名称", ["创建方案包"], "功能名称不能为空")
|
|
237
|
+
report.print_report()
|
|
238
|
+
sys.exit(1)
|
|
239
|
+
|
|
240
|
+
# 预验证 feature 名称有效性(检查规范化后是否为空)
|
|
241
|
+
try:
|
|
242
|
+
generate_package_name(feature)
|
|
243
|
+
except ValueError as e:
|
|
244
|
+
report = ExecutionReport("create_package")
|
|
245
|
+
report.mark_failed("验证功能名称", ["创建方案包"], str(e))
|
|
246
|
+
report.print_report()
|
|
247
|
+
sys.exit(1)
|
|
248
|
+
|
|
249
|
+
# 执行创建
|
|
250
|
+
report = create_package(feature, args.path, args.type)
|
|
251
|
+
|
|
252
|
+
# 输出执行报告(JSON格式,供 AI 解析)
|
|
253
|
+
report.print_report()
|
|
254
|
+
|
|
255
|
+
# 返回状态码
|
|
256
|
+
sys.exit(0 if report.success else 1)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
if __name__ == "__main__":
|
|
260
|
+
main()
|