mirror of
https://github.com/tradecatlabs/vibe-coding-cn.git
synced 2026-07-28 03:07:56 +00:00
feat: skills - add auto-tmux task dependencies
This commit is contained in:
@@ -151,6 +151,8 @@ skills/auto-tmux/scripts/auto-tmux.sh wait -t <session>:<window>.<pane> --patter
|
||||
skills/auto-tmux/scripts/swarm-state.sh init --dir /tmp/ai_swarm
|
||||
skills/auto-tmux/scripts/swarm-state.sh task-add --id task-001 --text "检查 README 链接"
|
||||
skills/auto-tmux/scripts/swarm-state.sh task-import --file /tmp/tasks.txt --prefix batch --dir /tmp/ai_swarm
|
||||
skills/auto-tmux/scripts/swarm-state.sh task-depend --id task-002 --blocked-by task-001 --dir /tmp/ai_swarm
|
||||
skills/auto-tmux/scripts/swarm-state.sh task-ready --dir /tmp/ai_swarm
|
||||
skills/auto-tmux/scripts/swarm-state.sh task-next --owner <session>:<window>.<pane>
|
||||
skills/auto-tmux/scripts/swarm-state.sh lock-acquire --name README.md --owner <session>:<window>.<pane>
|
||||
skills/auto-tmux/scripts/swarm-state.sh lock-prune --older-than 3600 --dry-run
|
||||
|
||||
@@ -196,6 +196,8 @@ skills/auto-tmux/scripts/swarm-state.sh init --dir /tmp/ai_swarm
|
||||
```bash
|
||||
skills/auto-tmux/scripts/swarm-state.sh task-add --id task-001 --text "检查 README 链接"
|
||||
skills/auto-tmux/scripts/swarm-state.sh task-import --file /tmp/tasks.txt --prefix batch
|
||||
skills/auto-tmux/scripts/swarm-state.sh task-depend --id batch-002 --blocked-by batch-001
|
||||
skills/auto-tmux/scripts/swarm-state.sh task-ready
|
||||
skills/auto-tmux/scripts/swarm-state.sh task-claim --id task-001 --owner "ai-hub:2.1"
|
||||
skills/auto-tmux/scripts/swarm-state.sh task-next --owner "ai-hub:2.1"
|
||||
```
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
| 14 | `b8e77f6` | pane 取证 | `auto-tmux.sh inspect` |
|
||||
| 15 | `bc37fc1` | 长文本粘贴 | `auto-tmux.sh paste --file` |
|
||||
| 16 | `075a803` | session 清理 | `auto-tmux.sh cleanup --session` |
|
||||
| 17 | `本轮` | 任务依赖 | `task-depend`、`task-ready` |
|
||||
|
||||
## 后续候选方向
|
||||
|
||||
|
||||
@@ -84,6 +84,15 @@ skills/auto-tmux/scripts/swarm-state.sh task-import --file /tmp/tasks.txt --pref
|
||||
|
||||
`task-import` 会跳过空行和 `#` 注释行,自动去掉行首 `- ` 或 `* `,并生成 `batch-001` 这类任务 ID。
|
||||
|
||||
声明任务依赖:
|
||||
|
||||
```bash
|
||||
skills/auto-tmux/scripts/swarm-state.sh task-depend --id batch-002 --blocked-by batch-001
|
||||
skills/auto-tmux/scripts/swarm-state.sh task-ready
|
||||
```
|
||||
|
||||
`task-ready` 只列出状态为 `TODO` 且所有依赖都已经 `DONE` 的任务,适合 commander 给空闲 worker 分配下一步。
|
||||
|
||||
认领任务:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -55,6 +55,8 @@ skills/auto-tmux/scripts/swarm-watch.sh --session ai-hub --swarm-dir /tmp/ai_swa
|
||||
skills/auto-tmux/scripts/swarm-state.sh init --dir /tmp/ai_swarm
|
||||
skills/auto-tmux/scripts/swarm-state.sh task-add --id task-001 --text "检查 README 链接"
|
||||
skills/auto-tmux/scripts/swarm-state.sh task-import --file /tmp/tasks.txt --prefix batch --dir /tmp/ai_swarm
|
||||
skills/auto-tmux/scripts/swarm-state.sh task-depend --id task-002 --blocked-by task-001 --dir /tmp/ai_swarm
|
||||
skills/auto-tmux/scripts/swarm-state.sh task-ready --dir /tmp/ai_swarm
|
||||
skills/auto-tmux/scripts/swarm-state.sh task-next --owner "$target" --dir /tmp/ai_swarm
|
||||
skills/auto-tmux/scripts/swarm-state.sh lock-prune --older-than 3600 --dry-run --dir /tmp/ai_swarm
|
||||
skills/auto-tmux/scripts/swarm-state.sh task-block --id task-001 --owner "$target" --reason "等待输入" --dir /tmp/ai_swarm
|
||||
|
||||
@@ -63,6 +63,14 @@ test -s "$SNAPSHOT_DIR/topology.txt"
|
||||
"$SWARM_STATE" task-add --dir "$SWARM_DIR" --id smoke-task --text "run smoke task" >/tmp/auto-tmux-smoke-task-add.txt
|
||||
printf '%s\n' "- import task one" "- import task two" > "$TASK_IMPORT_FILE"
|
||||
"$SWARM_STATE" task-import --dir "$SWARM_DIR" --file "$TASK_IMPORT_FILE" --prefix imported >/tmp/auto-tmux-smoke-task-import.txt
|
||||
"$SWARM_STATE" task-add --dir "$SWARM_DIR" --id dep-a --text "dependency root" >/tmp/auto-tmux-smoke-dep-a.txt
|
||||
"$SWARM_STATE" task-add --dir "$SWARM_DIR" --id dep-b --text "dependency child" >/tmp/auto-tmux-smoke-dep-b.txt
|
||||
"$SWARM_STATE" task-depend --dir "$SWARM_DIR" --id dep-b --blocked-by dep-a >/tmp/auto-tmux-smoke-depend.txt
|
||||
"$SWARM_STATE" task-ready --dir "$SWARM_DIR" >/tmp/auto-tmux-smoke-ready-before.txt
|
||||
! grep -q 'dep-b' /tmp/auto-tmux-smoke-ready-before.txt
|
||||
"$SWARM_STATE" task-done --dir "$SWARM_DIR" --id dep-a --owner "$worker_target" --result "dep ok"
|
||||
"$SWARM_STATE" task-ready --dir "$SWARM_DIR" >/tmp/auto-tmux-smoke-ready-after.txt
|
||||
grep -q 'dep-b' /tmp/auto-tmux-smoke-ready-after.txt
|
||||
"$SWARM_STATE" task-claim --dir "$SWARM_DIR" --id smoke-task --owner "$worker_target"
|
||||
"$SWARM_STATE" lock-acquire --dir "$SWARM_DIR" --name smoke-file --owner "$worker_target" >/tmp/auto-tmux-smoke-lock.txt
|
||||
"$SWARM_STATE" lock-release --dir "$SWARM_DIR" --name smoke-file --owner "$worker_target" >/tmp/auto-tmux-smoke-unlock.txt
|
||||
|
||||
@@ -5,6 +5,7 @@ set -euo pipefail
|
||||
SWARM_DIR="${AUTO_TMUX_SWARM_DIR:-/tmp/ai_swarm}"
|
||||
STATUS_LOG="$SWARM_DIR/status.log"
|
||||
TASKS_TSV="$SWARM_DIR/tasks.tsv"
|
||||
DEPS_TSV="$SWARM_DIR/deps.tsv"
|
||||
LOCKS_DIR="$SWARM_DIR/locks"
|
||||
RESULTS_DIR="$SWARM_DIR/results"
|
||||
STATE_LOCK_DIR="$SWARM_DIR/.state.lock.d"
|
||||
@@ -20,6 +21,8 @@ Usage:
|
||||
swarm-state.sh task-add --text TEXT [--id ID] [--dir DIR]
|
||||
swarm-state.sh task-import --file FILE [--prefix PREFIX] [--dir DIR]
|
||||
swarm-state.sh task-list [--status STATUS] [--owner TARGET] [--dir DIR]
|
||||
swarm-state.sh task-depend --id ID --blocked-by ID [--dir DIR]
|
||||
swarm-state.sh task-ready [--dir DIR]
|
||||
swarm-state.sh task-next --owner TARGET [--dir DIR]
|
||||
swarm-state.sh task-claim --id ID --owner TARGET [--dir DIR]
|
||||
swarm-state.sh task-done --id ID --owner TARGET [--result TEXT] [--dir DIR]
|
||||
@@ -53,6 +56,7 @@ set_dir() {
|
||||
SWARM_DIR="$dir"
|
||||
STATUS_LOG="$SWARM_DIR/status.log"
|
||||
TASKS_TSV="$SWARM_DIR/tasks.tsv"
|
||||
DEPS_TSV="$SWARM_DIR/deps.tsv"
|
||||
LOCKS_DIR="$SWARM_DIR/locks"
|
||||
RESULTS_DIR="$SWARM_DIR/results"
|
||||
STATE_LOCK_DIR="$SWARM_DIR/.state.lock.d"
|
||||
@@ -60,10 +64,13 @@ set_dir() {
|
||||
|
||||
ensure_init() {
|
||||
mkdir -p "$LOCKS_DIR" "$RESULTS_DIR"
|
||||
touch "$STATUS_LOG" "$TASKS_TSV"
|
||||
touch "$STATUS_LOG" "$TASKS_TSV" "$DEPS_TSV"
|
||||
if [[ ! -s "$TASKS_TSV" ]]; then
|
||||
printf 'id\tstatus\towner\ttext\tresult\n' > "$TASKS_TSV"
|
||||
fi
|
||||
if [[ ! -s "$DEPS_TSV" ]]; then
|
||||
printf 'task_id\tblocked_by\n' > "$DEPS_TSV"
|
||||
fi
|
||||
}
|
||||
|
||||
acquire_state_lock() {
|
||||
@@ -206,6 +213,11 @@ cmd_task_list() {
|
||||
' "$TASKS_TSV"
|
||||
}
|
||||
|
||||
task_exists() {
|
||||
local id="$1"
|
||||
awk -F '\t' -v id="$id" 'NR > 1 && $1 == id {found = 1} END {exit found ? 0 : 1}' "$TASKS_TSV"
|
||||
}
|
||||
|
||||
update_task() {
|
||||
local id="$1" status="$2" owner="$3" result="$4"
|
||||
local tmp
|
||||
@@ -226,6 +238,61 @@ update_task() {
|
||||
mv "$tmp" "$TASKS_TSV"
|
||||
}
|
||||
|
||||
cmd_task_depend() {
|
||||
local id="" blocked_by=""
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--dir) set_dir "${2:-}"; shift 2 ;;
|
||||
--id) id="${2:-}"; shift 2 ;;
|
||||
--blocked-by) blocked_by="${2:-}"; shift 2 ;;
|
||||
*) die "unknown task-depend option: $1" ;;
|
||||
esac
|
||||
done
|
||||
[[ -n "$id" ]] || die "missing --id"
|
||||
[[ -n "$blocked_by" ]] || die "missing --blocked-by"
|
||||
[[ "$id" != "$blocked_by" ]] || die "task cannot depend on itself: $id"
|
||||
ensure_init
|
||||
task_exists "$id" || die "task not found: $id"
|
||||
task_exists "$blocked_by" || die "blocked-by task not found: $blocked_by"
|
||||
if awk -F '\t' -v id="$id" -v blocked_by="$blocked_by" 'NR > 1 && $1 == id && $2 == blocked_by {found = 1} END {exit found ? 0 : 1}' "$DEPS_TSV"; then
|
||||
printf 'dependency already exists: %s blocked_by %s\n' "$id" "$blocked_by"
|
||||
return 0
|
||||
fi
|
||||
printf '%s\t%s\n' "$id" "$blocked_by" >> "$DEPS_TSV"
|
||||
printf 'dependency added: %s blocked_by %s\n' "$id" "$blocked_by"
|
||||
}
|
||||
|
||||
cmd_task_ready() {
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--dir) set_dir "${2:-}"; shift 2 ;;
|
||||
*) die "unknown task-ready option: $1" ;;
|
||||
esac
|
||||
done
|
||||
ensure_init
|
||||
awk -F '\t' -v OFS='\t' '
|
||||
FILENAME == ARGV[1] {
|
||||
if (FNR == 1) {header = $0; next}
|
||||
status[$1] = $2
|
||||
row[$1] = $0
|
||||
order[++n] = $1
|
||||
next
|
||||
}
|
||||
FILENAME == ARGV[2] {
|
||||
if (FNR == 1) next
|
||||
if (status[$2] != "DONE") blocked[$1] = 1
|
||||
next
|
||||
}
|
||||
END {
|
||||
print header
|
||||
for (i = 1; i <= n; i++) {
|
||||
id = order[i]
|
||||
if (status[id] == "TODO" && !blocked[id]) print row[id]
|
||||
}
|
||||
}
|
||||
' "$TASKS_TSV" "$DEPS_TSV" | column -t -s $'\t' 2>/dev/null || true
|
||||
}
|
||||
|
||||
cmd_task_claim() {
|
||||
local id="" owner=""
|
||||
while [[ $# -gt 0 ]]; do
|
||||
@@ -464,6 +531,8 @@ cmd_report() {
|
||||
cmd_task_list
|
||||
printf '\n## locks\n\n'
|
||||
cmd_lock_list || true
|
||||
printf '\n## dependencies\n\n'
|
||||
column -t -s $'\t' "$DEPS_TSV" 2>/dev/null || cat "$DEPS_TSV"
|
||||
printf '\n## recent status\n\n'
|
||||
cmd_status -n 20
|
||||
}
|
||||
@@ -500,6 +569,7 @@ cmd_validate() {
|
||||
|
||||
local failures=0
|
||||
local expected_header=$'id\tstatus\towner\ttext\tresult'
|
||||
local expected_deps_header=$'task_id\tblocked_by'
|
||||
local actual_header
|
||||
actual_header="$(head -n 1 "$TASKS_TSV")"
|
||||
if [[ "$actual_header" == "$expected_header" ]]; then
|
||||
@@ -508,6 +578,13 @@ cmd_validate() {
|
||||
printf '[FAIL] invalid tasks header: %s\n' "$actual_header" >&2
|
||||
failures=$((failures + 1))
|
||||
fi
|
||||
actual_header="$(head -n 1 "$DEPS_TSV")"
|
||||
if [[ "$actual_header" == "$expected_deps_header" ]]; then
|
||||
printf '[OK] deps header\n'
|
||||
else
|
||||
printf '[FAIL] invalid deps header: %s\n' "$actual_header" >&2
|
||||
failures=$((failures + 1))
|
||||
fi
|
||||
|
||||
local awk_output
|
||||
if awk_output="$(awk -F '\t' '
|
||||
@@ -539,6 +616,19 @@ cmd_validate() {
|
||||
esac
|
||||
done < <(tail -n +2 "$TASKS_TSV")
|
||||
|
||||
local task_id blocked_by
|
||||
while IFS=$'\t' read -r task_id blocked_by; do
|
||||
[[ -n "$task_id" ]] || continue
|
||||
if ! task_exists "$task_id"; then
|
||||
printf '[FAIL] dependency task missing: %s\n' "$task_id" >&2
|
||||
failures=$((failures + 1))
|
||||
fi
|
||||
if ! task_exists "$blocked_by"; then
|
||||
printf '[FAIL] dependency blocked_by missing: %s\n' "$blocked_by" >&2
|
||||
failures=$((failures + 1))
|
||||
fi
|
||||
done < <(tail -n +2 "$DEPS_TSV")
|
||||
|
||||
local path name
|
||||
while IFS= read -r path; do
|
||||
[[ -n "$path" ]] || continue
|
||||
@@ -571,6 +661,8 @@ main() {
|
||||
task-add) cmd_task_add "$@" ;;
|
||||
task-import) cmd_task_import "$@" ;;
|
||||
task-list) cmd_task_list "$@" ;;
|
||||
task-depend) cmd_task_depend "$@" ;;
|
||||
task-ready) cmd_task_ready "$@" ;;
|
||||
task-next) cmd_task_next "$@" ;;
|
||||
task-claim) cmd_task_claim "$@" ;;
|
||||
task-done) cmd_task_done "$@" ;;
|
||||
|
||||
Reference in New Issue
Block a user