triflux 10.0.0-alpha.1 → 10.0.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 (201) hide show
  1. package/bin/triflux.mjs +290 -25
  2. package/package.json +1 -1
  3. package/skills/_templates/base.md +9 -0
  4. package/skills/_templates/deep.md +6 -0
  5. package/skills/merge-worktree/SKILL.md.tmpl +144 -0
  6. package/skills/shared/arguments-processing.md +2 -0
  7. package/skills/shared/mandatory-rules.md +6 -0
  8. package/skills/shared/telemetry-segment.md +6 -0
  9. package/skills/star-prompt/SKILL.md.tmpl +122 -0
  10. package/skills/tfx-analysis/SKILL.md.tmpl +106 -0
  11. package/skills/tfx-analysis/skill.json +11 -0
  12. package/skills/tfx-auto/SKILL.md +8 -0
  13. package/skills/{tfx-workspace/skill-snapshot/tfx-auto/SKILL.md → tfx-auto/SKILL.md.tmpl} +91 -21
  14. package/skills/tfx-auto/skill.json +26 -0
  15. package/skills/{tfx-workspace/skill-snapshot/tfx-auto-codex/SKILL.md → tfx-auto-codex/SKILL.md.tmpl} +31 -3
  16. package/skills/tfx-auto-codex/skill.json +8 -0
  17. package/skills/tfx-autopilot/SKILL.md.tmpl +115 -0
  18. package/skills/tfx-autopilot/skill.json +10 -0
  19. package/skills/tfx-autoresearch/SKILL.md +5 -6
  20. package/skills/tfx-autoresearch/SKILL.md.tmpl +135 -0
  21. package/skills/tfx-autoresearch/skill.json +14 -0
  22. package/skills/tfx-autoroute/SKILL.md.tmpl +188 -0
  23. package/skills/tfx-autoroute/skill.json +12 -0
  24. package/skills/tfx-codex/SKILL.md +8 -0
  25. package/skills/{tfx-workspace/skill-snapshot/tfx-codex/SKILL.md → tfx-codex/SKILL.md.tmpl} +15 -7
  26. package/skills/tfx-codex/skill.json +8 -0
  27. package/skills/tfx-codex-swarm/SKILL.md +10 -627
  28. package/skills/tfx-codex-swarm/SKILL.md.tmpl +16 -0
  29. package/skills/tfx-codex-swarm/skill.json +5 -0
  30. package/skills/tfx-consensus/SKILL.md.tmpl +145 -0
  31. package/skills/tfx-consensus/skill.json +8 -0
  32. package/skills/tfx-debate/SKILL.md.tmpl +191 -0
  33. package/skills/tfx-debate/skill.json +12 -0
  34. package/skills/tfx-deep-analysis/SKILL.md.tmpl +227 -0
  35. package/skills/tfx-deep-analysis/skill.json +10 -0
  36. package/skills/tfx-deep-interview/SKILL.md +2 -1
  37. package/skills/tfx-deep-interview/SKILL.md.tmpl +203 -0
  38. package/skills/tfx-deep-interview/skill.json +12 -0
  39. package/skills/tfx-deep-plan/SKILL.md.tmpl +281 -0
  40. package/skills/tfx-deep-plan/skill.json +13 -0
  41. package/skills/tfx-deep-qa/SKILL.md.tmpl +164 -0
  42. package/skills/tfx-deep-qa/skill.json +11 -0
  43. package/skills/tfx-deep-research/SKILL.md.tmpl +216 -0
  44. package/skills/tfx-deep-research/skill.json +14 -0
  45. package/skills/tfx-deep-review/SKILL.md.tmpl +178 -0
  46. package/skills/tfx-deep-review/skill.json +12 -0
  47. package/skills/tfx-doctor/SKILL.md.tmpl +172 -0
  48. package/skills/tfx-doctor/skill.json +8 -0
  49. package/skills/tfx-find/SKILL.md +12 -1
  50. package/skills/tfx-find/SKILL.md.tmpl +129 -0
  51. package/skills/tfx-find/skill.json +12 -0
  52. package/skills/tfx-forge/SKILL.md.tmpl +187 -0
  53. package/skills/tfx-forge/skill.json +12 -0
  54. package/skills/tfx-fullcycle/SKILL.md.tmpl +285 -0
  55. package/skills/tfx-fullcycle/skill.json +11 -0
  56. package/skills/{tfx-workspace/skill-snapshot/tfx-gemini/SKILL.md → tfx-gemini/SKILL.md.tmpl} +14 -6
  57. package/skills/tfx-gemini/skill.json +8 -0
  58. package/skills/tfx-hooks/SKILL.md.tmpl +216 -0
  59. package/skills/tfx-hooks/skill.json +8 -0
  60. package/skills/tfx-hub/SKILL.md.tmpl +212 -0
  61. package/skills/tfx-hub/skill.json +8 -0
  62. package/skills/tfx-index/SKILL.md +12 -1
  63. package/skills/tfx-index/SKILL.md.tmpl +148 -0
  64. package/skills/tfx-index/skill.json +11 -0
  65. package/skills/tfx-interview/SKILL.md.tmpl +284 -0
  66. package/skills/tfx-interview/skill.json +12 -0
  67. package/skills/tfx-multi/SKILL.md.tmpl +183 -0
  68. package/skills/tfx-multi/skill.json +8 -0
  69. package/skills/tfx-panel/SKILL.md.tmpl +188 -0
  70. package/skills/tfx-panel/skill.json +12 -0
  71. package/skills/tfx-persist/SKILL.md.tmpl +269 -0
  72. package/skills/tfx-persist/skill.json +12 -0
  73. package/skills/tfx-plan/SKILL.md +8 -0
  74. package/skills/tfx-plan/SKILL.md.tmpl +68 -0
  75. package/skills/tfx-plan/skill.json +11 -0
  76. package/skills/tfx-profile/SKILL.md.tmpl +239 -0
  77. package/skills/tfx-profile/skill.json +8 -0
  78. package/skills/tfx-prune/SKILL.md.tmpl +199 -0
  79. package/skills/tfx-prune/skill.json +12 -0
  80. package/skills/tfx-psmux-rules/SKILL.md.tmpl +317 -0
  81. package/skills/tfx-psmux-rules/skill.json +8 -0
  82. package/skills/tfx-qa/SKILL.md +8 -0
  83. package/skills/tfx-qa/SKILL.md.tmpl +122 -0
  84. package/skills/tfx-qa/skill.json +11 -0
  85. package/skills/tfx-ralph/SKILL.md.tmpl +27 -0
  86. package/skills/tfx-ralph/skill.json +8 -0
  87. package/skills/tfx-remote-setup/SKILL.md.tmpl +576 -0
  88. package/skills/tfx-remote-setup/skill.json +8 -0
  89. package/skills/tfx-remote-spawn/SKILL.md +11 -8
  90. package/skills/tfx-remote-spawn/SKILL.md.tmpl +263 -0
  91. package/skills/tfx-remote-spawn/skill.json +9 -0
  92. package/skills/tfx-research/SKILL.md +8 -0
  93. package/skills/tfx-research/SKILL.md.tmpl +149 -0
  94. package/skills/tfx-research/skill.json +13 -0
  95. package/skills/tfx-review/SKILL.md +8 -0
  96. package/skills/tfx-review/SKILL.md.tmpl +57 -0
  97. package/skills/tfx-review/skill.json +11 -0
  98. package/skills/tfx-setup/SKILL.md.tmpl +380 -0
  99. package/skills/tfx-setup/skill.json +8 -0
  100. package/skills/tfx-swarm/SKILL.md +154 -0
  101. package/skills/tfx-swarm/SKILL.md.tmpl +154 -0
  102. package/skills/tfx-swarm/skill.json +5 -0
  103. package/skills/tfx-codex-swarm-workspace/iteration-1/benchmark.json +0 -33
  104. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/eval_metadata.json +0 -42
  105. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/grading.json +0 -11
  106. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/analysis.md +0 -87
  107. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/classification.md +0 -35
  108. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/commands.sh +0 -275
  109. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/routing.md +0 -56
  110. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/timing.json +0 -5
  111. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/grading.json +0 -11
  112. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/analysis.md +0 -92
  113. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/classification.md +0 -71
  114. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/commands.sh +0 -264
  115. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/routing.md +0 -113
  116. package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/timing.json +0 -5
  117. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/eval_metadata.json +0 -32
  118. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/grading.json +0 -9
  119. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/analysis.md +0 -96
  120. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/classification.md +0 -38
  121. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/commands.sh +0 -151
  122. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/routing.md +0 -51
  123. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/timing.json +0 -5
  124. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/grading.json +0 -9
  125. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/analysis.md +0 -127
  126. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/classification.md +0 -57
  127. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/commands.sh +0 -129
  128. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/routing.md +0 -84
  129. package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/timing.json +0 -5
  130. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/eval_metadata.json +0 -27
  131. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/grading.json +0 -8
  132. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/analysis.md +0 -98
  133. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/classification.md +0 -65
  134. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/commands.sh +0 -123
  135. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/routing.md +0 -66
  136. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/timing.json +0 -5
  137. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/grading.json +0 -8
  138. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/analysis.md +0 -88
  139. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/classification.md +0 -40
  140. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/commands.sh +0 -130
  141. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/routing.md +0 -61
  142. package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/timing.json +0 -5
  143. package/skills/tfx-workspace/async-tests/run-tests.sh +0 -203
  144. package/skills/tfx-workspace/evals/evals.json +0 -79
  145. package/skills/tfx-workspace/iteration-1/benchmark.json +0 -162
  146. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/eval_metadata.json +0 -11
  147. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/grading.json +0 -9
  148. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/outputs/analysis.md +0 -154
  149. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/timing.json +0 -5
  150. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/grading.json +0 -9
  151. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/outputs/analysis.md +0 -126
  152. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/timing.json +0 -5
  153. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/eval_metadata.json +0 -11
  154. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/grading.json +0 -9
  155. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/outputs/analysis.md +0 -119
  156. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/timing.json +0 -5
  157. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/grading.json +0 -9
  158. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/outputs/analysis.md +0 -115
  159. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/timing.json +0 -5
  160. package/skills/tfx-workspace/iteration-1/hub-start-sequence/eval_metadata.json +0 -10
  161. package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/grading.json +0 -8
  162. package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/outputs/analysis.md +0 -86
  163. package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/timing.json +0 -5
  164. package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/grading.json +0 -8
  165. package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/outputs/analysis.md +0 -81
  166. package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/timing.json +0 -5
  167. package/skills/tfx-workspace/iteration-1/multi-team-creation/eval_metadata.json +0 -12
  168. package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/grading.json +0 -10
  169. package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/outputs/analysis.md +0 -316
  170. package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/timing.json +0 -5
  171. package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/grading.json +0 -10
  172. package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/outputs/analysis.md +0 -352
  173. package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/timing.json +0 -5
  174. package/skills/tfx-workspace/iteration-1/review.html +0 -1325
  175. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/eval_metadata.json +0 -12
  176. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/grading.json +0 -10
  177. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/outputs/analysis.md +0 -97
  178. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/timing.json +0 -5
  179. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/grading.json +0 -10
  180. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/outputs/analysis.md +0 -94
  181. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/timing.json +0 -5
  182. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/eval_metadata.json +0 -12
  183. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/grading.json +0 -10
  184. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/outputs/analysis.md +0 -209
  185. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/timing.json +0 -5
  186. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/grading.json +0 -10
  187. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/outputs/analysis.md +0 -193
  188. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/timing.json +0 -5
  189. package/skills/tfx-workspace/iteration-2/benchmark.json +0 -62
  190. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/eval_metadata.json +0 -13
  191. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/grading.json +0 -11
  192. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/outputs/analysis.md +0 -382
  193. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/timing.json +0 -5
  194. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/grading.json +0 -11
  195. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/outputs/analysis.md +0 -333
  196. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/timing.json +0 -5
  197. package/skills/tfx-workspace/iteration-2/review.html +0 -1325
  198. package/skills/tfx-workspace/skill-snapshot/tfx-doctor/SKILL.md +0 -94
  199. package/skills/tfx-workspace/skill-snapshot/tfx-hub/SKILL.md +0 -133
  200. package/skills/tfx-workspace/skill-snapshot/tfx-multi/SKILL.md +0 -426
  201. package/skills/tfx-workspace/skill-snapshot/tfx-setup/SKILL.md +0 -101
