triflux 10.3.4 → 10.4.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 (120) hide show
  1. package/CLAUDE.md +193 -0
  2. package/LICENSE +21 -21
  3. package/hooks/hook-registry.json +256 -256
  4. package/hub/adaptive-inject.mjs +1 -1
  5. package/hub/assign-callbacks.mjs +120 -120
  6. package/hub/delegator/index.mjs +14 -14
  7. package/hub/delegator/tool-definitions.mjs +35 -35
  8. package/hub/hitl.mjs +143 -143
  9. package/hub/router.mjs +791 -791
  10. package/hub/session-fingerprint.mjs +1 -1
  11. package/hub/team/cli/commands/attach.mjs +37 -37
  12. package/hub/team/cli/commands/debug.mjs +74 -74
  13. package/hub/team/cli/commands/focus.mjs +53 -53
  14. package/hub/team/cli/commands/list.mjs +24 -24
  15. package/hub/team/cli/commands/start/start-in-process.mjs +40 -40
  16. package/hub/team/cli/commands/start/start-mux.mjs +73 -73
  17. package/hub/team/cli/commands/start/start-wt.mjs +69 -69
  18. package/hub/team/cli/commands/tasks.mjs +13 -13
  19. package/hub/team/cli/render.mjs +30 -30
  20. package/hub/team/cli/services/attach-fallback.mjs +54 -54
  21. package/hub/team/cli/services/member-selector.mjs +30 -30
  22. package/hub/team/cli/services/native-control.mjs +116 -116
  23. package/hub/team/cli/services/task-model.mjs +30 -30
  24. package/hub/team/notify.mjs +1 -1
  25. package/hub/team/orchestrator.mjs +161 -161
  26. package/hub/team/session.mjs +611 -611
  27. package/hub/team/shared.mjs +13 -13
  28. package/hub/tray.mjs +368 -368
  29. package/hub/workers/codex-mcp.mjs +507 -507
  30. package/hub/workers/factory.mjs +21 -21
  31. package/package.json +21 -55
  32. package/references/hosts.json +33 -0
  33. package/scripts/completions/tfx.bash +47 -47
  34. package/scripts/completions/tfx.fish +44 -44
  35. package/scripts/completions/tfx.zsh +83 -83
  36. package/scripts/hub-ensure.mjs +120 -120
  37. package/scripts/keyword-detector.mjs +272 -272
  38. package/scripts/keyword-rules-expander.mjs +521 -521
  39. package/scripts/lib/mcp-server-catalog.mjs +118 -118
  40. package/scripts/notion-read.mjs +553 -553
  41. package/scripts/test-tfx-route-no-claude-native.mjs +57 -57
  42. package/scripts/tfx-batch-stats.mjs +96 -96
  43. package/skills/.omc/state/agent-replay-8f0e10a9-9693-4410-96f5-a6b07e8ed995.jsonl +1 -0
  44. package/skills/.omc/state/idle-notif-cooldown.json +3 -0
  45. package/skills/.omc/state/last-tool-error.json +7 -0
  46. package/skills/.omc/state/subagent-tracking.json +7 -0
  47. package/skills/tfx-remote-spawn/references/hosts.json +16 -0
  48. package/skills/tfx-workspace/async-tests/run-tests.sh +203 -0
  49. package/skills/tfx-workspace/evals/evals.json +79 -0
  50. package/skills/tfx-workspace/iteration-1/benchmark.json +162 -0
  51. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/eval_metadata.json +11 -0
  52. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/grading.json +9 -0
  53. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/outputs/analysis.md +154 -0
  54. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/timing.json +5 -0
  55. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/grading.json +9 -0
  56. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/outputs/analysis.md +126 -0
  57. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/timing.json +5 -0
  58. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/eval_metadata.json +11 -0
  59. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/grading.json +9 -0
  60. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/outputs/analysis.md +119 -0
  61. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/timing.json +5 -0
  62. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/grading.json +9 -0
  63. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/outputs/analysis.md +115 -0
  64. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/timing.json +5 -0
  65. package/skills/tfx-workspace/iteration-1/hub-start-sequence/eval_metadata.json +10 -0
  66. package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/grading.json +8 -0
  67. package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/outputs/analysis.md +86 -0
  68. package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/timing.json +5 -0
  69. package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/grading.json +8 -0
  70. package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/outputs/analysis.md +81 -0
  71. package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/timing.json +5 -0
  72. package/skills/tfx-workspace/iteration-1/multi-team-creation/eval_metadata.json +12 -0
  73. package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/grading.json +10 -0
  74. package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/outputs/analysis.md +316 -0
  75. package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/timing.json +5 -0
  76. package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/grading.json +10 -0
  77. package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/outputs/analysis.md +352 -0
  78. package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/timing.json +5 -0
  79. package/skills/tfx-workspace/iteration-1/review.html +1325 -0
  80. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/eval_metadata.json +12 -0
  81. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/grading.json +10 -0
  82. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/outputs/analysis.md +97 -0
  83. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/timing.json +5 -0
  84. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/grading.json +10 -0
  85. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/outputs/analysis.md +94 -0
  86. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/timing.json +5 -0
  87. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/eval_metadata.json +12 -0
  88. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/grading.json +10 -0
  89. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/outputs/analysis.md +209 -0
  90. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/timing.json +5 -0
  91. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/grading.json +10 -0
  92. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/outputs/analysis.md +193 -0
  93. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/timing.json +5 -0
  94. package/skills/tfx-workspace/iteration-2/benchmark.json +62 -0
  95. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/eval_metadata.json +13 -0
  96. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/grading.json +11 -0
  97. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/outputs/analysis.md +382 -0
  98. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/timing.json +5 -0
  99. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/grading.json +11 -0
  100. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/outputs/analysis.md +333 -0
  101. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/timing.json +5 -0
  102. package/skills/tfx-workspace/iteration-2/review.html +1325 -0
  103. package/skills/tfx-workspace/skill-snapshot/tfx-auto/SKILL.md +217 -0
  104. package/skills/tfx-workspace/skill-snapshot/tfx-auto-codex/SKILL.md +77 -0
  105. package/skills/tfx-workspace/skill-snapshot/tfx-codex/SKILL.md +65 -0
  106. package/skills/tfx-workspace/skill-snapshot/tfx-doctor/SKILL.md +94 -0
  107. package/skills/tfx-workspace/skill-snapshot/tfx-gemini/SKILL.md +82 -0
  108. package/skills/tfx-workspace/skill-snapshot/tfx-hub/SKILL.md +133 -0
  109. package/skills/tfx-workspace/skill-snapshot/tfx-multi/SKILL.md +426 -0
  110. package/skills/tfx-workspace/skill-snapshot/tfx-setup/SKILL.md +101 -0
  111. package/.claude-plugin/marketplace.json +0 -34
  112. package/.claude-plugin/plugin.json +0 -22
  113. package/config/mcp-registry.json +0 -29
  114. package/tui/codex-profile.mjs +0 -402
  115. package/tui/core.mjs +0 -236
  116. package/tui/doctor.mjs +0 -328
  117. package/tui/gemini-profile.mjs +0 -254
  118. package/tui/monitor-data.mjs +0 -148
  119. package/tui/monitor.mjs +0 -295
  120. package/tui/setup.mjs +0 -442
