triflux 10.3.4 → 10.7.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.
- package/LICENSE +21 -21
- package/bin/tfx-doctor-tui.mjs +1 -1
- package/bin/tfx-doctor.mjs +6 -1
- package/bin/tfx-profile.mjs +1 -1
- package/bin/tfx-setup-tui.mjs +1 -1
- package/bin/tfx-setup.mjs +6 -1
- package/bin/triflux.mjs +2396 -1140
- package/hooks/agent-route-guard.mjs +12 -8
- package/hooks/cross-review-tracker.mjs +21 -8
- package/hooks/error-context.mjs +19 -7
- package/hooks/hook-adaptive-collector.mjs +18 -16
- package/hooks/hook-manager.mjs +93 -32
- package/hooks/hook-orchestrator.mjs +108 -24
- package/hooks/hook-registry.json +11 -0
- package/hooks/keyword-rules.json +6 -10
- package/hooks/lib/resolve-root.mjs +1 -1
- package/hooks/mcp-config-watcher.mjs +6 -2
- package/hooks/pipeline-stop.mjs +3 -6
- package/hooks/safety-guard.mjs +99 -28
- package/hooks/session-start-fast.mjs +143 -0
- package/hooks/subagent-verifier.mjs +5 -4
- package/hub/account-broker.mjs +256 -60
- package/hub/adaptive-diagnostic.mjs +75 -48
- package/hub/adaptive-inject.mjs +95 -57
- package/hub/adaptive-memory.mjs +156 -42
- package/hub/adaptive.mjs +60 -31
- package/hub/assign-callbacks.mjs +67 -30
- package/hub/bridge.mjs +0 -1
- package/hub/cli-adapter-base.mjs +200 -48
- package/hub/codex-adapter.mjs +76 -96
- package/hub/codex-compat.mjs +3 -3
- package/hub/codex-preflight.mjs +63 -37
- package/hub/delegator/contracts.mjs +19 -23
- package/hub/delegator/index.mjs +3 -3
- package/hub/delegator/service.mjs +88 -64
- package/hub/delegator/tool-definitions.mjs +5 -5
- package/hub/fullcycle.mjs +33 -17
- package/hub/gemini-adapter.mjs +69 -94
- package/hub/hitl.mjs +89 -30
- package/hub/intent.mjs +161 -38
- package/hub/lib/cache-guard.mjs +43 -17
- package/hub/lib/mcp-response-cache.mjs +66 -32
- package/hub/lib/memory-store.mjs +285 -111
- package/hub/lib/path-utils.mjs +35 -37
- package/hub/lib/process-utils.mjs +106 -37
- package/hub/lib/spawn-trace.mjs +527 -0
- package/hub/lib/ssh-command.mjs +34 -4
- package/hub/lib/ssh-retry.mjs +5 -1
- package/hub/lib/uuidv7.mjs +4 -3
- package/hub/memory-doctor.mjs +266 -106
- package/hub/middleware/request-logger.mjs +61 -34
- package/hub/paths.mjs +9 -9
- package/hub/pipeline/gates/confidence.mjs +34 -15
- package/hub/pipeline/gates/consensus.mjs +27 -15
- package/hub/pipeline/gates/index.mjs +7 -3
- package/hub/pipeline/gates/selfcheck.mjs +57 -19
- package/hub/pipeline/index.mjs +77 -42
- package/hub/pipeline/state.mjs +10 -10
- package/hub/pipeline/transitions.mjs +40 -23
- package/hub/platform.mjs +57 -48
- package/hub/promote-penalties.mjs +25 -7
- package/hub/quality/deslop.mjs +70 -49
- package/hub/research.mjs +32 -25
- package/hub/router.mjs +240 -107
- package/hub/routing/complexity.mjs +132 -29
- package/hub/routing/index.mjs +17 -12
- package/hub/routing/q-learning.mjs +76 -28
- package/hub/server.mjs +4 -4
- package/hub/session-fingerprint.mjs +126 -60
- package/hub/state.mjs +84 -43
- package/hub/store-adapter.mjs +59 -26
- package/hub/store.mjs +356 -153
- package/hub/team/agent-map.json +22 -7
- package/hub/team/ansi.mjs +186 -122
- package/hub/team/backend.mjs +28 -10
- package/hub/team/cli/commands/attach.mjs +29 -9
- package/hub/team/cli/commands/control.mjs +29 -8
- package/hub/team/cli/commands/debug.mjs +32 -11
- package/hub/team/cli/commands/focus.mjs +38 -11
- package/hub/team/cli/commands/interrupt.mjs +18 -6
- package/hub/team/cli/commands/kill.mjs +16 -5
- package/hub/team/cli/commands/list.mjs +11 -4
- package/hub/team/cli/commands/send.mjs +19 -6
- package/hub/team/cli/commands/start/index.mjs +154 -31
- package/hub/team/cli/commands/start/parse-args.mjs +38 -11
- package/hub/team/cli/commands/start/start-headless.mjs +112 -36
- package/hub/team/cli/commands/start/start-in-process.mjs +12 -2
- package/hub/team/cli/commands/start/start-mux.mjs +70 -21
- package/hub/team/cli/commands/start/start-wt.mjs +29 -12
- package/hub/team/cli/commands/status.mjs +43 -14
- package/hub/team/cli/commands/stop.mjs +11 -4
- package/hub/team/cli/commands/task.mjs +8 -3
- package/hub/team/cli/commands/tasks.mjs +1 -1
- package/hub/team/cli/index.mjs +2 -2
- package/hub/team/cli/manifest.mjs +38 -8
- package/hub/team/cli/render.mjs +30 -8
- package/hub/team/cli/services/attach-fallback.mjs +31 -11
- package/hub/team/cli/services/hub-client.mjs +42 -14
- package/hub/team/cli/services/member-selector.mjs +11 -4
- package/hub/team/cli/services/native-control.mjs +48 -21
- package/hub/team/cli/services/runtime-mode.mjs +2 -1
- package/hub/team/cli/services/state-store.mjs +25 -8
- package/hub/team/cli/services/task-model.mjs +16 -6
- package/hub/team/conductor-mesh-bridge.mjs +24 -23
- package/hub/team/conductor.mjs +8 -4
- package/hub/team/dashboard-anchor.mjs +4 -5
- package/hub/team/dashboard-layout.mjs +3 -1
- package/hub/team/dashboard-open.mjs +41 -21
- package/hub/team/dashboard.mjs +76 -28
- package/hub/team/event-log.mjs +18 -10
- package/hub/team/handoff.mjs +31 -15
- package/hub/team/headless.mjs +2 -1
- package/hub/team/health-probe.mjs +69 -54
- package/hub/team/launcher-template.mjs +16 -13
- package/hub/team/native-supervisor.mjs +65 -21
- package/hub/team/native.mjs +74 -35
- package/hub/team/nativeProxy.mjs +184 -113
- package/hub/team/notify.mjs +119 -76
- package/hub/team/orchestrator.mjs +9 -4
- package/hub/team/pane.mjs +12 -7
- package/hub/team/process-cleanup.mjs +25 -16
- package/hub/team/psmux.mjs +491 -201
- package/hub/team/remote-probe.mjs +68 -52
- package/hub/team/remote-session.mjs +117 -59
- package/hub/team/remote-watcher.mjs +61 -33
- package/hub/team/routing.mjs +51 -25
- package/hub/team/runtime-strategy.mjs +3 -1
- package/hub/team/session.mjs +98 -34
- package/hub/team/staleState.mjs +72 -30
- package/hub/team/swarm-locks.mjs +15 -13
- package/hub/team/swarm-planner.mjs +32 -21
- package/hub/team/swarm-reconciler.mjs +48 -23
- package/hub/team/tui-lite.mjs +266 -68
- package/hub/team/tui-remote-adapter.mjs +14 -10
- package/hub/team/tui-viewer.mjs +99 -43
- package/hub/team/tui.mjs +708 -271
- package/hub/team/worktree-lifecycle.mjs +152 -58
- package/hub/team/wt-manager.mjs +24 -14
- package/hub/token-mode.mjs +71 -71
- package/hub/tray.mjs +66 -23
- package/hub/workers/claude-worker.mjs +162 -118
- package/hub/workers/codex-mcp.mjs +192 -141
- package/hub/workers/delegator-mcp.mjs +507 -333
- package/hub/workers/factory.mjs +8 -8
- package/hub/workers/gemini-worker.mjs +115 -84
- package/hub/workers/interface.mjs +6 -1
- package/hub/workers/worker-utils.mjs +21 -14
- package/hud/colors.mjs +27 -9
- package/hud/constants.mjs +162 -26
- package/hud/context-monitor.mjs +82 -41
- package/hud/hud-qos-status.mjs +129 -49
- package/hud/mission-board.mjs +6 -3
- package/hud/providers/claude.mjs +226 -115
- package/hud/providers/codex.mjs +62 -22
- package/hud/providers/gemini.mjs +168 -56
- package/hud/renderers.mjs +384 -119
- package/hud/terminal.mjs +101 -31
- package/hud/utils.mjs +78 -38
- package/mesh/index.mjs +11 -5
- package/mesh/mesh-budget.mjs +18 -9
- package/mesh/mesh-heartbeat.mjs +1 -1
- package/mesh/mesh-queue.mjs +3 -5
- package/mesh/mesh-router.mjs +5 -4
- package/package.json +2 -1
- package/scripts/__tests__/gen-skill-docs.test.mjs +36 -7
- package/scripts/__tests__/keyword-detector.test.mjs +77 -28
- package/scripts/__tests__/mcp-guard-engine.test.mjs +58 -20
- package/scripts/__tests__/remote-spawn-transfer.test.mjs +30 -19
- package/scripts/__tests__/remote-spawn.test.mjs +10 -4
- package/scripts/__tests__/session-start-fast.test.mjs +36 -0
- package/scripts/__tests__/skill-template.test.mjs +98 -50
- package/scripts/__tests__/smoke.test.mjs +1 -1
- package/scripts/__tests__/spawn-trace.test.mjs +102 -0
- package/scripts/__tests__/tfx-doctor-diagnose.test.mjs +48 -0
- package/scripts/cache-doctor.mjs +11 -4
- package/scripts/cache-warmup.mjs +96 -37
- package/scripts/claudemd-sync.mjs +27 -17
- package/scripts/codex-gateway-preflight.mjs +52 -37
- package/scripts/codex-mcp-gateway-sync.mjs +59 -39
- package/scripts/completions/tfx.bash +47 -47
- package/scripts/completions/tfx.fish +44 -44
- package/scripts/completions/tfx.zsh +83 -83
- package/scripts/config-audit.mjs +232 -0
- package/scripts/convert-to-tmpl.mjs +54 -0
- package/scripts/cross-review-gate.mjs +35 -12
- package/scripts/cross-review-tracker.mjs +21 -8
- package/scripts/demo.mjs +35 -17
- package/scripts/doctor-diagnose.mjs +284 -0
- package/scripts/gen-skill-docs.mjs +7 -2
- package/scripts/gen-skill-manifest.mjs +2 -1
- package/scripts/headless-guard.mjs +86 -48
- package/scripts/hub-ensure.mjs +45 -26
- package/scripts/keyword-detector.mjs +41 -20
- package/scripts/keyword-rules-expander.mjs +47 -30
- package/scripts/lib/claudemd-scanner.mjs +6 -1
- package/scripts/lib/context.mjs +3 -3
- package/scripts/lib/cross-review-utils.mjs +6 -3
- package/scripts/lib/env-probe.mjs +47 -28
- package/scripts/lib/gemini-profiles.mjs +44 -10
- package/scripts/lib/handoff.mjs +33 -17
- package/scripts/lib/hook-utils.mjs +8 -6
- package/scripts/lib/keyword-rules.mjs +43 -19
- package/scripts/lib/logger.mjs +24 -24
- package/scripts/lib/mcp-filter.mjs +377 -239
- package/scripts/lib/mcp-guard-engine.mjs +194 -79
- package/scripts/lib/mcp-manifest.mjs +23 -13
- package/scripts/lib/mcp-server-catalog.mjs +300 -63
- package/scripts/lib/psmux-info.mjs +11 -6
- package/scripts/lib/remote-spawn-transfer.mjs +44 -14
- package/scripts/lib/skill-template.mjs +30 -7
- package/scripts/mcp-check.mjs +58 -39
- package/scripts/mcp-gateway-config.mjs +83 -39
- package/scripts/mcp-gateway-ensure.mjs +43 -35
- package/scripts/mcp-gateway-integration-test.mjs +70 -58
- package/scripts/mcp-gateway-start.mjs +126 -60
- package/scripts/mcp-gateway-verify.mjs +24 -22
- package/scripts/mcp-safety-guard.mjs +44 -11
- package/scripts/notion-read.mjs +199 -84
- package/scripts/pack.mjs +94 -89
- package/scripts/preflight-cache.mjs +27 -10
- package/scripts/preinstall.mjs +42 -13
- package/scripts/remote-spawn.mjs +309 -94
- package/scripts/run.cjs +8 -5
- package/scripts/session-spawn-helper.mjs +130 -39
- package/scripts/session-stale-cleanup.mjs +123 -0
- package/scripts/setup.mjs +941 -492
- package/scripts/test-lock.mjs +20 -7
- package/scripts/test-tfx-route-no-claude-native.mjs +16 -12
- package/scripts/tfx-batch-stats.mjs +32 -11
- package/scripts/tfx-gate-activate.mjs +11 -4
- package/scripts/tfx-route-post.mjs +87 -20
- package/scripts/tfx-route-worker.mjs +57 -51
- package/scripts/tfx-route.sh +41 -124
- package/scripts/tmp-cleanup.mjs +21 -7
- package/scripts/token-snapshot.mjs +204 -85
- package/skills/.omc/state/agent-replay-8f0e10a9-9693-4410-96f5-a6b07e8ed995.jsonl +1 -0
- package/skills/.omc/state/idle-notif-cooldown.json +3 -0
- package/skills/.omc/state/last-tool-error.json +7 -0
- package/skills/.omc/state/subagent-tracking.json +7 -0
- package/skills/_templates/base.md +1 -6
- package/skills/merge-worktree/SKILL.md.tmpl +144 -0
- package/skills/shared/telemetry-segment.md +6 -0
- package/skills/star-prompt/SKILL.md.tmpl +222 -0
- package/skills/tfx-analysis/SKILL.md.tmpl +107 -0
- package/skills/tfx-analysis/skill.json +1 -6
- package/skills/tfx-auto/SKILL.md +1 -0
- package/skills/tfx-auto-codex/SKILL.md.tmpl +106 -0
- package/skills/tfx-auto-codex/skill.json +1 -3
- package/skills/tfx-autopilot/SKILL.md.tmpl +116 -0
- package/skills/tfx-autopilot/skill.json +1 -5
- package/skills/tfx-autoresearch/SKILL.md.tmpl +136 -0
- package/skills/tfx-autoroute/SKILL.md.tmpl +189 -0
- package/skills/tfx-autoroute/skill.json +1 -7
- package/skills/tfx-codex/SKILL.md +1 -0
- package/skills/tfx-codex/skill.json +1 -3
- package/skills/tfx-codex-swarm/SKILL.md.tmpl +16 -0
- package/skills/tfx-codex-swarm/evals/evals.json +1 -1
- package/skills/tfx-codex-swarm/skill.json +1 -4
- package/skills/tfx-codex-swarm-workspace/iteration-1/benchmark.json +54 -12
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/grading.json +35 -7
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/grading.json +35 -7
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/grading.json +25 -5
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/grading.json +25 -5
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/grading.json +20 -4
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/grading.json +16 -4
- package/skills/tfx-consensus/SKILL.md.tmpl +146 -0
- package/skills/tfx-debate/SKILL.md.tmpl +192 -0
- package/skills/tfx-debate/skill.json +1 -7
- package/skills/tfx-deep-analysis/SKILL.md.tmpl +228 -0
- package/skills/tfx-deep-analysis/skill.json +1 -5
- package/skills/tfx-deep-interview/SKILL.md.tmpl +203 -0
- package/skills/tfx-deep-plan/SKILL.md.tmpl +282 -0
- package/skills/tfx-deep-qa/SKILL.md.tmpl +165 -0
- package/skills/tfx-deep-qa/skill.json +1 -6
- package/skills/tfx-deep-research/SKILL.md.tmpl +217 -0
- package/skills/tfx-deep-review/SKILL.md.tmpl +179 -0
- package/skills/tfx-doctor/SKILL.md +21 -0
- package/skills/tfx-doctor/SKILL.md.tmpl +172 -0
- package/skills/tfx-doctor/skill.json +1 -3
- package/skills/tfx-find/SKILL.md +1 -0
- package/skills/tfx-forge/SKILL.md.tmpl +187 -0
- package/skills/tfx-fullcycle/SKILL.md.tmpl +286 -0
- package/skills/tfx-fullcycle/skill.json +1 -6
- package/skills/tfx-gemini/SKILL.md.tmpl +91 -0
- package/skills/tfx-gemini/skill.json +1 -3
- package/skills/tfx-hooks/SKILL.md.tmpl +216 -0
- package/skills/tfx-hooks/skill.json +1 -3
- package/skills/tfx-hub/SKILL.md.tmpl +212 -0
- package/skills/tfx-hub/skill.json +1 -3
- package/skills/tfx-index/SKILL.md +1 -0
- package/skills/tfx-index/skill.json +1 -6
- package/skills/tfx-interview/SKILL.md.tmpl +285 -0
- package/skills/tfx-multi/SKILL.md.tmpl +183 -0
- package/skills/tfx-multi/skill.json +1 -3
- package/skills/tfx-panel/SKILL.md.tmpl +189 -0
- package/skills/tfx-panel/skill.json +1 -7
- package/skills/tfx-persist/SKILL.md.tmpl +270 -0
- package/skills/tfx-persist/skill.json +1 -7
- package/skills/tfx-plan/SKILL.md +1 -0
- package/skills/tfx-plan/skill.json +1 -6
- package/skills/tfx-profile/SKILL.md.tmpl +239 -0
- package/skills/tfx-profile/skill.json +1 -3
- package/skills/tfx-prune/SKILL.md.tmpl +200 -0
- package/skills/tfx-prune/skill.json +1 -7
- package/skills/tfx-psmux-rules/SKILL.md.tmpl +326 -0
- package/skills/tfx-psmux-rules/skill.json +1 -4
- package/skills/tfx-qa/SKILL.md +1 -0
- package/skills/tfx-qa/skill.json +1 -6
- package/skills/tfx-ralph/SKILL.md.tmpl +28 -0
- package/skills/tfx-ralph/skill.json +1 -4
- package/skills/tfx-remote-setup/SKILL.md.tmpl +576 -0
- package/skills/tfx-remote-setup/skill.json +1 -3
- package/skills/tfx-remote-spawn/SKILL.md.tmpl +263 -0
- package/skills/tfx-remote-spawn/references/hosts.json +16 -0
- package/skills/tfx-remote-spawn/skill.json +1 -4
- package/skills/tfx-research/SKILL.md +1 -0
- package/skills/tfx-review/SKILL.md +1 -0
- package/skills/tfx-review/skill.json +1 -6
- package/skills/tfx-setup/SKILL.md.tmpl +504 -0
- package/skills/tfx-setup/skill.json +1 -3
- package/skills/tfx-swarm/SKILL.md +22 -0
- package/skills/tfx-swarm/SKILL.md.tmpl +218 -0
- package/tui/codex-profile.mjs +88 -33
- package/tui/core.mjs +45 -15
- package/tui/doctor.mjs +75 -28
- package/tui/gemini-profile.mjs +74 -29
- package/tui/monitor-data.mjs +8 -4
- package/tui/monitor.mjs +71 -27
- package/tui/setup.mjs +133 -42
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { DIM, RESET, WHITE } from "../../shared.mjs";
|
|
2
|
+
import { ok } from "../render.mjs";
|
|
2
3
|
import { isTeamAlive } from "../services/runtime-mode.mjs";
|
|
3
4
|
import { loadTeamState, saveTeamState } from "../services/state-store.mjs";
|
|
4
|
-
import {
|
|
5
|
-
|
|
5
|
+
import {
|
|
6
|
+
normalizeTaskStatus,
|
|
7
|
+
updateTaskStatus,
|
|
8
|
+
} from "../services/task-model.mjs";
|
|
6
9
|
|
|
7
10
|
export function teamTaskUpdate(args = []) {
|
|
8
11
|
const state = loadTeamState();
|
|
@@ -14,7 +17,9 @@ export function teamTaskUpdate(args = []) {
|
|
|
14
17
|
const nextStatus = normalizeTaskStatus(args[0]);
|
|
15
18
|
const taskId = String(args[1] || "").toUpperCase();
|
|
16
19
|
if (!nextStatus || !taskId) {
|
|
17
|
-
console.log(
|
|
20
|
+
console.log(
|
|
21
|
+
`\n 사용법: ${WHITE}tfx multi task <pending|progress|done> <T1>${RESET}\n`,
|
|
22
|
+
);
|
|
18
23
|
return;
|
|
19
24
|
}
|
|
20
25
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DIM, RESET } from "../../shared.mjs";
|
|
2
|
+
import { renderTasks } from "../render.mjs";
|
|
2
3
|
import { isTeamAlive } from "../services/runtime-mode.mjs";
|
|
3
4
|
import { loadTeamState } from "../services/state-store.mjs";
|
|
4
|
-
import { renderTasks } from "../render.mjs";
|
|
5
5
|
|
|
6
6
|
export function teamTasks() {
|
|
7
7
|
const state = loadTeamState();
|
package/hub/team/cli/index.mjs
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { renderTeamHelp } from "./help.mjs";
|
|
2
|
-
import { resolveTeamCommand } from "./manifest.mjs";
|
|
3
1
|
import { teamAttach } from "./commands/attach.mjs";
|
|
4
2
|
import { teamControl } from "./commands/control.mjs";
|
|
5
3
|
import { teamDebug } from "./commands/debug.mjs";
|
|
@@ -13,6 +11,8 @@ import { teamStatus } from "./commands/status.mjs";
|
|
|
13
11
|
import { teamStop } from "./commands/stop.mjs";
|
|
14
12
|
import { teamTaskUpdate } from "./commands/task.mjs";
|
|
15
13
|
import { teamTasks } from "./commands/tasks.mjs";
|
|
14
|
+
import { renderTeamHelp } from "./help.mjs";
|
|
15
|
+
import { resolveTeamCommand } from "./manifest.mjs";
|
|
16
16
|
|
|
17
17
|
const handlers = {
|
|
18
18
|
attach: teamAttach,
|
|
@@ -1,18 +1,46 @@
|
|
|
1
1
|
export const TEAM_COMMANDS = [
|
|
2
2
|
{ name: "status", usage: "tfx multi status", desc: "현재 팀 상태" },
|
|
3
|
-
{
|
|
3
|
+
{
|
|
4
|
+
name: "debug",
|
|
5
|
+
usage: "tfx multi debug [--lines 30]",
|
|
6
|
+
desc: "강화 디버그 출력",
|
|
7
|
+
},
|
|
4
8
|
{ name: "tasks", usage: "tfx multi tasks", desc: "공유 태스크 목록" },
|
|
5
|
-
{
|
|
9
|
+
{
|
|
10
|
+
name: "task",
|
|
11
|
+
usage: "tfx multi task <pending|progress|done> <T1>",
|
|
12
|
+
desc: "태스크 상태 갱신",
|
|
13
|
+
},
|
|
6
14
|
{ name: "attach", usage: "tfx multi attach [--wt]", desc: "세션 재연결" },
|
|
7
|
-
{
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
15
|
+
{
|
|
16
|
+
name: "focus",
|
|
17
|
+
usage: "tfx multi focus <lead|이름|번호> [--wt]",
|
|
18
|
+
desc: "특정 팀메이트 포커스",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
name: "send",
|
|
22
|
+
usage: 'tfx multi send <lead|이름|번호> "msg"',
|
|
23
|
+
desc: "팀메이트에 메시지 주입",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: "interrupt",
|
|
27
|
+
usage: "tfx multi interrupt <대상>",
|
|
28
|
+
desc: "팀메이트 인터럽트(C-c)",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: "control",
|
|
32
|
+
usage: "tfx multi control <대상> <cmd> [사유]",
|
|
33
|
+
desc: "리드 제어명령 전송",
|
|
34
|
+
},
|
|
11
35
|
{ name: "stop", usage: "tfx multi stop", desc: "graceful 종료" },
|
|
12
36
|
{ name: "kill", usage: "tfx multi kill", desc: "모든 팀 세션 강제 종료" },
|
|
13
37
|
{ name: "list", usage: "tfx multi list", desc: "활성 세션 목록" },
|
|
14
38
|
{ name: "help", usage: "tfx multi help", desc: "도움말" },
|
|
15
|
-
{
|
|
39
|
+
{
|
|
40
|
+
name: "start",
|
|
41
|
+
usage: "tfx multi start [options]",
|
|
42
|
+
desc: "새 팀 세션 시작 (기본 커맨드)",
|
|
43
|
+
},
|
|
16
44
|
];
|
|
17
45
|
|
|
18
46
|
export const TEAM_COMMAND_ALIASES = new Map([
|
|
@@ -25,5 +53,7 @@ export const TEAM_SUBCOMMANDS = new Set(TEAM_COMMANDS.map(({ name }) => name));
|
|
|
25
53
|
export function resolveTeamCommand(raw) {
|
|
26
54
|
if (typeof raw !== "string") return null;
|
|
27
55
|
const command = raw.toLowerCase();
|
|
28
|
-
return TEAM_SUBCOMMANDS.has(command)
|
|
56
|
+
return TEAM_SUBCOMMANDS.has(command)
|
|
57
|
+
? command
|
|
58
|
+
: TEAM_COMMAND_ALIASES.get(command) || null;
|
|
29
59
|
}
|
package/hub/team/cli/render.mjs
CHANGED
|
@@ -1,8 +1,24 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
AMBER,
|
|
3
|
+
BOLD,
|
|
4
|
+
DIM,
|
|
5
|
+
GRAY,
|
|
6
|
+
GREEN,
|
|
7
|
+
RED,
|
|
8
|
+
RESET,
|
|
9
|
+
WHITE,
|
|
10
|
+
YELLOW,
|
|
11
|
+
} from "../shared.mjs";
|
|
2
12
|
|
|
3
|
-
export function ok(msg) {
|
|
4
|
-
|
|
5
|
-
|
|
13
|
+
export function ok(msg) {
|
|
14
|
+
console.log(` ${GREEN}✓${RESET} ${msg}`);
|
|
15
|
+
}
|
|
16
|
+
export function warn(msg) {
|
|
17
|
+
console.log(` ${YELLOW}⚠${RESET} ${msg}`);
|
|
18
|
+
}
|
|
19
|
+
export function fail(msg) {
|
|
20
|
+
console.log(` ${RED}✗${RESET} ${msg}`);
|
|
21
|
+
}
|
|
6
22
|
|
|
7
23
|
export function renderTasks(tasks = []) {
|
|
8
24
|
if (!tasks.length) {
|
|
@@ -12,9 +28,13 @@ export function renderTasks(tasks = []) {
|
|
|
12
28
|
|
|
13
29
|
console.log(`\n ${AMBER}${BOLD}⬡ Team Tasks${RESET}\n`);
|
|
14
30
|
for (const task of tasks) {
|
|
15
|
-
const dep = task.depends_on?.length
|
|
31
|
+
const dep = task.depends_on?.length
|
|
32
|
+
? ` ${DIM}(deps: ${task.depends_on.join(",")})${RESET}`
|
|
33
|
+
: "";
|
|
16
34
|
const owner = task.owner ? ` ${GRAY}[${task.owner}]${RESET}` : "";
|
|
17
|
-
console.log(
|
|
35
|
+
console.log(
|
|
36
|
+
` ${WHITE}${task.id}${RESET} ${String(task.status || "").padEnd(11)} ${task.title}${owner}${dep}`,
|
|
37
|
+
);
|
|
18
38
|
}
|
|
19
39
|
console.log("");
|
|
20
40
|
}
|
|
@@ -24,7 +44,9 @@ export function formatCompletionSuffix(member) {
|
|
|
24
44
|
if (member.completionStatus === "abnormal") {
|
|
25
45
|
return ` ${RED}[abnormal:${member.completionReason || "unknown"}]${RESET}`;
|
|
26
46
|
}
|
|
27
|
-
if (member.completionStatus === "normal")
|
|
28
|
-
|
|
47
|
+
if (member.completionStatus === "normal")
|
|
48
|
+
return ` ${GREEN}[route-ok]${RESET}`;
|
|
49
|
+
if (member.completionStatus === "unchecked")
|
|
50
|
+
return ` ${GRAY}[route-unchecked]${RESET}`;
|
|
29
51
|
return "";
|
|
30
52
|
}
|
|
@@ -19,11 +19,24 @@ export async function launchAttachInWindowsTerminal(sessionName) {
|
|
|
19
19
|
|
|
20
20
|
const beforeAttached = getSessionAttachedCount(sessionName);
|
|
21
21
|
try {
|
|
22
|
-
const child = spawn(
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
const child = spawn(
|
|
23
|
+
"wt",
|
|
24
|
+
[
|
|
25
|
+
"-w",
|
|
26
|
+
"0",
|
|
27
|
+
"split-pane",
|
|
28
|
+
"-V",
|
|
29
|
+
"-d",
|
|
30
|
+
PKG_ROOT,
|
|
31
|
+
attachSpec.command,
|
|
32
|
+
...attachSpec.args,
|
|
33
|
+
],
|
|
34
|
+
{
|
|
35
|
+
detached: true,
|
|
36
|
+
stdio: "ignore",
|
|
37
|
+
windowsHide: false,
|
|
38
|
+
},
|
|
39
|
+
);
|
|
27
40
|
child.unref();
|
|
28
41
|
|
|
29
42
|
if (beforeAttached == null) return true;
|
|
@@ -31,7 +44,8 @@ export async function launchAttachInWindowsTerminal(sessionName) {
|
|
|
31
44
|
while (Date.now() < deadline) {
|
|
32
45
|
await new Promise((resolve) => setTimeout(resolve, 120));
|
|
33
46
|
const nowAttached = getSessionAttachedCount(sessionName);
|
|
34
|
-
if (typeof nowAttached === "number" && nowAttached > beforeAttached)
|
|
47
|
+
if (typeof nowAttached === "number" && nowAttached > beforeAttached)
|
|
48
|
+
return true;
|
|
35
49
|
}
|
|
36
50
|
} catch {}
|
|
37
51
|
return false;
|
|
@@ -40,15 +54,21 @@ export async function launchAttachInWindowsTerminal(sessionName) {
|
|
|
40
54
|
export function buildManualAttachCommand(sessionName) {
|
|
41
55
|
try {
|
|
42
56
|
const spec = resolveAttachCommand(sessionName);
|
|
43
|
-
return [spec.command, ...spec.args]
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
57
|
+
return [spec.command, ...spec.args]
|
|
58
|
+
.map((value) => {
|
|
59
|
+
const text = String(value);
|
|
60
|
+
return /\s/.test(text) ? `"${text.replace(/"/g, '\\"')}"` : text;
|
|
61
|
+
})
|
|
62
|
+
.join(" ");
|
|
47
63
|
} catch {
|
|
48
64
|
return `tmux attach-session -t ${sessionName}`;
|
|
49
65
|
}
|
|
50
66
|
}
|
|
51
67
|
|
|
52
68
|
export function wantsWtAttachFallback(args = [], env = process.env) {
|
|
53
|
-
return
|
|
69
|
+
return (
|
|
70
|
+
args.includes("--wt") ||
|
|
71
|
+
args.includes("--spawn-wt") ||
|
|
72
|
+
env.TFX_ATTACH_WT_AUTO === "1"
|
|
73
|
+
);
|
|
54
74
|
}
|
|
@@ -1,10 +1,20 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
3
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";
|
|
4
10
|
|
|
5
11
|
import { publishLeadControl as publishLeadControlBridge } from "../../lead-control.mjs";
|
|
6
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
getTeamStatus as fetchTeamStatus,
|
|
14
|
+
subscribeToLeadCommands as pullLeadCommands,
|
|
15
|
+
} from "../../session-sync.mjs";
|
|
7
16
|
import { HUB_PID_DIR, PKG_ROOT } from "./state-store.mjs";
|
|
17
|
+
|
|
8
18
|
export { nativeGetStatus } from "./native-control.mjs";
|
|
9
19
|
|
|
10
20
|
const HUB_PID_FILE = join(HUB_PID_DIR, "hub.pid");
|
|
@@ -67,7 +77,9 @@ export async function getHubInfo() {
|
|
|
67
77
|
...(status ? {} : { degraded: true }),
|
|
68
78
|
};
|
|
69
79
|
} catch {
|
|
70
|
-
try {
|
|
80
|
+
try {
|
|
81
|
+
unlinkSync(HUB_PID_FILE);
|
|
82
|
+
} catch {}
|
|
71
83
|
}
|
|
72
84
|
}
|
|
73
85
|
|
|
@@ -86,7 +98,10 @@ export async function getHubInfo() {
|
|
|
86
98
|
if (Number.isFinite(recovered.pid) && recovered.pid > 0) {
|
|
87
99
|
try {
|
|
88
100
|
mkdirSync(HUB_PID_DIR, { recursive: true });
|
|
89
|
-
writeFileSync(
|
|
101
|
+
writeFileSync(
|
|
102
|
+
HUB_PID_FILE,
|
|
103
|
+
JSON.stringify({ ...recovered, started: Date.now() }),
|
|
104
|
+
);
|
|
90
105
|
} catch {}
|
|
91
106
|
}
|
|
92
107
|
return recovered;
|
|
@@ -159,7 +174,9 @@ export async function ensureHubAlive(maxRetries = 3) {
|
|
|
159
174
|
}
|
|
160
175
|
}
|
|
161
176
|
|
|
162
|
-
const error = new Error(
|
|
177
|
+
const error = new Error(
|
|
178
|
+
`Hub 재시작 ${maxRetries}회 모두 실패${lastError ? `: ${lastError.message}` : ""}`,
|
|
179
|
+
);
|
|
163
180
|
error.code = "HUB_RESTART_FAILED";
|
|
164
181
|
error.cause = lastError;
|
|
165
182
|
throw error;
|
|
@@ -178,16 +195,24 @@ export async function fetchHubTaskList(state) {
|
|
|
178
195
|
signal: AbortSignal.timeout(2000),
|
|
179
196
|
});
|
|
180
197
|
const data = await res.json();
|
|
181
|
-
return data?.ok ?
|
|
198
|
+
return data?.ok ? data.data?.tasks || [] : [];
|
|
182
199
|
} catch {
|
|
183
200
|
return [];
|
|
184
201
|
}
|
|
185
202
|
}
|
|
186
203
|
|
|
187
|
-
export async function publishLeadControl(
|
|
204
|
+
export async function publishLeadControl(
|
|
205
|
+
state,
|
|
206
|
+
targetMember,
|
|
207
|
+
command,
|
|
208
|
+
reason = "",
|
|
209
|
+
) {
|
|
188
210
|
const hubBase = (state?.hubUrl || getDefaultHubUrl()).replace(/\/mcp$/, "");
|
|
189
|
-
const leadAgent =
|
|
190
|
-
|
|
211
|
+
const leadAgent =
|
|
212
|
+
(state?.members || []).find((member) => member.role === "lead")?.agentId ||
|
|
213
|
+
"lead";
|
|
214
|
+
const targetAgent =
|
|
215
|
+
typeof targetMember === "string" ? targetMember : targetMember?.agentId;
|
|
191
216
|
|
|
192
217
|
const result = await publishLeadControlBridge({
|
|
193
218
|
hubUrl: hubBase,
|
|
@@ -206,10 +231,13 @@ export async function publishLeadControl(state, targetMember, command, reason =
|
|
|
206
231
|
|
|
207
232
|
export async function subscribeToLeadCommands(state, member, options = {}) {
|
|
208
233
|
const hubBase = (state?.hubUrl || getDefaultHubUrl()).replace(/\/mcp$/, "");
|
|
209
|
-
const fallbackAgentId =
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
234
|
+
const fallbackAgentId =
|
|
235
|
+
(state?.members || []).find((candidate) => candidate.role === "lead")
|
|
236
|
+
?.agentId || null;
|
|
237
|
+
const agentId =
|
|
238
|
+
typeof member === "string"
|
|
239
|
+
? member
|
|
240
|
+
: member?.agentId || options?.agentId || fallbackAgentId;
|
|
213
241
|
|
|
214
242
|
return await pullLeadCommands({
|
|
215
243
|
hubUrl: hubBase,
|
|
@@ -2,9 +2,12 @@ export function resolveMember(state, selector) {
|
|
|
2
2
|
const members = state?.members || [];
|
|
3
3
|
if (!selector) return null;
|
|
4
4
|
|
|
5
|
-
const direct = members.find(
|
|
6
|
-
member
|
|
7
|
-
|
|
5
|
+
const direct = members.find(
|
|
6
|
+
(member) =>
|
|
7
|
+
member.name === selector ||
|
|
8
|
+
member.role === selector ||
|
|
9
|
+
member.agentId === selector,
|
|
10
|
+
);
|
|
8
11
|
if (direct) return direct;
|
|
9
12
|
|
|
10
13
|
const workerAlias = /^worker-(\d+)$/i.exec(selector);
|
|
@@ -16,7 +19,11 @@ export function resolveMember(state, selector) {
|
|
|
16
19
|
|
|
17
20
|
const numeric = parseInt(selector, 10);
|
|
18
21
|
if (!Number.isNaN(numeric)) {
|
|
19
|
-
const byPane = members.find(
|
|
22
|
+
const byPane = members.find(
|
|
23
|
+
(member) =>
|
|
24
|
+
member.pane?.endsWith(`.${numeric}`) ||
|
|
25
|
+
member.pane?.endsWith(`:${numeric}`),
|
|
26
|
+
);
|
|
20
27
|
if (byPane) return byPane;
|
|
21
28
|
if (numeric >= 1 && numeric <= members.length) return members[numeric - 1];
|
|
22
29
|
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
1
2
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
3
|
import { join } from "node:path";
|
|
3
|
-
import {
|
|
4
|
-
|
|
4
|
+
import { buildExecArgs } from "../../../codex-adapter.mjs";
|
|
5
5
|
import { buildLeadPrompt, buildPrompt } from "../../orchestrator.mjs";
|
|
6
6
|
import { HUB_PID_DIR, PKG_ROOT } from "./state-store.mjs";
|
|
7
7
|
|
|
8
|
-
import { buildExecArgs } from "../../../codex-adapter.mjs";
|
|
9
|
-
|
|
10
8
|
export function buildNativeCliCommand(cli) {
|
|
11
9
|
switch (cli) {
|
|
12
10
|
case "codex":
|
|
@@ -20,9 +18,19 @@ export function buildNativeCliCommand(cli) {
|
|
|
20
18
|
}
|
|
21
19
|
}
|
|
22
20
|
|
|
23
|
-
export async function startNativeSupervisor({
|
|
21
|
+
export async function startNativeSupervisor({
|
|
22
|
+
sessionId,
|
|
23
|
+
task,
|
|
24
|
+
lead,
|
|
25
|
+
agents,
|
|
26
|
+
subtasks,
|
|
27
|
+
hubUrl,
|
|
28
|
+
}) {
|
|
24
29
|
const configPath = join(HUB_PID_DIR, `team-native-${sessionId}.config.json`);
|
|
25
|
-
const runtimePath = join(
|
|
30
|
+
const runtimePath = join(
|
|
31
|
+
HUB_PID_DIR,
|
|
32
|
+
`team-native-${sessionId}.runtime.json`,
|
|
33
|
+
);
|
|
26
34
|
const logsDir = join(HUB_PID_DIR, "team-logs", sessionId);
|
|
27
35
|
mkdirSync(logsDir, { recursive: true });
|
|
28
36
|
|
|
@@ -57,25 +65,44 @@ export async function startNativeSupervisor({ sessionId, task, lead, agents, sub
|
|
|
57
65
|
},
|
|
58
66
|
...workers.map((worker) => ({
|
|
59
67
|
...worker,
|
|
60
|
-
prompt: buildPrompt(worker.subtask, {
|
|
68
|
+
prompt: buildPrompt(worker.subtask, {
|
|
69
|
+
cli: worker.cli,
|
|
70
|
+
agentId: worker.agentId,
|
|
71
|
+
hubUrl,
|
|
72
|
+
}),
|
|
61
73
|
})),
|
|
62
74
|
];
|
|
63
75
|
|
|
64
|
-
writeFileSync(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
76
|
+
writeFileSync(
|
|
77
|
+
configPath,
|
|
78
|
+
JSON.stringify(
|
|
79
|
+
{
|
|
80
|
+
sessionName: sessionId,
|
|
81
|
+
hubUrl,
|
|
82
|
+
startupDelayMs: 3000,
|
|
83
|
+
logsDir,
|
|
84
|
+
runtimeFile: runtimePath,
|
|
85
|
+
members,
|
|
86
|
+
},
|
|
87
|
+
null,
|
|
88
|
+
2,
|
|
89
|
+
) + "\n",
|
|
90
|
+
);
|
|
72
91
|
|
|
73
|
-
const child = spawn(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
92
|
+
const child = spawn(
|
|
93
|
+
process.execPath,
|
|
94
|
+
[
|
|
95
|
+
join(PKG_ROOT, "hub", "team", "native-supervisor.mjs"),
|
|
96
|
+
"--config",
|
|
97
|
+
configPath,
|
|
98
|
+
],
|
|
99
|
+
{
|
|
100
|
+
detached: true,
|
|
101
|
+
stdio: "ignore",
|
|
102
|
+
env: { ...process.env },
|
|
103
|
+
windowsHide: true,
|
|
104
|
+
},
|
|
105
|
+
);
|
|
79
106
|
child.unref();
|
|
80
107
|
|
|
81
108
|
const deadline = Date.now() + 5000;
|
|
@@ -22,7 +22,8 @@ export function normalizeTeammateMode(mode = "auto") {
|
|
|
22
22
|
export function normalizeLayout(layout = "2x2") {
|
|
23
23
|
const raw = String(layout).toLowerCase();
|
|
24
24
|
if (raw === "2x2" || raw === "grid") return "2x2";
|
|
25
|
-
if (raw === "1xn" || raw === "1x3" || raw === "vertical" || raw === "columns")
|
|
25
|
+
if (raw === "1xn" || raw === "1x3" || raw === "vertical" || raw === "columns")
|
|
26
|
+
return "1xN";
|
|
26
27
|
if (raw === "nx1" || raw === "horizontal" || raw === "rows") return "Nx1";
|
|
27
28
|
return "2x2";
|
|
28
29
|
}
|
|
@@ -1,13 +1,20 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import {
|
|
2
|
+
existsSync,
|
|
3
|
+
mkdirSync,
|
|
4
|
+
readFileSync,
|
|
5
|
+
unlinkSync,
|
|
6
|
+
writeFileSync,
|
|
7
|
+
} from "node:fs";
|
|
4
8
|
import { homedir } from "node:os";
|
|
9
|
+
import { dirname, join } from "node:path";
|
|
5
10
|
import { fileURLToPath } from "node:url";
|
|
6
11
|
|
|
7
12
|
export const PKG_ROOT = fileURLToPath(new URL("../../../../", import.meta.url));
|
|
8
13
|
export const HUB_PID_DIR = join(homedir(), ".claude", "cache", "tfx-hub");
|
|
9
14
|
export const TEAM_PROFILE = (() => {
|
|
10
|
-
const raw = String(process.env.TFX_TEAM_PROFILE || "team")
|
|
15
|
+
const raw = String(process.env.TFX_TEAM_PROFILE || "team")
|
|
16
|
+
.trim()
|
|
17
|
+
.toLowerCase();
|
|
11
18
|
return raw === "codex-team" ? "codex-team" : "team";
|
|
12
19
|
})();
|
|
13
20
|
|
|
@@ -15,21 +22,28 @@ export const SESSION_ID = process.env.CLAUDE_SESSION_ID || `s${Date.now()}`;
|
|
|
15
22
|
|
|
16
23
|
function getStatePath(sessionId) {
|
|
17
24
|
if (sessionId) return join(HUB_PID_DIR, `team-state-${sessionId}.json`);
|
|
18
|
-
return join(
|
|
25
|
+
return join(
|
|
26
|
+
HUB_PID_DIR,
|
|
27
|
+
TEAM_PROFILE === "codex-team"
|
|
28
|
+
? "team-state-codex-team.json"
|
|
29
|
+
: "team-state.json",
|
|
30
|
+
);
|
|
19
31
|
}
|
|
20
32
|
|
|
21
33
|
export function loadTeamState(sessionId) {
|
|
22
34
|
const resolvedId = sessionId || SESSION_ID;
|
|
23
35
|
const sessionPath = getStatePath(resolvedId);
|
|
24
36
|
try {
|
|
25
|
-
if (existsSync(sessionPath))
|
|
37
|
+
if (existsSync(sessionPath))
|
|
38
|
+
return JSON.parse(readFileSync(sessionPath, "utf8"));
|
|
26
39
|
} catch {
|
|
27
40
|
return null;
|
|
28
41
|
}
|
|
29
42
|
// 세션별 파일 없으면 기존 team-state.json fallback
|
|
30
43
|
const legacyPath = getStatePath(null);
|
|
31
44
|
try {
|
|
32
|
-
if (existsSync(legacyPath))
|
|
45
|
+
if (existsSync(legacyPath))
|
|
46
|
+
return JSON.parse(readFileSync(legacyPath, "utf8"));
|
|
33
47
|
} catch {
|
|
34
48
|
return null;
|
|
35
49
|
}
|
|
@@ -39,7 +53,10 @@ export function loadTeamState(sessionId) {
|
|
|
39
53
|
export function saveTeamState(state, sessionId) {
|
|
40
54
|
const path = getStatePath(sessionId || state.sessionId || SESSION_ID);
|
|
41
55
|
mkdirSync(dirname(path), { recursive: true });
|
|
42
|
-
writeFileSync(
|
|
56
|
+
writeFileSync(
|
|
57
|
+
path,
|
|
58
|
+
JSON.stringify({ ...state, profile: TEAM_PROFILE }, null, 2) + "\n",
|
|
59
|
+
);
|
|
43
60
|
}
|
|
44
61
|
|
|
45
62
|
export function clearTeamState(sessionId) {
|
|
@@ -10,21 +10,31 @@ export function buildTasks(subtasks, workers) {
|
|
|
10
10
|
|
|
11
11
|
export function normalizeTaskStatus(action) {
|
|
12
12
|
const value = String(action || "").toLowerCase();
|
|
13
|
-
if (value === "done" || value === "complete" || value === "completed")
|
|
14
|
-
|
|
13
|
+
if (value === "done" || value === "complete" || value === "completed")
|
|
14
|
+
return "completed";
|
|
15
|
+
if (
|
|
16
|
+
value === "progress" ||
|
|
17
|
+
value === "in-progress" ||
|
|
18
|
+
value === "in_progress"
|
|
19
|
+
)
|
|
20
|
+
return "in_progress";
|
|
15
21
|
if (value === "pending") return "pending";
|
|
16
22
|
return null;
|
|
17
23
|
}
|
|
18
24
|
|
|
19
25
|
export function updateTaskStatus(tasks = [], taskId, nextStatus) {
|
|
20
26
|
const normalizedId = String(taskId || "").toUpperCase();
|
|
21
|
-
const target = tasks.find(
|
|
27
|
+
const target = tasks.find(
|
|
28
|
+
(task) => String(task.id).toUpperCase() === normalizedId,
|
|
29
|
+
);
|
|
22
30
|
if (!target) return { tasks, target: null };
|
|
23
31
|
|
|
24
32
|
return {
|
|
25
33
|
target: { ...target, status: nextStatus },
|
|
26
|
-
tasks: tasks.map((task) =>
|
|
27
|
-
String(task.id).toUpperCase() === normalizedId
|
|
28
|
-
|
|
34
|
+
tasks: tasks.map((task) =>
|
|
35
|
+
String(task.id).toUpperCase() === normalizedId
|
|
36
|
+
? { ...task, status: nextStatus }
|
|
37
|
+
: task,
|
|
38
|
+
),
|
|
29
39
|
};
|
|
30
40
|
}
|
|
@@ -14,10 +14,7 @@ const BRIDGE_AGENT_ID = "conductor";
|
|
|
14
14
|
* @returns {object} Bridge API
|
|
15
15
|
*/
|
|
16
16
|
export function createConductorMeshBridge(conductor, registry, opts = {}) {
|
|
17
|
-
const {
|
|
18
|
-
bridgeAgentId = BRIDGE_AGENT_ID,
|
|
19
|
-
onMessage,
|
|
20
|
-
} = opts;
|
|
17
|
+
const { bridgeAgentId = BRIDGE_AGENT_ID, onMessage } = opts;
|
|
21
18
|
|
|
22
19
|
const sessionAgentMap = new Map();
|
|
23
20
|
let attached = false;
|
|
@@ -49,12 +46,13 @@ export function createConductorMeshBridge(conductor, registry, opts = {}) {
|
|
|
49
46
|
}
|
|
50
47
|
|
|
51
48
|
// Emit mesh event
|
|
52
|
-
const msg = createMessage(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
49
|
+
const msg = createMessage(MSG_TYPES.EVENT, bridgeAgentId, "*", {
|
|
50
|
+
event: "stateChange",
|
|
51
|
+
sessionId,
|
|
52
|
+
from,
|
|
53
|
+
to,
|
|
54
|
+
reason,
|
|
55
|
+
});
|
|
58
56
|
emit(msg);
|
|
59
57
|
|
|
60
58
|
// Unregister on terminal states
|
|
@@ -68,12 +66,10 @@ export function createConductorMeshBridge(conductor, registry, opts = {}) {
|
|
|
68
66
|
* Handle conductor completed events.
|
|
69
67
|
*/
|
|
70
68
|
function handleCompleted(event) {
|
|
71
|
-
const msg = createMessage(
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
{ event: "completed", sessionId: event.sessionId },
|
|
76
|
-
);
|
|
69
|
+
const msg = createMessage(MSG_TYPES.EVENT, bridgeAgentId, "*", {
|
|
70
|
+
event: "completed",
|
|
71
|
+
sessionId: event.sessionId,
|
|
72
|
+
});
|
|
77
73
|
emit(msg);
|
|
78
74
|
}
|
|
79
75
|
|
|
@@ -81,12 +77,11 @@ export function createConductorMeshBridge(conductor, registry, opts = {}) {
|
|
|
81
77
|
* Handle conductor dead events.
|
|
82
78
|
*/
|
|
83
79
|
function handleDead(event) {
|
|
84
|
-
const msg = createMessage(
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
);
|
|
80
|
+
const msg = createMessage(MSG_TYPES.EVENT, bridgeAgentId, "*", {
|
|
81
|
+
event: "dead",
|
|
82
|
+
sessionId: event.sessionId,
|
|
83
|
+
reason: event.reason,
|
|
84
|
+
});
|
|
90
85
|
emit(msg);
|
|
91
86
|
}
|
|
92
87
|
|
|
@@ -117,5 +112,11 @@ export function createConductorMeshBridge(conductor, registry, opts = {}) {
|
|
|
117
112
|
attached = false;
|
|
118
113
|
}
|
|
119
114
|
|
|
120
|
-
return {
|
|
115
|
+
return {
|
|
116
|
+
attach,
|
|
117
|
+
detach,
|
|
118
|
+
get isAttached() {
|
|
119
|
+
return attached;
|
|
120
|
+
},
|
|
121
|
+
};
|
|
121
122
|
}
|