triflux 3.3.0-dev.1 → 3.3.0-dev.3
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/bin/triflux.mjs +169 -39
- package/hooks/hooks.json +5 -0
- package/hub/pipe.mjs +23 -0
- package/hub/router.mjs +322 -1
- package/hub/schema.sql +40 -7
- package/hub/server.mjs +95 -0
- package/hub/store.mjs +259 -1
- package/hub/team/native.mjs +200 -190
- package/hub/team/psmux.mjs +555 -115
- package/hub/tools.mjs +101 -26
- package/hub/workers/delegator-mcp.mjs +900 -0
- package/hub/workers/factory.mjs +3 -0
- package/hub/workers/interface.mjs +2 -2
- package/hud/hud-qos-status.mjs +1735 -1790
- package/package.json +1 -1
- package/scripts/__tests__/keyword-detector.test.mjs +3 -3
- package/scripts/__tests__/smoke.test.mjs +34 -0
- package/scripts/hub-ensure.mjs +21 -3
- package/scripts/setup.mjs +15 -10
package/hub/team/native.mjs
CHANGED
|
@@ -1,190 +1,200 @@
|
|
|
1
|
-
// hub/team/native.mjs — Claude Native Teams 래퍼
|
|
2
|
-
// teammate 프롬프트 템플릿 + 팀 설정 빌더
|
|
3
|
-
//
|
|
4
|
-
// Claude Code 네이티브 Agent Teams (CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1)
|
|
5
|
-
// 환경에서 teammate를 Codex/Gemini CLI 래퍼로 구성하는 유틸리티.
|
|
6
|
-
// SKILL.md가 인라인 프롬프트를 사용하므로, 이 모듈은 CLI(tfx multi --native)에서
|
|
7
|
-
// 팀 설정을 프로그래밍적으로 생성할 때 사용한다.
|
|
8
|
-
|
|
9
|
-
const ROUTE_SCRIPT = "~/.claude/scripts/tfx-route.sh";
|
|
10
|
-
|
|
11
|
-
function inferWorkerIndex(agentName = "") {
|
|
12
|
-
const match = /(\d+)(?!.*\d)/.exec(agentName);
|
|
13
|
-
if (!match) return null;
|
|
14
|
-
const index = Number(match[1]);
|
|
15
|
-
return Number.isInteger(index) && index > 0 ? index : null;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function buildRouteEnvPrefix(agentName, workerIndex, searchTool) {
|
|
19
|
-
const effectiveWorkerIndex = Number.isInteger(workerIndex) && workerIndex > 0
|
|
20
|
-
? workerIndex
|
|
21
|
-
: inferWorkerIndex(agentName);
|
|
22
|
-
|
|
23
|
-
let envPrefix = "";
|
|
24
|
-
if (effectiveWorkerIndex) envPrefix += ` TFX_WORKER_INDEX="${effectiveWorkerIndex}"`;
|
|
25
|
-
if (searchTool) envPrefix += ` TFX_SEARCH_TOOL="${searchTool}"`;
|
|
26
|
-
return envPrefix;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* role/mcp_profile별 tfx-route.sh 기본 timeout (초)
|
|
31
|
-
* analyze/review 프로필이나 설계·분석 역할은 더 긴 timeout을 부여한다.
|
|
32
|
-
* @param {string} role — 워커 역할
|
|
33
|
-
* @param {string} mcpProfile — MCP 프로필
|
|
34
|
-
* @returns {number} timeout(초)
|
|
35
|
-
*/
|
|
36
|
-
function getRouteTimeout(role, mcpProfile) {
|
|
37
|
-
if (mcpProfile === "analyze" || mcpProfile === "review") return 3600;
|
|
38
|
-
if (role === "architect" || role === "analyst") return 3600;
|
|
39
|
-
return 1080; // 기본 18분
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* v2.2 슬림 래퍼 프롬프트 생성
|
|
44
|
-
* Agent spawn으로 네비게이션에 등록하되, 실제 작업은 tfx-route.sh가 수행.
|
|
45
|
-
* 프롬프트 ~100 토큰 목표 (v2의 ~500 대비 80% 감소).
|
|
46
|
-
*
|
|
47
|
-
* @param {'codex'|'gemini'} cli — CLI 타입
|
|
48
|
-
* @param {object} opts
|
|
49
|
-
* @param {string} opts.subtask — 서브태스크 설명
|
|
50
|
-
* @param {string} [opts.role] — 역할 (executor, designer, reviewer 등)
|
|
51
|
-
* @param {string} [opts.teamName] — 팀 이름
|
|
52
|
-
* @param {string} [opts.taskId] — Hub task ID
|
|
53
|
-
* @param {string} [opts.agentName] — 워커 표시 이름
|
|
54
|
-
* @param {string} [opts.leadName] — 리드 수신자 이름
|
|
55
|
-
* @param {string} [opts.mcp_profile] — MCP 프로필
|
|
56
|
-
* @param {number} [opts.workerIndex] — 검색 힌트 회전에 사용할 워커 인덱스(1-based)
|
|
57
|
-
* @param {string} [opts.searchTool] — 전용 검색 도구 힌트(brave-search|tavily|exa)
|
|
58
|
-
* @param {number} [opts.bashTimeout] — Bash timeout(ms). 미지정 시 role/profile 기반 자동 산출.
|
|
59
|
-
* @returns {string} 슬림 래퍼 프롬프트
|
|
60
|
-
*/
|
|
61
|
-
export function buildSlimWrapperPrompt(cli, opts = {}) {
|
|
62
|
-
const {
|
|
63
|
-
subtask,
|
|
64
|
-
role = "executor",
|
|
65
|
-
teamName = "tfx-multi",
|
|
66
|
-
taskId = "",
|
|
67
|
-
agentName = "",
|
|
68
|
-
leadName = "team-lead",
|
|
69
|
-
mcp_profile = "auto",
|
|
70
|
-
workerIndex,
|
|
71
|
-
searchTool = "",
|
|
72
|
-
pipelinePhase = "",
|
|
73
|
-
bashTimeout,
|
|
74
|
-
} = opts;
|
|
75
|
-
|
|
76
|
-
// role/profile 기반 timeout 산출 (기본 timeout + 60초 여유, ms 변환)
|
|
77
|
-
const bashTimeoutMs = bashTimeout ?? (getRouteTimeout(role, mcp_profile) + 60) * 1000;
|
|
78
|
-
|
|
79
|
-
// 셸 이스케이프
|
|
80
|
-
const escaped = subtask.replace(/'/g, "'\\''");
|
|
81
|
-
const pipelineHint = pipelinePhase
|
|
82
|
-
? `\n파이프라인 단계: ${pipelinePhase}`
|
|
83
|
-
: '';
|
|
84
|
-
const routeEnvPrefix = buildRouteEnvPrefix(agentName, workerIndex, searchTool);
|
|
85
|
-
|
|
86
|
-
const taskIdRef = taskId ? `taskId: "${taskId}"` : "";
|
|
87
|
-
|
|
88
|
-
return `인터럽트 프로토콜:
|
|
89
|
-
1. TaskUpdate(${taskIdRef ? `${taskIdRef}, ` : ""}status: in_progress) — task claim
|
|
90
|
-
2. SendMessage(to: ${leadName}, "작업 시작: ${agentName}") — 시작 보고 (턴 경계 생성)
|
|
91
|
-
3. Bash(command, timeout: ${bashTimeoutMs}) — 아래 명령 1회 실행
|
|
92
|
-
4. 결과 보고 후 반드시 종료${pipelineHint}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
* @param {
|
|
117
|
-
* @param {
|
|
118
|
-
* @param {string}
|
|
119
|
-
* @param {string} [opts.
|
|
120
|
-
* @param {
|
|
121
|
-
* @param {string} [opts.
|
|
122
|
-
* @param {string} [opts.
|
|
123
|
-
* @param {string} [opts.
|
|
124
|
-
* @param {string} [opts.
|
|
125
|
-
* @
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
Bash: node ${psmuxPath}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
Bash: node ${psmuxPath}
|
|
170
|
-
→
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
}
|
|
1
|
+
// hub/team/native.mjs — Claude Native Teams 래퍼
|
|
2
|
+
// teammate 프롬프트 템플릿 + 팀 설정 빌더
|
|
3
|
+
//
|
|
4
|
+
// Claude Code 네이티브 Agent Teams (CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1)
|
|
5
|
+
// 환경에서 teammate를 Codex/Gemini CLI 래퍼로 구성하는 유틸리티.
|
|
6
|
+
// SKILL.md가 인라인 프롬프트를 사용하므로, 이 모듈은 CLI(tfx multi --native)에서
|
|
7
|
+
// 팀 설정을 프로그래밍적으로 생성할 때 사용한다.
|
|
8
|
+
|
|
9
|
+
const ROUTE_SCRIPT = "~/.claude/scripts/tfx-route.sh";
|
|
10
|
+
|
|
11
|
+
function inferWorkerIndex(agentName = "") {
|
|
12
|
+
const match = /(\d+)(?!.*\d)/.exec(agentName);
|
|
13
|
+
if (!match) return null;
|
|
14
|
+
const index = Number(match[1]);
|
|
15
|
+
return Number.isInteger(index) && index > 0 ? index : null;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function buildRouteEnvPrefix(agentName, workerIndex, searchTool) {
|
|
19
|
+
const effectiveWorkerIndex = Number.isInteger(workerIndex) && workerIndex > 0
|
|
20
|
+
? workerIndex
|
|
21
|
+
: inferWorkerIndex(agentName);
|
|
22
|
+
|
|
23
|
+
let envPrefix = "";
|
|
24
|
+
if (effectiveWorkerIndex) envPrefix += ` TFX_WORKER_INDEX="${effectiveWorkerIndex}"`;
|
|
25
|
+
if (searchTool) envPrefix += ` TFX_SEARCH_TOOL="${searchTool}"`;
|
|
26
|
+
return envPrefix;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* role/mcp_profile별 tfx-route.sh 기본 timeout (초)
|
|
31
|
+
* analyze/review 프로필이나 설계·분석 역할은 더 긴 timeout을 부여한다.
|
|
32
|
+
* @param {string} role — 워커 역할
|
|
33
|
+
* @param {string} mcpProfile — MCP 프로필
|
|
34
|
+
* @returns {number} timeout(초)
|
|
35
|
+
*/
|
|
36
|
+
function getRouteTimeout(role, mcpProfile) {
|
|
37
|
+
if (mcpProfile === "analyze" || mcpProfile === "review") return 3600;
|
|
38
|
+
if (role === "architect" || role === "analyst") return 3600;
|
|
39
|
+
return 1080; // 기본 18분
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* v2.2 슬림 래퍼 프롬프트 생성
|
|
44
|
+
* Agent spawn으로 네비게이션에 등록하되, 실제 작업은 tfx-route.sh가 수행.
|
|
45
|
+
* 프롬프트 ~100 토큰 목표 (v2의 ~500 대비 80% 감소).
|
|
46
|
+
*
|
|
47
|
+
* @param {'codex'|'gemini'} cli — CLI 타입
|
|
48
|
+
* @param {object} opts
|
|
49
|
+
* @param {string} opts.subtask — 서브태스크 설명
|
|
50
|
+
* @param {string} [opts.role] — 역할 (executor, designer, reviewer 등)
|
|
51
|
+
* @param {string} [opts.teamName] — 팀 이름
|
|
52
|
+
* @param {string} [opts.taskId] — Hub task ID
|
|
53
|
+
* @param {string} [opts.agentName] — 워커 표시 이름
|
|
54
|
+
* @param {string} [opts.leadName] — 리드 수신자 이름
|
|
55
|
+
* @param {string} [opts.mcp_profile] — MCP 프로필
|
|
56
|
+
* @param {number} [opts.workerIndex] — 검색 힌트 회전에 사용할 워커 인덱스(1-based)
|
|
57
|
+
* @param {string} [opts.searchTool] — 전용 검색 도구 힌트(brave-search|tavily|exa)
|
|
58
|
+
* @param {number} [opts.bashTimeout] — Bash timeout(ms). 미지정 시 role/profile 기반 자동 산출.
|
|
59
|
+
* @returns {string} 슬림 래퍼 프롬프트
|
|
60
|
+
*/
|
|
61
|
+
export function buildSlimWrapperPrompt(cli, opts = {}) {
|
|
62
|
+
const {
|
|
63
|
+
subtask,
|
|
64
|
+
role = "executor",
|
|
65
|
+
teamName = "tfx-multi",
|
|
66
|
+
taskId = "",
|
|
67
|
+
agentName = "",
|
|
68
|
+
leadName = "team-lead",
|
|
69
|
+
mcp_profile = "auto",
|
|
70
|
+
workerIndex,
|
|
71
|
+
searchTool = "",
|
|
72
|
+
pipelinePhase = "",
|
|
73
|
+
bashTimeout,
|
|
74
|
+
} = opts;
|
|
75
|
+
|
|
76
|
+
// role/profile 기반 timeout 산출 (기본 timeout + 60초 여유, ms 변환)
|
|
77
|
+
const bashTimeoutMs = bashTimeout ?? (getRouteTimeout(role, mcp_profile) + 60) * 1000;
|
|
78
|
+
|
|
79
|
+
// 셸 이스케이프
|
|
80
|
+
const escaped = subtask.replace(/'/g, "'\\''");
|
|
81
|
+
const pipelineHint = pipelinePhase
|
|
82
|
+
? `\n파이프라인 단계: ${pipelinePhase}`
|
|
83
|
+
: '';
|
|
84
|
+
const routeEnvPrefix = buildRouteEnvPrefix(agentName, workerIndex, searchTool);
|
|
85
|
+
|
|
86
|
+
const taskIdRef = taskId ? `taskId: "${taskId}"` : "";
|
|
87
|
+
|
|
88
|
+
return `인터럽트 프로토콜:
|
|
89
|
+
1. TaskUpdate(${taskIdRef ? `${taskIdRef}, ` : ""}status: in_progress) — task claim
|
|
90
|
+
2. SendMessage(to: ${leadName}, "작업 시작: ${agentName}") — 시작 보고 (턴 경계 생성)
|
|
91
|
+
3. Bash(command, timeout: ${bashTimeoutMs}) — 아래 명령 1회 실행
|
|
92
|
+
4. 결과 보고 후 반드시 종료${pipelineHint}
|
|
93
|
+
|
|
94
|
+
[HARD CONSTRAINT] 너는 Bash, TaskUpdate, TaskGet, TaskList, SendMessage만 사용할 수 있다.
|
|
95
|
+
Read, Edit, Write, Grep, Glob, Agent, WebSearch, WebFetch 등 다른 모든 도구 사용을 금지한다.
|
|
96
|
+
코드를 직접 읽거나 수정하면 안 된다. 반드시 아래 Bash 명령(tfx-route.sh)을 통해 Codex/Gemini에 위임하라.
|
|
97
|
+
이 규칙을 위반하면 작업 실패로 간주한다.
|
|
98
|
+
|
|
99
|
+
gemini/codex를 직접 호출하지 마라. 반드시 tfx-route.sh를 거쳐야 한다.
|
|
100
|
+
프롬프트를 파일로 저장하지 마라. tfx-route.sh가 인자로 받는다.
|
|
101
|
+
|
|
102
|
+
Bash(command: 'TFX_TEAM_NAME="${teamName}" TFX_TEAM_TASK_ID="${taskId}" TFX_TEAM_AGENT_NAME="${agentName}" TFX_TEAM_LEAD_NAME="${leadName}"${routeEnvPrefix} bash ${ROUTE_SCRIPT} "${role}" '"'"'${escaped}'"'"' ${mcp_profile}', timeout: ${bashTimeoutMs})
|
|
103
|
+
|
|
104
|
+
성공 → TaskUpdate(${taskIdRef ? `${taskIdRef}, ` : ""}status: completed, metadata: {result: "success"}) + SendMessage(to: ${leadName}).
|
|
105
|
+
실패 → TaskUpdate(${taskIdRef ? `${taskIdRef}, ` : ""}status: completed, metadata: {result: "failed", error: "에러 요약"}) + SendMessage(to: ${leadName}).
|
|
106
|
+
|
|
107
|
+
중요: TaskUpdate의 status는 "completed"만 사용. "failed"는 API 미지원.
|
|
108
|
+
실패 여부는 metadata.result로 구분. Bash 실패 시에도 반드시 TaskUpdate + SendMessage 후 종료.`;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* v3 하이브리드 래퍼 프롬프트 생성
|
|
113
|
+
* psmux pane 기반 비동기 실행 + polling 패턴.
|
|
114
|
+
* Agent가 idle 상태를 유지하여 인터럽트 수신이 가능하다.
|
|
115
|
+
*
|
|
116
|
+
* @param {'codex'|'gemini'} cli — CLI 타입
|
|
117
|
+
* @param {object} opts
|
|
118
|
+
* @param {string} opts.subtask — 서브태스크 설명
|
|
119
|
+
* @param {string} [opts.role] — 역할
|
|
120
|
+
* @param {string} [opts.teamName] — 팀 이름
|
|
121
|
+
* @param {string} [opts.taskId] — Hub task ID
|
|
122
|
+
* @param {string} [opts.agentName] — 워커 표시 이름
|
|
123
|
+
* @param {string} [opts.leadName] — 리드 수신자 이름
|
|
124
|
+
* @param {string} [opts.mcp_profile] — MCP 프로필
|
|
125
|
+
* @param {number} [opts.workerIndex] — 검색 힌트 회전에 사용할 워커 인덱스(1-based)
|
|
126
|
+
* @param {string} [opts.searchTool] — 전용 검색 도구 힌트(brave-search|tavily|exa)
|
|
127
|
+
* @param {string} [opts.sessionName] — psmux 세션 이름
|
|
128
|
+
* @param {string} [opts.pipelinePhase] — 파이프라인 단계
|
|
129
|
+
* @param {string} [opts.psmuxPath] — psmux.mjs 경로
|
|
130
|
+
* @returns {string} 하이브리드 래퍼 프롬프트
|
|
131
|
+
*/
|
|
132
|
+
export function buildHybridWrapperPrompt(cli, opts = {}) {
|
|
133
|
+
const {
|
|
134
|
+
subtask,
|
|
135
|
+
role = "executor",
|
|
136
|
+
teamName = "tfx-multi",
|
|
137
|
+
taskId = "",
|
|
138
|
+
agentName = "",
|
|
139
|
+
leadName = "team-lead",
|
|
140
|
+
mcp_profile = "auto",
|
|
141
|
+
workerIndex,
|
|
142
|
+
searchTool = "",
|
|
143
|
+
sessionName = teamName,
|
|
144
|
+
pipelinePhase = "",
|
|
145
|
+
psmuxPath = "hub/team/psmux.mjs",
|
|
146
|
+
} = opts;
|
|
147
|
+
|
|
148
|
+
const escaped = subtask.replace(/'/g, "'\\''");
|
|
149
|
+
const pipelineHint = pipelinePhase ? `\n파이프라인 단계: ${pipelinePhase}` : "";
|
|
150
|
+
const taskIdRef = taskId ? `taskId: "${taskId}"` : "";
|
|
151
|
+
const taskIdArg = taskIdRef ? `${taskIdRef}, ` : "";
|
|
152
|
+
const routeEnvPrefix = buildRouteEnvPrefix(agentName, workerIndex, searchTool);
|
|
153
|
+
|
|
154
|
+
const routeCmd = `TFX_TEAM_NAME="${teamName}" TFX_TEAM_TASK_ID="${taskId}" TFX_TEAM_AGENT_NAME="${agentName}" TFX_TEAM_LEAD_NAME="${leadName}"${routeEnvPrefix} bash ${ROUTE_SCRIPT} "${role}" '${escaped}' ${mcp_profile}`;
|
|
155
|
+
|
|
156
|
+
return `하이브리드 psmux 워커 프로토콜:
|
|
157
|
+
|
|
158
|
+
1. TaskUpdate(${taskIdArg}status: in_progress) + SendMessage(to: ${leadName}, "작업 시작: ${agentName}")
|
|
159
|
+
|
|
160
|
+
2. pane 생성 (비동기 실행):
|
|
161
|
+
Bash: node ${psmuxPath} spawn --session "${sessionName}" --name "${agentName}" --cmd "${routeCmd}"
|
|
162
|
+
|
|
163
|
+
3. 폴링 루프 (10초 간격, idle 유지 → 인터럽트 수신 가능):
|
|
164
|
+
Bash: node ${psmuxPath} status --session "${sessionName}" --name "${agentName}"
|
|
165
|
+
- status: "running" → 10초 대기 후 재확인
|
|
166
|
+
- status: "exited" → 5단계로
|
|
167
|
+
|
|
168
|
+
4. 인터럽트 수신 시:
|
|
169
|
+
Bash: node ${psmuxPath} kill --session "${sessionName}" --name "${agentName}"
|
|
170
|
+
→ SendMessage(to: ${leadName}, "인터럽트 수신, 방향 전환")
|
|
171
|
+
→ 새 지시에 따라 2단계부터 재실행
|
|
172
|
+
|
|
173
|
+
5. 완료 시:
|
|
174
|
+
Bash: node ${psmuxPath} output --session "${sessionName}" --name "${agentName}" --lines 100
|
|
175
|
+
→ 결과를 TaskUpdate + SendMessage로 보고
|
|
176
|
+
${pipelineHint}
|
|
177
|
+
[HARD CONSTRAINT] 너는 Bash, TaskUpdate, TaskGet, TaskList, SendMessage만 사용할 수 있다.
|
|
178
|
+
Read, Edit, Write, Grep, Glob, Agent, WebSearch, WebFetch 등 다른 모든 도구 사용을 금지한다.
|
|
179
|
+
코드를 직접 읽거나 수정하면 안 된다. 반드시 아래 Bash 명령(tfx-route.sh)을 통해 Codex/Gemini에 위임하라.
|
|
180
|
+
이 규칙을 위반하면 작업 실패로 간주한다.
|
|
181
|
+
|
|
182
|
+
gemini/codex를 직접 호출하지 마라. psmux spawn이 tfx-route.sh를 통해 실행한다.
|
|
183
|
+
프롬프트를 파일로 저장하지 마라. psmux spawn --cmd 인자로 전달된다.
|
|
184
|
+
|
|
185
|
+
성공 → TaskUpdate(${taskIdArg}status: completed, metadata: {result: "success"}) + SendMessage(to: ${leadName}).
|
|
186
|
+
실패 → TaskUpdate(${taskIdArg}status: completed, metadata: {result: "failed", error: "에러 요약"}) + SendMessage(to: ${leadName}).
|
|
187
|
+
|
|
188
|
+
중요: TaskUpdate의 status는 "completed"만 사용. "failed"는 API 미지원.
|
|
189
|
+
실패 여부는 metadata.result로 구분. pane 실패 시에도 반드시 TaskUpdate + SendMessage 후 종료.`;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* 팀 이름 생성 (타임스탬프 기반)
|
|
194
|
+
* @returns {string}
|
|
195
|
+
*/
|
|
196
|
+
export function generateTeamName() {
|
|
197
|
+
const ts = Date.now().toString(36).slice(-4);
|
|
198
|
+
const rand = Math.random().toString(36).slice(2, 6);
|
|
199
|
+
return `tfx-${ts}${rand}`;
|
|
200
|
+
}
|