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.
Files changed (329) hide show
  1. package/LICENSE +21 -21
  2. package/bin/tfx-doctor-tui.mjs +1 -1
  3. package/bin/tfx-doctor.mjs +6 -1
  4. package/bin/tfx-profile.mjs +1 -1
  5. package/bin/tfx-setup-tui.mjs +1 -1
  6. package/bin/tfx-setup.mjs +6 -1
  7. package/bin/triflux.mjs +2396 -1140
  8. package/hooks/agent-route-guard.mjs +12 -8
  9. package/hooks/cross-review-tracker.mjs +21 -8
  10. package/hooks/error-context.mjs +19 -7
  11. package/hooks/hook-adaptive-collector.mjs +18 -16
  12. package/hooks/hook-manager.mjs +93 -32
  13. package/hooks/hook-orchestrator.mjs +108 -24
  14. package/hooks/hook-registry.json +11 -0
  15. package/hooks/keyword-rules.json +6 -10
  16. package/hooks/lib/resolve-root.mjs +1 -1
  17. package/hooks/mcp-config-watcher.mjs +6 -2
  18. package/hooks/pipeline-stop.mjs +3 -6
  19. package/hooks/safety-guard.mjs +99 -28
  20. package/hooks/session-start-fast.mjs +143 -0
  21. package/hooks/subagent-verifier.mjs +5 -4
  22. package/hub/account-broker.mjs +256 -60
  23. package/hub/adaptive-diagnostic.mjs +75 -48
  24. package/hub/adaptive-inject.mjs +95 -57
  25. package/hub/adaptive-memory.mjs +156 -42
  26. package/hub/adaptive.mjs +60 -31
  27. package/hub/assign-callbacks.mjs +67 -30
  28. package/hub/bridge.mjs +0 -1
  29. package/hub/cli-adapter-base.mjs +200 -48
  30. package/hub/codex-adapter.mjs +76 -96
  31. package/hub/codex-compat.mjs +3 -3
  32. package/hub/codex-preflight.mjs +63 -37
  33. package/hub/delegator/contracts.mjs +19 -23
  34. package/hub/delegator/index.mjs +3 -3
  35. package/hub/delegator/service.mjs +88 -64
  36. package/hub/delegator/tool-definitions.mjs +5 -5
  37. package/hub/fullcycle.mjs +33 -17
  38. package/hub/gemini-adapter.mjs +69 -94
  39. package/hub/hitl.mjs +89 -30
  40. package/hub/intent.mjs +161 -38
  41. package/hub/lib/cache-guard.mjs +43 -17
  42. package/hub/lib/mcp-response-cache.mjs +66 -32
  43. package/hub/lib/memory-store.mjs +285 -111
  44. package/hub/lib/path-utils.mjs +35 -37
  45. package/hub/lib/process-utils.mjs +106 -37
  46. package/hub/lib/spawn-trace.mjs +527 -0
  47. package/hub/lib/ssh-command.mjs +34 -4
  48. package/hub/lib/ssh-retry.mjs +5 -1
  49. package/hub/lib/uuidv7.mjs +4 -3
  50. package/hub/memory-doctor.mjs +266 -106
  51. package/hub/middleware/request-logger.mjs +61 -34
  52. package/hub/paths.mjs +9 -9
  53. package/hub/pipeline/gates/confidence.mjs +34 -15
  54. package/hub/pipeline/gates/consensus.mjs +27 -15
  55. package/hub/pipeline/gates/index.mjs +7 -3
  56. package/hub/pipeline/gates/selfcheck.mjs +57 -19
  57. package/hub/pipeline/index.mjs +77 -42
  58. package/hub/pipeline/state.mjs +10 -10
  59. package/hub/pipeline/transitions.mjs +40 -23
  60. package/hub/platform.mjs +57 -48
  61. package/hub/promote-penalties.mjs +25 -7
  62. package/hub/quality/deslop.mjs +70 -49
  63. package/hub/research.mjs +32 -25
  64. package/hub/router.mjs +240 -107
  65. package/hub/routing/complexity.mjs +132 -29
  66. package/hub/routing/index.mjs +17 -12
  67. package/hub/routing/q-learning.mjs +76 -28
  68. package/hub/server.mjs +4 -4
  69. package/hub/session-fingerprint.mjs +126 -60
  70. package/hub/state.mjs +84 -43
  71. package/hub/store-adapter.mjs +59 -26
  72. package/hub/store.mjs +356 -153
  73. package/hub/team/agent-map.json +22 -7
  74. package/hub/team/ansi.mjs +186 -122
  75. package/hub/team/backend.mjs +28 -10
  76. package/hub/team/cli/commands/attach.mjs +29 -9
  77. package/hub/team/cli/commands/control.mjs +29 -8
  78. package/hub/team/cli/commands/debug.mjs +32 -11
  79. package/hub/team/cli/commands/focus.mjs +38 -11
  80. package/hub/team/cli/commands/interrupt.mjs +18 -6
  81. package/hub/team/cli/commands/kill.mjs +16 -5
  82. package/hub/team/cli/commands/list.mjs +11 -4
  83. package/hub/team/cli/commands/send.mjs +19 -6
  84. package/hub/team/cli/commands/start/index.mjs +154 -31
  85. package/hub/team/cli/commands/start/parse-args.mjs +38 -11
  86. package/hub/team/cli/commands/start/start-headless.mjs +112 -36
  87. package/hub/team/cli/commands/start/start-in-process.mjs +12 -2
  88. package/hub/team/cli/commands/start/start-mux.mjs +70 -21
  89. package/hub/team/cli/commands/start/start-wt.mjs +29 -12
  90. package/hub/team/cli/commands/status.mjs +43 -14
  91. package/hub/team/cli/commands/stop.mjs +11 -4
  92. package/hub/team/cli/commands/task.mjs +8 -3
  93. package/hub/team/cli/commands/tasks.mjs +1 -1
  94. package/hub/team/cli/index.mjs +2 -2
  95. package/hub/team/cli/manifest.mjs +38 -8
  96. package/hub/team/cli/render.mjs +30 -8
  97. package/hub/team/cli/services/attach-fallback.mjs +31 -11
  98. package/hub/team/cli/services/hub-client.mjs +42 -14
  99. package/hub/team/cli/services/member-selector.mjs +11 -4
  100. package/hub/team/cli/services/native-control.mjs +48 -21
  101. package/hub/team/cli/services/runtime-mode.mjs +2 -1
  102. package/hub/team/cli/services/state-store.mjs +25 -8
  103. package/hub/team/cli/services/task-model.mjs +16 -6
  104. package/hub/team/conductor-mesh-bridge.mjs +24 -23
  105. package/hub/team/conductor.mjs +8 -4
  106. package/hub/team/dashboard-anchor.mjs +4 -5
  107. package/hub/team/dashboard-layout.mjs +3 -1
  108. package/hub/team/dashboard-open.mjs +41 -21
  109. package/hub/team/dashboard.mjs +76 -28
  110. package/hub/team/event-log.mjs +18 -10
  111. package/hub/team/handoff.mjs +31 -15
  112. package/hub/team/headless.mjs +2 -1
  113. package/hub/team/health-probe.mjs +69 -54
  114. package/hub/team/launcher-template.mjs +16 -13
  115. package/hub/team/native-supervisor.mjs +65 -21
  116. package/hub/team/native.mjs +74 -35
  117. package/hub/team/nativeProxy.mjs +184 -113
  118. package/hub/team/notify.mjs +119 -76
  119. package/hub/team/orchestrator.mjs +9 -4
  120. package/hub/team/pane.mjs +12 -7
  121. package/hub/team/process-cleanup.mjs +25 -16
  122. package/hub/team/psmux.mjs +491 -201
  123. package/hub/team/remote-probe.mjs +68 -52
  124. package/hub/team/remote-session.mjs +117 -59
  125. package/hub/team/remote-watcher.mjs +61 -33
  126. package/hub/team/routing.mjs +51 -25
  127. package/hub/team/runtime-strategy.mjs +3 -1
  128. package/hub/team/session.mjs +98 -34
  129. package/hub/team/staleState.mjs +72 -30
  130. package/hub/team/swarm-locks.mjs +15 -13
  131. package/hub/team/swarm-planner.mjs +32 -21
  132. package/hub/team/swarm-reconciler.mjs +48 -23
  133. package/hub/team/tui-lite.mjs +266 -68
  134. package/hub/team/tui-remote-adapter.mjs +14 -10
  135. package/hub/team/tui-viewer.mjs +99 -43
  136. package/hub/team/tui.mjs +708 -271
  137. package/hub/team/worktree-lifecycle.mjs +152 -58
  138. package/hub/team/wt-manager.mjs +24 -14
  139. package/hub/token-mode.mjs +71 -71
  140. package/hub/tray.mjs +66 -23
  141. package/hub/workers/claude-worker.mjs +162 -118
  142. package/hub/workers/codex-mcp.mjs +192 -141
  143. package/hub/workers/delegator-mcp.mjs +507 -333
  144. package/hub/workers/factory.mjs +8 -8
  145. package/hub/workers/gemini-worker.mjs +115 -84
  146. package/hub/workers/interface.mjs +6 -1
  147. package/hub/workers/worker-utils.mjs +21 -14
  148. package/hud/colors.mjs +27 -9
  149. package/hud/constants.mjs +162 -26
  150. package/hud/context-monitor.mjs +82 -41
  151. package/hud/hud-qos-status.mjs +129 -49
  152. package/hud/mission-board.mjs +6 -3
  153. package/hud/providers/claude.mjs +226 -115
  154. package/hud/providers/codex.mjs +62 -22
  155. package/hud/providers/gemini.mjs +168 -56
  156. package/hud/renderers.mjs +384 -119
  157. package/hud/terminal.mjs +101 -31
  158. package/hud/utils.mjs +78 -38
  159. package/mesh/index.mjs +11 -5
  160. package/mesh/mesh-budget.mjs +18 -9
  161. package/mesh/mesh-heartbeat.mjs +1 -1
  162. package/mesh/mesh-queue.mjs +3 -5
  163. package/mesh/mesh-router.mjs +5 -4
  164. package/package.json +2 -1
  165. package/scripts/__tests__/gen-skill-docs.test.mjs +36 -7
  166. package/scripts/__tests__/keyword-detector.test.mjs +77 -28
  167. package/scripts/__tests__/mcp-guard-engine.test.mjs +58 -20
  168. package/scripts/__tests__/remote-spawn-transfer.test.mjs +30 -19
  169. package/scripts/__tests__/remote-spawn.test.mjs +10 -4
  170. package/scripts/__tests__/session-start-fast.test.mjs +36 -0
  171. package/scripts/__tests__/skill-template.test.mjs +98 -50
  172. package/scripts/__tests__/smoke.test.mjs +1 -1
  173. package/scripts/__tests__/spawn-trace.test.mjs +102 -0
  174. package/scripts/__tests__/tfx-doctor-diagnose.test.mjs +48 -0
  175. package/scripts/cache-doctor.mjs +11 -4
  176. package/scripts/cache-warmup.mjs +96 -37
  177. package/scripts/claudemd-sync.mjs +27 -17
  178. package/scripts/codex-gateway-preflight.mjs +52 -37
  179. package/scripts/codex-mcp-gateway-sync.mjs +59 -39
  180. package/scripts/completions/tfx.bash +47 -47
  181. package/scripts/completions/tfx.fish +44 -44
  182. package/scripts/completions/tfx.zsh +83 -83
  183. package/scripts/config-audit.mjs +232 -0
  184. package/scripts/convert-to-tmpl.mjs +54 -0
  185. package/scripts/cross-review-gate.mjs +35 -12
  186. package/scripts/cross-review-tracker.mjs +21 -8
  187. package/scripts/demo.mjs +35 -17
  188. package/scripts/doctor-diagnose.mjs +284 -0
  189. package/scripts/gen-skill-docs.mjs +7 -2
  190. package/scripts/gen-skill-manifest.mjs +2 -1
  191. package/scripts/headless-guard.mjs +86 -48
  192. package/scripts/hub-ensure.mjs +45 -26
  193. package/scripts/keyword-detector.mjs +41 -20
  194. package/scripts/keyword-rules-expander.mjs +47 -30
  195. package/scripts/lib/claudemd-scanner.mjs +6 -1
  196. package/scripts/lib/context.mjs +3 -3
  197. package/scripts/lib/cross-review-utils.mjs +6 -3
  198. package/scripts/lib/env-probe.mjs +47 -28
  199. package/scripts/lib/gemini-profiles.mjs +44 -10
  200. package/scripts/lib/handoff.mjs +33 -17
  201. package/scripts/lib/hook-utils.mjs +8 -6
  202. package/scripts/lib/keyword-rules.mjs +43 -19
  203. package/scripts/lib/logger.mjs +24 -24
  204. package/scripts/lib/mcp-filter.mjs +377 -239
  205. package/scripts/lib/mcp-guard-engine.mjs +194 -79
  206. package/scripts/lib/mcp-manifest.mjs +23 -13
  207. package/scripts/lib/mcp-server-catalog.mjs +300 -63
  208. package/scripts/lib/psmux-info.mjs +11 -6
  209. package/scripts/lib/remote-spawn-transfer.mjs +44 -14
  210. package/scripts/lib/skill-template.mjs +30 -7
  211. package/scripts/mcp-check.mjs +58 -39
  212. package/scripts/mcp-gateway-config.mjs +83 -39
  213. package/scripts/mcp-gateway-ensure.mjs +43 -35
  214. package/scripts/mcp-gateway-integration-test.mjs +70 -58
  215. package/scripts/mcp-gateway-start.mjs +126 -60
  216. package/scripts/mcp-gateway-verify.mjs +24 -22
  217. package/scripts/mcp-safety-guard.mjs +44 -11
  218. package/scripts/notion-read.mjs +199 -84
  219. package/scripts/pack.mjs +94 -89
  220. package/scripts/preflight-cache.mjs +27 -10
  221. package/scripts/preinstall.mjs +42 -13
  222. package/scripts/remote-spawn.mjs +309 -94
  223. package/scripts/run.cjs +8 -5
  224. package/scripts/session-spawn-helper.mjs +130 -39
  225. package/scripts/session-stale-cleanup.mjs +123 -0
  226. package/scripts/setup.mjs +941 -492
  227. package/scripts/test-lock.mjs +20 -7
  228. package/scripts/test-tfx-route-no-claude-native.mjs +16 -12
  229. package/scripts/tfx-batch-stats.mjs +32 -11
  230. package/scripts/tfx-gate-activate.mjs +11 -4
  231. package/scripts/tfx-route-post.mjs +87 -20
  232. package/scripts/tfx-route-worker.mjs +57 -51
  233. package/scripts/tfx-route.sh +41 -124
  234. package/scripts/tmp-cleanup.mjs +21 -7
  235. package/scripts/token-snapshot.mjs +204 -85
  236. package/skills/.omc/state/agent-replay-8f0e10a9-9693-4410-96f5-a6b07e8ed995.jsonl +1 -0
  237. package/skills/.omc/state/idle-notif-cooldown.json +3 -0
  238. package/skills/.omc/state/last-tool-error.json +7 -0
  239. package/skills/.omc/state/subagent-tracking.json +7 -0
  240. package/skills/_templates/base.md +1 -6
  241. package/skills/merge-worktree/SKILL.md.tmpl +144 -0
  242. package/skills/shared/telemetry-segment.md +6 -0
  243. package/skills/star-prompt/SKILL.md.tmpl +222 -0
  244. package/skills/tfx-analysis/SKILL.md.tmpl +107 -0
  245. package/skills/tfx-analysis/skill.json +1 -6
  246. package/skills/tfx-auto/SKILL.md +1 -0
  247. package/skills/tfx-auto-codex/SKILL.md.tmpl +106 -0
  248. package/skills/tfx-auto-codex/skill.json +1 -3
  249. package/skills/tfx-autopilot/SKILL.md.tmpl +116 -0
  250. package/skills/tfx-autopilot/skill.json +1 -5
  251. package/skills/tfx-autoresearch/SKILL.md.tmpl +136 -0
  252. package/skills/tfx-autoroute/SKILL.md.tmpl +189 -0
  253. package/skills/tfx-autoroute/skill.json +1 -7
  254. package/skills/tfx-codex/SKILL.md +1 -0
  255. package/skills/tfx-codex/skill.json +1 -3
  256. package/skills/tfx-codex-swarm/SKILL.md.tmpl +16 -0
  257. package/skills/tfx-codex-swarm/evals/evals.json +1 -1
  258. package/skills/tfx-codex-swarm/skill.json +1 -4
  259. package/skills/tfx-codex-swarm-workspace/iteration-1/benchmark.json +54 -12
  260. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/grading.json +35 -7
  261. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/grading.json +35 -7
  262. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/grading.json +25 -5
  263. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/grading.json +25 -5
  264. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/grading.json +20 -4
  265. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/grading.json +16 -4
  266. package/skills/tfx-consensus/SKILL.md.tmpl +146 -0
  267. package/skills/tfx-debate/SKILL.md.tmpl +192 -0
  268. package/skills/tfx-debate/skill.json +1 -7
  269. package/skills/tfx-deep-analysis/SKILL.md.tmpl +228 -0
  270. package/skills/tfx-deep-analysis/skill.json +1 -5
  271. package/skills/tfx-deep-interview/SKILL.md.tmpl +203 -0
  272. package/skills/tfx-deep-plan/SKILL.md.tmpl +282 -0
  273. package/skills/tfx-deep-qa/SKILL.md.tmpl +165 -0
  274. package/skills/tfx-deep-qa/skill.json +1 -6
  275. package/skills/tfx-deep-research/SKILL.md.tmpl +217 -0
  276. package/skills/tfx-deep-review/SKILL.md.tmpl +179 -0
  277. package/skills/tfx-doctor/SKILL.md +21 -0
  278. package/skills/tfx-doctor/SKILL.md.tmpl +172 -0
  279. package/skills/tfx-doctor/skill.json +1 -3
  280. package/skills/tfx-find/SKILL.md +1 -0
  281. package/skills/tfx-forge/SKILL.md.tmpl +187 -0
  282. package/skills/tfx-fullcycle/SKILL.md.tmpl +286 -0
  283. package/skills/tfx-fullcycle/skill.json +1 -6
  284. package/skills/tfx-gemini/SKILL.md.tmpl +91 -0
  285. package/skills/tfx-gemini/skill.json +1 -3
  286. package/skills/tfx-hooks/SKILL.md.tmpl +216 -0
  287. package/skills/tfx-hooks/skill.json +1 -3
  288. package/skills/tfx-hub/SKILL.md.tmpl +212 -0
  289. package/skills/tfx-hub/skill.json +1 -3
  290. package/skills/tfx-index/SKILL.md +1 -0
  291. package/skills/tfx-index/skill.json +1 -6
  292. package/skills/tfx-interview/SKILL.md.tmpl +285 -0
  293. package/skills/tfx-multi/SKILL.md.tmpl +183 -0
  294. package/skills/tfx-multi/skill.json +1 -3
  295. package/skills/tfx-panel/SKILL.md.tmpl +189 -0
  296. package/skills/tfx-panel/skill.json +1 -7
  297. package/skills/tfx-persist/SKILL.md.tmpl +270 -0
  298. package/skills/tfx-persist/skill.json +1 -7
  299. package/skills/tfx-plan/SKILL.md +1 -0
  300. package/skills/tfx-plan/skill.json +1 -6
  301. package/skills/tfx-profile/SKILL.md.tmpl +239 -0
  302. package/skills/tfx-profile/skill.json +1 -3
  303. package/skills/tfx-prune/SKILL.md.tmpl +200 -0
  304. package/skills/tfx-prune/skill.json +1 -7
  305. package/skills/tfx-psmux-rules/SKILL.md.tmpl +326 -0
  306. package/skills/tfx-psmux-rules/skill.json +1 -4
  307. package/skills/tfx-qa/SKILL.md +1 -0
  308. package/skills/tfx-qa/skill.json +1 -6
  309. package/skills/tfx-ralph/SKILL.md.tmpl +28 -0
  310. package/skills/tfx-ralph/skill.json +1 -4
  311. package/skills/tfx-remote-setup/SKILL.md.tmpl +576 -0
  312. package/skills/tfx-remote-setup/skill.json +1 -3
  313. package/skills/tfx-remote-spawn/SKILL.md.tmpl +263 -0
  314. package/skills/tfx-remote-spawn/references/hosts.json +16 -0
  315. package/skills/tfx-remote-spawn/skill.json +1 -4
  316. package/skills/tfx-research/SKILL.md +1 -0
  317. package/skills/tfx-review/SKILL.md +1 -0
  318. package/skills/tfx-review/skill.json +1 -6
  319. package/skills/tfx-setup/SKILL.md.tmpl +504 -0
  320. package/skills/tfx-setup/skill.json +1 -3
  321. package/skills/tfx-swarm/SKILL.md +22 -0
  322. package/skills/tfx-swarm/SKILL.md.tmpl +218 -0
  323. package/tui/codex-profile.mjs +88 -33
  324. package/tui/core.mjs +45 -15
  325. package/tui/doctor.mjs +75 -28
  326. package/tui/gemini-profile.mjs +74 -29
  327. package/tui/monitor-data.mjs +8 -4
  328. package/tui/monitor.mjs +71 -27
  329. package/tui/setup.mjs +133 -42
