@triflux/remote 10.50.2 → 10.52.0

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 (134) hide show
  1. package/cto/brief.mjs +0 -20
  2. package/cto/collect.mjs +1 -200
  3. package/cto/current.schema.json +2 -23
  4. package/cto/hygiene.mjs +2 -61
  5. package/cto/lake-root.mjs +0 -56
  6. package/cto/status.mjs +5 -187
  7. package/hub/index.mjs +0 -17
  8. package/hub/team/agent-map.json +0 -1
  9. package/hub/team/agents-row-attach.py +120 -0
  10. package/hub/team/agents-row.mjs +200 -0
  11. package/hub/team/ansi.mjs +1 -35
  12. package/hub/team/backend.mjs +9 -145
  13. package/hub/team/claude-daemon-control.mjs +1 -2
  14. package/hub/team/claude-session-projection.mjs +5 -73
  15. package/hub/team/cli/commands/attach.mjs +1 -17
  16. package/hub/team/cli/commands/control.mjs +12 -38
  17. package/hub/team/cli/commands/debug.mjs +2 -39
  18. package/hub/team/cli/commands/focus.mjs +5 -31
  19. package/hub/team/cli/commands/interrupt.mjs +6 -25
  20. package/hub/team/cli/commands/kill.mjs +1 -30
  21. package/hub/team/cli/commands/list.mjs +0 -16
  22. package/hub/team/cli/commands/send.mjs +6 -26
  23. package/hub/team/cli/commands/start/index.mjs +42 -133
  24. package/hub/team/cli/commands/start/parse-args.mjs +15 -40
  25. package/hub/team/cli/commands/start/start-headless.mjs +138 -105
  26. package/hub/team/cli/commands/start/start-mux.mjs +2 -7
  27. package/hub/team/cli/commands/status.mjs +2 -57
  28. package/hub/team/cli/commands/stop.mjs +14 -19
  29. package/hub/team/cli/help.mjs +4 -5
  30. package/hub/team/cli/manifest.mjs +5 -1
  31. package/hub/team/cli/render.mjs +0 -12
  32. package/hub/team/cli/services/runtime-mode.mjs +27 -98
  33. package/hub/team/cli/services/state-store.mjs +5 -20
  34. package/hub/team/handoff.mjs +3 -34
  35. package/hub/team/headless.mjs +108 -1296
  36. package/hub/team/orchestrator.mjs +4 -30
  37. package/hub/team/pane.mjs +6 -28
  38. package/hub/team/psmux.mjs +3 -34
  39. package/hub/team/remote-session.mjs +1 -2
  40. package/hub/team/session-context.mjs +1 -1
  41. package/hub/team/session.mjs +7 -91
  42. package/hub/team/tui-core.mjs +1 -1
  43. package/hub/team/tui-viewer.mjs +11 -58
  44. package/hub/team/tui.mjs +8 -306
  45. package/hub/team/uds-orchestrator.mjs +2 -580
  46. package/hub/team/wt-manager.mjs +2 -2
  47. package/hub/workers/factory.mjs +6 -84
  48. package/hub/workers/interface.mjs +1 -7
  49. package/hub/workers/lib/jsonrpc-core.mjs +11 -0
  50. package/hub/workers/lib/jsonrpc-ws-uds.mjs +5 -8
  51. package/package.json +3 -8
  52. package/scripts/lib/agent-route-policy.mjs +143 -62
  53. package/scripts/lib/cli-claude.mjs +0 -14
  54. package/scripts/lib/env-probe.mjs +2 -131
  55. package/scripts/lib/gemini-profiles.mjs +2 -69
  56. package/scripts/lib/legacy-mcp-cleanup.mjs +283 -0
  57. package/scripts/lib/machine-profile.mjs +3 -17
  58. package/scripts/lib/mcp-filter.mjs +109 -53
  59. package/scripts/lib/mcp-guard-engine.mjs +40 -98
  60. package/scripts/lib/mcp-health.mjs +2 -2
  61. package/scripts/lib/mcp-server-catalog.mjs +2 -2
  62. package/scripts/lib/psmux-info.mjs +11 -59
  63. package/scripts/lib/skill-template.mjs +0 -245
  64. package/hub/hub-lifecycle.mjs +0 -248
  65. package/hub/pipe.mjs +0 -825
  66. package/hub/promote-penalties.mjs +0 -138
  67. package/hub/public/dashboard.html +0 -416
  68. package/hub/schema.sql +0 -209
  69. package/hub/server.mjs +0 -3048
  70. package/hub/store-adapter.mjs +0 -182
  71. package/hub/store.mjs +0 -1736
  72. package/hub/team/build-worker-prompt.mjs +0 -92
  73. package/hub/team/check-mcp-hub.mjs +0 -49
  74. package/hub/team/claude-native-bridge.mjs +0 -987
  75. package/hub/team/cli/commands/start/start-in-process.mjs +0 -50
  76. package/hub/team/cli/commands/start/start-wt.mjs +0 -86
  77. package/hub/team/cli/services/hub-client.mjs +0 -264
  78. package/hub/team/cli/services/native-control.mjs +0 -145
  79. package/hub/team/codex-review.mjs +0 -520
  80. package/hub/team/conductor-mesh-bridge.mjs +0 -122
  81. package/hub/team/conductor-registry.mjs +0 -121
  82. package/hub/team/conductor.mjs +0 -1529
  83. package/hub/team/consensus-meta.mjs +0 -176
  84. package/hub/team/cto-auto-collect.mjs +0 -115
  85. package/hub/team/cto-pull.mjs +0 -31
  86. package/hub/team/daemon-pty-tmux-bridge.mjs +0 -146
  87. package/hub/team/dashboard.mjs +0 -322
  88. package/hub/team/event-log.mjs +0 -84
  89. package/hub/team/execution-mode.mjs +0 -324
  90. package/hub/team/extract-completion-payload.mjs +0 -110
  91. package/hub/team/headless-bridge-session.mjs +0 -17
  92. package/hub/team/health-probe.mjs +0 -435
  93. package/hub/team/interactive-native-launcher.mjs +0 -119
  94. package/hub/team/interactive-native-worker.mjs +0 -80
  95. package/hub/team/interactive-tui-transport.mjs +0 -479
  96. package/hub/team/launcher-template.mjs +0 -144
  97. package/hub/team/lead-control.mjs +0 -191
  98. package/hub/team/mcp-selector.mjs +0 -145
  99. package/hub/team/native-supervisor.mjs +0 -460
  100. package/hub/team/native.mjs +0 -727
  101. package/hub/team/recovery-store.mjs +0 -149
  102. package/hub/team/remote-probe.mjs +0 -292
  103. package/hub/team/remote-watcher.mjs +0 -506
  104. package/hub/team/runtime-strategy.mjs +0 -200
  105. package/hub/team/schemas/worker-completion.json +0 -39
  106. package/hub/team/sentinel-capture.mjs +0 -127
  107. package/hub/team/session-sync.mjs +0 -316
  108. package/hub/team/swarm-cli.mjs +0 -390
  109. package/hub/team/swarm-hypervisor.mjs +0 -2206
  110. package/hub/team/swarm-intent.mjs +0 -216
  111. package/hub/team/swarm-locks.mjs +0 -335
  112. package/hub/team/swarm-planner.mjs +0 -371
  113. package/hub/team/swarm-preflight.mjs +0 -366
  114. package/hub/team/swarm-reconciler.mjs +0 -242
  115. package/hub/team/synapse-cli.mjs +0 -458
  116. package/hub/team/synapse-http.mjs +0 -311
  117. package/hub/team/synapse-registry.mjs +0 -618
  118. package/hub/team/tui-remote-adapter.mjs +0 -377
  119. package/hub/team/tui-synapse.mjs +0 -223
  120. package/hub/team/worker-completion-validator.mjs +0 -79
  121. package/hub/team/worker-sandbox.mjs +0 -125
  122. package/hub/team/worktree-lifecycle.mjs +0 -639
  123. package/hub/team/wt-templates.json +0 -43
  124. package/hub/tools.mjs +0 -900
  125. package/hub/workers/antigravity-route-worker.mjs +0 -179
  126. package/hub/workers/codex-app-server-worker.mjs +0 -1067
  127. package/hub/workers/delegator-mcp.mjs +0 -1098
  128. package/hub/workers/lib/jsonrpc-stdio.mjs +0 -204
  129. package/scripts/lib/claudemd-scanner.mjs +0 -223
  130. package/scripts/lib/context.mjs +0 -67
  131. package/scripts/lib/dynamic-route-cli.mjs +0 -107
  132. package/scripts/lib/handoff.mjs +0 -187
  133. package/scripts/lib/logger.mjs +0 -122
  134. package/scripts/lib/stealth-fetch.mjs +0 -176
