@brandon_9527/tcode 1.0.2 → 1.0.6

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.
Files changed (73) hide show
  1. package/dist/python-src/.autodev/skills/teams/scripts/README.md +29 -0
  2. package/dist/python-src/.autodev/skills/teams/scripts/cursor_dispatch.sh +88 -0
  3. package/dist/python-src/.autodev/skills/teams/scripts/dispatch.sh +112 -0
  4. package/dist/python-src/.autodev/skills/teams/scripts/label.sh +62 -0
  5. package/dist/python-src/.autodev/skills/teams/scripts/layout.sh +181 -0
  6. package/dist/python-src/.autodev/skills/teams/scripts/old_dispatch.sh +42 -0
  7. package/dist/python-src/.autodev/skills/teams/scripts/pipe.sh +19 -0
  8. package/dist/python-src/.autodev/skills/teams/scripts/pipe_dispatch.sh +59 -0
  9. package/dist/python-src/.autodev/skills/teams/scripts/run.sh +18 -0
  10. package/dist/python-src/.autodev/skills/teams/scripts/stop.sh +26 -0
  11. package/dist/python-src/.autodev/skills/teams/scripts/tmux-layout.sh +43 -0
  12. package/dist/python-src/entry.py +71 -2
  13. package/dist/python-src/main.py +440 -3
  14. package/dist/python-src/pyproject.toml +3 -2
  15. package/dist/python-src/src/ai_tcode.egg-info/PKG-INFO +30 -0
  16. package/dist/python-src/src/ai_tcode.egg-info/SOURCES.txt +48 -0
  17. package/dist/python-src/src/ai_tcode.egg-info/dependency_links.txt +1 -0
  18. package/dist/python-src/src/ai_tcode.egg-info/requires.txt +26 -0
  19. package/dist/python-src/src/ai_tcode.egg-info/top_level.txt +9 -0
  20. package/dist/python-src/src/core/deepagents.py +1 -1
  21. package/dist/python-src/src/managers/manager_agent.py +200 -0
  22. package/dist/python-src/src/managers/manager_context.py +49 -0
  23. package/dist/python-src/src/managers/manager_instruction.py +192 -0
  24. package/dist/python-src/src/middlewares/dynamic_content.py +66 -0
  25. package/dist/python-src/src/middlewares/hitl.py +3 -3
  26. package/dist/python-src/src/middlewares/inject_content.py +0 -0
  27. package/dist/python-src/src/middlewares/memory.py +44 -0
  28. package/dist/python-src/src/middlewares/subagents.py +25 -25
  29. package/dist/python-src/src/middlewares/summary.py +37 -37
  30. package/dist/python-src/src/middlewares/utils.py +5 -0
  31. package/dist/python-src/src/prompts/prompts.py +1 -0
  32. package/dist/python-src/src/stream/formatter.py +19 -19
  33. package/dist/python-src/src/stream/handler.py +105 -78
  34. package/dist/python-src/src/stream/handler_with_tracker.py +7 -7
  35. package/dist/python-src/src/tools/tools.py +2 -2
  36. package/dist/python-src/src/tools/web.py +10 -9
  37. package/dist/python-src/src/tui/chatui.py +57 -45
  38. package/dist/python-src/src/tui/components/tlist.py +6 -6
  39. package/dist/python-src/src/tui/demo.py +22 -0
  40. package/dist/python-src/src/tui/utils/trender.py +32 -32
  41. package/dist/python-src/src/utils/prompt.py +15 -4
  42. package/dist/python-src/uv.lock +2019 -2098
  43. package/package.json +1 -1
  44. package/dist/python-src/src/__pycache__/__init__.cpython-311.pyc +0 -0
  45. package/dist/python-src/src/managers/__pycache__/__init__.cpython-311.pyc +0 -0
  46. package/dist/python-src/src/managers/__pycache__/sandbox.cpython-311.pyc +0 -0
  47. package/dist/python-src/src/middlewares/__pycache__/__init__.cpython-311.pyc +0 -0
  48. package/dist/python-src/src/middlewares/__pycache__/hitl.cpython-311.pyc +0 -0
  49. package/dist/python-src/src/middlewares/dynamic_prompt.py +0 -15
  50. package/dist/python-src/src/stream/__pycache__/__init__.cpython-311.pyc +0 -0
  51. package/dist/python-src/src/stream/__pycache__/emitter.cpython-311.pyc +0 -0
  52. package/dist/python-src/src/stream/__pycache__/file_write_parser.cpython-311.pyc +0 -0
  53. package/dist/python-src/src/stream/__pycache__/formatter.cpython-311.pyc +0 -0
  54. package/dist/python-src/src/stream/__pycache__/handler.cpython-311.pyc +0 -0
  55. package/dist/python-src/src/stream/__pycache__/tracker.cpython-311.pyc +0 -0
  56. package/dist/python-src/src/stream/__pycache__/utils.cpython-311.pyc +0 -0
  57. package/dist/python-src/src/tools/__pycache__/__init__.cpython-311.pyc +0 -0
  58. package/dist/python-src/src/tools/__pycache__/skill_loader.cpython-311.pyc +0 -0
  59. package/dist/python-src/src/tools/__pycache__/tools.cpython-311.pyc +0 -0
  60. package/dist/python-src/src/tools/__pycache__/web.cpython-311.pyc +0 -0
  61. package/dist/python-src/src/tui/__pycache__/chatui.cpython-311.pyc +0 -0
  62. package/dist/python-src/src/tui/__pycache__/config.cpython-311.pyc +0 -0
  63. package/dist/python-src/src/tui/components/__pycache__/__init__.cpython-311.pyc +0 -0
  64. package/dist/python-src/src/tui/components/__pycache__/live_spinner.cpython-311.pyc +0 -0
  65. package/dist/python-src/src/tui/components/__pycache__/tdiff.cpython-311.pyc +0 -0
  66. package/dist/python-src/src/tui/components/__pycache__/tdisplay.cpython-311.pyc +0 -0
  67. package/dist/python-src/src/tui/components/__pycache__/tlist.cpython-311.pyc +0 -0
  68. package/dist/python-src/src/tui/components/__pycache__/tscroll_panel.cpython-311.pyc +0 -0
  69. package/dist/python-src/src/tui/utils/__pycache__/__init__.cpython-311.pyc +0 -0
  70. package/dist/python-src/src/tui/utils/__pycache__/render.cpython-311.pyc +0 -0
  71. package/dist/python-src/src/tui/utils/__pycache__/trender.cpython-311.pyc +0 -0
  72. package/dist/python-src/src/utils/__pycache__/__init__.cpython-311.pyc +0 -0
  73. package/dist/python-src/src/utils/__pycache__/utils.cpython-311.pyc +0 -0
