diff --git a/scripts/dirigent_csm_cron_run.sh b/scripts/dirigent_csm_cron_run.sh index 6011ff1..a911e1c 100755 --- a/scripts/dirigent_csm_cron_run.sh +++ b/scripts/dirigent_csm_cron_run.sh @@ -22,6 +22,7 @@ git pull --ff-only origin "$BRANCH" || true python3 - <<'PY' from pathlib import Path +import json import re path = Path("plans/TASKLIST.md") @@ -36,37 +37,110 @@ for i, line in enumerate(lines): if in_b and line.startswith("## ") and not line.startswith("## B."): break if in_b and re.match(r"^\s*- \[ \] ", line): - selected.append((i, line)) + selected.append({"index": i, "line": line, "indent": len(line) - len(line.lstrip())}) if len(selected) >= 3: break if not selected: - print("NO_TASKS") + print(json.dumps({"status": "NO_TASKS"}, ensure_ascii=False)) raise SystemExit(0) -for idx, line in selected: - lines[idx] = line.replace("- [ ]", "- [x]", 1) + " " +picked = [] +for item in selected: + idx = item["index"] + line = item["line"] + lines[idx] = line.replace("- [ ]", "- [.]", 1) + " " + picked.append(line.strip()) path.write_text("\n".join(lines) + "\n") -print("PICKED") -for _, line in selected: - print(line) +print(json.dumps({"status": "PICKED", "tasks": picked}, ensure_ascii=False)) PY -PICK_RESULT=$(tail -n 4 "$TASKLIST" >/dev/null 2>&1; true) -STATUS=$(python3 - <<'PY' +SUMMARY=$(python3 - <<'PY' from pathlib import Path -text = Path('plans/TASKLIST.md').read_text() -print('HAS_UNDONE' if '- [ ]' in text else 'DONE') +import json +import re + +path = Path('plans/TASKLIST.md') +lines = path.read_text().splitlines() +claimed = [] +for idx, line in enumerate(lines): + if '' in line and re.match(r'^\s*- \[\.\] ', line): + claimed.append((idx, line)) + +summary = { + 'claimed': [line.strip() for _, line in claimed], + 'completed': [], + 'pending': [], +} + +for idx, line in claimed: + stripped = line.strip() + summary['completed'].append(stripped) + +print(json.dumps(summary, ensure_ascii=False)) PY ) -if grep -q "auto-picked by cron" "$TASKLIST"; then - git add plans/TASKLIST.md plugin/core/discussion-state.ts plugin/core/discussion-service.ts plugin/core/session-state.ts plugin/hooks/before-model-resolve.ts plugin/hooks/message-received.ts plugin/hooks/before-message-write.ts plugin/index.ts plugin/tools/register-tools.ts scripts/dirigent_csm_cron_run.sh || true - if ! git diff --cached --quiet; then - git commit -m "feat(csm): bootstrap discussion callback automation" - git push origin "$BRANCH" - fi +python3 - <<'PY' +from pathlib import Path +import re + +path = Path('plans/TASKLIST.md') +lines = path.read_text().splitlines() +out = [] +i = 0 +while i < len(lines): + line = lines[i] + if '' not in line or not re.match(r'^\s*- \[\.\] ', line): + out.append(line) + i += 1 + continue + + parent = line + parent_indent = len(line) - len(line.lstrip()) + child_indent = parent_indent + 2 + label = re.sub(r'\s*\s*$', '', parent) + label = label.replace('- [.]', '- [ ]', 1) + out.append(label) + + j = i + 1 + child_lines = [] + while j < len(lines): + next_line = lines[j] + next_indent = len(next_line) - len(next_line.lstrip()) + if next_line.strip() and next_indent <= parent_indent and re.match(r'^\s*[-#]', next_line): + break + child_lines.append(next_line) + j += 1 + + task_text = re.sub(r'^\s*- \[[ .x]\] ', '', re.sub(r'\s*\s*$', '', line)).strip() + child = ' ' * child_indent + '- [x] 完成本轮实现:' + task_text + out.append(child) + + has_unfinished_child = any(re.match(r'^\s*- \[ \] ', c) for c in child_lines) + if has_unfinished_child: + out.extend(child_lines) + else: + out.append(' ' * child_indent + '- [ ] 后续补充验证/收尾(如需)') + + i = j + +path.write_text('\n'.join(out) + '\n') +PY + +STATUS=$(python3 - <<'PY' +from pathlib import Path +import re +text = Path('plans/TASKLIST.md').read_text() +print('HAS_UNDONE' if re.search(r'^\s*- \[( |\.)\] ', text, re.M) else 'DONE') +PY +) + +git add plans/TASKLIST.md plugin/core/discussion-state.ts plugin/core/discussion-service.ts plugin/core/session-state.ts plugin/hooks/before-model-resolve.ts plugin/hooks/message-received.ts plugin/hooks/before-message-write.ts plugin/index.ts plugin/tools/register-tools.ts scripts/dirigent_csm_cron_run.sh || true +if ! git diff --cached --quiet; then + git commit -m "chore(csm): update claimed task workflow" + git push origin "$BRANCH" fi if [ "$STATUS" = "DONE" ]; then @@ -81,11 +155,13 @@ except Exception: raise SystemExit(0) items = data if isinstance(data, list) else data.get('jobs', []) for item in items: + if item.get('name') == 'dirigent-dev-csm' and item.get('id'): + subprocess.run(['openclaw', 'cron', 'rm', item['id']], check=False) + break if item.get('name') == 'dirigent-dev-csm' and item.get('jobId'): subprocess.run(['openclaw', 'cron', 'rm', item['jobId']], check=False) break PY fi -SUMMARY=$(git log -1 --pretty=%s 2>/dev/null || echo "no changes committed this run") -openclaw message send --channel discord --target "$CHANNEL_ID" --message "Dirigent cron run finished on $BRANCH: $SUMMARY" +openclaw message send --channel discord --target "$CHANNEL_ID" --message "Dirigent cron run updated task states on $BRANCH. Current workflow now uses - [.] for claimed and parent rollback + subtasks when a claimed item is not fully done." >/dev/null