package/bin/triflux.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  // triflux CLI — setup, doctor, version
3
3
  import { copyFileSync, existsSync, readFileSync, readSync, writeFileSync, mkdirSync, chmodSync, readdirSync, unlinkSync, statSync, openSync, closeSync } from "fs";
4
- import { join, dirname, basename } from "path";
4
+ import { join, dirname, basename, resolve } from "path";
5
5
  import { homedir, tmpdir } from "os";
6
6
  import { execSync, execFileSync, spawn } from "child_process";
7
7
  import { fileURLToPath } from "url";
@@ -11,14 +11,17 @@ import { detectMultiplexer, getSessionAttachedCount, killSession, listSessions,
11
11
  import { forceCleanupTeam } from "../hub/team/nativeProxy.mjs";
12
12
  import { cleanupStaleOmcTeams, inspectStaleOmcTeams } from "../hub/team/staleState.mjs";
13
13
  import { getPipelineStateDbPath } from "../hub/pipeline/state.mjs";
14
+ import { serializeHandoff } from "../scripts/lib/handoff.mjs";
14
15
  import { ensureGeminiProfiles } from "../scripts/lib/gemini-profiles.mjs";
15
16
  import { probePsmuxSupport, formatPsmuxInstallGuidance, formatPsmuxUpdateGuidance } from "../scripts/lib/psmux-info.mjs";
16
17
  import {
17
18
  addRegistryServer,
19
+ createDefaultRegistry,
18
20
  inspectRegistry,
19
21
  inspectRegistryStatus,
20
22
  removeRegistryServer,
21
23
  removeServerFromTargets,
24
+ saveRegistry,
22
25
  syncRegistryTargets,
23
26
  } from "../scripts/lib/mcp-guard-engine.mjs";
24
27
  import {
@@ -28,7 +31,13 @@ import {
28
31
  extractManagedHookFilename, getManagedRegistryHooks, ensureHooksInSettings,
29
32
  ensureCodexHubServerConfig,
30
33
  } from "../scripts/setup.mjs";
34
+ import {
35
+ ensureGlobalClaudeRoutingSection,
36
+ ensureTfxSection,
37
+ getLatestRoutingTable,
38
+ } from "../scripts/claudemd-sync.mjs";
31
39
  import { cleanupTmpFiles } from "../scripts/tmp-cleanup.mjs";
40
+ import { checkNetworkAvailability, validateRuntimeCachePaths } from "../hub/lib/cache-guard.mjs";
32
41
 
33
42
  const PKG_ROOT = dirname(dirname(fileURLToPath(import.meta.url)));
34
43
  const CLAUDE_DIR = join(homedir(), ".claude");
@@ -98,6 +107,17 @@ const CLI_COMMAND_SCHEMAS = Object.freeze({
98
107
  { name: "--json", type: "boolean", description: "버전 정보를 JSON으로 출력" },
99
108
  ],
100
109
  },
110
+ handoff: {
111
+ usage: "tfx handoff [--target local|remote] [--decision <text>] [--decision-file <path>] [--output <path>] [--json]",
112
+ description: "현재 작업 컨텍스트를 세션 핸드오프 프롬프트로 직렬화",
113
+ options: [
114
+ { name: "--target", type: "string", description: "주입 대상 (local|remote, 기본값 remote)" },
115
+ { name: "--decision", type: "string", description: "핸드오프 결정사항 (반복 지정 가능)" },
116
+ { name: "--decision-file", type: "string", description: "결정사항 파일 (라인/불릿 단위)" },
117
+ { name: "--output", type: "string", description: "생성한 핸드오프 프롬프트 저장 경로" },
118
+ { name: "--json", type: "boolean", description: "핸드오프 결과를 JSON으로 출력" },
119
+ ],
120
+ },
101
121
  list: {
102
122
  usage: "tfx list [--json]",
103
123
  description: "패키지 스킬과 사용자 스킬 목록 표시",
@@ -522,6 +542,26 @@ function describeSyncAction(src, dst, label) {
522
542
  };
523
543
  }
524
544
 
545
+ function syncClaudeRoutingSectionsForCli() {
546
+ try {
547
+ const routingTable = getLatestRoutingTable();
548
+ return [
549
+ ensureTfxSection(join(PKG_ROOT, "CLAUDE.md"), routingTable),
550
+ ensureGlobalClaudeRoutingSection(CLAUDE_DIR),
551
+ ];
552
+ } catch (error) {
553
+ const reason = error instanceof Error ? error.message : "routing_sync_failed";
554
+ return [{ action: "unchanged", path: join(PKG_ROOT, "CLAUDE.md"), skipped: true, reason }];
555
+ }
556
+ }
557
+
558
+ function getClaudeRoutingSyncSummary(results) {
559
+ return results.reduce((summary, result) => ({
560
+ changed: summary.changed + (result.action === "created" || result.action === "updated" ? 1 : 0),
561
+ skipped: summary.skipped + (result.skipped ? 1 : 0),
562
+ }), { changed: 0, skipped: 0 });
563
+ }
564
+
525
565
  // ── 크로스 셸 진단 ──
526
566
 
527
567
  function checkCliCrossShell(cmd, installHint) {
@@ -691,7 +731,7 @@ function buildSetupDryRunPlan() {
691
731
  }
692
732
 
693
733
  function cmdSetup(options = {}) {
694
- const { dryRun = false, overrideVersion } = options;
734
+ const { dryRun = false, overrideVersion, skipClaudeMdSync = false } = options;
695
735
  if (dryRun) {
696
736
  printJson(buildSetupDryRunPlan());
697
737
  return;
@@ -781,6 +821,21 @@ function cmdSetup(options = {}) {
781
821
  // ── 결과 추적 ──
782
822
  const summary = [];
783
823
 
824
+ if (!skipClaudeMdSync) {
825
+ const claudeRoutingResults = syncClaudeRoutingSectionsForCli();
826
+ const claudeRoutingSummary = getClaudeRoutingSyncSummary(claudeRoutingResults);
827
+ if (claudeRoutingSummary.changed > 0) {
828
+ ok(`CLAUDE.md 라우팅: ${claudeRoutingSummary.changed}개 파일 반영`);
829
+ summary.push({ item: "CLAUDE.md 라우팅", status: "✅", detail: `${claudeRoutingSummary.changed}개 파일 반영` });
830
+ } else if (claudeRoutingSummary.skipped > 0) {
831
+ ok("CLAUDE.md 라우팅: 대상 파일 없음 (건너뜀)");
832
+ summary.push({ item: "CLAUDE.md 라우팅", status: "⏭️", detail: "대상 파일 없음" });
833
+ } else {
834
+ ok("CLAUDE.md 라우팅: 최신 상태");
835
+ summary.push({ item: "CLAUDE.md 라우팅", status: "✅", detail: "최신 상태" });
836
+ }
837
+ }
838
+
784
839
  const codexProfileResult = ensureCodexProfiles();
785
840
  if (!codexProfileResult.ok) {
786
841
  warn(`Codex profiles 설정 실패: ${codexProfileResult.message}`);
@@ -1128,13 +1183,10 @@ function buildMcpStatusRows(statusInfo) {
1128
1183
  }
1129
1184
 
1130
1185
  function ensureValidRegistryState() {
1131
- const registryState = inspectRegistry();
1186
+ let registryState = inspectRegistry();
1132
1187
  if (!registryState.exists) {
1133
- throw createCliError(`MCP registry missing: ${registryState.path}`, {
1134
- exitCode: EXIT_CONFIG_ERROR,
1135
- reason: "configError",
1136
- fix: "config/mcp-registry.json을 복원하거나 `tfx mcp add <name> --url <url>`로 다시 생성하세요.",
1137
- });
1188
+ saveRegistry(createDefaultRegistry());
1189
+ registryState = inspectRegistry();
1138
1190
  }
1139
1191
  if (!registryState.valid) {
1140
1192
  throw createCliError(`MCP registry invalid: ${registryState.errors.join("; ")}`, {
@@ -1335,9 +1387,13 @@ async function cmdDoctor(options = {}) {
1335
1387
  warn(`MCP registry 자동 동기화 실패: ${error.message}`);
1336
1388
  }
1337
1389
  } else if (registryStateForFix.exists) {
1338
- warn("MCP registry invalid — auto sync 건너뜀");
1390
+ saveRegistry(createDefaultRegistry());
1391
+ report.actions.push({ type: "mcp-registry-reset", status: "ok" });
1392
+ ok("MCP registry 손상 → 기본값으로 재생성됨");
1339
1393
  } else {
1340
- info("MCP registry 없음 — auto sync 건너뜀");
1394
+ saveRegistry(createDefaultRegistry());
1395
+ report.actions.push({ type: "mcp-registry-create", status: "ok" });
1396
+ ok("MCP registry 없음 → 기본값으로 자동 생성됨");
1341
1397
  }
1342
1398
  console.log(`\n ${LINE}`);
1343
1399
  info("수정 완료 — 아래 진단 결과를 확인하세요");
@@ -2157,28 +2213,27 @@ async function cmdDoctor(options = {}) {
2157
2213
  // ── MCP 중앙 레지스트리 ──
2158
2214
  section("MCP Registry");
2159
2215
  {
2160
- const registryState = inspectRegistry();
2216
+ let registryState = inspectRegistry();
2161
2217
  if (!registryState.exists) {
2218
+ saveRegistry(createDefaultRegistry());
2219
+ registryState = inspectRegistry();
2162
2220
  addDoctorCheck(report, {
2163
2221
  name: "mcp-registry",
2164
- status: "missing",
2222
+ status: "fixed",
2165
2223
  path: registryState.path,
2166
- fix: "config/mcp-registry.json을 복원하거나 `tfx mcp add <name> --url <url>`를 실행하세요.",
2224
+ action: "기본값으로 자동 생성됨",
2167
2225
  });
2168
- warn("mcp-registry.json 없음");
2169
- info(`path: ${registryState.path}`);
2170
- issues++;
2226
+ ok("mcp-registry.json 없음 → 기본값으로 자동 생성됨");
2171
2227
  } else if (!registryState.valid) {
2228
+ saveRegistry(createDefaultRegistry());
2229
+ registryState = inspectRegistry();
2172
2230
  addDoctorCheck(report, {
2173
2231
  name: "mcp-registry",
2174
- status: "invalid",
2232
+ status: "fixed",
2175
2233
  path: registryState.path,
2176
- errors: registryState.errors,
2177
- fix: "config/mcp-registry.json 구조를 수정하세요.",
2234
+ action: "손상 감지 → 기본값으로 재생성됨",
2178
2235
  });
2179
- fail("mcp-registry.json invalid");
2180
- for (const entry of registryState.errors) info(entry);
2181
- issues++;
2236
+ warn("mcp-registry.json 손상 → 기본값으로 재생성됨");
2182
2237
  } else {
2183
2238
  const statusInfo = inspectRegistryStatus(registryState.registry);
2184
2239
  const invalidConfigs = statusInfo.configs.filter((config) => config.parseError);
@@ -2434,7 +2489,56 @@ async function cmdDoctor(options = {}) {
2434
2489
  });
2435
2490
  }
2436
2491
 
2437
- function cmdUpdate() {
2492
+ function normalizeRemoteReachabilityUrl(remoteUrl) {
2493
+ if (!remoteUrl) return null;
2494
+ if (/^https?:\/\//iu.test(remoteUrl)) {
2495
+ try {
2496
+ return new URL(remoteUrl).origin;
2497
+ } catch {
2498
+ return null;
2499
+ }
2500
+ }
2501
+ const scpMatch = /^git@([^:]+):/iu.exec(remoteUrl);
2502
+ if (scpMatch) return `https://${scpMatch[1]}`;
2503
+ if (/^ssh:\/\//iu.test(remoteUrl)) {
2504
+ try {
2505
+ return `https://${new URL(remoteUrl).hostname}`;
2506
+ } catch {
2507
+ return null;
2508
+ }
2509
+ }
2510
+ return null;
2511
+ }
2512
+
2513
+ function resolveGitUpdateUrl(repoDir) {
2514
+ try {
2515
+ const remoteUrl = execSync("git remote get-url origin", {
2516
+ encoding: "utf8",
2517
+ timeout: 10_000,
2518
+ cwd: repoDir,
2519
+ stdio: ["pipe", "pipe", "ignore"],
2520
+ windowsHide: true,
2521
+ }).trim();
2522
+ return normalizeRemoteReachabilityUrl(remoteUrl);
2523
+ } catch {
2524
+ return null;
2525
+ }
2526
+ }
2527
+
2528
+ function resolveUpdateTargets({ installMode, pluginPath }) {
2529
+ const repoDir = installMode === "plugin" ? (pluginPath || PKG_ROOT) : PKG_ROOT;
2530
+ const gitUrl = resolveGitUpdateUrl(repoDir);
2531
+
2532
+ if (installMode === "npm-global" || installMode === "npm-local") {
2533
+ return ["https://registry.npmjs.org/triflux"];
2534
+ }
2535
+ if (installMode === "plugin" || installMode === "git-local") {
2536
+ return gitUrl ? [gitUrl] : ["https://github.com"];
2537
+ }
2538
+ return [];
2539
+ }
2540
+
2541
+ async function cmdUpdate() {
2438
2542
  const isDev = isDevUpdateRequested(NORMALIZED_ARGS);
2439
2543
  const tagLabel = isDev ? ` ${YELLOW}--dev${RESET}` : "";
2440
2544
  console.log(`\n${BOLD}triflux update${RESET}${tagLabel}\n`);
@@ -2490,6 +2594,27 @@ function cmdUpdate() {
2490
2594
 
2491
2595
  info(`검색: ${installMode === "plugin" ? "플러그인" : installMode === "npm-global" ? "npm global" : installMode === "npm-local" ? "npm local" : installMode === "git-local" ? "git 로컬 저장소" : "알 수 없음"} 설치 감지`);
2492
2596
 
2597
+ const networkTargets = resolveUpdateTargets({ installMode, pluginPath });
2598
+ if (networkTargets.length > 0) {
2599
+ const networkStatus = await checkNetworkAvailability(networkTargets);
2600
+ if (!networkStatus.online) {
2601
+ fail(`네트워크 확인 실패: ${networkStatus.unreachable.join(", ")}`);
2602
+ info("네트워크 연결을 확인한 뒤 다시 시도하세요.");
2603
+ return;
2604
+ }
2605
+ ok(`네트워크 확인 완료 (${networkStatus.reachable.join(", ")})`);
2606
+ }
2607
+
2608
+ const cacheValidation = validateRuntimeCachePaths(join(CLAUDE_DIR, "cache"));
2609
+ if (!cacheValidation.ok) {
2610
+ warn(`런타임 캐시 검증 이슈 ${cacheValidation.issues.length}건 발견`);
2611
+ for (const issue of cacheValidation.issues) {
2612
+ info(`${issue.file}: ${issue.error}`);
2613
+ }
2614
+ } else {
2615
+ ok("런타임 캐시 검증 완료");
2616
+ }
2617
+
2493
2618
  // 2. 설치 방식에 따라 업데이트
2494
2619
  const oldVer = PKG.version;
2495
2620
  let updated = false;
@@ -2654,9 +2779,23 @@ function cmdUpdate() {
2654
2779
  }
2655
2780
  }
2656
2781
 
2782
+ // ── Post-update: CLAUDE.md 라우팅 동기화 ──
2783
+ console.log(`\n${CYAN}── CLAUDE.md 라우팅 동기화 ──${RESET}`);
2784
+ {
2785
+ const claudeRoutingResults = syncClaudeRoutingSectionsForCli();
2786
+ const claudeRoutingSummary = getClaudeRoutingSyncSummary(claudeRoutingResults);
2787
+ if (claudeRoutingSummary.changed > 0) {
2788
+ ok(`CLAUDE.md 라우팅 ${claudeRoutingSummary.changed}개 파일 반영`);
2789
+ } else if (claudeRoutingSummary.skipped > 0) {
2790
+ ok("CLAUDE.md 라우팅 대상 파일 없음 (건너뜀)");
2791
+ } else {
2792
+ ok("CLAUDE.md 라우팅 최신 상태");
2793
+ }
2794
+ }
2795
+
2657
2796
  // ── Post-update: 설정 동기화 ──
2658
2797
  console.log(`\n${CYAN}── 설정 동기화 ──${RESET}`);
2659
- cmdSetup({ fromUpdate: true, overrideVersion: newVer });
2798
+ cmdSetup({ fromUpdate: true, overrideVersion: newVer, skipClaudeMdSync: true });
2660
2799
 
2661
2800
  // ── Post-update: 훅 오케스트레이터 적용 ──
2662
2801
  {
@@ -2783,6 +2922,128 @@ function cmdVersion(options = {}) {
2783
2922
  console.log("");
2784
2923
  }
2785
2924
 
2925
+ function cmdHandoff(args = [], options = {}) {
2926
+ const { json = false } = options;
2927
+ const parsed = {
2928
+ target: "remote",
2929
+ decisions: [],
2930
+ decisionFile: null,
2931
+ output: null,
2932
+ cwd: process.cwd(),
2933
+ };
2934
+
2935
+ for (let index = 0; index < args.length; index += 1) {
2936
+ const arg = args[index];
2937
+ const next = args[index + 1];
2938
+
2939
+ if (arg === "--target") {
2940
+ if (!next || next.startsWith("-")) {
2941
+ throw createCliError("--target 값이 필요합니다 (local|remote)", {
2942
+ exitCode: EXIT_ARG_ERROR,
2943
+ reason: "argError",
2944
+ fix: "tfx handoff --target remote",
2945
+ });
2946
+ }
2947
+ if (!["local", "remote"].includes(next)) {
2948
+ throw createCliError(`지원하지 않는 --target 값: ${next}`, {
2949
+ exitCode: EXIT_ARG_ERROR,
2950
+ reason: "argError",
2951
+ fix: "tfx handoff --target local|remote",
2952
+ });
2953
+ }
2954
+ parsed.target = next;
2955
+ index += 1;
2956
+ continue;
2957
+ }
2958
+
2959
+ if (arg === "--decision") {
2960
+ if (!next || next.startsWith("-")) {
2961
+ throw createCliError("--decision 값이 필요합니다", {
2962
+ exitCode: EXIT_ARG_ERROR,
2963
+ reason: "argError",
2964
+ fix: "tfx handoff --decision \"결정사항\"",
2965
+ });
2966
+ }
2967
+ parsed.decisions.push(next);
2968
+ index += 1;
2969
+ continue;
2970
+ }
2971
+
2972
+ if (arg === "--decision-file") {
2973
+ if (!next || next.startsWith("-")) {
2974
+ throw createCliError("--decision-file 경로가 필요합니다", {
2975
+ exitCode: EXIT_ARG_ERROR,
2976
+ reason: "argError",
2977
+ fix: "tfx handoff --decision-file .omx/notepad.md",
2978
+ });
2979
+ }
2980
+ parsed.decisionFile = resolve(next);
2981
+ index += 1;
2982
+ continue;
2983
+ }
2984
+
2985
+ if (arg === "--output" || arg === "--out") {
2986
+ if (!next || next.startsWith("-")) {
2987
+ throw createCliError(`${arg} 경로가 필요합니다`, {
2988
+ exitCode: EXIT_ARG_ERROR,
2989
+ reason: "argError",
2990
+ fix: "tfx handoff --output .omx/handoff.md",
2991
+ });
2992
+ }
2993
+ parsed.output = resolve(next);
2994
+ index += 1;
2995
+ continue;
2996
+ }
2997
+
2998
+ if (arg === "--cwd") {
2999
+ if (!next || next.startsWith("-")) {
3000
+ throw createCliError("--cwd 경로가 필요합니다", {
3001
+ exitCode: EXIT_ARG_ERROR,
3002
+ reason: "argError",
3003
+ fix: "tfx handoff --cwd <project-path>",
3004
+ });
3005
+ }
3006
+ parsed.cwd = resolve(next);
3007
+ index += 1;
3008
+ continue;
3009
+ }
3010
+
3011
+ throw createCliError(`알 수 없는 handoff 옵션: ${arg}`, {
3012
+ exitCode: EXIT_ARG_ERROR,
3013
+ reason: "argError",
3014
+ fix: "tfx handoff --target remote --output .omx/handoff.md",
3015
+ });
3016
+ }
3017
+
3018
+ const result = serializeHandoff({
3019
+ target: parsed.target,
3020
+ decisions: parsed.decisions,
3021
+ decisionFile: parsed.decisionFile,
3022
+ cwd: parsed.cwd,
3023
+ });
3024
+
3025
+ if (parsed.output) {
3026
+ const outputDir = dirname(parsed.output);
3027
+ if (!existsSync(outputDir)) mkdirSync(outputDir, { recursive: true });
3028
+ writeFileSync(parsed.output, `${result.prompt}\n`, "utf8");
3029
+ }
3030
+
3031
+ if (json) {
3032
+ printJson({
3033
+ handoff: {
3034
+ ...result,
3035
+ ...(parsed.output ? { output: parsed.output } : {}),
3036
+ },
3037
+ });
3038
+ return;
3039
+ }
3040
+
3041
+ console.log(result.prompt);
3042
+ if (parsed.output) {
3043
+ console.log(`\n${DIM}saved:${RESET} ${parsed.output}`);
3044
+ }
3045
+ }
3046
+
2786
3047
  function cmdSchema(args = []) {
2787
3048
  const bundle = loadDelegatorSchemaBundle();
2788
3049
  const selector = String(args[0] || "").trim();
@@ -3054,6 +3315,7 @@ ${updateNotice}
3054
3315
  ${WHITE_BRIGHT}tfx update${RESET} ${GRAY}최신 안정 버전으로 업데이트${RESET}
3055
3316
  ${DIM} --dev / dev${RESET} ${GRAY}dev 태그로 업데이트${RESET}
3056
3317
  ${WHITE_BRIGHT}tfx list${RESET} ${GRAY}설치된 스킬 목록${RESET}
3318
+ ${WHITE_BRIGHT}tfx handoff${RESET} ${GRAY}현재 컨텍스트를 원격/로컬 핸드오프 프롬프트로 생성${RESET}
3057
3319
  ${WHITE_BRIGHT}tfx schema${RESET} ${GRAY}CLI/Hub schema JSON 출력${RESET}
3058
3320
  ${WHITE_BRIGHT}tfx hub${RESET} ${GRAY}MCP 메시지 버스 관리 (start/stop/status)${RESET}
3059
3321
  ${WHITE_BRIGHT}tfx tray${RESET} ${GRAY}Windows 시스템 트레이 실행${RESET}
@@ -3553,12 +3815,15 @@ async function main() {
3553
3815
  cmdSchema(cmdArgs);
3554
3816
  return;
3555
3817
  case "update":
3556
- cmdUpdate();
3818
+ await cmdUpdate();
3557
3819
  return;
3558
3820
  case "list":
3559
3821
  case "ls":
3560
3822
  cmdList({ json: JSON_OUTPUT });
3561
3823
  return;
3824
+ case "handoff":
3825
+ cmdHandoff(cmdArgs, { json: JSON_OUTPUT });
3826
+ return;
3562
3827
  case "hub":
3563
3828
  await cmdHub(cmdArgs, { json: JSON_OUTPUT && (cmdArgs[0] || "status") === "status" });
3564
3829
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "triflux",
3
- "version": "10.0.0-alpha.1",
3
+ "version": "10.0.0",
4
4
  "description": "CLI-first multi-model orchestrator for Claude Code — route tasks to Codex, Gemini, and Claude",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,9 @@
1
+ > **ARGUMENTS 처리**: 이 스킬이 `ARGUMENTS: <값>`과 함께 호출되면, 해당 값을 사용자 입력으로 취급하여
2
+ > 워크플로우의 첫 단계 입력으로 사용한다. ARGUMENTS가 비어있거나 없으면 기존 절차대로 사용자에게 입력을 요청한다.
3
+
4
+ > **Telemetry**
5
+ >
6
+ > - Skill: `{{SKILL_NAME}}`
7
+ > - Description: `{{SKILL_DESCRIPTION}}`
8
+ > - Session: 요청별 식별자를 유지해 단계별 실행 로그를 추적한다.
9
+ > - Errors: 실패 시 원인/복구/재시도 여부를 구조화해 기록한다.
@@ -0,0 +1,6 @@
1
+ ## Deep Consensus Protocol
2
+
3
+ 1. Planner / Architect / Critic 역할을 분리해 독립적으로 초안을 만든다.
4
+ 2. 교차 검토로 충돌 항목을 수집하고 합의 가능한 변경을 우선 반영한다.
5
+ 3. 남은 불일치는 근거(리스크/비용/검증 가능성)와 함께 명시한다.
6
+ 4. 합의된 결과만 최종 실행 입력으로 승격한다.
@@ -0,0 +1,144 @@
1
+ ---
2
+ name: merge-worktree
3
+ description: "워크트리 브랜치를 main으로 squash-merge + conventional commit 자동 생성. codex-swarm 워크트리 자동 인식. '머지해', 'merge worktree', '워크트리 머지', '결과 수집', 'squash merge' 요청에 사용."
4
+ argument-hint: "[target-branch]"
5
+ disable-model-invocation: true
6
+ ---
7
+
8
+ # Merge Worktree
9
+
10
+ 워크트리 브랜치를 대상 브랜치로 squash-merge하고 conventional commit 메시지를 자동 작성한다.
11
+
12
+ ## Current context
13
+
14
+ * Git dir: `!git rev-parse --git-dir`
15
+ * Current branch: `!git branch --show-current`
16
+ * Recent commits: `!git log --oneline -20`
17
+ * Working tree status: `!git status --short`
18
+
19
+ ## Instructions
20
+
21
+ ### Phase 1: Validation
22
+
23
+ 1. **Worktree 확인**: `git rev-parse --git-dir` 출력에 `/worktrees/`가 포함되어야 한다. 아니면 중지.
24
+
25
+ 2. **현재 브랜치 확인**: `git branch --show-current`
26
+
27
+ 3. **대상 브랜치 결정**:
28
+ * `$ARGUMENTS`가 있으면 해당 브랜치 사용
29
+ * 없으면 `main` 존재 확인, 없으면 `master`
30
+
31
+ 4. **원본 레포 경로 확인**: `git rev-parse --git-common-dir`의 부모 디렉토리
32
+
33
+ 5. **클린 상태 확인**: `git status --porcelain`이 비어있어야 한다. 미커밋 변경이 있으면 먼저 커밋/스태시 안내.
34
+
35
+ ### Phase 2: Research
36
+
37
+ 1. **커밋 이력**: `git log --oneline <target>..HEAD`
38
+
39
+ 2. **변경 파일 요약**: `git diff <target>...HEAD --stat`
40
+
41
+ 3. **전체 diff**: `git diff <target>...HEAD` — 꼼꼼히 읽는다.
42
+
43
+ 4. **핵심 파일 읽기**: 가장 큰 변경, 신규 파일, 삭제 파일을 Read로 확인.
44
+
45
+ 5. **변경 분류**:
46
+ * Features (신규 기능)
47
+ * Fixes (버그 수정)
48
+ * Refactors (구조 변경)
49
+ * Tests (테스트)
50
+ * Docs (문서)
51
+ * Config/Chore (빌드, CI, 의존성)
52
+
53
+ 6. **dominant type 결정**: `feat`, `fix`, `refactor`, `docs`, `chore`, `test` 중 하나
54
+
55
+ ### Phase 3: 대상 브랜치 준비
56
+
57
+ 1. **대상 브랜치 최근 커밋 확인**: `git -C <원본레포> log --oneline -10 <target>`
58
+
59
+ 2. **WIP 커밋 감지**: `wip:`, `auto-commit`, `WIP` 시작 커밋이 있으면 사용자에게 경고.
60
+
61
+ 3. **최신 fetch**: `git -C <원본레포> fetch origin <target> 2>/dev/null`
62
+
63
+ ### Phase 4: Squash Merge
64
+
65
+ 1. **대상 브랜치 checkout**:
66
+ ```
67
+ git -C <원본레포> checkout <target>
68
+ ```
69
+
70
+ 2. **squash merge 실행**:
71
+ ```
72
+ git -C <원본레포> merge --squash <워크트리브랜치>
73
+ ```
74
+
75
+ 3. **충돌 처리**: 충돌 발생 시 충돌 파일 목록 + 마커를 보여주고 **중지**. 자동 해결 시도 금지.
76
+
77
+ ### Phase 5: 커밋 메시지 작성 + 커밋
78
+
79
+ Phase 2 분석 기반으로 아래 구조의 커밋 메시지를 작성한다:
80
+
81
+ ```
82
+ <type>: <명령형 요약, 72자 이내, 마침표 없음>
83
+
84
+ <무엇을 왜 했는지 2-4문장. 동기와 접근 방식 중심.>
85
+
86
+ Changes:
87
+ * <그룹별 변경 사항>
88
+ * <하위 항목은 서브 불릿>
89
+ ```
90
+
91
+ **규칙:**
92
+ * `<type>`은 `feat`, `fix`, `refactor`, `docs`, `chore`, `test` 중 하나
93
+ * 여러 유형이 섞이면 dominant 사용
94
+ * 요약: 명령형 ("add", "fix", "refactor"), 마침표 없음, 72자 제한
95
+ * 본문: *왜*와 *맥락*, *무엇*만이 아님
96
+ * Changes: 관련 항목 그룹핑, 중요한 것 먼저
97
+ * Co-Authored-By 푸터 **절대 추가 금지** (글로벌 설정 `includeCoAuthoredBy: false`)
98
+
99
+ **커밋 실행**:
100
+ ```bash
101
+ git -C <원본레포> commit -m "$(cat <<'EOF'
102
+ <커밋 메시지>
103
+ EOF
104
+ )"
105
+ ```
106
+
107
+ ### Phase 6: 정리 + 검증
108
+
109
+ 1. **커밋 확인**: `git -C <원본레포> log --oneline -3`
110
+
111
+ 2. **워크트리 자동 정리**:
112
+ ```bash
113
+ git -C <원본레포> worktree remove <워크트리경로>
114
+ git -C <원본레포> branch -d <워크트리브랜치>
115
+ ```
116
+
117
+ 3. **codex-swarm 정리 감지**: 워크트리 경로가 `.codex-swarm/wt-*` 패턴이면:
118
+ * 같은 `.codex-swarm/` 디렉토리에 다른 워크트리가 남아있는지 확인
119
+ * 모든 워크트리가 머지 완료되었으면 `.codex-swarm/` 전체 정리 제안
120
+ * `git worktree prune` 실행
121
+
122
+ 4. **결과 보고**:
123
+ * 커밋 해시 + 요약
124
+ * 머지 대상 브랜치
125
+ * 워크트리 정리 완료 여부
126
+ * push 안내 (`git push`)
127
+
128
+ ## codex-swarm 연동
129
+
130
+ 이 스킬은 `tfx-codex-swarm`의 Step 10 "결과 수집"에서 자동으로 호출된다.
131
+ codex-swarm이 완료한 각 워크트리에 대해 순차적으로 실행:
132
+
133
+ ```
134
+ 각 워크트리에 대해:
135
+ 1. 워크트리로 cd
136
+ 2. /merge-worktree main
137
+ 3. 다음 워크트리로 이동
138
+ ```
139
+
140
+ ## 주의사항
141
+
142
+ * force-push, destructive 연산은 사용자 확인 없이 절대 실행 금지
143
+ * pre-commit hook 건너뛰기(`--no-verify`) 금지
144
+ * 예상치 못한 상황이면 추측하지 말고 **중지 후 설명**
@@ -0,0 +1,2 @@
1
+ > **ARGUMENTS 처리**: 이 스킬이 `ARGUMENTS: <값>`과 함께 호출되면, 해당 값을 사용자 입력으로 취급하여
2
+ > 워크플로우의 첫 단계 입력으로 사용한다. ARGUMENTS가 비어있거나 없으면 기존 절차대로 사용자에게 입력을 요청한다.
@@ -0,0 +1,6 @@
1
+ > headless-guard가 이 규칙 위반을 **자동 차단**한다. 우회 불가.
2
+
3
+ 1. **`codex exec` / `gemini -p` 직접 호출 절대 금지**
4
+ 2. Codex·Gemini 작업은 직접 CLI 대신 반드시 TFX 래퍼(이 계열 스킬에서는 `Bash("tfx multi --teammate-mode headless --auto-attach --dashboard --assign 'cli:프롬프트:역할' --timeout 600")`)로만 실행
5
+ 3. Claude 작업은 `Agent(run_in_background=true)`
6
+ 4. 교차 검토/병렬 단계에서는 Bash + Agent를 같은 메시지에서 동시 호출
@@ -0,0 +1,6 @@
1
+ > **Telemetry**
2
+ >
3
+ > - Skill: `{{SKILL_NAME}}`
4
+ > - Description: `{{SKILL_DESCRIPTION}}`
5
+ > - Session: 요청별 식별자를 유지해 단계별 실행 로그를 추적한다.
6
+ > - Errors: 실패 시 원인/복구/재시도 여부를 구조화해 기록한다.