@@ -0,0 +1,29 @@
1
+ # 启动(带角色)
2
+ ./run.sh brain coder tester reviewer
3
+
4
+ # 动态扩容
5
+ ./layout.sh scale brain coder tester reviewer ops logger
6
+
7
+ # 派发任务
8
+ ./dispatch.sh coder "echo coding"
9
+ ./dispatch.sh tester "echo testing"
10
+
11
+ ./layout.sh up
12
+ ./layoyt.sh down
13
+
14
+
15
+ 👉 绑定快捷键(tmux 内)
16
+ ```bash
17
+ tmux bind-key -n C-j run-shell "./layout.sh down"
18
+ tmux bind-key -n C-k run-shell "./layout.sh up"
19
+ ```
20
+ 👉 直接:
21
+ ```bash
22
+ Ctrl + j ↓
23
+ Ctrl + k ↑
24
+ ```
25
+
26
+ 滚动 agent
27
+
28
+
29
+
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env bash
2
+
3
+ SOCKET="/tmp/tmux-agent.sock"
4
+ SESSION="agent"
5
+ MAP_FILE="/tmp/tmux-agent.map"
6
+ CURSOR_FILE="/tmp/tmux-agent.cursor"
7
+
8
+ ROLE=$1
9
+ TASK=$2
10
+
11
+ if [ -z "$ROLE" ] || [ -z "$TASK" ]; then
12
+ echo "Usage: $0 <role> <task>"
13
+ exit 1
14
+ fi
15
+
16
+ # ----------------------------
17
+ # 查找 pane
18
+ # ----------------------------
19
+ PANE=$(grep "^$ROLE " "$MAP_FILE" | awk '{print $2}')
20
+
21
+ if [ -z "$PANE" ]; then
22
+ echo "Role not found: $ROLE"
23
+ exit 1
24
+ fi
25
+
26
+ # ----------------------------
27
+ # cursor 工具
28
+ # ----------------------------
29
+ get_cursor() {
30
+ grep "^$1 " "$CURSOR_FILE" 2>/dev/null | awk '{print $2}'
31
+ }
32
+
33
+ set_cursor() {
34
+ grep -v "^$1 " "$CURSOR_FILE" 2>/dev/null > "$CURSOR_FILE.tmp" || true
35
+ echo "$1 $2" >> "$CURSOR_FILE.tmp"
36
+ mv "$CURSOR_FILE.tmp" "$CURSOR_FILE"
37
+ }
38
+
39
+ # ----------------------------
40
+ # 获取当前总行数
41
+ # ----------------------------
42
+ TOTAL_BEFORE=$(tmux -S $SOCKET capture-pane -t "$PANE" -p -J | wc -l)
43
+
44
+ LAST=$(get_cursor "$PANE")
45
+
46
+ # ✅ 修复点 1(关键)
47
+ if [ -z "$LAST" ]; then
48
+ LAST=$((TOTAL_BEFORE - 1))
49
+ if [ "$LAST" -lt 0 ]; then
50
+ LAST=0
51
+ fi
52
+ fi
53
+
54
+ # ----------------------------
55
+ # 发送任务
56
+ # ----------------------------
57
+ tmux -S $SOCKET send-keys -t "$PANE" "$TASK" C-m
58
+
59
+ # ----------------------------
60
+ # 等待输出变化
61
+ # ----------------------------
62
+ for i in {1..20}; do
63
+ TOTAL_AFTER=$(tmux -S $SOCKET capture-pane -t "$PANE" -p -J | wc -l)
64
+
65
+ if [ "$TOTAL_AFTER" -gt "$TOTAL_BEFORE" ]; then
66
+ break
67
+ fi
68
+
69
+ sleep 0.2
70
+ done
71
+
72
+ # ----------------------------
73
+ # 增量读取
74
+ # ----------------------------
75
+
76
+ # ✅ 修复点 2(-J)
77
+ NEW_OUTPUT=$(tmux -S $SOCKET capture-pane -t "$PANE" -p -J -S $((LAST + 1)))
78
+
79
+ # ----------------------------
80
+ # 更新 cursor
81
+ # ----------------------------
82
+ FINAL_TOTAL=$(tmux -S $SOCKET capture-pane -t "$PANE" -p -J | wc -l)
83
+ set_cursor "$PANE" "$FINAL_TOTAL"
84
+
85
+ # ----------------------------
86
+ # 输出
87
+ # ----------------------------
88
+ echo "$NEW_OUTPUT"
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env bash
2
+
3
+ SOCKET="/tmp/tmux-agent.sock"
4
+ SESSION="agent"
5
+ MAP_FILE="/tmp/tmux-agent.map"
6
+
7
+ ROLE=$1
8
+ TASK=$2
9
+
10
+ if [ -z "$ROLE" ] || [ -z "$TASK" ]; then
11
+ echo "Usage: $0 <role> <task>"
12
+ exit 1
13
+ fi
14
+
15
+ # ----------------------------
16
+ # 找 pane
17
+ # ----------------------------
18
+ PANE=$(grep "^$ROLE " "$MAP_FILE" | awk '{print $2}')
19
+
20
+ if [ -z "$PANE" ]; then
21
+ echo "Role not found: $ROLE"
22
+ exit 1
23
+ fi
24
+
25
+ # ----------------------------
26
+ # task id
27
+ # ----------------------------
28
+ TASK_ID=$(date +%s%N)
29
+ START="__START__${TASK_ID}"
30
+ END="__END__${TASK_ID}"
31
+
32
+ # CMD="echo $START; $TASK; echo $END"
33
+ # CMD="echo $START; bash -c '$TASK'; echo $END"
34
+ CMD="echo $START; bash -c $(printf %q "$TASK"); echo $END"
35
+
36
+ tmux -S $SOCKET send-keys -t "$PANE" "$CMD" C-m
37
+
38
+ # ----------------------------
39
+ # streaming
40
+ # ----------------------------
41
+ FOUND=0
42
+ LAST_LINES=0
43
+
44
+ START_TIME=$(date +%s)
45
+ TIMEOUT=15 # 秒
46
+
47
+ while true; do
48
+
49
+ OUTPUT=$(tmux -S $SOCKET capture-pane -t "$PANE" -p -J)
50
+
51
+ # ----------------------------
52
+ # ⏱ timeout 防卡死
53
+ # ----------------------------
54
+ NOW=$(date +%s)
55
+ if [ $((NOW - START_TIME)) -gt $TIMEOUT ]; then
56
+ echo "[dispatch timeout]"
57
+ break
58
+ fi
59
+
60
+ # ----------------------------
61
+ # 🧠 START 检测(带 clear 修复)
62
+ # ----------------------------
63
+ if [ $FOUND -eq 0 ]; then
64
+
65
+ if echo "$OUTPUT" | grep -q "$START"; then
66
+ FOUND=1
67
+
68
+ elif echo "$OUTPUT" | grep -q "$END"; then
69
+ # ❗ START 被 clear 掉了
70
+ # 直接结束(无输出任务)
71
+ break
72
+
73
+ else
74
+ sleep 0.1
75
+ continue
76
+ fi
77
+ fi
78
+
79
+ # ----------------------------
80
+ # 截 START 后内容
81
+ # ----------------------------
82
+ STREAM=$(echo "$OUTPUT" | awk "/$START/{flag=1;next} flag")
83
+
84
+ # ----------------------------
85
+ # 如果遇到 END
86
+ # ----------------------------
87
+ if echo "$STREAM" | grep -q "$END"; then
88
+
89
+ RESULT=$(echo "$STREAM" | awk "/$END/{exit} {print}")
90
+
91
+ TOTAL=$(echo "$RESULT" | wc -l)
92
+
93
+ if [ "$TOTAL" -gt "$LAST_LINES" ]; then
94
+ echo "$RESULT" | tail -n $(($TOTAL - $LAST_LINES))
95
+ fi
96
+
97
+ break
98
+ fi
99
+
100
+ # ----------------------------
101
+ # ✅ 增量输出(去重核心)
102
+ # ----------------------------
103
+ TOTAL=$(echo "$STREAM" | wc -l)
104
+
105
+ if [ "$TOTAL" -gt "$LAST_LINES" ]; then
106
+ NEW_LINES=$(($TOTAL - $LAST_LINES))
107
+ echo "$STREAM" | tail -n $NEW_LINES
108
+ LAST_LINES=$TOTAL
109
+ fi
110
+
111
+ sleep 0.2
112
+ done
@@ -0,0 +1,62 @@
1
+ #!/bin/bash
2
+
3
+ SOCKET="/tmp/tmux-agent.sock"
4
+ SESSION="agent"
5
+
6
+ # shift
7
+ ROLES=("$@")
8
+
9
+ tmux -S $SOCKET set-option -g pane-border-status top
10
+ tmux -S $SOCKET set-option -g pane-border-format "#{pane_index} | #{pane_title}"
11
+
12
+ MAP_FILE="/tmp/tmux-agent.map"
13
+ > $MAP_FILE # 清空
14
+
15
+ PANES=($(tmux -S $SOCKET list-panes -t $SESSION -F "#{pane_id}"))
16
+
17
+ # ----------------------------
18
+ # 1️⃣ 固定主 pane(pane[0])
19
+ # ----------------------------
20
+ MAIN_PANE=${PANES[0]}
21
+ tmux -S $SOCKET select-pane -t "$MAIN_PANE" -T "main"
22
+
23
+ echo "main $MAIN_PANE" >> $MAP_FILE
24
+
25
+ # ----------------------------
26
+ # 2️⃣ 从 pane[1] 开始分配 agent
27
+ # ----------------------------
28
+ for i in "${!ROLES[@]}"; do
29
+ PANE_INDEX=$((i + 1)) # ⭐ 关键:跳过 main
30
+
31
+ PANE=${PANES[$PANE_INDEX]}
32
+ ROLE=${ROLES[$i]}
33
+
34
+ if [ -z "$PANE" ]; then
35
+ break
36
+ fi
37
+
38
+ # 设置 UI 标题
39
+ tmux -S $SOCKET select-pane -t "$PANE" -T "$ROLE"
40
+
41
+ # 写入映射
42
+ echo "$ROLE $PANE" >> $MAP_FILE
43
+ done
44
+
45
+ # ----------------------------
46
+ # 3️⃣ 多余 pane → worker
47
+ # ----------------------------
48
+ TOTAL_PANES=${#PANES[@]}
49
+ USED_PANES=$(( ${#ROLES[@]} + 1 ))
50
+
51
+ for ((i=USED_PANES; i<TOTAL_PANES; i++)); do
52
+ PANE=${PANES[$i]}
53
+ ROLE="worker-$i"
54
+
55
+ tmux -S $SOCKET select-pane -t "$PANE" -T "$ROLE"
56
+ done
57
+
58
+ # # ✅ 多余 pane 清空
59
+ # for ((i=USED_PANES; i<TOTAL_PANES; i++)); do
60
+ # PANE=${PANES[$i]}
61
+ # tmux -S $SOCKET select-pane -t "$PANE" -T ""
62
+ # done
@@ -0,0 +1,181 @@
1
+ #!/bin/bash
2
+
3
+ SOCKET="/tmp/tmux-agent.sock"
4
+ SESSION="agent"
5
+ STATE_FILE="/tmp/tmux-agent.state"
6
+
7
+ MAX_VISIBLE=4
8
+
9
+ # ----------------------------
10
+ # 初始化
11
+ # ----------------------------
12
+ init() {
13
+ tmux -S $SOCKET kill-server 2>/dev/null || true
14
+ tmux -S $SOCKET new-session -d -s $SESSION -n main
15
+
16
+ tmux -S $SOCKET split-window -h -p 30 -t $SESSION
17
+
18
+ tmux -S $SOCKET select-layout -t $SESSION main-vertical
19
+
20
+ echo "OFFSET=0" > $STATE_FILE
21
+ }
22
+
23
+ # ----------------------------
24
+ # scale(创建所有 agent)
25
+ # ----------------------------
26
+ scale() {
27
+ shift
28
+ ROLES=("$@")
29
+
30
+ # 保存 roles
31
+ echo "ROLES=\"${ROLES[*]}\"" >> $STATE_FILE
32
+
33
+ TOTAL=${#ROLES[@]}
34
+ CURRENT=$(tmux -S $SOCKET list-panes -t $SESSION | wc -l)
35
+
36
+ # TARGET=$((TOTAL + 1))
37
+ VISIBLE=$TOTAL
38
+ [ "$VISIBLE" -gt "$MAX_VISIBLE" ] && VISIBLE=$MAX_VISIBLE
39
+
40
+ TARGET=$((VISIBLE + 1))
41
+
42
+ while [ "$CURRENT" -lt "$TARGET" ]; do
43
+ tmux -S $SOCKET split-window -t $SESSION -d
44
+ ((CURRENT++))
45
+ done
46
+
47
+ while [ "$CURRENT" -gt "$TARGET" ]; do
48
+ tmux -S $SOCKET kill-pane -t $SESSION:.-
49
+ ((CURRENT--))
50
+ done
51
+
52
+ # while [ "$CURRENT" -gt "$TARGET" ]; do
53
+ # LAST_PANE=$(tmux -S $SOCKET list-panes -t $SESSION -F "#{pane_id}" | tail -n1)
54
+ # tmux -S $SOCKET kill-pane -t "$LAST_PANE"
55
+ # ((CURRENT--))
56
+ # done
57
+
58
+ tmux -S $SOCKET select-layout -t $SESSION main-vertical
59
+
60
+ render
61
+ }
62
+
63
+ # ----------------------------
64
+ # 渲染当前窗口(最多显示4个)
65
+ # ----------------------------
66
+ render() {
67
+ source $STATE_FILE
68
+
69
+ IFS=' ' read -r -a ROLES <<< "$ROLES"
70
+
71
+ PANES=($(tmux -S $SOCKET list-panes -t $SESSION -F "#{pane_id}"))
72
+
73
+ TOTAL_PANES=${#PANES[@]}
74
+ if [ "$TOTAL_PANES" -lt "$MAX_VISIBLE" ]; then
75
+ VISIBLE=$TOTAL_PANES
76
+ else
77
+ VISIBLE=$MAX_VISIBLE
78
+ fi
79
+
80
+
81
+ # pane[0] 是 main
82
+ for ((i=1; i<=VISIBLE; i++)); do
83
+ IDX=$((OFFSET + i - 1))
84
+ ROLE=${ROLES[$IDX]}
85
+
86
+ if [ -z "$ROLE" ]; then
87
+ ROLE="empty"
88
+ fi
89
+
90
+ PANE=${PANES[$i]}
91
+
92
+ tmux -S $SOCKET select-pane -t $PANE -T "$ROLE"
93
+ done
94
+ }
95
+
96
+ # render() {
97
+ # source $STATE_FILE
98
+
99
+ # IFS=' ' read -r -a ROLES <<< "$ROLES"
100
+
101
+ # PANES=($(tmux -S $SOCKET list-panes -t $SESSION -F "#{pane_id}"))
102
+
103
+ # TOTAL_ROLES=${#ROLES[@]}
104
+ # TOTAL_PANES=${#PANES[@]}
105
+
106
+ # # pane[0] 是 main
107
+ # AVAILABLE_PANES=$((TOTAL_PANES - 1))
108
+
109
+ # # 剩余 roles(考虑 OFFSET)
110
+ # REMAINING=$((TOTAL_ROLES - OFFSET))
111
+
112
+ # # 实际要显示的数量
113
+ # VISIBLE=$MAX_VISIBLE
114
+
115
+ # [ "$VISIBLE" -gt "$AVAILABLE_PANES" ] && VISIBLE=$AVAILABLE_PANES
116
+ # [ "$VISIBLE" -gt "$REMAINING" ] && VISIBLE=$REMAINING
117
+
118
+ # # ----------------------------
119
+ # # 渲染有效 pane
120
+ # # ----------------------------
121
+ # for ((i=1; i<=VISIBLE; i++)); do
122
+ # IDX=$((OFFSET + i - 1))
123
+ # ROLE=${ROLES[$IDX]}
124
+
125
+ # PANE=${PANES[$i]}
126
+
127
+ # tmux -S $SOCKET select-pane -t $PANE -T "$ROLE"
128
+ # done
129
+
130
+ # # ----------------------------
131
+ # # 多余 pane 标记为空
132
+ # # ----------------------------
133
+ # for ((i=VISIBLE+1; i<=AVAILABLE_PANES; i++)); do
134
+ # PANE=${PANES[$i]}
135
+ # tmux -S $SOCKET select-pane -t $PANE -T "empty"
136
+ # done
137
+ # }
138
+
139
+ # ----------------------------
140
+ # 向下滚动
141
+ # ----------------------------
142
+ down() {
143
+ source $STATE_FILE
144
+
145
+ IFS=' ' read -r -a ROLES <<< "$ROLES"
146
+
147
+ TOTAL=${#ROLES[@]}
148
+
149
+ if [ $((OFFSET + MAX_VISIBLE)) -lt $TOTAL ]; then
150
+ OFFSET=$((OFFSET + 1))
151
+ fi
152
+
153
+ echo "OFFSET=$OFFSET" > $STATE_FILE
154
+ echo "ROLES=\"${ROLES[*]}\"" >> $STATE_FILE
155
+
156
+ render
157
+ }
158
+
159
+ # ----------------------------
160
+ # 向上滚动
161
+ # ----------------------------
162
+ up() {
163
+ source $STATE_FILE
164
+
165
+ if [ "$OFFSET" -gt 0 ]; then
166
+ OFFSET=$((OFFSET - 1))
167
+ fi
168
+
169
+ echo "OFFSET=$OFFSET" > $STATE_FILE
170
+ echo "ROLES=\"$ROLES\"" >> $STATE_FILE
171
+
172
+ render
173
+ }
174
+
175
+ case "$1" in
176
+ init) init ;;
177
+ scale) scale "$@" ;;
178
+ up) up ;;
179
+ down) down ;;
180
+ render) render ;;
181
+ esac
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env bash
2
+
3
+ SOCKET="/tmp/tmux-agent.sock"
4
+ SESSION="agent"
5
+ MAP_FILE="/tmp/tmux-agent.map"
6
+
7
+
8
+ ROLE=$1
9
+ TASK=$2
10
+
11
+ if [ -z "$ROLE" ] || [ -z "$TASK" ]; then
12
+ echo "Usage: $0 <role> <task>"
13
+ exit 1
14
+ fi
15
+
16
+ # ----------------------------
17
+ # 查找 pane(只取第一个)
18
+ # ----------------------------
19
+ # PANE=$(tmux -S $SOCKET list-panes -t $SESSION -F "#{pane_id} #{pane_title}" \
20
+ # | grep " $ROLE$" \
21
+ # | head -n1 \
22
+ # | awk '{print $1}')
23
+
24
+ PANE=$(grep "^$ROLE " $MAP_FILE | awk '{print $2}')
25
+
26
+
27
+ if [ -z "$PANE" ]; then
28
+ echo "Role not found: $ROLE"
29
+ exit 1
30
+ fi
31
+
32
+ # ----------------------------
33
+ # 发送任务
34
+ # ----------------------------
35
+ tmux -S $SOCKET send-keys -t "$PANE" "$TASK" C-m
36
+
37
+ sleep 1
38
+
39
+ # ----------------------------
40
+ # 捕获输出
41
+ # ----------------------------
42
+ tmux -S $SOCKET capture-pane -t "$PANE" -p
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env bash
2
+
3
+ SOCKET="/tmp/tmux-agent.sock"
4
+ SESSION="agent"
5
+ LOG_DIR="/tmp/tmux-agent-logs"
6
+
7
+ mkdir -p "$LOG_DIR"
8
+
9
+ tmux -S $SOCKET list-panes -t $SESSION -F "#{pane_id}" | while read pane; do
10
+
11
+ LOG_FILE="$LOG_DIR/${pane}.log"
12
+
13
+ # 清空旧日志
14
+ : > "$LOG_FILE"
15
+
16
+ # 绑定 pipe-pane(实时输出)
17
+ tmux -S $SOCKET pipe-pane -o -t "$pane" "cat >> $LOG_FILE"
18
+
19
+ done
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env bash
2
+
3
+ SOCKET="/tmp/tmux-agent.sock"
4
+ MAP_FILE="/tmp/tmux-agent.map"
5
+ LOG_DIR="/tmp/tmux-agent-logs"
6
+
7
+ ROLE=$1
8
+ TASK=$2
9
+
10
+ if [ -z "$ROLE" ] || [ -z "$TASK" ]; then
11
+ echo "Usage: $0 <role> <task>"
12
+ exit 1
13
+ fi
14
+
15
+ # ----------------------------
16
+ # 找 pane
17
+ # ----------------------------
18
+ PANE=$(grep "^$ROLE " "$MAP_FILE" | awk '{print $2}')
19
+
20
+ if [ -z "$PANE" ]; then
21
+ echo "Role not found: $ROLE"
22
+ exit 1
23
+ fi
24
+
25
+ LOG_FILE="$LOG_DIR/${PANE}.log"
26
+
27
+ # ----------------------------
28
+ # marker
29
+ # ----------------------------
30
+ TASK_ID=$(date +%s%N)
31
+ START="__START__${TASK_ID}"
32
+ END="__END__${TASK_ID}"
33
+
34
+ # 安全命令
35
+ SAFE_TASK=$(printf %q "$TASK")
36
+
37
+ CMD="echo $START; bash -c $SAFE_TASK; echo $END"
38
+
39
+ tmux -S $SOCKET send-keys -t "$PANE" "$CMD" C-m
40
+
41
+ # ----------------------------
42
+ # 真流式读取
43
+ # ----------------------------
44
+ STARTED=0
45
+
46
+ tail -n 0 -f "$LOG_FILE" | while read line; do
47
+
48
+ if [ $STARTED -eq 0 ]; then
49
+ [[ "$line" == *"$START"* ]] && STARTED=1
50
+ continue
51
+ fi
52
+
53
+ if [[ "$line" == *"$END"* ]]; then
54
+ break
55
+ fi
56
+
57
+ echo "$line"
58
+
59
+ done
@@ -0,0 +1,18 @@
1
+ #!/bin/bash
2
+
3
+ SOCKET="/tmp/tmux-agent.sock"
4
+
5
+ ROLES=("$@")
6
+
7
+ # echo "ROLES: ${ROLES[@]}"
8
+
9
+ if [ ${#ROLES[@]} -eq 0 ]; then
10
+ echo "Usage: $0 brain coder tester ..."
11
+ exit 1
12
+ fi
13
+
14
+ ./layout.sh init
15
+ ./layout.sh scale "${ROLES[@]}"
16
+ ./label.sh "${ROLES[@]}"
17
+
18
+ tmux -S $SOCKET attach -t agent
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env bash
2
+
3
+ SOCKET="/tmp/tmux-agent.sock"
4
+ LOG_DIR="/tmp/tmux-agent-logs"
5
+ MAP_FILE="/tmp/tmux-agent.map"
6
+
7
+ # ----------------------------
8
+ # 关闭 tmux server
9
+ # ----------------------------
10
+ tmux -S $SOCKET kill-server 2>/dev/null || true
11
+
12
+ # ----------------------------
13
+ # 清理日志
14
+ # ----------------------------
15
+ if [ -d "$LOG_DIR" ]; then
16
+ rm -rf "$LOG_DIR"
17
+ fi
18
+
19
+ # ----------------------------
20
+ # 清理 pane 映射
21
+ # ----------------------------
22
+ if [ -f "$MAP_FILE" ]; then
23
+ rm -f "$MAP_FILE"
24
+ fi
25
+
26
+ echo "✅ tmux 已关闭 + 日志已清理"
@@ -0,0 +1,43 @@
1
+ #!/bin/bash
2
+ set -e
3
+
4
+ SOCKET="/tmp/tmux-demo.sock"
5
+ SESSION="demo"
6
+ WORKERS=4
7
+
8
+ # ========= 1. 清理 =========
9
+ tmux -S $SOCKET kill-server 2>/dev/null || true
10
+
11
+ # ========= 2. 创建主会话 =========
12
+ tmux -S $SOCKET new-session -d -s $SESSION -n main
13
+
14
+ # ========= 3. 左右分割(主结构) =========
15
+ RIGHT=$(tmux -S $SOCKET split-window -h -p 30 -t $SESSION -d -P -F "#{pane_id}")
16
+
17
+ # ========= 4. 在右侧创建纵向 worker =========
18
+ tmux -S $SOCKET select-pane -t $RIGHT
19
+
20
+ for ((i=1; i<WORKERS; i++)); do
21
+ tmux -S $SOCKET split-window -v -d
22
+ done
23
+
24
+ # ========= 5. 使用 main-vertical(核心!!!) =========
25
+ tmux -S $SOCKET select-layout -t $SESSION main-vertical
26
+
27
+ # ========= 6. 设置 pane label =========
28
+ tmux -S $SOCKET set-option -g pane-border-status top
29
+ tmux -S $SOCKET set-option -g pane-border-format "#{pane_index} | #{pane_title}"
30
+
31
+ # ========= 7. 命名 =========
32
+ INDEX=0
33
+ for pane in $(tmux -S $SOCKET list-panes -t $SESSION -F "#{pane_id}"); do
34
+ if [ "$INDEX" -eq 0 ]; then
35
+ tmux -S $SOCKET select-pane -t $pane -T "main"
36
+ else
37
+ tmux -S $SOCKET select-pane -t $pane -T "agent-$INDEX"
38
+ fi
39
+ ((INDEX++))
40
+ done
41
+
42
+ # ========= 8. 进入 =========
43
+ tmux -S $SOCKET attach -t $SESSION