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
|
@@ -9,9 +9,8 @@
|
|
|
9
9
|
|
|
10
10
|
import { execFileSync } from "node:child_process";
|
|
11
11
|
import { EventEmitter } from "node:events";
|
|
12
|
-
|
|
12
|
+
import { detectHostOs, shellQuoteForHost } from "../lib/ssh-command.mjs";
|
|
13
13
|
import { detectInputWait, PROBE_LEVELS } from "./health-probe.mjs";
|
|
14
|
-
import { shellQuoteForHost, detectHostOs } from "../lib/ssh-command.mjs";
|
|
15
14
|
|
|
16
15
|
export const REMOTE_WATCHER_STATES = Object.freeze({
|
|
17
16
|
WATCHING: "watching",
|
|
@@ -62,7 +61,10 @@ function freezeStatus(status) {
|
|
|
62
61
|
Object.fromEntries(
|
|
63
62
|
Object.entries(status.sessions || {})
|
|
64
63
|
.sort(([left], [right]) => left.localeCompare(right))
|
|
65
|
-
.map(([sessionName, record]) => [
|
|
64
|
+
.map(([sessionName, record]) => [
|
|
65
|
+
sessionName,
|
|
66
|
+
freezeSessionRecord(record),
|
|
67
|
+
]),
|
|
66
68
|
),
|
|
67
69
|
);
|
|
68
70
|
|
|
@@ -117,7 +119,9 @@ function hasMeaningfulActivity(captured) {
|
|
|
117
119
|
}
|
|
118
120
|
|
|
119
121
|
function detectCompletion(captured) {
|
|
120
|
-
const matches = Array.from(
|
|
122
|
+
const matches = Array.from(
|
|
123
|
+
String(captured || "").matchAll(COMPLETION_TOKEN_RE),
|
|
124
|
+
);
|
|
121
125
|
const match = matches.at(-1);
|
|
122
126
|
if (!match) {
|
|
123
127
|
return {
|
|
@@ -128,7 +132,8 @@ function detectCompletion(captured) {
|
|
|
128
132
|
};
|
|
129
133
|
}
|
|
130
134
|
|
|
131
|
-
const parsedExitCode =
|
|
135
|
+
const parsedExitCode =
|
|
136
|
+
match[2] == null ? null : Number.parseInt(match[2], 10);
|
|
132
137
|
return {
|
|
133
138
|
detected: true,
|
|
134
139
|
exitCode: Number.isFinite(parsedExitCode) ? parsedExitCode : null,
|
|
@@ -143,7 +148,10 @@ function parseSessionNames(rawOutput, sessionPrefix) {
|
|
|
143
148
|
.map((line) => line.trim())
|
|
144
149
|
.filter(Boolean)
|
|
145
150
|
.map((line) => line.split(":")[0]?.trim())
|
|
146
|
-
.filter(
|
|
151
|
+
.filter(
|
|
152
|
+
(sessionName) =>
|
|
153
|
+
Boolean(sessionName) && sessionName.startsWith(sessionPrefix),
|
|
154
|
+
);
|
|
147
155
|
}
|
|
148
156
|
|
|
149
157
|
function buildExecOptions(config) {
|
|
@@ -187,7 +195,9 @@ function captureSpawnSession(sessionName, config) {
|
|
|
187
195
|
);
|
|
188
196
|
return {
|
|
189
197
|
paneTarget,
|
|
190
|
-
captured: String(output || "")
|
|
198
|
+
captured: String(output || "")
|
|
199
|
+
.replace(/\r/g, "")
|
|
200
|
+
.trimEnd(),
|
|
191
201
|
};
|
|
192
202
|
}
|
|
193
203
|
|
|
@@ -221,7 +231,10 @@ function createSessionRecord(sessionName, config, now) {
|
|
|
221
231
|
}
|
|
222
232
|
|
|
223
233
|
function isTerminalState(state) {
|
|
224
|
-
return
|
|
234
|
+
return (
|
|
235
|
+
state === REMOTE_WATCHER_STATES.COMPLETED ||
|
|
236
|
+
state === REMOTE_WATCHER_STATES.FAILED
|
|
237
|
+
);
|
|
225
238
|
}
|
|
226
239
|
|
|
227
240
|
export function createRemoteWatcher(opts = {}) {
|
|
@@ -252,26 +265,30 @@ export function createRemoteWatcher(opts = {}) {
|
|
|
252
265
|
}
|
|
253
266
|
|
|
254
267
|
function emitSessionEvent(eventName, nextRecord, now) {
|
|
255
|
-
emitter.emit(
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
+
emitter.emit(
|
|
269
|
+
eventName,
|
|
270
|
+
Object.freeze({
|
|
271
|
+
exitCode: nextRecord.exitCode,
|
|
272
|
+
host: nextRecord.host,
|
|
273
|
+
inputWaitPattern: nextRecord.inputWaitPattern,
|
|
274
|
+
output: nextRecord.lastOutput,
|
|
275
|
+
paneTarget: nextRecord.paneTarget,
|
|
276
|
+
probeLevel: nextRecord.lastProbeLevel,
|
|
277
|
+
promptIdlePattern: nextRecord.promptIdlePattern,
|
|
278
|
+
reason: nextRecord.reason,
|
|
279
|
+
sessionName: nextRecord.sessionName,
|
|
280
|
+
state: nextRecord.state,
|
|
281
|
+
ts: now,
|
|
282
|
+
}),
|
|
283
|
+
);
|
|
268
284
|
}
|
|
269
285
|
|
|
270
286
|
function classifySession(previousRecord, captured, now) {
|
|
271
287
|
const completion = detectCompletion(captured);
|
|
272
288
|
const inputWait = detectInputWait(captured);
|
|
273
289
|
const promptIdle = detectPromptIdle(captured);
|
|
274
|
-
const hasActivity =
|
|
290
|
+
const hasActivity =
|
|
291
|
+
previousRecord.hasActivity || hasMeaningfulActivity(captured);
|
|
275
292
|
|
|
276
293
|
let nextState = REMOTE_WATCHER_STATES.WATCHING;
|
|
277
294
|
let reason = "watching";
|
|
@@ -292,9 +309,9 @@ export function createRemoteWatcher(opts = {}) {
|
|
|
292
309
|
eventName = "sessionCompleted";
|
|
293
310
|
}
|
|
294
311
|
} else if (
|
|
295
|
-
promptIdle.detected
|
|
296
|
-
&&
|
|
297
|
-
|
|
312
|
+
promptIdle.detected &&
|
|
313
|
+
hasActivity &&
|
|
314
|
+
(!inputWait.detected || inputWait.pattern === BARE_INPUT_WAIT_PATTERN)
|
|
298
315
|
) {
|
|
299
316
|
nextState = REMOTE_WATCHER_STATES.COMPLETED;
|
|
300
317
|
reason = "prompt_idle";
|
|
@@ -325,10 +342,10 @@ export function createRemoteWatcher(opts = {}) {
|
|
|
325
342
|
};
|
|
326
343
|
|
|
327
344
|
if (
|
|
328
|
-
eventName
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
345
|
+
eventName &&
|
|
346
|
+
previousRecord.state === nextRecord.state &&
|
|
347
|
+
previousRecord.reason === nextRecord.reason &&
|
|
348
|
+
previousRecord.exitCode === nextRecord.exitCode
|
|
332
349
|
) {
|
|
333
350
|
return { eventName: null, nextRecord };
|
|
334
351
|
}
|
|
@@ -375,7 +392,10 @@ export function createRemoteWatcher(opts = {}) {
|
|
|
375
392
|
: createSessionRecord(sessionName, config, now);
|
|
376
393
|
|
|
377
394
|
try {
|
|
378
|
-
const { paneTarget, captured } = captureSpawnSession(
|
|
395
|
+
const { paneTarget, captured } = captureSpawnSession(
|
|
396
|
+
sessionName,
|
|
397
|
+
config,
|
|
398
|
+
);
|
|
379
399
|
const { eventName, nextRecord } = classifySession(
|
|
380
400
|
{ ...previousRecord, paneTarget },
|
|
381
401
|
captured,
|
|
@@ -396,7 +416,10 @@ export function createRemoteWatcher(opts = {}) {
|
|
|
396
416
|
state: REMOTE_WATCHER_STATES.FAILED,
|
|
397
417
|
};
|
|
398
418
|
nextSessions[sessionName] = failedRecord;
|
|
399
|
-
queuedEvents.push({
|
|
419
|
+
queuedEvents.push({
|
|
420
|
+
eventName: "sessionFailed",
|
|
421
|
+
record: failedRecord,
|
|
422
|
+
});
|
|
400
423
|
setStatus({
|
|
401
424
|
...status,
|
|
402
425
|
lastError: toErrorRecord(error),
|
|
@@ -407,9 +430,14 @@ export function createRemoteWatcher(opts = {}) {
|
|
|
407
430
|
}
|
|
408
431
|
}
|
|
409
432
|
|
|
410
|
-
for (const [sessionName, previousRecord] of Object.entries(
|
|
433
|
+
for (const [sessionName, previousRecord] of Object.entries(
|
|
434
|
+
status.sessions,
|
|
435
|
+
)) {
|
|
411
436
|
if (activeSet.has(sessionName)) continue;
|
|
412
|
-
const { eventName, nextRecord } = markMissingSession(
|
|
437
|
+
const { eventName, nextRecord } = markMissingSession(
|
|
438
|
+
previousRecord,
|
|
439
|
+
now,
|
|
440
|
+
);
|
|
413
441
|
nextSessions[sessionName] = nextRecord;
|
|
414
442
|
if (eventName) {
|
|
415
443
|
queuedEvents.push({ eventName, record: nextRecord });
|
package/hub/team/routing.mjs
CHANGED
|
@@ -15,31 +15,55 @@
|
|
|
15
15
|
export function resolveRoutingStrategy({ subtasks, graph_type, thorough }) {
|
|
16
16
|
const N = subtasks.length;
|
|
17
17
|
if (N === 0) {
|
|
18
|
-
const dagContext = {
|
|
19
|
-
|
|
18
|
+
const dagContext = {
|
|
19
|
+
dag_width: 0,
|
|
20
|
+
levels: {},
|
|
21
|
+
edges: [],
|
|
22
|
+
max_complexity: "S",
|
|
23
|
+
taskResults: {},
|
|
24
|
+
};
|
|
25
|
+
return {
|
|
26
|
+
strategy: "quick_single",
|
|
27
|
+
reason: "empty_subtasks",
|
|
28
|
+
dag_width: 0,
|
|
29
|
+
max_complexity: "S",
|
|
30
|
+
dagContext,
|
|
31
|
+
};
|
|
20
32
|
}
|
|
21
33
|
|
|
22
|
-
const {
|
|
34
|
+
const {
|
|
35
|
+
width: dag_width,
|
|
36
|
+
levels,
|
|
37
|
+
edges,
|
|
38
|
+
} = computeDagInfo(subtasks, graph_type);
|
|
23
39
|
const max_complexity = getMaxComplexity(subtasks);
|
|
24
|
-
const dagContext = {
|
|
25
|
-
|
|
40
|
+
const dagContext = {
|
|
41
|
+
dag_width,
|
|
42
|
+
levels,
|
|
43
|
+
edges,
|
|
44
|
+
max_complexity,
|
|
45
|
+
taskResults: {},
|
|
46
|
+
};
|
|
47
|
+
const isHighComplexity = ["L", "XL"].includes(max_complexity);
|
|
26
48
|
const allSameAgent = new Set(subtasks.map((s) => s.agent)).size === 1;
|
|
27
|
-
const allSmall = subtasks.every(
|
|
49
|
+
const allSmall = subtasks.every(
|
|
50
|
+
(s) => normalizeComplexity(s.complexity) === "S",
|
|
51
|
+
);
|
|
28
52
|
|
|
29
53
|
// N==1: λ¨μΌ νμ€ν¬
|
|
30
54
|
if (N === 1) {
|
|
31
55
|
if (thorough || isHighComplexity) {
|
|
32
56
|
return {
|
|
33
|
-
strategy:
|
|
34
|
-
reason:
|
|
57
|
+
strategy: "thorough_single",
|
|
58
|
+
reason: "single_high_complexity",
|
|
35
59
|
dag_width,
|
|
36
60
|
max_complexity,
|
|
37
61
|
dagContext,
|
|
38
62
|
};
|
|
39
63
|
}
|
|
40
64
|
return {
|
|
41
|
-
strategy:
|
|
42
|
-
reason:
|
|
65
|
+
strategy: "quick_single",
|
|
66
|
+
reason: "single_low_complexity",
|
|
43
67
|
dag_width,
|
|
44
68
|
max_complexity,
|
|
45
69
|
dagContext,
|
|
@@ -50,16 +74,16 @@ export function resolveRoutingStrategy({ subtasks, graph_type, thorough }) {
|
|
|
50
74
|
if (dag_width === 1) {
|
|
51
75
|
if (thorough || isHighComplexity) {
|
|
52
76
|
return {
|
|
53
|
-
strategy:
|
|
54
|
-
reason:
|
|
77
|
+
strategy: "thorough_single",
|
|
78
|
+
reason: "sequential_chain",
|
|
55
79
|
dag_width,
|
|
56
80
|
max_complexity,
|
|
57
81
|
dagContext,
|
|
58
82
|
};
|
|
59
83
|
}
|
|
60
84
|
return {
|
|
61
|
-
strategy:
|
|
62
|
-
reason:
|
|
85
|
+
strategy: "quick_single",
|
|
86
|
+
reason: "sequential_chain",
|
|
63
87
|
dag_width,
|
|
64
88
|
max_complexity,
|
|
65
89
|
dagContext,
|
|
@@ -69,8 +93,8 @@ export function resolveRoutingStrategy({ subtasks, graph_type, thorough }) {
|
|
|
69
93
|
// λμΌ μμ΄μ νΈ + λͺ¨λ S: ν둬ννΈ λ³ν© -> batch single
|
|
70
94
|
if (allSameAgent && allSmall) {
|
|
71
95
|
return {
|
|
72
|
-
strategy:
|
|
73
|
-
reason:
|
|
96
|
+
strategy: "batch_single",
|
|
97
|
+
reason: "same_agent_small_batch",
|
|
74
98
|
dag_width,
|
|
75
99
|
max_complexity,
|
|
76
100
|
dagContext,
|
|
@@ -80,16 +104,16 @@ export function resolveRoutingStrategy({ subtasks, graph_type, thorough }) {
|
|
|
80
104
|
// dag_width >= 2: ν
|
|
81
105
|
if (thorough || isHighComplexity) {
|
|
82
106
|
return {
|
|
83
|
-
strategy:
|
|
84
|
-
reason:
|
|
107
|
+
strategy: "thorough_team",
|
|
108
|
+
reason: "parallel_high_complexity",
|
|
85
109
|
dag_width,
|
|
86
110
|
max_complexity,
|
|
87
111
|
dagContext,
|
|
88
112
|
};
|
|
89
113
|
}
|
|
90
114
|
return {
|
|
91
|
-
strategy:
|
|
92
|
-
reason:
|
|
115
|
+
strategy: "quick_team",
|
|
116
|
+
reason: "parallel_low_complexity",
|
|
93
117
|
dag_width,
|
|
94
118
|
max_complexity,
|
|
95
119
|
dagContext,
|
|
@@ -103,7 +127,7 @@ export function resolveRoutingStrategy({ subtasks, graph_type, thorough }) {
|
|
|
103
127
|
* @returns {{ width: number, levels: Record<number, string[]>, edges: Array<{from:string, to:string}> }}
|
|
104
128
|
*/
|
|
105
129
|
function computeDagInfo(subtasks, graph_type) {
|
|
106
|
-
if (graph_type ===
|
|
130
|
+
if (graph_type === "SEQUENTIAL") {
|
|
107
131
|
const levels = {};
|
|
108
132
|
const edges = [];
|
|
109
133
|
subtasks.forEach((t, i) => {
|
|
@@ -112,7 +136,7 @@ function computeDagInfo(subtasks, graph_type) {
|
|
|
112
136
|
});
|
|
113
137
|
return { width: 1, levels, edges };
|
|
114
138
|
}
|
|
115
|
-
if (graph_type ===
|
|
139
|
+
if (graph_type === "INDEPENDENT") {
|
|
116
140
|
const levels = { 0: subtasks.map((t) => t.id) };
|
|
117
141
|
return { width: subtasks.length, levels, edges: [] };
|
|
118
142
|
}
|
|
@@ -173,7 +197,9 @@ function computeDagInfo(subtasks, graph_type) {
|
|
|
173
197
|
export function getUpstreamResults(taskId, pipelineState) {
|
|
174
198
|
const ctx = pipelineState?.dagContext;
|
|
175
199
|
if (!ctx) return {};
|
|
176
|
-
const upstreamIds = ctx.edges
|
|
200
|
+
const upstreamIds = ctx.edges
|
|
201
|
+
.filter((e) => e.to === taskId)
|
|
202
|
+
.map((e) => e.from);
|
|
177
203
|
const results = {};
|
|
178
204
|
for (const id of upstreamIds) {
|
|
179
205
|
if (id in (ctx.taskResults || {})) {
|
|
@@ -205,7 +231,7 @@ export function updateTaskResult(taskId, result, pipelineState) {
|
|
|
205
231
|
*/
|
|
206
232
|
function getMaxComplexity(subtasks) {
|
|
207
233
|
const order = { S: 0, M: 1, L: 2, XL: 3 };
|
|
208
|
-
let max =
|
|
234
|
+
let max = "S";
|
|
209
235
|
for (const s of subtasks) {
|
|
210
236
|
const complexity = normalizeComplexity(s.complexity);
|
|
211
237
|
if (order[complexity] > order[max]) max = complexity;
|
|
@@ -219,5 +245,5 @@ function getMaxComplexity(subtasks) {
|
|
|
219
245
|
* @returns {"S" | "M" | "L" | "XL"}
|
|
220
246
|
*/
|
|
221
247
|
function normalizeComplexity(complexity) {
|
|
222
|
-
return [
|
|
248
|
+
return ["S", "M", "L", "XL"].includes(complexity) ? complexity : "M";
|
|
223
249
|
}
|
|
@@ -60,7 +60,9 @@ export function createPsmuxRuntime(adapter = defaultPsmuxAdapter) {
|
|
|
60
60
|
* @returns {TeamRuntime & { name: string }}
|
|
61
61
|
*/
|
|
62
62
|
export function createRuntime(mode) {
|
|
63
|
-
const normalizedMode = String(mode || "")
|
|
63
|
+
const normalizedMode = String(mode || "")
|
|
64
|
+
.trim()
|
|
65
|
+
.toLowerCase();
|
|
64
66
|
|
|
65
67
|
if (normalizedMode === "psmux") {
|
|
66
68
|
return createPsmuxRuntime();
|
package/hub/team/session.mjs
CHANGED
|
@@ -22,7 +22,11 @@ const GIT_BASH_CANDIDATES = [
|
|
|
22
22
|
function findGitBashExe() {
|
|
23
23
|
for (const p of GIT_BASH_CANDIDATES) {
|
|
24
24
|
try {
|
|
25
|
-
execSync(`"${p}" --version`, {
|
|
25
|
+
execSync(`"${p}" --version`, {
|
|
26
|
+
stdio: "ignore",
|
|
27
|
+
timeout: 3000,
|
|
28
|
+
windowsHide: true,
|
|
29
|
+
});
|
|
26
30
|
return p;
|
|
27
31
|
} catch {
|
|
28
32
|
// λ€μ ν보
|
|
@@ -35,7 +39,11 @@ function findGitBashExe() {
|
|
|
35
39
|
export function hasWindowsTerminal() {
|
|
36
40
|
if (process.platform !== "win32") return false;
|
|
37
41
|
try {
|
|
38
|
-
execSync("where wt.exe", {
|
|
42
|
+
execSync("where wt.exe", {
|
|
43
|
+
stdio: "ignore",
|
|
44
|
+
timeout: 3000,
|
|
45
|
+
windowsHide: true,
|
|
46
|
+
});
|
|
39
47
|
return true;
|
|
40
48
|
} catch {
|
|
41
49
|
return false;
|
|
@@ -60,7 +68,11 @@ function hasTmux() {
|
|
|
60
68
|
/** WSL2 λ΄ tmux μ¬μ© κ°λ₯ μ¬λΆ (Windows μ μ©) */
|
|
61
69
|
function hasWslTmux() {
|
|
62
70
|
try {
|
|
63
|
-
execSync("wsl tmux -V", {
|
|
71
|
+
execSync("wsl tmux -V", {
|
|
72
|
+
stdio: "ignore",
|
|
73
|
+
timeout: 5000,
|
|
74
|
+
windowsHide: true,
|
|
75
|
+
});
|
|
64
76
|
return true;
|
|
65
77
|
} catch {
|
|
66
78
|
return false;
|
|
@@ -91,10 +103,22 @@ function hasGitBashTmux() {
|
|
|
91
103
|
let _cachedMux;
|
|
92
104
|
export function detectMultiplexer() {
|
|
93
105
|
if (_cachedMux !== undefined) return _cachedMux;
|
|
94
|
-
if (hasPsmux()) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
106
|
+
if (hasPsmux()) {
|
|
107
|
+
_cachedMux = "psmux";
|
|
108
|
+
return _cachedMux;
|
|
109
|
+
}
|
|
110
|
+
if (hasTmux()) {
|
|
111
|
+
_cachedMux = "tmux";
|
|
112
|
+
return _cachedMux;
|
|
113
|
+
}
|
|
114
|
+
if (process.platform === "win32" && hasGitBashTmux()) {
|
|
115
|
+
_cachedMux = "git-bash-tmux";
|
|
116
|
+
return _cachedMux;
|
|
117
|
+
}
|
|
118
|
+
if (process.platform === "win32" && hasWslTmux()) {
|
|
119
|
+
_cachedMux = "wsl-tmux";
|
|
120
|
+
return _cachedMux;
|
|
121
|
+
}
|
|
98
122
|
_cachedMux = null;
|
|
99
123
|
return _cachedMux;
|
|
100
124
|
}
|
|
@@ -110,15 +134,15 @@ function tmux(args, opts = {}) {
|
|
|
110
134
|
if (!mux) {
|
|
111
135
|
throw new Error(
|
|
112
136
|
"tmux/psmux λ―Έλ°κ²¬.\n\n" +
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
137
|
+
"tfx multiμ tmux κ³μ΄ λ©ν°νλ μκ° νμν©λλ€:\n" +
|
|
138
|
+
" Windows: psmux μ€μΉ λλ WSL2 tmux μ¬μ©\n" +
|
|
139
|
+
" WSL2: wsl sudo apt install tmux\n" +
|
|
140
|
+
" macOS: brew install tmux\n" +
|
|
141
|
+
" Linux: apt install tmux\n\n" +
|
|
142
|
+
"Windowsμμλ WSL2λ₯Ό κΆμ₯ν©λλ€:\n" +
|
|
143
|
+
" 1. wsl --install\n" +
|
|
144
|
+
" 2. wsl sudo apt install tmux\n" +
|
|
145
|
+
' 3. tfx multi "μμ
" (μλμΌλ‘ WSL tmux μ¬μ©)',
|
|
122
146
|
);
|
|
123
147
|
}
|
|
124
148
|
if (mux === "psmux") {
|
|
@@ -272,7 +296,17 @@ export function createWtSession(sessionName, opts = {}) {
|
|
|
272
296
|
const cwd = pane.cwd || process.cwd();
|
|
273
297
|
if (!command) continue;
|
|
274
298
|
|
|
275
|
-
wt([
|
|
299
|
+
wt([
|
|
300
|
+
"-w",
|
|
301
|
+
"0",
|
|
302
|
+
"sp",
|
|
303
|
+
splitFlag,
|
|
304
|
+
"--title",
|
|
305
|
+
title,
|
|
306
|
+
"-d",
|
|
307
|
+
cwd,
|
|
308
|
+
...buildWtCmdArgs(command),
|
|
309
|
+
]);
|
|
276
310
|
panes.push(`wt:${i}`);
|
|
277
311
|
titles.push(title);
|
|
278
312
|
}
|
|
@@ -305,7 +339,11 @@ export function focusWtPane(paneIndex, opts = {}) {
|
|
|
305
339
|
|
|
306
340
|
// μ΅μ»€λ‘ μ΅λν 볡κ·
|
|
307
341
|
for (let i = 0; i < 10; i++) {
|
|
308
|
-
try {
|
|
342
|
+
try {
|
|
343
|
+
wt(["-w", "0", "move-focus", backDir]);
|
|
344
|
+
} catch {
|
|
345
|
+
break;
|
|
346
|
+
}
|
|
309
347
|
}
|
|
310
348
|
|
|
311
349
|
for (let i = 0; i <= idx; i++) {
|
|
@@ -334,7 +372,11 @@ export function closeWtSession(opts = {}) {
|
|
|
334
372
|
|
|
335
373
|
// μ΅μ»€(μλ tfx μ€ν pane)λ‘ μ΅λν 볡κ·
|
|
336
374
|
for (let i = 0; i < 10; i++) {
|
|
337
|
-
try {
|
|
375
|
+
try {
|
|
376
|
+
wt(["-w", "0", "move-focus", backDir]);
|
|
377
|
+
} catch {
|
|
378
|
+
break;
|
|
379
|
+
}
|
|
338
380
|
}
|
|
339
381
|
|
|
340
382
|
for (let i = 0; i < paneCount; i++) {
|
|
@@ -424,7 +466,9 @@ export function focusPane(target, opts = {}) {
|
|
|
424
466
|
const { zoom = false } = opts;
|
|
425
467
|
tmux(`select-pane -t ${target}`);
|
|
426
468
|
if (zoom) {
|
|
427
|
-
try {
|
|
469
|
+
try {
|
|
470
|
+
tmux(`resize-pane -t ${target} -Z`);
|
|
471
|
+
} catch {}
|
|
428
472
|
}
|
|
429
473
|
}
|
|
430
474
|
|
|
@@ -461,29 +505,49 @@ export function configureTeammateKeybindings(sessionName, opts = {}) {
|
|
|
461
505
|
|
|
462
506
|
if (inProcess) {
|
|
463
507
|
// λ¨μΌ λ·°(zoom) μνμμ νλ©μ΄νΈ μν
|
|
464
|
-
tmux(
|
|
465
|
-
|
|
508
|
+
tmux(
|
|
509
|
+
`bind-key -T root -n S-Down if-shell -F '${cond}' ${bindNext} 'send-keys S-Down'`,
|
|
510
|
+
);
|
|
511
|
+
tmux(
|
|
512
|
+
`bind-key -T root -n S-Up if-shell -F '${cond}' ${bindPrev} 'send-keys S-Up'`,
|
|
513
|
+
);
|
|
466
514
|
} else {
|
|
467
515
|
// λΆν λ·°μμ νλ©μ΄νΈ μν
|
|
468
|
-
tmux(
|
|
469
|
-
|
|
516
|
+
tmux(
|
|
517
|
+
`bind-key -T root -n S-Down if-shell -F '${cond}' ${bindNext} 'send-keys S-Down'`,
|
|
518
|
+
);
|
|
519
|
+
tmux(
|
|
520
|
+
`bind-key -T root -n S-Up if-shell -F '${cond}' ${bindPrev} 'send-keys S-Up'`,
|
|
521
|
+
);
|
|
470
522
|
}
|
|
471
523
|
|
|
472
524
|
// λ체 ν€: μΌλΆ νκ²½μμ S-Upμ΄ λλ½λ λ μ¬μ©
|
|
473
|
-
tmux(
|
|
474
|
-
|
|
475
|
-
|
|
525
|
+
tmux(
|
|
526
|
+
`bind-key -T root -n S-Right if-shell -F '${cond}' ${bindNext} 'send-keys S-Right'`,
|
|
527
|
+
);
|
|
528
|
+
tmux(
|
|
529
|
+
`bind-key -T root -n S-Left if-shell -F '${cond}' ${bindPrev} 'send-keys S-Left'`,
|
|
530
|
+
);
|
|
531
|
+
tmux(
|
|
532
|
+
`bind-key -T root -n BTab if-shell -F '${cond}' ${bindPrev} 'send-keys BTab'`,
|
|
533
|
+
);
|
|
476
534
|
|
|
477
535
|
// νμ¬ νμ± pane μΈν°λ½νΈ
|
|
478
|
-
tmux(
|
|
536
|
+
tmux(
|
|
537
|
+
`bind-key -T root -n Escape if-shell -F '${cond}' 'send-keys C-c' 'send-keys Escape'`,
|
|
538
|
+
);
|
|
479
539
|
|
|
480
540
|
// νμ€ν¬ λͺ©λ‘ ν κΈ (tmux 3.2+ popup μ°μ , μ€ν¨ μ μλ΄ λ©μμ§)
|
|
481
541
|
if (taskListCommand) {
|
|
482
542
|
const escaped = taskListCommand.replace(/'/g, "'\\''");
|
|
483
543
|
try {
|
|
484
|
-
tmux(
|
|
544
|
+
tmux(
|
|
545
|
+
`bind-key -T root -n C-t if-shell -F '${cond}' "display-popup -E '${escaped}'" "send-keys C-t"`,
|
|
546
|
+
);
|
|
485
547
|
} catch {
|
|
486
|
-
tmux(
|
|
548
|
+
tmux(
|
|
549
|
+
`bind-key -T root -n C-t if-shell -F '${cond}' 'display-message "tfx multi tasks λͺ
λ ΉμΌλ‘ νμ€ν¬ νμΈ"' 'send-keys C-t'`,
|
|
550
|
+
);
|
|
487
551
|
}
|
|
488
552
|
}
|
|
489
553
|
}
|
|
@@ -558,9 +622,7 @@ export function listSessions() {
|
|
|
558
622
|
|
|
559
623
|
try {
|
|
560
624
|
const output = tmux('list-sessions -F "#{session_name}"');
|
|
561
|
-
return output
|
|
562
|
-
.split("\n")
|
|
563
|
-
.filter((s) => s.startsWith("tfx-multi-"));
|
|
625
|
+
return output.split("\n").filter((s) => s.startsWith("tfx-multi-"));
|
|
564
626
|
} catch {
|
|
565
627
|
return [];
|
|
566
628
|
}
|
|
@@ -577,7 +639,9 @@ export function getSessionAttachedCount(sessionName) {
|
|
|
577
639
|
}
|
|
578
640
|
|
|
579
641
|
try {
|
|
580
|
-
const output = tmux(
|
|
642
|
+
const output = tmux(
|
|
643
|
+
'list-sessions -F "#{session_name} #{session_attached}"',
|
|
644
|
+
);
|
|
581
645
|
const line = output
|
|
582
646
|
.split("\n")
|
|
583
647
|
.find((l) => l.startsWith(`${sessionName} `));
|