#!/usr/bin/env bash # ============================================================================= # create_kanban_task.sh — Tạo Kanban task với tự động enforce governance rules # ============================================================================= # Usage: # ./scripts/create_kanban_task.sh [--parent PARENT] [--body BODY] # # Rules enforced: # 1. --assignee bắt buộc, phải khớp departments.json # 2. --parent bắt buộc nếu là sub-task (title có dấu chấm: X.Y hoặc X.Y.Z) # 3. Tự động notify-subscribe cho assignee # 4. Kiểm tra dot-notation format # ============================================================================= set -euo pipefail DEPARTMENTS_JSON="/opt/ai-os/products/ceo/config/departments.json" CHAT_ID="-1003707758328" # --- Color helpers --- red() { echo -e "\033[31m$*\033[0m"; } green() { echo -e "\033[32m$*\033[0m"; } yellow(){ echo -e "\033[33m$*\033[0m"; } # --- Validate args --- if [ $# -lt 2 ]; then echo "Usage: $0 <assignee> <title> [--parent PARENT] [--body BODY]" exit 1 fi ASSIGNEE="$1" TITLE="$2" shift 2 PARENT="" BODY="" while [ $# -gt 0 ]; do case "$1" in --parent) PARENT="$2"; shift 2 ;; --body) BODY="$2"; shift 2 ;; *) echo "Unknown arg: $1"; exit 1 ;; esac done # --- Rule 1: Check assignee in departments.json --- echo -n "🔍 Kiểm tra assignee '$ASSIGNEE'..." # Read thread_id, prefix, and aliases from centralized JSON using python LOOKUP_RESULT=$(python3 -c " import json, sys with open('$DEPARTMENTS_JSON') as f: cfg = json.load(f) deps = cfg.get('departments', {}) aliases = cfg.get('aliases', {}) canonical = aliases.get('$ASSIGNEE', '$ASSIGNEE') info = deps.get(canonical) if info: print(json.dumps({ 'thread_id': info['thread_id'], 'prefix': info['prefix'], 'name': info['name'] })) sys.exit(0) else: print('ERROR: not found') sys.exit(1) " 2>&1) || true if echo "$LOOKUP_RESULT" | grep -q '^{'; then THREAD_ID=$(echo "$LOOKUP_RESULT" | python3 -c "import json,sys; print(json.load(sys.stdin).get('thread_id',''))") PREFIX=$(echo "$LOOKUP_RESULT" | python3 -c "import json,sys; print(json.load(sys.stdin).get('prefix',''))") echo " ✅ (thread $THREAD_ID, prefix $PREFIX)" else echo "" red "❌ Assignee '$ASSIGNEE' không có trong departments.json." echo " Danh sách hợp lệ: it-ai, r-and-d, str-mkt, writers, grill-qa (+ aliases: r-d, rd, it, sm, wr, gq, ...)" exit 1 fi # --- Rule 2: Check dot-notation for sub-tasks --- if echo "$TITLE" | grep -qP '^\w+\.\d+\.'; then # This is a sub-sub-task (X.Y.Z) if [ -z "$PARENT" ]; then echo "" yellow "⚠️ Sub-task '$TITLE' có dạng dot-notation nhưng không có --parent." echo " Gắn --parent để context inheritance hoạt động (Story 3)." fi elif echo "$TITLE" | grep -qP '^\w+\.\d+'; then # This is a child task (X.Y) true # parent optional but recommended fi # --- Create the task --- echo -n "📝 Tạo task: $TITLE..." CMD="hermes kanban create \"$TITLE\" --assignee $ASSIGNEE" if [ -n "$BODY" ]; then # Escape body for shell ESCAPED_BODY=$(echo "$BODY" | sed 's/"/\\"/g') CMD="$CMD --body \"$ESCAPED_BODY\"" fi if [ -n "$PARENT" ]; then CMD="$CMD --parent $PARENT" fi OUTPUT=$(eval "$CMD" 2>&1) TASK_ID=$(echo "$OUTPUT" | grep -oP 't_[a-f0-9]+' | head -1) if [ -z "$TASK_ID" ]; then echo "" red "❌ Tạo task thất bại: $OUTPUT" exit 1 fi echo " ✅ $TASK_ID" # --- Rule 3: Auto notify-subscribe to the correct thread --- if [ -n "$THREAD_ID" ]; then echo -n "🔔 Subscribe notification thread $THREAD_ID..." SUB_OUTPUT=$(hermes kanban notify-subscribe "$TASK_ID" --platform telegram --chat-id "$CHAT_ID" --thread-id "$THREAD_ID" 2>&1) if echo "$SUB_OUTPUT" | grep -qi "subscribed"; then echo " ✅" else echo " ⚠️ $SUB_OUTPUT" fi fi # --- Summary --- echo "" green "✅ Task $TASK_ID đã tạo thành công!" echo " Title: $TITLE" echo " Assignee: $ASSIGNEE (thread $THREAD_ID)" [ -n "$PARENT" ] && echo " Parent: $PARENT" echo ""