@@ -1,50 +0,0 @@
1
- import { startNativeSupervisor } from "../../services/native-control.mjs";
2
- import { buildTasks } from "../../services/task-model.mjs";
3
-
4
- export async function startInProcessTeam({
5
- sessionId,
6
- task,
7
- lead,
8
- agents,
9
- subtasks,
10
- hubUrl,
11
- }) {
12
- const { runtime, members } = await startNativeSupervisor({
13
- sessionId,
14
- task,
15
- lead,
16
- agents,
17
- subtasks,
18
- hubUrl,
19
- });
20
-
21
- if (!runtime?.controlUrl) return null;
22
-
23
- return {
24
- sessionName: sessionId,
25
- task,
26
- lead,
27
- agents,
28
- layout: "native",
29
- teammateMode: "in-process",
30
- startedAt: Date.now(),
31
- hubUrl,
32
- members: members.map((member, index) => ({
33
- role: member.role,
34
- name: member.name,
35
- cli: member.cli,
36
- agentId: member.agentId,
37
- pane: `native:${index}`,
38
- subtask: member.subtask || null,
39
- })),
40
- panes: {},
41
- tasks: buildTasks(
42
- subtasks,
43
- members.filter((member) => member.role === "worker"),
44
- ),
45
- native: {
46
- controlUrl: runtime.controlUrl,
47
- supervisorPid: runtime.supervisorPid,
48
- },
49
- };
50
- }
@@ -1,86 +0,0 @@
1
- import { buildCliCommand } from "../../../pane.mjs";
2
- import { createWtSession } from "../../../session.mjs";
3
- import { warn } from "../../render.mjs";
4
- import { toAgentId } from "../../services/member-selector.mjs";
5
- import { buildTasks } from "../../services/task-model.mjs";
6
-
7
- export async function startWtTeam({
8
- sessionId,
9
- task,
10
- lead,
11
- agents,
12
- subtasks,
13
- layout,
14
- hubUrl,
15
- }) {
16
- const paneCount = agents.length + 1;
17
- const effectiveLayout = layout === "Nx1" ? "Nx1" : "1xN";
18
- if (layout !== effectiveLayout)
19
- warn(`wt 모드에서 ${layout} 레이아웃은 미지원 — ${effectiveLayout}로 대체`);
20
- console.log(` 레이아웃: ${effectiveLayout} (${paneCount} panes)`);
21
-
22
- const session = await createWtSession(sessionId, {
23
- layout: effectiveLayout,
24
- paneCommands: [
25
- { title: `${sessionId}-lead`, command: buildCliCommand(lead) },
26
- ...agents.map((cli, index) => ({
27
- title: `${sessionId}-${cli}-${index + 1}`,
28
- command: buildCliCommand(cli),
29
- })),
30
- ],
31
- });
32
-
33
- const members = [
34
- {
35
- role: "lead",
36
- name: "lead",
37
- cli: lead,
38
- pane: session.panes[0] || "wt:0",
39
- agentId: toAgentId(lead, session.panes[0] || "wt:0"),
40
- },
41
- ...agents.map((cli, index) => {
42
- const pane = session.panes[index + 1] || `wt:${index + 1}`;
43
- return {
44
- role: "worker",
45
- name: `${cli}-${index + 1}`,
46
- cli,
47
- pane,
48
- subtask: subtasks[index],
49
- agentId: toAgentId(cli, pane),
50
- };
51
- }),
52
- ];
53
-
54
- return {
55
- sessionName: sessionId,
56
- task,
57
- lead,
58
- agents,
59
- layout: effectiveLayout,
60
- teammateMode: "wt",
61
- startedAt: Date.now(),
62
- hubUrl,
63
- members,
64
- panes: Object.fromEntries(
65
- members.map((member) => [
66
- member.pane,
67
- {
68
- role: member.role,
69
- name: member.name,
70
- cli: member.cli,
71
- agentId: member.agentId,
72
- subtask: member.subtask || null,
73
- },
74
- ]),
75
- ),
76
- tasks: buildTasks(
77
- subtasks,
78
- members.filter((member) => member.role === "worker"),
79
- ),
80
- wt: {
81
- windowId: 0,
82
- layout: effectiveLayout,
83
- paneCount: session.paneCount,
84
- },
85
- };
86
- }
@@ -1,264 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import {
3
- existsSync,
4
- mkdirSync,
5
- readFileSync,
6
- unlinkSync,
7
- writeFileSync,
8
- } from "node:fs";
9
- import { join } from "node:path";
10
- import { resolveHubPortForContext } from "../../../hub-lifecycle.mjs";
11
- import { publishLeadControl as publishLeadControlBridge } from "../../lead-control.mjs";
12
- import {
13
- getTeamStatus as fetchTeamStatus,
14
- subscribeToLeadCommands as pullLeadCommands,
15
- } from "../../session-sync.mjs";
16
- import { HUB_PID_DIR, PKG_ROOT } from "./state-store.mjs";
17
-
18
- export { nativeGetStatus } from "./native-control.mjs";
19
-
20
- const HUB_PID_FILE = join(HUB_PID_DIR, "hub.pid");
21
- const LOOPBACK_HOSTS = new Set(["127.0.0.1", "localhost", "::1"]);
22
-
23
- export function formatHostForUrl(host) {
24
- return host.includes(":") ? `[${host}]` : host;
25
- }
26
-
27
- export function buildHubBaseUrl(host, port) {
28
- return `http://${formatHostForUrl(host)}:${port}`;
29
- }
30
-
31
- export function getDefaultHubPort() {
32
- const envPortRaw = Number(process.env.TFX_HUB_PORT || "27888");
33
- return Number.isFinite(envPortRaw) && envPortRaw > 0 ? envPortRaw : 27888;
34
- }
35
-
36
- export function getDefaultHubUrl() {
37
- return `${buildHubBaseUrl("127.0.0.1", getDefaultHubPort())}/mcp`;
38
- }
39
-
40
- function normalizeLoopbackHost(host) {
41
- if (typeof host !== "string") return "127.0.0.1";
42
- const candidate = host.trim();
43
- return LOOPBACK_HOSTS.has(candidate) ? candidate : "127.0.0.1";
44
- }
45
-
46
- async function probeHubStatus(host, port, timeoutMs = 1500) {
47
- try {
48
- const res = await fetch(`${buildHubBaseUrl(host, port)}/status`, {
49
- signal: AbortSignal.timeout(timeoutMs),
50
- });
51
- if (!res.ok) return null;
52
- const data = await res.json();
53
- return data?.hub ? data : null;
54
- } catch {
55
- return null;
56
- }
57
- }
58
-
59
- export async function getHubInfo() {
60
- const probePort = getDefaultHubPort();
61
-
62
- if (existsSync(HUB_PID_FILE)) {
63
- try {
64
- const raw = JSON.parse(readFileSync(HUB_PID_FILE, "utf8"));
65
- const pid = Number(raw?.pid);
66
- if (!Number.isFinite(pid) || pid <= 0) throw new Error("invalid pid");
67
- process.kill(pid, 0);
68
- const host = normalizeLoopbackHost(raw?.host);
69
- const port = Number(raw?.port) || probePort;
70
- const status = await probeHubStatus(host, port, 1200);
71
- if (!status) throw new Error("pid file process is not a healthy hub");
72
- return {
73
- ...raw,
74
- pid,
75
- host,
76
- port,
77
- url: `${buildHubBaseUrl(host, port)}/mcp`,
78
- };
79
- } catch {
80
- try {
81
- unlinkSync(HUB_PID_FILE);
82
- } catch {}
83
- }
84
- }
85
-
86
- for (const portCandidate of Array.from(new Set([probePort, 27888]))) {
87
- const data = await probeHubStatus("127.0.0.1", portCandidate, 1200);
88
- if (!data) continue;
89
- const port = Number(data.port) || portCandidate;
90
- const pid = Number(data.pid);
91
- const recovered = {
92
- pid: Number.isFinite(pid) ? pid : null,
93
- host: "127.0.0.1",
94
- port,
95
- url: `${buildHubBaseUrl("127.0.0.1", port)}/mcp`,
96
- discovered: true,
97
- };
98
- if (Number.isFinite(recovered.pid) && recovered.pid > 0) {
99
- try {
100
- mkdirSync(HUB_PID_DIR, { recursive: true });
101
- writeFileSync(
102
- HUB_PID_FILE,
103
- JSON.stringify({ ...recovered, started: Date.now() }),
104
- );
105
- } catch {}
106
- }
107
- return recovered;
108
- }
109
- return null;
110
- }
111
-
112
- export async function startHubDaemon() {
113
- const serverPath = join(PKG_ROOT, "hub", "server.mjs");
114
- if (!existsSync(serverPath)) {
115
- const error = new Error("hub/server.mjs 없음");
116
- error.code = "HUB_SERVER_MISSING";
117
- throw error;
118
- }
119
-
120
- // Resolve the canonical port. server.mjs forces 27888 in worktree/ephemeral
121
- // contexts via resolveHubPortForContext; mirror that here so a polluted
122
- // TFX_HUB_PORT does not make us spawn with / probe a port the daemon never
123
- // binds (defense-in-depth — do not rely solely on server.mjs's boundary guard).
124
- const resolvedPort = resolveHubPortForContext({
125
- env: process.env,
126
- cwd: process.cwd(),
127
- });
128
-
129
- const child = spawn(process.execPath, [serverPath], {
130
- env: { ...process.env, TFX_HUB_PORT: String(resolvedPort) },
131
- stdio: "ignore",
132
- detached: true,
133
- windowsHide: true,
134
- });
135
- child.unref();
136
-
137
- const expectedPort = resolvedPort;
138
- const deadline = Date.now() + 3000;
139
- while (Date.now() < deadline) {
140
- const status = await probeHubStatus("127.0.0.1", expectedPort, 500);
141
- if (status?.hub) {
142
- return {
143
- pid: Number(status.pid) || child.pid,
144
- host: "127.0.0.1",
145
- port: expectedPort,
146
- url: `${buildHubBaseUrl("127.0.0.1", expectedPort)}/mcp`,
147
- };
148
- }
149
- await new Promise((resolve) => setTimeout(resolve, 100));
150
- }
151
-
152
- return null;
153
- }
154
-
155
- /**
156
- * Hub가 살아있는지 확인하고, 죽어있으면 재시작을 시도한다.
157
- * exponential backoff: 1초, 2초, 4초
158
- * 모든 재시작 실패 시 에러를 throw한다 (silent fail 아님).
159
- * @param {number} [maxRetries=3]
160
- * @returns {Promise<object>} Hub 정보
161
- * @throws {Error} 모든 재시작 시도 실패 시
162
- */
163
- export async function ensureHubAlive(maxRetries = 3) {
164
- const hub = await getHubInfo();
165
- if (hub && !hub.degraded) return hub;
166
-
167
- let lastError = null;
168
- for (let i = 0; i < maxRetries; i++) {
169
- try {
170
- const restarted = await startHubDaemon();
171
- if (restarted) {
172
- // 재시작 후 연결 복구 확인
173
- const recovered = await getHubInfo();
174
- if (recovered) return recovered;
175
- }
176
- } catch (err) {
177
- lastError = err;
178
- }
179
- // 다음 재시도 전 대기: 1초, 2초, 4초 (마지막 시도 후에는 대기 없음)
180
- if (i < maxRetries - 1) {
181
- const backoffMs = 2 ** i * 1000; // i=0: 1초, i=1: 2초, i=2: 4초
182
- await new Promise((resolve) => setTimeout(resolve, backoffMs));
183
- }
184
- }
185
-
186
- const error = new Error(
187
- `Hub 재시작 ${maxRetries}회 모두 실패${lastError ? `: ${lastError.message}` : ""}`,
188
- );
189
- error.code = "HUB_RESTART_FAILED";
190
- error.cause = lastError;
191
- throw error;
192
- }
193
-
194
- export async function fetchHubTaskList(state) {
195
- const hubBase = (state?.hubUrl || getDefaultHubUrl()).replace(/\/mcp$/, "");
196
- const teamName = state?.native?.teamName || state?.sessionName || null;
197
- if (!teamName) return [];
198
-
199
- try {
200
- const res = await fetch(`${hubBase}/bridge/team/task-list`, {
201
- method: "POST",
202
- headers: { "Content-Type": "application/json" },
203
- body: JSON.stringify({ team_name: teamName }),
204
- signal: AbortSignal.timeout(2000),
205
- });
206
- const data = await res.json();
207
- return data?.ok ? data.data?.tasks || [] : [];
208
- } catch {
209
- return [];
210
- }
211
- }
212
-
213
- export async function publishLeadControl(
214
- state,
215
- targetMember,
216
- command,
217
- reason = "",
218
- ) {
219
- const hubBase = (state?.hubUrl || getDefaultHubUrl()).replace(/\/mcp$/, "");
220
- const leadAgent =
221
- (state?.members || []).find((member) => member.role === "lead")?.agentId ||
222
- "lead";
223
- const targetAgent =
224
- typeof targetMember === "string" ? targetMember : targetMember?.agentId;
225
-
226
- const result = await publishLeadControlBridge({
227
- hubUrl: hubBase,
228
- fromAgent: leadAgent,
229
- toAgent: targetAgent,
230
- command,
231
- reason,
232
- payload: {
233
- issued_by: leadAgent,
234
- issued_at: Date.now(),
235
- },
236
- });
237
-
238
- return !!result?.ok;
239
- }
240
-
241
- export async function subscribeToLeadCommands(state, member, options = {}) {
242
- const hubBase = (state?.hubUrl || getDefaultHubUrl()).replace(/\/mcp$/, "");
243
- const fallbackAgentId =
244
- (state?.members || []).find((candidate) => candidate.role === "lead")
245
- ?.agentId || null;
246
- const agentId =
247
- typeof member === "string"
248
- ? member
249
- : member?.agentId || options?.agentId || fallbackAgentId;
250
-
251
- return await pullLeadCommands({
252
- hubUrl: hubBase,
253
- agentId,
254
- ...options,
255
- });
256
- }
257
-
258
- export async function getTeamStatus(state, options = {}) {
259
- const hubBase = (state?.hubUrl || getDefaultHubUrl()).replace(/\/mcp$/, "");
260
- return await fetchTeamStatus({
261
- hubUrl: hubBase,
262
- ...options,
263
- });
264
- }
@@ -1,145 +0,0 @@
1
- import { spawn } from "node:child_process";
2
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
3
- import { join } from "node:path";
4
- import { buildExecArgs } from "@triflux/core/hub/codex-adapter.mjs";
5
- import { buildLeadPrompt, buildPrompt } from "../../orchestrator.mjs";
6
- import { HUB_PID_DIR, PKG_ROOT } from "./state-store.mjs";
7
-
8
- export function buildNativeCliCommand(cli) {
9
- switch (cli) {
10
- case "codex":
11
- return buildExecArgs({});
12
- case "gemini":
13
- return "gemini";
14
- case "claude":
15
- return "claude";
16
- default:
17
- return cli;
18
- }
19
- }
20
-
21
- export async function startNativeSupervisor({
22
- sessionId,
23
- task,
24
- lead,
25
- agents,
26
- subtasks,
27
- hubUrl,
28
- }) {
29
- const configPath = join(HUB_PID_DIR, `team-native-${sessionId}.config.json`);
30
- const runtimePath = join(
31
- HUB_PID_DIR,
32
- `team-native-${sessionId}.runtime.json`,
33
- );
34
- const logsDir = join(HUB_PID_DIR, "team-logs", sessionId);
35
- mkdirSync(logsDir, { recursive: true });
36
-
37
- const leadMember = {
38
- role: "lead",
39
- name: "lead",
40
- cli: lead,
41
- agentId: `${lead}-lead`,
42
- command: buildNativeCliCommand(lead),
43
- };
44
- const workers = agents.map((cli, index) => ({
45
- role: "worker",
46
- name: `${cli}-${index + 1}`,
47
- cli,
48
- agentId: `${cli}-w${index + 1}`,
49
- command: buildNativeCliCommand(cli),
50
- subtask: subtasks[index],
51
- }));
52
- const members = [
53
- {
54
- ...leadMember,
55
- prompt: buildLeadPrompt(task, {
56
- agentId: leadMember.agentId,
57
- hubUrl,
58
- teammateMode: "in-process",
59
- workers: workers.map((worker) => ({
60
- agentId: worker.agentId,
61
- cli: worker.cli,
62
- subtask: worker.subtask,
63
- })),
64
- }),
65
- },
66
- ...workers.map((worker) => ({
67
- ...worker,
68
- prompt: buildPrompt(worker.subtask, {
69
- cli: worker.cli,
70
- agentId: worker.agentId,
71
- hubUrl,
72
- }),
73
- })),
74
- ];
75
-
76
- writeFileSync(
77
- configPath,
78
- JSON.stringify(
79
- {
80
- sessionName: sessionId,
81
- hubUrl,
82
- workdir: process.cwd(),
83
- startupDelayMs: 3000,
84
- logsDir,
85
- runtimeFile: runtimePath,
86
- members,
87
- },
88
- null,
89
- 2,
90
- ) + "\n",
91
- );
92
-
93
- const child = spawn(
94
- process.execPath,
95
- [
96
- join(PKG_ROOT, "hub", "team", "native-supervisor.mjs"),
97
- "--config",
98
- configPath,
99
- ],
100
- {
101
- detached: true,
102
- stdio: "ignore",
103
- env: { ...process.env },
104
- windowsHide: true,
105
- },
106
- );
107
- child.unref();
108
-
109
- const deadline = Date.now() + 5000;
110
- while (Date.now() < deadline) {
111
- if (existsSync(runtimePath)) {
112
- try {
113
- const runtime = JSON.parse(readFileSync(runtimePath, "utf8"));
114
- return { runtime, members };
115
- } catch {}
116
- }
117
- await new Promise((resolve) => setTimeout(resolve, 100));
118
- }
119
-
120
- return { runtime: null, members };
121
- }
122
-
123
- export async function nativeRequest(state, path, body = {}) {
124
- if (!state?.native?.controlUrl) return null;
125
- try {
126
- const res = await fetch(`${state.native.controlUrl}${path}`, {
127
- method: "POST",
128
- headers: { "Content-Type": "application/json" },
129
- body: JSON.stringify(body),
130
- });
131
- return await res.json();
132
- } catch {
133
- return null;
134
- }
135
- }
136
-
137
- export async function nativeGetStatus(state) {
138
- if (!state?.native?.controlUrl) return null;
139
- try {
140
- const res = await fetch(`${state.native.controlUrl}/status`);
141
- return await res.json();
142
- } catch {
143
- return null;
144
- }
145
- }