@@ -1,69 +1,69 @@
1
- import { createWtSession } from "../../../session.mjs";
2
- import { buildCliCommand } from "../../../pane.mjs";
3
- import { toAgentId } from "../../services/member-selector.mjs";
4
- import { buildTasks } from "../../services/task-model.mjs";
5
- import { warn } from "../../render.mjs";
6
-
7
- export async function startWtTeam({ sessionId, task, lead, agents, subtasks, layout, hubUrl }) {
8
- const paneCount = agents.length + 1;
9
- const effectiveLayout = layout === "Nx1" ? "Nx1" : "1xN";
10
- if (layout !== effectiveLayout) warn(`wt 모드에서 ${layout} 레이아웃은 미지원 — ${effectiveLayout}로 대체`);
11
- console.log(` 레이아웃: ${effectiveLayout} (${paneCount} panes)`);
12
-
13
- const session = createWtSession(sessionId, {
14
- layout: effectiveLayout,
15
- paneCommands: [
16
- { title: `${sessionId}-lead`, command: buildCliCommand(lead) },
17
- ...agents.map((cli, index) => ({
18
- title: `${sessionId}-${cli}-${index + 1}`,
19
- command: buildCliCommand(cli),
20
- })),
21
- ],
22
- });
23
-
24
- const members = [
25
- {
26
- role: "lead",
27
- name: "lead",
28
- cli: lead,
29
- pane: session.panes[0] || "wt:0",
30
- agentId: toAgentId(lead, session.panes[0] || "wt:0"),
31
- },
32
- ...agents.map((cli, index) => {
33
- const pane = session.panes[index + 1] || `wt:${index + 1}`;
34
- return {
35
- role: "worker",
36
- name: `${cli}-${index + 1}`,
37
- cli,
38
- pane,
39
- subtask: subtasks[index],
40
- agentId: toAgentId(cli, pane),
41
- };
42
- }),
43
- ];
44
-
45
- return {
46
- sessionName: sessionId,
47
- task,
48
- lead,
49
- agents,
50
- layout: effectiveLayout,
51
- teammateMode: "wt",
52
- startedAt: Date.now(),
53
- hubUrl,
54
- members,
55
- panes: Object.fromEntries(members.map((member) => [member.pane, {
56
- role: member.role,
57
- name: member.name,
58
- cli: member.cli,
59
- agentId: member.agentId,
60
- subtask: member.subtask || null,
61
- }])),
62
- tasks: buildTasks(subtasks, members.filter((member) => member.role === "worker")),
63
- wt: {
64
- windowId: 0,
65
- layout: effectiveLayout,
66
- paneCount: session.paneCount,
67
- },
68
- };
69
- }
1
+ import { createWtSession } from "../../../session.mjs";
2
+ import { buildCliCommand } from "../../../pane.mjs";
3
+ import { toAgentId } from "../../services/member-selector.mjs";
4
+ import { buildTasks } from "../../services/task-model.mjs";
5
+ import { warn } from "../../render.mjs";
6
+
7
+ export async function startWtTeam({ sessionId, task, lead, agents, subtasks, layout, hubUrl }) {
8
+ const paneCount = agents.length + 1;
9
+ const effectiveLayout = layout === "Nx1" ? "Nx1" : "1xN";
10
+ if (layout !== effectiveLayout) warn(`wt 모드에서 ${layout} 레이아웃은 미지원 — ${effectiveLayout}로 대체`);
11
+ console.log(` 레이아웃: ${effectiveLayout} (${paneCount} panes)`);
12
+
13
+ const session = createWtSession(sessionId, {
14
+ layout: effectiveLayout,
15
+ paneCommands: [
16
+ { title: `${sessionId}-lead`, command: buildCliCommand(lead) },
17
+ ...agents.map((cli, index) => ({
18
+ title: `${sessionId}-${cli}-${index + 1}`,
19
+ command: buildCliCommand(cli),
20
+ })),
21
+ ],
22
+ });
23
+
24
+ const members = [
25
+ {
26
+ role: "lead",
27
+ name: "lead",
28
+ cli: lead,
29
+ pane: session.panes[0] || "wt:0",
30
+ agentId: toAgentId(lead, session.panes[0] || "wt:0"),
31
+ },
32
+ ...agents.map((cli, index) => {
33
+ const pane = session.panes[index + 1] || `wt:${index + 1}`;
34
+ return {
35
+ role: "worker",
36
+ name: `${cli}-${index + 1}`,
37
+ cli,
38
+ pane,
39
+ subtask: subtasks[index],
40
+ agentId: toAgentId(cli, pane),
41
+ };
42
+ }),
43
+ ];
44
+
45
+ return {
46
+ sessionName: sessionId,
47
+ task,
48
+ lead,
49
+ agents,
50
+ layout: effectiveLayout,
51
+ teammateMode: "wt",
52
+ startedAt: Date.now(),
53
+ hubUrl,
54
+ members,
55
+ panes: Object.fromEntries(members.map((member) => [member.pane, {
56
+ role: member.role,
57
+ name: member.name,
58
+ cli: member.cli,
59
+ agentId: member.agentId,
60
+ subtask: member.subtask || null,
61
+ }])),
62
+ tasks: buildTasks(subtasks, members.filter((member) => member.role === "worker")),
63
+ wt: {
64
+ windowId: 0,
65
+ layout: effectiveLayout,
66
+ paneCount: session.paneCount,
67
+ },
68
+ };
69
+ }
@@ -1,13 +1,13 @@
1
- import { DIM, RESET } from "../../shared.mjs";
2
- import { isTeamAlive } from "../services/runtime-mode.mjs";
3
- import { loadTeamState } from "../services/state-store.mjs";
4
- import { renderTasks } from "../render.mjs";
5
-
6
- export function teamTasks() {
7
- const state = loadTeamState();
8
- if (!state || !isTeamAlive(state)) {
9
- console.log(`\n ${DIM}활성 팀 세션 없음${RESET}\n`);
10
- return;
11
- }
12
- renderTasks(state.tasks || []);
13
- }
1
+ import { DIM, RESET } from "../../shared.mjs";
2
+ import { isTeamAlive } from "../services/runtime-mode.mjs";
3
+ import { loadTeamState } from "../services/state-store.mjs";
4
+ import { renderTasks } from "../render.mjs";
5
+
6
+ export function teamTasks() {
7
+ const state = loadTeamState();
8
+ if (!state || !isTeamAlive(state)) {
9
+ console.log(`\n ${DIM}활성 팀 세션 없음${RESET}\n`);
10
+ return;
11
+ }
12
+ renderTasks(state.tasks || []);
13
+ }
@@ -1,30 +1,30 @@
1
- import { AMBER, BOLD, DIM, GRAY, GREEN, RED, RESET, WHITE, YELLOW } from "../shared.mjs";
2
-
3
- export function ok(msg) { console.log(` ${GREEN}✓${RESET} ${msg}`); }
4
- export function warn(msg) { console.log(` ${YELLOW}⚠${RESET} ${msg}`); }
5
- export function fail(msg) { console.log(` ${RED}✗${RESET} ${msg}`); }
6
-
7
- export function renderTasks(tasks = []) {
8
- if (!tasks.length) {
9
- console.log(`\n ${DIM}태스크 없음${RESET}\n`);
10
- return;
11
- }
12
-
13
- console.log(`\n ${AMBER}${BOLD}⬡ Team Tasks${RESET}\n`);
14
- for (const task of tasks) {
15
- const dep = task.depends_on?.length ? ` ${DIM}(deps: ${task.depends_on.join(",")})${RESET}` : "";
16
- const owner = task.owner ? ` ${GRAY}[${task.owner}]${RESET}` : "";
17
- console.log(` ${WHITE}${task.id}${RESET} ${String(task.status || "").padEnd(11)} ${task.title}${owner}${dep}`);
18
- }
19
- console.log("");
20
- }
21
-
22
- export function formatCompletionSuffix(member) {
23
- if (!member?.completionStatus) return "";
24
- if (member.completionStatus === "abnormal") {
25
- return ` ${RED}[abnormal:${member.completionReason || "unknown"}]${RESET}`;
26
- }
27
- if (member.completionStatus === "normal") return ` ${GREEN}[route-ok]${RESET}`;
28
- if (member.completionStatus === "unchecked") return ` ${GRAY}[route-unchecked]${RESET}`;
29
- return "";
30
- }
1
+ import { AMBER, BOLD, DIM, GRAY, GREEN, RED, RESET, WHITE, YELLOW } from "../shared.mjs";
2
+
3
+ export function ok(msg) { console.log(` ${GREEN}✓${RESET} ${msg}`); }
4
+ export function warn(msg) { console.log(` ${YELLOW}⚠${RESET} ${msg}`); }
5
+ export function fail(msg) { console.log(` ${RED}✗${RESET} ${msg}`); }
6
+
7
+ export function renderTasks(tasks = []) {
8
+ if (!tasks.length) {
9
+ console.log(`\n ${DIM}태스크 없음${RESET}\n`);
10
+ return;
11
+ }
12
+
13
+ console.log(`\n ${AMBER}${BOLD}⬡ Team Tasks${RESET}\n`);
14
+ for (const task of tasks) {
15
+ const dep = task.depends_on?.length ? ` ${DIM}(deps: ${task.depends_on.join(",")})${RESET}` : "";
16
+ const owner = task.owner ? ` ${GRAY}[${task.owner}]${RESET}` : "";
17
+ console.log(` ${WHITE}${task.id}${RESET} ${String(task.status || "").padEnd(11)} ${task.title}${owner}${dep}`);
18
+ }
19
+ console.log("");
20
+ }
21
+
22
+ export function formatCompletionSuffix(member) {
23
+ if (!member?.completionStatus) return "";
24
+ if (member.completionStatus === "abnormal") {
25
+ return ` ${RED}[abnormal:${member.completionReason || "unknown"}]${RESET}`;
26
+ }
27
+ if (member.completionStatus === "normal") return ` ${GREEN}[route-ok]${RESET}`;
28
+ if (member.completionStatus === "unchecked") return ` ${GRAY}[route-unchecked]${RESET}`;
29
+ return "";
30
+ }
@@ -1,54 +1,54 @@
1
- import { spawn } from "node:child_process";
2
-
3
- import {
4
- getSessionAttachedCount,
5
- hasWindowsTerminal,
6
- resolveAttachCommand,
7
- } from "../../session.mjs";
8
- import { PKG_ROOT } from "./state-store.mjs";
9
-
10
- export async function launchAttachInWindowsTerminal(sessionName) {
11
- if (!hasWindowsTerminal()) return false;
12
-
13
- let attachSpec;
14
- try {
15
- attachSpec = resolveAttachCommand(sessionName);
16
- } catch {
17
- return false;
18
- }
19
-
20
- const beforeAttached = getSessionAttachedCount(sessionName);
21
- try {
22
- const child = spawn("wt", ["-w", "0", "split-pane", "-V", "-d", PKG_ROOT, attachSpec.command, ...attachSpec.args], {
23
- detached: true,
24
- stdio: "ignore",
25
- windowsHide: false,
26
- });
27
- child.unref();
28
-
29
- if (beforeAttached == null) return true;
30
- const deadline = Date.now() + 3500;
31
- while (Date.now() < deadline) {
32
- await new Promise((resolve) => setTimeout(resolve, 120));
33
- const nowAttached = getSessionAttachedCount(sessionName);
34
- if (typeof nowAttached === "number" && nowAttached > beforeAttached) return true;
35
- }
36
- } catch {}
37
- return false;
38
- }
39
-
40
- export function buildManualAttachCommand(sessionName) {
41
- try {
42
- const spec = resolveAttachCommand(sessionName);
43
- return [spec.command, ...spec.args].map((value) => {
44
- const text = String(value);
45
- return /\s/.test(text) ? `"${text.replace(/"/g, '\\"')}"` : text;
46
- }).join(" ");
47
- } catch {
48
- return `tmux attach-session -t ${sessionName}`;
49
- }
50
- }
51
-
52
- export function wantsWtAttachFallback(args = [], env = process.env) {
53
- return args.includes("--wt") || args.includes("--spawn-wt") || env.TFX_ATTACH_WT_AUTO === "1";
54
- }
1
+ import { spawn } from "node:child_process";
2
+
3
+ import {
4
+ getSessionAttachedCount,
5
+ hasWindowsTerminal,
6
+ resolveAttachCommand,
7
+ } from "../../session.mjs";
8
+ import { PKG_ROOT } from "./state-store.mjs";
9
+
10
+ export async function launchAttachInWindowsTerminal(sessionName) {
11
+ if (!hasWindowsTerminal()) return false;
12
+
13
+ let attachSpec;
14
+ try {
15
+ attachSpec = resolveAttachCommand(sessionName);
16
+ } catch {
17
+ return false;
18
+ }
19
+
20
+ const beforeAttached = getSessionAttachedCount(sessionName);
21
+ try {
22
+ const child = spawn("wt", ["-w", "0", "split-pane", "-V", "-d", PKG_ROOT, attachSpec.command, ...attachSpec.args], {
23
+ detached: true,
24
+ stdio: "ignore",
25
+ windowsHide: false,
26
+ });
27
+ child.unref();
28
+
29
+ if (beforeAttached == null) return true;
30
+ const deadline = Date.now() + 3500;
31
+ while (Date.now() < deadline) {
32
+ await new Promise((resolve) => setTimeout(resolve, 120));
33
+ const nowAttached = getSessionAttachedCount(sessionName);
34
+ if (typeof nowAttached === "number" && nowAttached > beforeAttached) return true;
35
+ }
36
+ } catch {}
37
+ return false;
38
+ }
39
+
40
+ export function buildManualAttachCommand(sessionName) {
41
+ try {
42
+ const spec = resolveAttachCommand(sessionName);
43
+ return [spec.command, ...spec.args].map((value) => {
44
+ const text = String(value);
45
+ return /\s/.test(text) ? `"${text.replace(/"/g, '\\"')}"` : text;
46
+ }).join(" ");
47
+ } catch {
48
+ return `tmux attach-session -t ${sessionName}`;
49
+ }
50
+ }
51
+
52
+ export function wantsWtAttachFallback(args = [], env = process.env) {
53
+ return args.includes("--wt") || args.includes("--spawn-wt") || env.TFX_ATTACH_WT_AUTO === "1";
54
+ }
@@ -1,30 +1,30 @@
1
- export function resolveMember(state, selector) {
2
- const members = state?.members || [];
3
- if (!selector) return null;
4
-
5
- const direct = members.find((member) => (
6
- member.name === selector || member.role === selector || member.agentId === selector
7
- ));
8
- if (direct) return direct;
9
-
10
- const workerAlias = /^worker-(\d+)$/i.exec(selector);
11
- if (workerAlias) {
12
- const index = parseInt(workerAlias[1], 10) - 1;
13
- const workers = members.filter((member) => member.role === "worker");
14
- if (index >= 0 && index < workers.length) return workers[index];
15
- }
16
-
17
- const numeric = parseInt(selector, 10);
18
- if (!Number.isNaN(numeric)) {
19
- const byPane = members.find((member) => member.pane?.endsWith(`.${numeric}`) || member.pane?.endsWith(`:${numeric}`));
20
- if (byPane) return byPane;
21
- if (numeric >= 1 && numeric <= members.length) return members[numeric - 1];
22
- }
23
-
24
- return null;
25
- }
26
-
27
- export function toAgentId(cli, target) {
28
- const suffix = String(target).split(/[:.]/).pop();
29
- return `${cli}-${suffix}`;
30
- }
1
+ export function resolveMember(state, selector) {
2
+ const members = state?.members || [];
3
+ if (!selector) return null;
4
+
5
+ const direct = members.find((member) => (
6
+ member.name === selector || member.role === selector || member.agentId === selector
7
+ ));
8
+ if (direct) return direct;
9
+
10
+ const workerAlias = /^worker-(\d+)$/i.exec(selector);
11
+ if (workerAlias) {
12
+ const index = parseInt(workerAlias[1], 10) - 1;
13
+ const workers = members.filter((member) => member.role === "worker");
14
+ if (index >= 0 && index < workers.length) return workers[index];
15
+ }
16
+
17
+ const numeric = parseInt(selector, 10);
18
+ if (!Number.isNaN(numeric)) {
19
+ const byPane = members.find((member) => member.pane?.endsWith(`.${numeric}`) || member.pane?.endsWith(`:${numeric}`));
20
+ if (byPane) return byPane;
21
+ if (numeric >= 1 && numeric <= members.length) return members[numeric - 1];
22
+ }
23
+
24
+ return null;
25
+ }
26
+
27
+ export function toAgentId(cli, target) {
28
+ const suffix = String(target).split(/[:.]/).pop();
29
+ return `${cli}-${suffix}`;
30
+ }
@@ -1,117 +1,117 @@
1
- import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
- import { join } from "node:path";
3
- import { spawn } from "node:child_process";
4
-
5
- import { buildLeadPrompt, buildPrompt } from "../../orchestrator.mjs";
6
- import { HUB_PID_DIR, PKG_ROOT } from "./state-store.mjs";
7
-
8
- import { buildExecArgs } from "../../../codex-adapter.mjs";
9
-
10
- export function buildNativeCliCommand(cli) {
11
- switch (cli) {
12
- case "codex":
13
- return buildExecArgs({});
14
- case "gemini":
15
- return "gemini";
16
- case "claude":
17
- return "claude";
18
- default:
19
- return cli;
20
- }
21
- }
22
-
23
- export async function startNativeSupervisor({ sessionId, task, lead, agents, subtasks, hubUrl }) {
24
- const configPath = join(HUB_PID_DIR, `team-native-${sessionId}.config.json`);
25
- const runtimePath = join(HUB_PID_DIR, `team-native-${sessionId}.runtime.json`);
26
- const logsDir = join(HUB_PID_DIR, "team-logs", sessionId);
27
- mkdirSync(logsDir, { recursive: true });
28
-
29
- const leadMember = {
30
- role: "lead",
31
- name: "lead",
32
- cli: lead,
33
- agentId: `${lead}-lead`,
34
- command: buildNativeCliCommand(lead),
35
- };
36
- const workers = agents.map((cli, index) => ({
37
- role: "worker",
38
- name: `${cli}-${index + 1}`,
39
- cli,
40
- agentId: `${cli}-w${index + 1}`,
41
- command: buildNativeCliCommand(cli),
42
- subtask: subtasks[index],
43
- }));
44
- const members = [
45
- {
46
- ...leadMember,
47
- prompt: buildLeadPrompt(task, {
48
- agentId: leadMember.agentId,
49
- hubUrl,
50
- teammateMode: "in-process",
51
- workers: workers.map((worker) => ({
52
- agentId: worker.agentId,
53
- cli: worker.cli,
54
- subtask: worker.subtask,
55
- })),
56
- }),
57
- },
58
- ...workers.map((worker) => ({
59
- ...worker,
60
- prompt: buildPrompt(worker.subtask, { cli: worker.cli, agentId: worker.agentId, hubUrl }),
61
- })),
62
- ];
63
-
64
- writeFileSync(configPath, JSON.stringify({
65
- sessionName: sessionId,
66
- hubUrl,
67
- startupDelayMs: 3000,
68
- logsDir,
69
- runtimeFile: runtimePath,
70
- members,
71
- }, null, 2) + "\n");
72
-
73
- const child = spawn(process.execPath, [join(PKG_ROOT, "hub", "team", "native-supervisor.mjs"), "--config", configPath], {
74
- detached: true,
75
- stdio: "ignore",
76
- env: { ...process.env },
77
- windowsHide: true,
78
- });
79
- child.unref();
80
-
81
- const deadline = Date.now() + 5000;
82
- while (Date.now() < deadline) {
83
- if (existsSync(runtimePath)) {
84
- try {
85
- const runtime = JSON.parse(readFileSync(runtimePath, "utf8"));
86
- return { runtime, members };
87
- } catch {}
88
- }
89
- await new Promise((resolve) => setTimeout(resolve, 100));
90
- }
91
-
92
- return { runtime: null, members };
93
- }
94
-
95
- export async function nativeRequest(state, path, body = {}) {
96
- if (!state?.native?.controlUrl) return null;
97
- try {
98
- const res = await fetch(`${state.native.controlUrl}${path}`, {
99
- method: "POST",
100
- headers: { "Content-Type": "application/json" },
101
- body: JSON.stringify(body),
102
- });
103
- return await res.json();
104
- } catch {
105
- return null;
106
- }
107
- }
108
-
109
- export async function nativeGetStatus(state) {
110
- if (!state?.native?.controlUrl) return null;
111
- try {
112
- const res = await fetch(`${state.native.controlUrl}/status`);
113
- return await res.json();
114
- } catch {
115
- return null;
116
- }
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { spawn } from "node:child_process";
4
+
5
+ import { buildLeadPrompt, buildPrompt } from "../../orchestrator.mjs";
6
+ import { HUB_PID_DIR, PKG_ROOT } from "./state-store.mjs";
7
+
8
+ import { buildExecArgs } from "../../../codex-adapter.mjs";
9
+
10
+ export function buildNativeCliCommand(cli) {
11
+ switch (cli) {
12
+ case "codex":
13
+ return buildExecArgs({});
14
+ case "gemini":
15
+ return "gemini";
16
+ case "claude":
17
+ return "claude";
18
+ default:
19
+ return cli;
20
+ }
21
+ }
22
+
23
+ export async function startNativeSupervisor({ sessionId, task, lead, agents, subtasks, hubUrl }) {
24
+ const configPath = join(HUB_PID_DIR, `team-native-${sessionId}.config.json`);
25
+ const runtimePath = join(HUB_PID_DIR, `team-native-${sessionId}.runtime.json`);
26
+ const logsDir = join(HUB_PID_DIR, "team-logs", sessionId);
27
+ mkdirSync(logsDir, { recursive: true });
28
+
29
+ const leadMember = {
30
+ role: "lead",
31
+ name: "lead",
32
+ cli: lead,
33
+ agentId: `${lead}-lead`,
34
+ command: buildNativeCliCommand(lead),
35
+ };
36
+ const workers = agents.map((cli, index) => ({
37
+ role: "worker",
38
+ name: `${cli}-${index + 1}`,
39
+ cli,
40
+ agentId: `${cli}-w${index + 1}`,
41
+ command: buildNativeCliCommand(cli),
42
+ subtask: subtasks[index],
43
+ }));
44
+ const members = [
45
+ {
46
+ ...leadMember,
47
+ prompt: buildLeadPrompt(task, {
48
+ agentId: leadMember.agentId,
49
+ hubUrl,
50
+ teammateMode: "in-process",
51
+ workers: workers.map((worker) => ({
52
+ agentId: worker.agentId,
53
+ cli: worker.cli,
54
+ subtask: worker.subtask,
55
+ })),
56
+ }),
57
+ },
58
+ ...workers.map((worker) => ({
59
+ ...worker,
60
+ prompt: buildPrompt(worker.subtask, { cli: worker.cli, agentId: worker.agentId, hubUrl }),
61
+ })),
62
+ ];
63
+
64
+ writeFileSync(configPath, JSON.stringify({
65
+ sessionName: sessionId,
66
+ hubUrl,
67
+ startupDelayMs: 3000,
68
+ logsDir,
69
+ runtimeFile: runtimePath,
70
+ members,
71
+ }, null, 2) + "\n");
72
+
73
+ const child = spawn(process.execPath, [join(PKG_ROOT, "hub", "team", "native-supervisor.mjs"), "--config", configPath], {
74
+ detached: true,
75
+ stdio: "ignore",
76
+ env: { ...process.env },
77
+ windowsHide: true,
78
+ });
79
+ child.unref();
80
+
81
+ const deadline = Date.now() + 5000;
82
+ while (Date.now() < deadline) {
83
+ if (existsSync(runtimePath)) {
84
+ try {
85
+ const runtime = JSON.parse(readFileSync(runtimePath, "utf8"));
86
+ return { runtime, members };
87
+ } catch {}
88
+ }
89
+ await new Promise((resolve) => setTimeout(resolve, 100));
90
+ }
91
+
92
+ return { runtime: null, members };
93
+ }
94
+
95
+ export async function nativeRequest(state, path, body = {}) {
96
+ if (!state?.native?.controlUrl) return null;
97
+ try {
98
+ const res = await fetch(`${state.native.controlUrl}${path}`, {
99
+ method: "POST",
100
+ headers: { "Content-Type": "application/json" },
101
+ body: JSON.stringify(body),
102
+ });
103
+ return await res.json();
104
+ } catch {
105
+ return null;
106
+ }
107
+ }
108
+
109
+ export async function nativeGetStatus(state) {
110
+ if (!state?.native?.controlUrl) return null;
111
+ try {
112
+ const res = await fetch(`${state.native.controlUrl}/status`);
113
+ return await res.json();
114
+ } catch {
115
+ return null;
116
+ }
117
117
  }