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
package/tui/doctor.mjs
CHANGED
|
@@ -1,15 +1,32 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// tui/doctor.mjs — Interactive triflux doctor TUI
|
|
3
3
|
import { execFileSync } from "node:child_process";
|
|
4
|
-
import { existsSync, readFileSync, unlinkSync
|
|
5
|
-
import { join, dirname } from "node:path";
|
|
4
|
+
import { existsSync, readdirSync, readFileSync, unlinkSync } from "node:fs";
|
|
6
5
|
import { homedir } from "node:os";
|
|
6
|
+
import { dirname, join } from "node:path";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
8
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
BOLD,
|
|
10
|
+
box,
|
|
11
|
+
clear,
|
|
12
|
+
confirm,
|
|
13
|
+
DIM,
|
|
14
|
+
divider,
|
|
15
|
+
fail,
|
|
16
|
+
GRAY,
|
|
17
|
+
GREEN,
|
|
18
|
+
info,
|
|
19
|
+
label,
|
|
20
|
+
ok,
|
|
21
|
+
onExit,
|
|
22
|
+
RED,
|
|
23
|
+
RESET,
|
|
24
|
+
select,
|
|
25
|
+
showCursor,
|
|
26
|
+
spinner,
|
|
27
|
+
table,
|
|
28
|
+
warn,
|
|
29
|
+
YELLOW,
|
|
13
30
|
} from "./core.mjs";
|
|
14
31
|
|
|
15
32
|
const PKG_ROOT = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
@@ -75,8 +92,12 @@ function showReport(report) {
|
|
|
75
92
|
}
|
|
76
93
|
|
|
77
94
|
console.log();
|
|
78
|
-
const statusColor =
|
|
79
|
-
|
|
95
|
+
const statusColor =
|
|
96
|
+
report.issue_count === 0 ? GREEN : report.issue_count <= 2 ? YELLOW : RED;
|
|
97
|
+
label(
|
|
98
|
+
"상태",
|
|
99
|
+
`${statusColor}${report.issue_count === 0 ? "정상" : `${report.issue_count}개 이슈`}${RESET}`,
|
|
100
|
+
);
|
|
80
101
|
label("모드", report.mode);
|
|
81
102
|
console.log();
|
|
82
103
|
|
|
@@ -84,12 +105,17 @@ function showReport(report) {
|
|
|
84
105
|
const rows = (report.checks || []).map((c) => {
|
|
85
106
|
let note = "";
|
|
86
107
|
if (c.version) note = `v${c.version}`;
|
|
87
|
-
if (c.missing_profiles?.length)
|
|
108
|
+
if (c.missing_profiles?.length)
|
|
109
|
+
note = `누락: ${c.missing_profiles.join(", ")}`;
|
|
88
110
|
if (c.fix) note += note ? ` → ${c.fix}` : c.fix;
|
|
89
111
|
if (c.path && !c.fix) note = c.path;
|
|
90
112
|
|
|
91
|
-
const icon =
|
|
92
|
-
|
|
113
|
+
const icon =
|
|
114
|
+
c.status === "ok"
|
|
115
|
+
? statusIcon("ok")
|
|
116
|
+
: c.optional
|
|
117
|
+
? statusIcon("optional_missing")
|
|
118
|
+
: statusIcon(c.status);
|
|
93
119
|
|
|
94
120
|
return [
|
|
95
121
|
`${icon} ${c.name}`,
|
|
@@ -105,8 +131,11 @@ function showReport(report) {
|
|
|
105
131
|
console.log();
|
|
106
132
|
info(`수행된 작업: ${report.actions.length}개`);
|
|
107
133
|
for (const action of report.actions) {
|
|
108
|
-
const icon =
|
|
109
|
-
|
|
134
|
+
const icon =
|
|
135
|
+
action.status === "ok" ? `${GREEN}✓${RESET}` : `${RED}✗${RESET}`;
|
|
136
|
+
console.log(
|
|
137
|
+
` ${icon} ${action.type}: ${action.name || action.path || ""}`,
|
|
138
|
+
);
|
|
110
139
|
}
|
|
111
140
|
}
|
|
112
141
|
}
|
|
@@ -119,12 +148,16 @@ function getCacheStatus() {
|
|
|
119
148
|
const fp = join(CACHE_DIR, name);
|
|
120
149
|
if (existsSync(fp)) {
|
|
121
150
|
let size = 0;
|
|
122
|
-
try {
|
|
151
|
+
try {
|
|
152
|
+
size = readFileSync(fp).length;
|
|
153
|
+
} catch {}
|
|
123
154
|
let hasError = false;
|
|
124
155
|
try {
|
|
125
156
|
const parsed = JSON.parse(readFileSync(fp, "utf8"));
|
|
126
157
|
hasError = !!parsed.error;
|
|
127
|
-
} catch {
|
|
158
|
+
} catch {
|
|
159
|
+
hasError = true;
|
|
160
|
+
}
|
|
128
161
|
results.push({ name, desc, exists: true, size, hasError });
|
|
129
162
|
} else {
|
|
130
163
|
results.push({ name, desc, exists: false, size: 0, hasError: false });
|
|
@@ -187,7 +220,8 @@ async function selectiveReset() {
|
|
|
187
220
|
|
|
188
221
|
if (targets.length === 0) return;
|
|
189
222
|
|
|
190
|
-
if (!(await confirm(`${targets.length}개 캐시 파일을 삭제하시겠습니까?`)))
|
|
223
|
+
if (!(await confirm(`${targets.length}개 캐시 파일을 삭제하시겠습니까?`)))
|
|
224
|
+
return;
|
|
191
225
|
|
|
192
226
|
let deleted = 0;
|
|
193
227
|
for (const c of targets) {
|
|
@@ -227,9 +261,15 @@ async function checkOrphanTeams() {
|
|
|
227
261
|
const spin = spinner("팀 정리 중...");
|
|
228
262
|
try {
|
|
229
263
|
// Delegate to triflux's cleanup
|
|
230
|
-
execFileSync(
|
|
231
|
-
|
|
232
|
-
|
|
264
|
+
execFileSync(
|
|
265
|
+
process.execPath,
|
|
266
|
+
[join(PKG_ROOT, "bin", "triflux.mjs"), "doctor", "--fix"],
|
|
267
|
+
{
|
|
268
|
+
timeout: 30000,
|
|
269
|
+
stdio: "ignore",
|
|
270
|
+
windowsHide: true,
|
|
271
|
+
},
|
|
272
|
+
);
|
|
233
273
|
spin.stop();
|
|
234
274
|
ok("팀 정리 완료");
|
|
235
275
|
} catch {
|
|
@@ -242,12 +282,12 @@ async function checkOrphanTeams() {
|
|
|
242
282
|
// ── Main Menu ──
|
|
243
283
|
|
|
244
284
|
const MENU = [
|
|
245
|
-
{ label: "진단 (Diagnose)",
|
|
246
|
-
{ label: "수정 (Fix)",
|
|
247
|
-
{ label: "캐시 관리 (Cache)",
|
|
248
|
-
{ label: "팀 세션 정리 (Teams)",
|
|
249
|
-
{ label: "전체 초기화 (Reset)",
|
|
250
|
-
{ label: "종료",
|
|
285
|
+
{ label: "진단 (Diagnose)", hint: "읽기 전용 검사" },
|
|
286
|
+
{ label: "수정 (Fix)", hint: "자동 수정 + 진단" },
|
|
287
|
+
{ label: "캐시 관리 (Cache)", hint: "캐시 조회/선택 삭제" },
|
|
288
|
+
{ label: "팀 세션 정리 (Teams)", hint: "잔존 팀 감지/정리" },
|
|
289
|
+
{ label: "전체 초기화 (Reset)", hint: "캐시 전체 삭제 + 재생성" },
|
|
290
|
+
{ label: "종료", hint: "Ctrl+C" },
|
|
251
291
|
];
|
|
252
292
|
|
|
253
293
|
async function main() {
|
|
@@ -299,12 +339,19 @@ async function main() {
|
|
|
299
339
|
}
|
|
300
340
|
|
|
301
341
|
case 4: {
|
|
302
|
-
if (
|
|
342
|
+
if (
|
|
343
|
+
!(await confirm(
|
|
344
|
+
`${RED}전체 캐시를 초기화${RESET}하시겠습니까?`,
|
|
345
|
+
false,
|
|
346
|
+
))
|
|
347
|
+
)
|
|
348
|
+
break;
|
|
303
349
|
const spin = spinner("초기화 + 재생성 중...");
|
|
304
350
|
try {
|
|
305
|
-
execFileSync(
|
|
351
|
+
execFileSync(
|
|
352
|
+
process.execPath,
|
|
306
353
|
[join(PKG_ROOT, "bin", "triflux.mjs"), "doctor", "--reset"],
|
|
307
|
-
{ timeout: 60000, encoding: "utf8", windowsHide: true }
|
|
354
|
+
{ timeout: 60000, encoding: "utf8", windowsHide: true },
|
|
308
355
|
);
|
|
309
356
|
spin.stop();
|
|
310
357
|
ok("전체 초기화 + 재생성 완료");
|
package/tui/gemini-profile.mjs
CHANGED
|
@@ -1,36 +1,66 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// tui/gemini-profile.mjs — Interactive Gemini Profile Manager
|
|
3
3
|
// Codex config.toml 대칭 구조 — JSON 기반 프로필 CRUD
|
|
4
|
-
import {
|
|
5
|
-
|
|
4
|
+
import {
|
|
5
|
+
copyFileSync,
|
|
6
|
+
existsSync,
|
|
7
|
+
mkdirSync,
|
|
8
|
+
readFileSync,
|
|
9
|
+
writeFileSync,
|
|
10
|
+
} from "node:fs";
|
|
6
11
|
import { homedir } from "node:os";
|
|
12
|
+
import { join } from "node:path";
|
|
7
13
|
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
14
|
+
BOLD,
|
|
15
|
+
box,
|
|
16
|
+
CYAN,
|
|
17
|
+
clear,
|
|
18
|
+
confirm,
|
|
19
|
+
DIM,
|
|
20
|
+
divider,
|
|
21
|
+
fail,
|
|
22
|
+
GREEN,
|
|
23
|
+
info,
|
|
24
|
+
input,
|
|
25
|
+
label,
|
|
26
|
+
ok,
|
|
27
|
+
onExit,
|
|
28
|
+
RED,
|
|
29
|
+
RESET,
|
|
30
|
+
select,
|
|
31
|
+
showCursor,
|
|
32
|
+
table,
|
|
33
|
+
WHITE,
|
|
34
|
+
warn,
|
|
35
|
+
YELLOW,
|
|
12
36
|
} from "./core.mjs";
|
|
13
37
|
|
|
14
38
|
const GEMINI_DIR = join(homedir(), ".gemini");
|
|
15
39
|
const CONFIG_PATH = join(GEMINI_DIR, "triflux-profiles.json");
|
|
16
40
|
|
|
17
41
|
const KNOWN_MODELS = [
|
|
18
|
-
{ label: "gemini-3.1-pro-preview",
|
|
19
|
-
{ label: "gemini-3-flash-preview",
|
|
20
|
-
{ label: "gemini-2.5-pro",
|
|
21
|
-
{ label: "gemini-2.5-flash",
|
|
22
|
-
{ label: "gemini-2.5-flash-lite",
|
|
23
|
-
{ label: "직접 입력",
|
|
42
|
+
{ label: "gemini-3.1-pro-preview", hint: "3.1 Pro — 플래그십" },
|
|
43
|
+
{ label: "gemini-3-flash-preview", hint: "3.0 Flash — 빠른 응답" },
|
|
44
|
+
{ label: "gemini-2.5-pro", hint: "2.5 Pro — 안정" },
|
|
45
|
+
{ label: "gemini-2.5-flash", hint: "2.5 Flash — 경량" },
|
|
46
|
+
{ label: "gemini-2.5-flash-lite", hint: "2.5 Flash Lite — 최경량" },
|
|
47
|
+
{ label: "직접 입력", hint: "" },
|
|
24
48
|
];
|
|
25
49
|
|
|
26
50
|
const DEFAULT_CONFIG = {
|
|
27
51
|
model: "gemini-3.1-pro-preview",
|
|
28
52
|
profiles: {
|
|
29
|
-
pro31:
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
53
|
+
pro31: {
|
|
54
|
+
model: "gemini-3.1-pro-preview",
|
|
55
|
+
hint: "3.1 Pro — 플래그십 (1M ctx, 멀티모달)",
|
|
56
|
+
},
|
|
57
|
+
flash3: {
|
|
58
|
+
model: "gemini-3-flash-preview",
|
|
59
|
+
hint: "3.0 Flash — 빠른 응답, 비용 효율",
|
|
60
|
+
},
|
|
61
|
+
pro25: { model: "gemini-2.5-pro", hint: "2.5 Pro — 안정 (추론 강화)" },
|
|
62
|
+
flash25: { model: "gemini-2.5-flash", hint: "2.5 Flash — 경량 범용" },
|
|
63
|
+
lite25: { model: "gemini-2.5-flash-lite", hint: "2.5 Flash Lite — 최경량" },
|
|
34
64
|
},
|
|
35
65
|
};
|
|
36
66
|
|
|
@@ -88,7 +118,9 @@ function modelColor(model) {
|
|
|
88
118
|
|
|
89
119
|
async function pickModel(current) {
|
|
90
120
|
const idx = KNOWN_MODELS.findIndex((m) => m.label === current);
|
|
91
|
-
const choice = await select("모델 선택", KNOWN_MODELS, {
|
|
121
|
+
const choice = await select("모델 선택", KNOWN_MODELS, {
|
|
122
|
+
initial: Math.max(0, idx),
|
|
123
|
+
});
|
|
92
124
|
if (!choice) return null;
|
|
93
125
|
if (choice.value.label === "직접 입력") {
|
|
94
126
|
return await input("모델 ID", current || "");
|
|
@@ -125,7 +157,10 @@ async function editProfile(config) {
|
|
|
125
157
|
|
|
126
158
|
if (!(await confirm("저장하시겠습니까?"))) return config;
|
|
127
159
|
|
|
128
|
-
config.profiles[profile.name] = {
|
|
160
|
+
config.profiles[profile.name] = {
|
|
161
|
+
model: newModel,
|
|
162
|
+
hint: hint || profile.hint,
|
|
163
|
+
};
|
|
129
164
|
save(config);
|
|
130
165
|
ok(`${profile.name} 프로필 저장 완료`);
|
|
131
166
|
return readConfig();
|
|
@@ -184,7 +219,9 @@ async function removeProfile(config) {
|
|
|
184
219
|
if (!picked) return config;
|
|
185
220
|
|
|
186
221
|
const name = profiles[picked.index].name;
|
|
187
|
-
if (
|
|
222
|
+
if (
|
|
223
|
+
!(await confirm(`${RED}${name}${RESET} 프로필을 삭제하시겠습니까?`, false))
|
|
224
|
+
) {
|
|
188
225
|
return config;
|
|
189
226
|
}
|
|
190
227
|
|
|
@@ -208,11 +245,11 @@ function save(config) {
|
|
|
208
245
|
// ── Main Loop ──
|
|
209
246
|
|
|
210
247
|
const MENU = [
|
|
211
|
-
{ label: "프로필 모델 변경",
|
|
212
|
-
{ label: "기본 모델 변경",
|
|
213
|
-
{ label: "프로필 추가",
|
|
214
|
-
{ label: "프로필 삭제",
|
|
215
|
-
{ label: "종료",
|
|
248
|
+
{ label: "프로필 모델 변경", hint: "모델 수정" },
|
|
249
|
+
{ label: "기본 모델 변경", hint: "top-level default" },
|
|
250
|
+
{ label: "프로필 추가", hint: "새 프로필 생성" },
|
|
251
|
+
{ label: "프로필 삭제", hint: "기존 프로필 제거" },
|
|
252
|
+
{ label: "종료", hint: "Ctrl+C" },
|
|
216
253
|
];
|
|
217
254
|
|
|
218
255
|
async function main() {
|
|
@@ -236,10 +273,18 @@ async function main() {
|
|
|
236
273
|
|
|
237
274
|
console.log();
|
|
238
275
|
switch (choice.index) {
|
|
239
|
-
case 0:
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
case
|
|
276
|
+
case 0:
|
|
277
|
+
config = await editProfile(config);
|
|
278
|
+
break;
|
|
279
|
+
case 1:
|
|
280
|
+
config = await editDefault(config);
|
|
281
|
+
break;
|
|
282
|
+
case 2:
|
|
283
|
+
config = await addProfile(config);
|
|
284
|
+
break;
|
|
285
|
+
case 3:
|
|
286
|
+
config = await removeProfile(config);
|
|
287
|
+
break;
|
|
243
288
|
}
|
|
244
289
|
|
|
245
290
|
console.log();
|
package/tui/monitor-data.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readdirSync, readFileSync, unlinkSync } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
3
2
|
import { get as httpGet } from "node:http";
|
|
3
|
+
import { join } from "node:path";
|
|
4
4
|
|
|
5
5
|
const HUB_URL = "http://127.0.0.1:27888";
|
|
6
6
|
const AGENT_FILE_PREFIX = "tfx-agent-";
|
|
@@ -126,10 +126,14 @@ function fetchHubStatus(hubUrl = HUB_URL, deps = {}) {
|
|
|
126
126
|
const req = get(buildStatusUrl(hubUrl), (res) => {
|
|
127
127
|
let body = "";
|
|
128
128
|
res.setEncoding?.("utf8");
|
|
129
|
-
res.on("data", (chunk) => {
|
|
129
|
+
res.on("data", (chunk) => {
|
|
130
|
+
body += chunk;
|
|
131
|
+
});
|
|
130
132
|
res.on("end", () => {
|
|
131
133
|
try {
|
|
132
|
-
finish(
|
|
134
|
+
finish(
|
|
135
|
+
res.statusCode === 200 ? parseStatus(body) : { online: false },
|
|
136
|
+
);
|
|
133
137
|
} catch {
|
|
134
138
|
finish({ online: false });
|
|
135
139
|
}
|
|
@@ -145,4 +149,4 @@ function fetchHubStatus(hubUrl = HUB_URL, deps = {}) {
|
|
|
145
149
|
});
|
|
146
150
|
}
|
|
147
151
|
|
|
148
|
-
export {
|
|
152
|
+
export { fetchHubStatus, pollAgents };
|
package/tui/monitor.mjs
CHANGED
|
@@ -26,7 +26,9 @@ function clamp(value, min, max) {
|
|
|
26
26
|
|
|
27
27
|
function pad(text, width) {
|
|
28
28
|
const value = String(text ?? "");
|
|
29
|
-
return value.length >= width
|
|
29
|
+
return value.length >= width
|
|
30
|
+
? value
|
|
31
|
+
: value + " ".repeat(width - value.length);
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
function formatElapsed(ms) {
|
|
@@ -34,7 +36,8 @@ function formatElapsed(ms) {
|
|
|
34
36
|
const hours = Math.floor(total / 3600);
|
|
35
37
|
const minutes = Math.floor((total % 3600) / 60);
|
|
36
38
|
const seconds = total % 60;
|
|
37
|
-
if (hours > 0)
|
|
39
|
+
if (hours > 0)
|
|
40
|
+
return `${hours}:${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`;
|
|
38
41
|
return `${String(minutes).padStart(2, "0")}:${String(seconds).padStart(2, "0")}`;
|
|
39
42
|
}
|
|
40
43
|
|
|
@@ -49,20 +52,25 @@ function escapePs(value) {
|
|
|
49
52
|
}
|
|
50
53
|
|
|
51
54
|
function sanitizeTitle(value, fallback = "agent") {
|
|
52
|
-
const safe = String(value || "")
|
|
55
|
+
const safe = String(value || "")
|
|
56
|
+
.replace(/[\r\n<>:"/\\|?*\x00-\x1f]/g, " ")
|
|
57
|
+
.trim();
|
|
53
58
|
return safe || fallback;
|
|
54
59
|
}
|
|
55
60
|
|
|
56
61
|
function stripUnsafeText(value) {
|
|
57
|
-
return String(value || "")
|
|
62
|
+
return String(value || "")
|
|
63
|
+
.replace(/[\r\n\t]+/g, " ")
|
|
64
|
+
.trim();
|
|
58
65
|
}
|
|
59
66
|
|
|
60
67
|
function buildOpenCommand(agent) {
|
|
61
68
|
const sessionName = escapePs(agent.agent || "");
|
|
62
69
|
const pid = Number(agent.pid) || 0;
|
|
63
|
-
const processInfo =
|
|
64
|
-
|
|
65
|
-
|
|
70
|
+
const processInfo =
|
|
71
|
+
pid > 0
|
|
72
|
+
? `Get-Process -Id ${pid} -ErrorAction SilentlyContinue | Format-List Id,ProcessName,StartTime`
|
|
73
|
+
: "Write-Host 'PID 정보가 없습니다.'";
|
|
66
74
|
return [
|
|
67
75
|
"$ErrorActionPreference = 'Continue'",
|
|
68
76
|
`if (Get-Command psmux -ErrorAction SilentlyContinue) { try { psmux attach-session -t '${sessionName}' } catch { Write-Host 'psmux attach 실패:' $_.Exception.Message } }`,
|
|
@@ -79,7 +87,9 @@ function resolveRatio(agent, maxElapsed) {
|
|
|
79
87
|
export function createMonitor(opts = {}) {
|
|
80
88
|
const stream = opts.stream || process.stdout;
|
|
81
89
|
const input = opts.input || process.stdin;
|
|
82
|
-
const refreshMs = Number.isFinite(opts.refreshMs)
|
|
90
|
+
const refreshMs = Number.isFinite(opts.refreshMs)
|
|
91
|
+
? Math.max(0, opts.refreshMs)
|
|
92
|
+
: 1000;
|
|
83
93
|
const deps = {
|
|
84
94
|
pollAgents,
|
|
85
95
|
fetchHubStatus,
|
|
@@ -116,25 +126,45 @@ export function createMonitor(opts = {}) {
|
|
|
116
126
|
return false;
|
|
117
127
|
}
|
|
118
128
|
|
|
119
|
-
const title = sanitizeTitle(
|
|
129
|
+
const title = sanitizeTitle(
|
|
130
|
+
`tfx ${agent.agent || agent.cli || agent.pid}`,
|
|
131
|
+
"tfx-agent",
|
|
132
|
+
);
|
|
120
133
|
const command = buildOpenCommand(agent);
|
|
121
134
|
|
|
122
135
|
try {
|
|
123
136
|
try {
|
|
124
|
-
const { createWtManager } = await deps.importModule(
|
|
137
|
+
const { createWtManager } = await deps.importModule(
|
|
138
|
+
"../hub/team/wt-manager.mjs",
|
|
139
|
+
);
|
|
125
140
|
const manager = createWtManager();
|
|
126
|
-
await manager.createTab({
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
"
|
|
131
|
-
"--",
|
|
132
|
-
"powershell.exe", "-NoExit", "-Command", command,
|
|
133
|
-
], {
|
|
134
|
-
detached: true,
|
|
135
|
-
stdio: "ignore",
|
|
136
|
-
windowsHide: false,
|
|
141
|
+
await manager.createTab({
|
|
142
|
+
title,
|
|
143
|
+
command,
|
|
144
|
+
cwd: process.cwd(),
|
|
145
|
+
profile: "triflux",
|
|
137
146
|
});
|
|
147
|
+
} catch {
|
|
148
|
+
const child = deps.spawn(
|
|
149
|
+
"wt.exe",
|
|
150
|
+
[
|
|
151
|
+
"-w",
|
|
152
|
+
"new",
|
|
153
|
+
"nt",
|
|
154
|
+
"--title",
|
|
155
|
+
title,
|
|
156
|
+
"--",
|
|
157
|
+
"powershell.exe",
|
|
158
|
+
"-NoExit",
|
|
159
|
+
"-Command",
|
|
160
|
+
command,
|
|
161
|
+
],
|
|
162
|
+
{
|
|
163
|
+
detached: true,
|
|
164
|
+
stdio: "ignore",
|
|
165
|
+
windowsHide: false,
|
|
166
|
+
},
|
|
167
|
+
);
|
|
138
168
|
child?.unref?.();
|
|
139
169
|
}
|
|
140
170
|
statusMessage = `${GREEN}${stripUnsafeText(agent.agent || "agent")} 열기 시도 완료${RESET}`;
|
|
@@ -152,11 +182,17 @@ export function createMonitor(opts = {}) {
|
|
|
152
182
|
]);
|
|
153
183
|
|
|
154
184
|
agents = Array.isArray(nextAgents) ? nextAgents : [];
|
|
155
|
-
hubStatus =
|
|
185
|
+
hubStatus =
|
|
186
|
+
nextHubStatus && typeof nextHubStatus === "object"
|
|
187
|
+
? nextHubStatus
|
|
188
|
+
: { online: false };
|
|
156
189
|
syncCursor();
|
|
157
190
|
|
|
158
191
|
const width = viewportWidth();
|
|
159
|
-
const maxElapsed = agents.reduce(
|
|
192
|
+
const maxElapsed = agents.reduce(
|
|
193
|
+
(max, agent) => Math.max(max, Number(agent.elapsed) || 0),
|
|
194
|
+
0,
|
|
195
|
+
);
|
|
160
196
|
const hubLabel = hubStatus.online
|
|
161
197
|
? `${GREEN}online${RESET}`
|
|
162
198
|
: `${RED}offline${RESET}`;
|
|
@@ -177,10 +213,14 @@ export function createMonitor(opts = {}) {
|
|
|
177
213
|
const cli = stripUnsafeText(agent.cli || "unknown");
|
|
178
214
|
const name = stripUnsafeText(agent.agent || `pid:${agent.pid || "?"}`);
|
|
179
215
|
const elapsed = formatElapsed(agent.elapsed);
|
|
180
|
-
const alive = agent.alive
|
|
216
|
+
const alive = agent.alive
|
|
217
|
+
? `${GREEN}alive${RESET}`
|
|
218
|
+
: `${RED}dead${RESET}`;
|
|
181
219
|
const left = `${marker} ${colorCli(cli)}${cli}${RESET} ${BOLD}${name}${RESET} ${GRAY}${elapsed}${RESET}`;
|
|
182
220
|
if (hubStatus.online) {
|
|
183
|
-
lines.push(
|
|
221
|
+
lines.push(
|
|
222
|
+
`${left} ${BLUE}${progressBar(resolveRatio(agent, maxElapsed))}${RESET}`,
|
|
223
|
+
);
|
|
184
224
|
} else {
|
|
185
225
|
lines.push(`${left} ${alive}`);
|
|
186
226
|
}
|
|
@@ -198,7 +238,10 @@ export function createMonitor(opts = {}) {
|
|
|
198
238
|
}
|
|
199
239
|
|
|
200
240
|
if (statusMessage) lines.push("", statusMessage);
|
|
201
|
-
lines.push(
|
|
241
|
+
lines.push(
|
|
242
|
+
"",
|
|
243
|
+
`${DIM}[Enter] open [j/k] select [r] refresh [h] help [q] quit${RESET}`,
|
|
244
|
+
);
|
|
202
245
|
|
|
203
246
|
write("\x1b[H");
|
|
204
247
|
write(lines.join("\n"));
|
|
@@ -210,7 +253,8 @@ export function createMonitor(opts = {}) {
|
|
|
210
253
|
const name = key?.name || "";
|
|
211
254
|
if (str === "j" || name === "down") {
|
|
212
255
|
syncCursor();
|
|
213
|
-
cursor =
|
|
256
|
+
cursor =
|
|
257
|
+
agents.length === 0 ? 0 : Math.min(cursor + 1, agents.length - 1);
|
|
214
258
|
await renderFrame();
|
|
215
259
|
return;
|
|
216
260
|
}
|