@triflux/remote 10.0.0-alpha.1
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/hub/pipe.mjs +579 -0
- package/hub/public/dashboard.html +355 -0
- package/hub/public/tray-icon.ico +0 -0
- package/hub/public/tray-icon.png +0 -0
- package/hub/server.mjs +1124 -0
- package/hub/store-adapter.mjs +851 -0
- package/hub/store.mjs +897 -0
- package/hub/team/agent-map.json +11 -0
- package/hub/team/ansi.mjs +379 -0
- package/hub/team/backend.mjs +90 -0
- package/hub/team/cli/commands/attach.mjs +37 -0
- package/hub/team/cli/commands/control.mjs +43 -0
- package/hub/team/cli/commands/debug.mjs +74 -0
- package/hub/team/cli/commands/focus.mjs +53 -0
- package/hub/team/cli/commands/interrupt.mjs +36 -0
- package/hub/team/cli/commands/kill.mjs +37 -0
- package/hub/team/cli/commands/list.mjs +24 -0
- package/hub/team/cli/commands/send.mjs +37 -0
- package/hub/team/cli/commands/start/index.mjs +106 -0
- package/hub/team/cli/commands/start/parse-args.mjs +130 -0
- package/hub/team/cli/commands/start/start-headless.mjs +109 -0
- package/hub/team/cli/commands/start/start-in-process.mjs +40 -0
- package/hub/team/cli/commands/start/start-mux.mjs +73 -0
- package/hub/team/cli/commands/start/start-wt.mjs +69 -0
- package/hub/team/cli/commands/status.mjs +87 -0
- package/hub/team/cli/commands/stop.mjs +31 -0
- package/hub/team/cli/commands/task.mjs +30 -0
- package/hub/team/cli/commands/tasks.mjs +13 -0
- package/hub/team/cli/help.mjs +42 -0
- package/hub/team/cli/index.mjs +41 -0
- package/hub/team/cli/manifest.mjs +29 -0
- package/hub/team/cli/render.mjs +30 -0
- package/hub/team/cli/services/attach-fallback.mjs +54 -0
- package/hub/team/cli/services/hub-client.mjs +208 -0
- package/hub/team/cli/services/member-selector.mjs +30 -0
- package/hub/team/cli/services/native-control.mjs +117 -0
- package/hub/team/cli/services/runtime-mode.mjs +62 -0
- package/hub/team/cli/services/state-store.mjs +48 -0
- package/hub/team/cli/services/task-model.mjs +30 -0
- package/hub/team/dashboard-anchor.mjs +14 -0
- package/hub/team/dashboard-layout.mjs +33 -0
- package/hub/team/dashboard-open.mjs +153 -0
- package/hub/team/dashboard.mjs +274 -0
- package/hub/team/handoff.mjs +303 -0
- package/hub/team/headless.mjs +1149 -0
- package/hub/team/native-supervisor.mjs +392 -0
- package/hub/team/native.mjs +649 -0
- package/hub/team/nativeProxy.mjs +681 -0
- package/hub/team/orchestrator.mjs +161 -0
- package/hub/team/pane.mjs +153 -0
- package/hub/team/psmux.mjs +1354 -0
- package/hub/team/routing.mjs +223 -0
- package/hub/team/session.mjs +611 -0
- package/hub/team/shared.mjs +13 -0
- package/hub/team/staleState.mjs +361 -0
- package/hub/team/tui-lite.mjs +380 -0
- package/hub/team/tui-viewer.mjs +463 -0
- package/hub/team/tui.mjs +1245 -0
- package/hub/tools.mjs +554 -0
- package/hub/tray.mjs +376 -0
- package/hub/workers/claude-worker.mjs +475 -0
- package/hub/workers/codex-mcp.mjs +504 -0
- package/hub/workers/delegator-mcp.mjs +1076 -0
- package/hub/workers/factory.mjs +21 -0
- package/hub/workers/gemini-worker.mjs +373 -0
- package/hub/workers/interface.mjs +52 -0
- package/hub/workers/worker-utils.mjs +104 -0
- package/package.json +31 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 라우팅 결정 함수
|
|
3
|
+
* @param {object} opts
|
|
4
|
+
* @param {Array<{id:string, description?:string, agent?:string, depends_on?:string[], complexity?:string}>} opts.subtasks
|
|
5
|
+
* @param {string} opts.graph_type - "INDEPENDENT" | "SEQUENTIAL" | "DAG"
|
|
6
|
+
* @param {boolean} opts.thorough - thorough 모드 여부
|
|
7
|
+
* @returns {{
|
|
8
|
+
* strategy: "quick_single" | "thorough_single" | "quick_team" | "thorough_team" | "batch_single",
|
|
9
|
+
* reason: string,
|
|
10
|
+
* dag_width: number,
|
|
11
|
+
* max_complexity: string,
|
|
12
|
+
* dagContext: { dag_width: number, levels: Record<number, string[]>, edges: Array<{from:string, to:string}>, max_complexity: string, taskResults: Record<string, *> }
|
|
13
|
+
* }}
|
|
14
|
+
*/
|
|
15
|
+
export function resolveRoutingStrategy({ subtasks, graph_type, thorough }) {
|
|
16
|
+
const N = subtasks.length;
|
|
17
|
+
if (N === 0) {
|
|
18
|
+
const dagContext = { dag_width: 0, levels: {}, edges: [], max_complexity: 'S', taskResults: {} };
|
|
19
|
+
return { strategy: 'quick_single', reason: 'empty_subtasks', dag_width: 0, max_complexity: 'S', dagContext };
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const { width: dag_width, levels, edges } = computeDagInfo(subtasks, graph_type);
|
|
23
|
+
const max_complexity = getMaxComplexity(subtasks);
|
|
24
|
+
const dagContext = { dag_width, levels, edges, max_complexity, taskResults: {} };
|
|
25
|
+
const isHighComplexity = ['L', 'XL'].includes(max_complexity);
|
|
26
|
+
const allSameAgent = new Set(subtasks.map((s) => s.agent)).size === 1;
|
|
27
|
+
const allSmall = subtasks.every((s) => normalizeComplexity(s.complexity) === 'S');
|
|
28
|
+
|
|
29
|
+
// N==1: 단일 태스크
|
|
30
|
+
if (N === 1) {
|
|
31
|
+
if (thorough || isHighComplexity) {
|
|
32
|
+
return {
|
|
33
|
+
strategy: 'thorough_single',
|
|
34
|
+
reason: 'single_high_complexity',
|
|
35
|
+
dag_width,
|
|
36
|
+
max_complexity,
|
|
37
|
+
dagContext,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
strategy: 'quick_single',
|
|
42
|
+
reason: 'single_low_complexity',
|
|
43
|
+
dag_width,
|
|
44
|
+
max_complexity,
|
|
45
|
+
dagContext,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// dag_width==1: 사실상 순차 -> single
|
|
50
|
+
if (dag_width === 1) {
|
|
51
|
+
if (thorough || isHighComplexity) {
|
|
52
|
+
return {
|
|
53
|
+
strategy: 'thorough_single',
|
|
54
|
+
reason: 'sequential_chain',
|
|
55
|
+
dag_width,
|
|
56
|
+
max_complexity,
|
|
57
|
+
dagContext,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
strategy: 'quick_single',
|
|
62
|
+
reason: 'sequential_chain',
|
|
63
|
+
dag_width,
|
|
64
|
+
max_complexity,
|
|
65
|
+
dagContext,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 동일 에이전트 + 모두 S: 프롬프트 병합 -> batch single
|
|
70
|
+
if (allSameAgent && allSmall) {
|
|
71
|
+
return {
|
|
72
|
+
strategy: 'batch_single',
|
|
73
|
+
reason: 'same_agent_small_batch',
|
|
74
|
+
dag_width,
|
|
75
|
+
max_complexity,
|
|
76
|
+
dagContext,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// dag_width >= 2: 팀
|
|
81
|
+
if (thorough || isHighComplexity) {
|
|
82
|
+
return {
|
|
83
|
+
strategy: 'thorough_team',
|
|
84
|
+
reason: 'parallel_high_complexity',
|
|
85
|
+
dag_width,
|
|
86
|
+
max_complexity,
|
|
87
|
+
dagContext,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
strategy: 'quick_team',
|
|
92
|
+
reason: 'parallel_low_complexity',
|
|
93
|
+
dag_width,
|
|
94
|
+
max_complexity,
|
|
95
|
+
dagContext,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* DAG 정보 계산 — 레벨별 태스크 배열, 간선, 최대 폭
|
|
101
|
+
* @param {Array<{id:string, depends_on?:string[]}>} subtasks
|
|
102
|
+
* @param {string} graph_type
|
|
103
|
+
* @returns {{ width: number, levels: Record<number, string[]>, edges: Array<{from:string, to:string}> }}
|
|
104
|
+
*/
|
|
105
|
+
function computeDagInfo(subtasks, graph_type) {
|
|
106
|
+
if (graph_type === 'SEQUENTIAL') {
|
|
107
|
+
const levels = {};
|
|
108
|
+
const edges = [];
|
|
109
|
+
subtasks.forEach((t, i) => {
|
|
110
|
+
levels[i] = [t.id];
|
|
111
|
+
if (i > 0) edges.push({ from: subtasks[i - 1].id, to: t.id });
|
|
112
|
+
});
|
|
113
|
+
return { width: 1, levels, edges };
|
|
114
|
+
}
|
|
115
|
+
if (graph_type === 'INDEPENDENT') {
|
|
116
|
+
const levels = { 0: subtasks.map((t) => t.id) };
|
|
117
|
+
return { width: subtasks.length, levels, edges: [] };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// DAG: 레벨별 계산 (순환 의존 방어)
|
|
121
|
+
const taskLevels = {};
|
|
122
|
+
const visiting = new Set();
|
|
123
|
+
|
|
124
|
+
function getLevel(task) {
|
|
125
|
+
if (taskLevels[task.id] !== undefined) return taskLevels[task.id];
|
|
126
|
+
if (visiting.has(task.id)) {
|
|
127
|
+
taskLevels[task.id] = 0; // 순환 끊기
|
|
128
|
+
return 0;
|
|
129
|
+
}
|
|
130
|
+
if (!task.depends_on || task.depends_on.length === 0) {
|
|
131
|
+
taskLevels[task.id] = 0;
|
|
132
|
+
return 0;
|
|
133
|
+
}
|
|
134
|
+
visiting.add(task.id);
|
|
135
|
+
const depLevels = task.depends_on.map((depId) => {
|
|
136
|
+
const dep = subtasks.find((s) => s.id === depId);
|
|
137
|
+
return dep ? getLevel(dep) : 0;
|
|
138
|
+
});
|
|
139
|
+
visiting.delete(task.id);
|
|
140
|
+
taskLevels[task.id] = Math.max(...depLevels) + 1;
|
|
141
|
+
return taskLevels[task.id];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
subtasks.forEach(getLevel);
|
|
145
|
+
|
|
146
|
+
// 레벨별 태스크 그룹핑
|
|
147
|
+
const levels = {};
|
|
148
|
+
for (const [id, level] of Object.entries(taskLevels)) {
|
|
149
|
+
if (!levels[level]) levels[level] = [];
|
|
150
|
+
levels[level].push(id);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// 간선 수집
|
|
154
|
+
const edges = [];
|
|
155
|
+
for (const task of subtasks) {
|
|
156
|
+
if (task.depends_on) {
|
|
157
|
+
for (const depId of task.depends_on) {
|
|
158
|
+
edges.push({ from: depId, to: task.id });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const width = Math.max(...Object.values(levels).map((arr) => arr.length), 1);
|
|
164
|
+
return { width, levels, edges };
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* 선행 태스크의 결과를 dagContext.edges에서 조회하여 반환
|
|
169
|
+
* @param {string} taskId - 조회 대상 태스크 ID
|
|
170
|
+
* @param {{ dagContext?: { edges: Array<{from:string, to:string}>, taskResults: Record<string, *> } }} pipelineState
|
|
171
|
+
* @returns {Record<string, *>} 선행 태스크 ID → 결과 매핑
|
|
172
|
+
*/
|
|
173
|
+
export function getUpstreamResults(taskId, pipelineState) {
|
|
174
|
+
const ctx = pipelineState?.dagContext;
|
|
175
|
+
if (!ctx) return {};
|
|
176
|
+
const upstreamIds = ctx.edges.filter((e) => e.to === taskId).map((e) => e.from);
|
|
177
|
+
const results = {};
|
|
178
|
+
for (const id of upstreamIds) {
|
|
179
|
+
if (id in (ctx.taskResults || {})) {
|
|
180
|
+
results[id] = ctx.taskResults[id];
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return results;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* 태스크 완료 시 결과를 dagContext에 기록
|
|
188
|
+
* @param {string} taskId - 완료된 태스크 ID
|
|
189
|
+
* @param {*} result - 태스크 결과
|
|
190
|
+
* @param {{ dagContext?: { taskResults: Record<string, *> } }} pipelineState
|
|
191
|
+
* @returns {boolean} 기록 성공 여부
|
|
192
|
+
*/
|
|
193
|
+
export function updateTaskResult(taskId, result, pipelineState) {
|
|
194
|
+
const ctx = pipelineState?.dagContext;
|
|
195
|
+
if (!ctx) return false;
|
|
196
|
+
if (!ctx.taskResults) ctx.taskResults = {};
|
|
197
|
+
ctx.taskResults[taskId] = result;
|
|
198
|
+
return true;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* 최대 복잡도 추출
|
|
203
|
+
* @param {Array<{complexity?:string}>} subtasks
|
|
204
|
+
* @returns {"S" | "M" | "L" | "XL"}
|
|
205
|
+
*/
|
|
206
|
+
function getMaxComplexity(subtasks) {
|
|
207
|
+
const order = { S: 0, M: 1, L: 2, XL: 3 };
|
|
208
|
+
let max = 'S';
|
|
209
|
+
for (const s of subtasks) {
|
|
210
|
+
const complexity = normalizeComplexity(s.complexity);
|
|
211
|
+
if (order[complexity] > order[max]) max = complexity;
|
|
212
|
+
}
|
|
213
|
+
return max;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* complexity 기본값 보정
|
|
218
|
+
* @param {string | undefined} complexity
|
|
219
|
+
* @returns {"S" | "M" | "L" | "XL"}
|
|
220
|
+
*/
|
|
221
|
+
function normalizeComplexity(complexity) {
|
|
222
|
+
return ['S', 'M', 'L', 'XL'].includes(complexity) ? complexity : 'M';
|
|
223
|
+
}
|