@@ -0,0 +1,576 @@
1
+ ---
2
+ name: tfx-remote-setup
3
+ description: >
4
+ 원격 호스트 설정 위저드. AskUserQuestion 기반 인터랙티브 UI로
5
+ Tailscale 네트워크 감지, SSH 연결 확인, Claude 설치 프로브, hosts.json 관리를 수행합니다.
6
+ Use when: remote setup, 원격 설정, 호스트 추가, hosts.json, 원격 환경, remote config,
7
+ tailscale, 테일스케일
8
+ triggers:
9
+ - tfx-remote-setup
10
+ argument-hint: "[--add|--edit|--probe-all|--diagnose]"
11
+ ---
12
+
13
+ # {{SKILL_NAME}} — 원격 호스트 설정 위저드
14
+
15
+ > **ARGUMENTS 처리**: 이 스킬이 `ARGUMENTS: <값>`과 함께 호출되면, 해당 값을 사용자 입력으로 취급하여
16
+ > 워크플로우의 첫 단계 입력으로 사용한다. ARGUMENTS가 비어있거나 없으면 기존 절차대로 사용자에게 입력을 요청한다.
17
+
18
+
19
+ > 원격 세션(tfx-remote-spawn)을 쓰기 전에 호스트를 설정합니다.
20
+ > Tailscale 네트워크 자동 감지 → SSH 연결 → Claude 프로브 → hosts.json 등록을 한번에.
21
+
22
+ ## 워크플로우
23
+
24
+ ### Step 1: 모드 선택 (AskUserQuestion)
25
+
26
+ 인자 없이 호출된 경우:
27
+
28
+ ```
29
+ question: "어떤 설정을 하시겠습니까?"
30
+ header: "원격 설정"
31
+ options:
32
+ - label: "새 호스트 추가 (Add)"
33
+ description: "Tailscale 감지 → SSH 연결 → Claude 프로브 → hosts.json 등록"
34
+ - label: "기존 호스트 편집 (Edit)"
35
+ description: "별칭, 기본 디렉토리, 설명 수정"
36
+ - label: "전체 프로브 (Probe All)"
37
+ description: "등록된 모든 호스트 환경을 일괄 점검"
38
+ - label: "진단 (Diagnose)"
39
+ description: "Tailscale, SSH, psmux, WT, hosts.json 전체 상태 확인"
40
+ ```
41
+
42
+ `--add` → 바로 호스트 추가 플로우.
43
+ `--edit` → 바로 편집 플로우.
44
+ `--probe-all` → 바로 전체 프로브.
45
+ `--diagnose` → 바로 진단.
46
+
47
+ ### Step 2: 모드별 실행
48
+
49
+ #### 새 호스트 추가 (Add)
50
+
51
+ **2-1. Tailscale 네트워크 감지**
52
+
53
+ 먼저 Tailscale tailnet의 피어 목록을 조회한다:
54
+
55
+ ```bash
56
+ tailscale status --json 2>/dev/null
57
+ ```
58
+
59
+ Tailscale이 설치되어 있고 로그인 상태이면, 피어 목록에서 호스트를 AskUserQuestion으로 표시:
60
+
61
+ ```
62
+ question: "Tailscale 네트워크에서 호스트가 감지되었습니다. 선택하세요."
63
+ header: "Tailscale 피어"
64
+ options:
65
+ - label: "ultra4 (100.x.x.x)"
66
+ description: "Windows | online | ultra4.yak-bebop.ts.net"
67
+ - label: "m2 (100.y.y.y)"
68
+ description: "macOS | online | m2.yak-bebop.ts.net"
69
+ - label: "SSH config에서 선택"
70
+ description: "Tailscale 대신 ~/.ssh/config에서 호스트 선택"
71
+ - label: "직접 입력"
72
+ description: "호스트명을 수동 입력"
73
+ ```
74
+
75
+ 옵션은 `tailscale status --json`에서 동적 생성. 피어별로 HostName, TailscaleIPs[0], OS, Online 상태를 파싱.
76
+
77
+ **피어 IP 추출 명령어:**
78
+ ```bash
79
+ # 특정 호스트 IPv4
80
+ tailscale status --json | jq -r '.Peer[] | select(.HostName == "{host}") | .TailscaleIPs[0]'
81
+
82
+ # 전체 hostname → IPv4 맵
83
+ tailscale status --json | jq '[.Self] + [.Peer[]] | map({(.DNSName | split(".")[0]): (.TailscaleIPs[0])}) | add'
84
+ ```
85
+
86
+ **PowerShell 대체:**
87
+ ```powershell
88
+ $ts = tailscale status --json | ConvertFrom-Json
89
+ $ts.Peer.PSObject.Properties.Value | Select-Object HostName, @{N='IP';E={$_.TailscaleIPs[0]}}, Online
90
+ ```
91
+
92
+ Tailscale 미설치 또는 미로그인 → SSH config 선택으로 fallback:
93
+
94
+ ```
95
+ question: "SSH config에서 호스트를 선택하거나 직접 입력하세요"
96
+ header: "SSH 호스트"
97
+ options:
98
+ - label: "ultra4"
99
+ description: "192.168.0.10 (SSH config)"
100
+ - label: "m2"
101
+ description: "100.x.x.x (SSH config)"
102
+ - label: "직접 입력"
103
+ description: "SSH config에 없는 호스트를 수동 입력"
104
+ ```
105
+
106
+ 옵션은 `~/.ssh/config`에서 동적 생성. hosts.json에 이미 등록된 호스트는 `(등록됨)` 표시.
107
+
108
+ **2-2. 연결 방식 선택**
109
+
110
+ Tailscale 피어를 선택한 경우, 연결 방식을 결정한다:
111
+
112
+ ```
113
+ question: "어떤 SSH 연결 방식을 사용하시겠습니까?"
114
+ header: "연결 방식"
115
+ options:
116
+ - label: "Tailscale SSH (Recommended)"
117
+ description: "SSH 키 불필요 — Tailscale identity로 인증. tailscale set --ssh 필요"
118
+ - label: "SSH over Tailscale VPN"
119
+ description: "기존 OpenSSH 사용 — Tailscale은 터널만 제공. SSH 키/비밀번호 필요"
120
+ - label: "MagicDNS + ProxyCommand"
121
+ description: "tailscale nc ProxyCommand 사용 — NAT 환경에서 안정적"
122
+ ```
123
+
124
+ **각 방식의 차이:**
125
+
126
+ | 방식 | 인증 | SSH 키 필요 | known_hosts | 제약 |
127
+ |------|------|-------------|-------------|------|
128
+ | Tailscale SSH | Tailscale identity (WireGuard 노드 키) | 아니오 | 자동 관리 | 서버측 `tailscale set --ssh` + ACL 필요 |
129
+ | SSH over VPN | OpenSSH 표준 | 예 | 수동 관리 | 100.x.x.x IP 직접 사용 |
130
+ | MagicDNS + nc | OpenSSH + tailscale nc | 예 | 수동 관리 | ProxyCommand 설정 |
131
+
132
+ **Tailscale SSH 선택 시 — 서버 설정 안내:**
133
+
134
+ 원격 호스트에서 Tailscale SSH를 활성화해야 한다:
135
+
136
+ ```bash
137
+ # 원격 호스트에서 실행
138
+ tailscale set --ssh
139
+ ```
140
+
141
+ **플랫폼별 주의사항:**
142
+ - **macOS**: App Store 버전은 샌드박스 제한으로 Tailscale SSH 서버 불가 → **Homebrew/standalone CLI 버전** 필요 (`brew install tailscale`)
143
+ - **Windows**: Tailscale SSH 서버 **미지원** (클라이언트만 가능) → "SSH over Tailscale VPN" 사용
144
+ - **Linux**: 제한 없음
145
+
146
+ 원격 호스트가 Windows인 경우 자동으로 "SSH over Tailscale VPN"으로 전환:
147
+ ```
148
+ "대상이 Windows입니다. Tailscale SSH 서버는 Windows에서 미지원 →
149
+ SSH over Tailscale VPN 모드로 전환합니다."
150
+ ```
151
+
152
+ 원격 호스트가 macOS인 경우 확인:
153
+ ```
154
+ question: "macOS에서 Tailscale SSH를 사용하려면 Homebrew 버전이 필요합니다. 확인되었습니까?"
155
+ header: "macOS Tailscale"
156
+ options:
157
+ - label: "Homebrew 버전 사용 중"
158
+ description: "brew install tailscale로 설치됨"
159
+ - label: "App Store 버전 사용 중"
160
+ description: "SSH over Tailscale VPN으로 전환"
161
+ - label: "모르겠음"
162
+ description: "SSH over Tailscale VPN으로 전환 (안전한 선택)"
163
+ ```
164
+
165
+ **2-3. SSH config 자동 생성**
166
+
167
+ 선택한 연결 방식에 따라 `~/.ssh/config` 엔트리를 생성/갱신한다.
168
+
169
+ **Tailscale SSH:**
170
+ ```ssh-config
171
+ Host {host}
172
+ HostName {host}.{tailnet-name}.ts.net
173
+ # Tailscale SSH — 키 불필요, identity 자동 인증
174
+ ```
175
+
176
+ **SSH over Tailscale VPN (MagicDNS 사용 — 권장):**
177
+ ```ssh-config
178
+ Host {host}
179
+ HostName {host}.{tailnet-name}.ts.net
180
+ User {username}
181
+ IdentityFile ~/.ssh/id_ed25519
182
+ ```
183
+
184
+ > **MagicDNS 호스트명 사용 권장.** `100.x.y.z` IP는 CGNAT 범위로 보통 안정적이지만,
185
+ > 노드 삭제 후 재등록 시 변경될 수 있다. MagicDNS(`{host}.{tailnet}.ts.net`)는 항상 현재 IP로 해석된다.
186
+
187
+ **MagicDNS + ProxyCommand:**
188
+ ```ssh-config
189
+ Host {host}
190
+ HostName {host}.{tailnet-name}.ts.net
191
+ User {username}
192
+ ProxyCommand tailscale nc %h %p
193
+ IdentityFile ~/.ssh/id_ed25519
194
+ ```
195
+
196
+ SSH config 갱신 여부 확인:
197
+ ```
198
+ question: "SSH config에 {host} 엔트리를 추가/갱신하시겠습니까?"
199
+ header: "SSH Config"
200
+ options:
201
+ - label: "추가 (Recommended)"
202
+ description: "{연결 방식} 설정을 ~/.ssh/config에 추가"
203
+ - label: "기존 엔트리 유지"
204
+ description: "이미 설정된 SSH config를 그대로 사용"
205
+ - label: "건너뛰기"
206
+ description: "SSH config 수정 없이 진행"
207
+ ```
208
+
209
+ **2-4. SSH 연결 테스트**
210
+
211
+ ```bash
212
+ ssh -o ConnectTimeout=5 -o BatchMode=yes {host} "echo ok" 2>&1
213
+ ```
214
+
215
+ | 결과 | 동작 |
216
+ |------|------|
217
+ | ok | 다음 단계 |
218
+ | 실패 | 에러 메시지 표시 + AskUserQuestion ↓ |
219
+
220
+ ```
221
+ question: "{host} SSH 연결에 실패했습니다. 어떻게 하시겠습니까?"
222
+ header: "SSH 실패"
223
+ options:
224
+ - label: "Tailscale IP 갱신"
225
+ description: "tailscale status로 최신 IP 조회 후 SSH config 갱신"
226
+ - label: "Tailscale SSH 활성화 안내"
227
+ description: "원격 호스트에서 tailscale set --ssh 실행 가이드"
228
+ - label: "다른 호스트로 재시도"
229
+ description: "호스트 선택 메뉴로 돌아감"
230
+ - label: "취소"
231
+ description: "설정 중단"
232
+ ```
233
+
234
+ **Tailscale IP 갱신 선택 시:**
235
+ ```bash
236
+ # 해당 호스트의 최신 IP 조회
237
+ tailscale status --json | jq -r '.Peer[] | select(.HostName == "{host}") | .TailscaleIPs[0]'
238
+ ```
239
+ 결과를 표시하고, SSH config의 HostName을 MagicDNS로 갱신:
240
+ ```
241
+ "{host}의 Tailscale IP: 100.x.x.x
242
+ MagicDNS: {host}.{tailnet}.ts.net
243
+ → SSH config HostName을 MagicDNS로 갱신합니다."
244
+ ```
245
+
246
+ **2-5. 원격 환경 프로브**
247
+
248
+ ```bash
249
+ node scripts/remote-spawn.mjs --probe {host}
250
+ ```
251
+
252
+ 결과를 표시:
253
+ ```
254
+ {host} 환경:
255
+ OS: {os}
256
+ Shell: {shell}
257
+ Home: {home}
258
+ Claude: {claudePath || "미설치"}
259
+ Node: {nodeVersion}
260
+ Tailscale SSH: {enabled/disabled/unknown}
261
+ ```
262
+
263
+ Claude 미설치 시 AskUserQuestion:
264
+ ```
265
+ question: "Claude Code가 설치되어 있지 않습니다. 어떻게 하시겠습니까?"
266
+ header: "Claude 미설치"
267
+ options:
268
+ - label: "원격 설치 실행"
269
+ description: "SSH로 npm install -g @anthropic-ai/claude-code 실행"
270
+ - label: "설치 없이 등록"
271
+ description: "hosts.json에 등록만 (나중에 수동 설치)"
272
+ - label: "취소"
273
+ description: "이 호스트 등록 중단"
274
+ ```
275
+
276
+ 원격 설치 선택 시:
277
+ ```bash
278
+ ssh {host} "npm install -g @anthropic-ai/claude-code"
279
+ ```
280
+ 설치 후 다시 프로브하여 확인.
281
+
282
+ **2-6. 호스트 정보 입력**
283
+
284
+ AskUserQuestion으로 순차 수집:
285
+
286
+ ```
287
+ question: "이 호스트의 표시 이름(설명)을 입력하세요"
288
+ header: "설명"
289
+ defaultValue: "{host}"
290
+ ```
291
+
292
+ ```
293
+ question: "한글 별칭을 입력하세요 (쉼표로 구분, 예: 맥북,맥)"
294
+ header: "별칭"
295
+ defaultValue: ""
296
+ ```
297
+
298
+ ```
299
+ question: "기본 작업 디렉토리를 입력하세요"
300
+ header: "디렉토리"
301
+ defaultValue: "~/projects"
302
+ ```
303
+
304
+ **2-7. hosts.json 저장**
305
+
306
+ `skills/tfx-remote-spawn/references/hosts.json`을 Read → Edit:
307
+
308
+ - 파일이 없으면 새로 생성 (기본 구조)
309
+ - 파일이 있으면 hosts 객체에 새 호스트 추가
310
+
311
+ ```json
312
+ {
313
+ "hosts": {
314
+ "{host}": {
315
+ "description": "{description}",
316
+ "aliases": ["{alias1}", "{alias2}"],
317
+ "default_dir": "{default_dir}",
318
+ "tailscale": {
319
+ "ip": "100.x.x.x",
320
+ "dns": "{host}.{tailnet}.ts.net",
321
+ "ssh_mode": "tailscale-ssh | ssh-over-vpn | magicdns-nc"
322
+ }
323
+ }
324
+ },
325
+ "default_host": "{host}",
326
+ "triggers": ["원격에서", "다른 머신에서", "다른 컴퓨터에서"]
327
+ }
328
+ ```
329
+
330
+ 첫 호스트면 default_host로 자동 설정.
331
+ 2번째 이상이면 AskUserQuestion:
332
+ ```
333
+ question: "이 호스트를 기본 호스트로 설정하시겠습니까?"
334
+ header: "기본 호스트"
335
+ options:
336
+ - label: "예 — {host}를 기본으로"
337
+ description: "호스트명 생략 시 이 호스트 사용"
338
+ - label: "아니오 — 기존 유지 ({current_default})"
339
+ description: "현재 기본 호스트 유지"
340
+ ```
341
+
342
+ 저장 후 결과 보고.
343
+
344
+ **2-8. MCP 고아 프로세스 정리 훅 배포 (Windows 원격 호스트)**
345
+
346
+ 원격 호스트가 Windows인 경우, MCP 고아 프로세스 정리 훅을 자동 배포한다.
347
+ Claude Code 세션 종료 시 MCP 서버 프로세스가 정리되지 않는 Windows 고유 버그 대응.
348
+ (GitHub Issues #1935, #15211, #28126)
349
+
350
+ ```bash
351
+ # mcp-cleanup.ps1 배포
352
+ scp "$(npm root -g)/triflux/scripts/mcp-cleanup.ps1" {host}:~/.claude/scripts/mcp-cleanup.ps1
353
+ ```
354
+
355
+ 배포 후 원격 호스트의 `~/.claude/settings.json`에 Stop 훅을 등록한다:
356
+
357
+ ```bash
358
+ ssh {host} "node -e \"
359
+ const fs = require('fs');
360
+ const p = require('path').join(require('os').homedir(), '.claude', 'settings.json');
361
+ const s = JSON.parse(fs.readFileSync(p, 'utf8'));
362
+ if (!s.hooks) s.hooks = {};
363
+ if (!Array.isArray(s.hooks.Stop)) s.hooks.Stop = [];
364
+ const has = s.hooks.Stop.some(e => e.hooks?.some(h => h.command?.includes('mcp-cleanup')));
365
+ if (!has) {
366
+ const script = require('path').join(require('os').homedir(), '.claude/scripts/mcp-cleanup.ps1').replace(/\\\\\\\\/g, '/');
367
+ const entry = s.hooks.Stop.find(e => e.matcher === '*' && Array.isArray(e.hooks));
368
+ const hook = { type: 'command', command: 'powershell -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File \\\"' + script + '\\\"', timeout: 8 };
369
+ if (entry) entry.hooks.push(hook); else s.hooks.Stop.push({ matcher: '*', hooks: [hook] });
370
+ fs.writeFileSync(p, JSON.stringify(s, null, 2) + '\\n');
371
+ console.log('mcp-cleanup hook registered');
372
+ } else { console.log('mcp-cleanup hook already exists'); }
373
+ \""
374
+ ```
375
+
376
+ macOS/Linux 원격 호스트에서는 이 단계를 건너뛴다 (PGID 기반 kill이 정상 동작).
377
+
378
+ 프로브 결과에서 OS를 확인하여 자동 판단:
379
+ - Windows → 배포 실행
380
+ - macOS/Linux → 건너뛰기 (표시만)
381
+
382
+ ```
383
+ "{host}는 Windows입니다. MCP 고아 프로세스 정리 훅을 배포합니다."
384
+ ```
385
+
386
+ **2-9. 후속 작업**
387
+
388
+ ```
389
+ question: "호스트가 등록되었습니다. 추가 작업이 있습니까?"
390
+ header: "다음"
391
+ options:
392
+ - label: "다른 호스트도 추가"
393
+ description: "호스트 추가 플로우 반복"
394
+ - label: "세션 spawn 테스트"
395
+ description: "/tfx-remote-spawn으로 세션 생성 테스트"
396
+ - label: "완료"
397
+ description: "설정 종료"
398
+ ```
399
+
400
+ #### 기존 호스트 편집 (Edit)
401
+
402
+ `references/hosts.json`을 읽어 등록된 호스트 목록을 AskUserQuestion으로 표시:
403
+
404
+ ```
405
+ question: "어떤 호스트를 편집하시겠습니까?"
406
+ header: "호스트"
407
+ options:
408
+ - label: "ultra4"
409
+ description: "Windows 데스크탑 (SSAFY) | 별칭: 울트라, 데스크탑 | tailscale-ssh"
410
+ - label: "m2"
411
+ description: "MacBook Pro | 별칭: 맥북, 맥 | ssh-over-vpn"
412
+ - label: "호스트 삭제"
413
+ description: "등록된 호스트를 제거"
414
+ ```
415
+
416
+ 호스트 선택 후 편집 항목 선택:
417
+
418
+ ```
419
+ question: "무엇을 수정하시겠습니까?"
420
+ header: "편집"
421
+ multiSelect: true
422
+ options:
423
+ - label: "설명"
424
+ description: "현재: {description}"
425
+ - label: "별칭"
426
+ description: "현재: {aliases}"
427
+ - label: "기본 디렉토리"
428
+ description: "현재: {default_dir}"
429
+ - label: "SSH 연결 방식"
430
+ description: "현재: {ssh_mode} → 변경"
431
+ - label: "Tailscale IP 갱신"
432
+ description: "tailscale status로 최신 IP/DNS 조회"
433
+ - label: "기본 호스트로 설정"
434
+ description: "현재 기본: {default_host}"
435
+ ```
436
+
437
+ 선택된 항목에 대해 순차 AskUserQuestion으로 새 값 입력받아 Edit 도구로 hosts.json 수정.
438
+
439
+ #### 전체 프로브 (Probe All)
440
+
441
+ 등록된 모든 호스트를 순회하며 프로브:
442
+
443
+ ```bash
444
+ node scripts/remote-spawn.mjs --probe {host}
445
+ ```
446
+
447
+ 결과를 종합 테이블로 표시:
448
+
449
+ ```
450
+ | 호스트 | OS | SSH 방식 | Claude | Tailscale | 상태 |
451
+ |--------|----|----------|--------|-----------|------|
452
+ | ultra4 | Windows | ssh-over-vpn | v1.x.x | online (100.x.x.x) | ✅ |
453
+ | m2 | macOS | tailscale-ssh | 미설치 | online (100.y.y.y) | ⚠ |
454
+ ```
455
+
456
+ 이슈가 있는 호스트가 있으면 AskUserQuestion:
457
+ ```
458
+ question: "이슈가 있는 호스트가 있습니다. 어떻게 하시겠습니까?"
459
+ header: "이슈"
460
+ options:
461
+ - label: "이슈 호스트 수정"
462
+ description: "{host}: Claude 미설치 → 원격 설치 시도"
463
+ - label: "Tailscale IP 일괄 갱신"
464
+ description: "모든 호스트의 Tailscale IP/DNS를 최신으로 갱신"
465
+ - label: "무시하고 계속"
466
+ description: "이슈를 확인만 하고 넘어감"
467
+ ```
468
+
469
+ #### 진단 (Diagnose)
470
+
471
+ 전체 환경을 점검하고 테이블로 보고:
472
+
473
+ ```
474
+ | 항목 | 상태 | 비고 |
475
+ |------|------|------|
476
+ | Tailscale | ✅ | 로그인됨, tailnet: yak-bebop |
477
+ | hosts.json | ✅ | 2개 호스트 등록 |
478
+ | SSH config | ✅ | ultra4, m2 존재 |
479
+ | psmux | ✅ | 설치됨 |
480
+ | Windows Terminal | ✅ | 감지됨 |
481
+ | 원격 캐시 | ✅ | .omc/state/remote-env/ |
482
+ ```
483
+
484
+ 점검 항목:
485
+ 1. **Tailscale 상태** — `tailscale status` 실행, 로그인/tailnet 이름/피어 수
486
+ 2. `references/hosts.json` 존재 및 유효성
487
+ 3. `~/.ssh/config`에 hosts.json 호스트들 등록 여부 (MagicDNS 사용 여부)
488
+ 4. Tailscale IP와 SSH config HostName 일치 여부
489
+ 5. psmux 설치 여부 (`hub/team/psmux.mjs` 존재)
490
+ 6. Windows Terminal 감지
491
+ 7. `.omc/state/remote-env/` 캐시 상태 (TTL 만료 여부)
492
+ 8. `remoteControlAtStartup` 설정 여부
493
+
494
+ 이슈 발견 시 AskUserQuestion:
495
+ ```
496
+ question: "N개 이슈가 발견되었습니다. 자동 수정을 시도하시겠습니까?"
497
+ header: "수정"
498
+ options:
499
+ - label: "자동 수정 (Recommended)"
500
+ description: "가능한 이슈를 자동으로 해결"
501
+ - label: "수동 확인"
502
+ description: "이슈별로 하나씩 확인"
503
+ - label: "건너뛰기"
504
+ description: "진단 결과만 확인"
505
+ ```
506
+
507
+ ### Step 3: 완료 후 후속 작업
508
+
509
+ ```
510
+ question: "다른 설정 작업을 하시겠습니까?"
511
+ header: "계속"
512
+ options:
513
+ - label: "다른 모드 실행"
514
+ description: "추가/편집/프로브/진단 메뉴로 돌아감"
515
+ - label: "원격 세션 시작"
516
+ description: "/tfx-remote-spawn으로 세션 생성"
517
+ - label: "종료"
518
+ description: "설정 완료"
519
+ ```
520
+
521
+ ## Tailscale 참조
522
+
523
+ ### 100.x.y.z IP 안정성
524
+
525
+ Tailscale의 CGNAT 주소(100.x.y.z)는 **영구적으로 안정**하다.
526
+ 네트워크 이동, 재부팅, VPN 재연결에도 변경되지 않는다.
527
+ 변경되는 경우: 노드를 tailnet에서 삭제 후 재등록, IP pool 변경, Tailscale 재설치.
528
+
529
+ 그럼에도 **MagicDNS 호스트명 사용을 권장**한다 — IP가 변경되어도 DNS가 자동 추적.
530
+
531
+ ### 플랫폼별 Tailscale SSH 지원
532
+
533
+ | 플랫폼 | SSH 클라이언트 | SSH 서버 | 비고 |
534
+ |--------|---------------|----------|------|
535
+ | Linux | ✅ | ✅ | 제한 없음 |
536
+ | macOS (Homebrew) | ✅ | ✅ | `brew install tailscale` |
537
+ | macOS (App Store) | ✅ | ❌ | 샌드박스 제한 |
538
+ | Windows | ✅ | ❌ | 클라이언트만 가능 |
539
+
540
+ ### Tailscale SSH 활성화 (서버측)
541
+
542
+ ```bash
543
+ # 서버에서 실행
544
+ tailscale set --ssh
545
+
546
+ # ACL policy에도 ssh 블록 필요 (admin console에서):
547
+ # {
548
+ # "ssh": [{
549
+ # "action": "accept",
550
+ # "src": ["autogroup:member"],
551
+ # "dst": ["autogroup:self"],
552
+ # "users": ["autogroup:nonroot", "root"]
553
+ # }]
554
+ # }
555
+ ```
556
+
557
+ ## 에러 처리
558
+
559
+ | 상황 | 처리 |
560
+ |------|------|
561
+ | Tailscale 미설치 | SSH config fallback, 설치 안내 |
562
+ | Tailscale 미로그인 | `tailscale login` 안내 |
563
+ | SSH config 없음 | 생성 가이드 출력 |
564
+ | SSH 연결 실패 | Tailscale IP 갱신 / MagicDNS 전환 안내 |
565
+ | macOS App Store Tailscale | SSH over VPN으로 자동 전환 |
566
+ | Windows 서버 대상 | SSH over VPN으로 자동 전환 |
567
+ | hosts.json 파싱 실패 | 백업 생성 후 새로 작성 |
568
+ | 원격 npm 없음 | Node.js 설치 안내 |
569
+ | psmux 미설치 | WT+SSH fallback 안내 |
570
+
571
+ ## 전제 조건
572
+
573
+ - SSH 클라이언트 (ssh 명령어)
574
+ - `scripts/remote-spawn.mjs` 설치됨 (`triflux setup` 자동)
575
+ - (권장) Tailscale — 네트워크 자동 감지 + MagicDNS
576
+ - (권장) psmux, Windows Terminal
@@ -1,8 +1,6 @@
1
1
  {
2
2
  "name": "tfx-remote-setup",
3
3
  "description": "원격 호스트 설정 위저드. AskUserQuestion 기반 인터랙티브 UI로 Tailscale 네트워크 감지, SSH 연결 확인, Claude 설치 프로브, hosts.json 관리를 수행합니다. Use when: remote setup, 원격 설정, 호스트 추가, hosts.json, 원격 환경, remote config, tailscale, 테일스케일",
4
- "triggers": [
5
- "tfx-remote-setup"
6
- ],
4
+ "triggers": ["tfx-remote-setup"],
7
5
  "argument_hint": "[--add|--edit|--probe-all|--diagnose]"
8
6
  }