triflux 10.9.14 → 10.9.15

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 (80) hide show
  1. package/.claude-plugin/marketplace.json +34 -0
  2. package/.claude-plugin/plugin.json +22 -0
  3. package/config/mcp-registry.json +29 -0
  4. package/hub/server.mjs +41 -0
  5. package/hub/team/conductor.mjs +69 -26
  6. package/hub/team/synapse-registry.mjs +4 -2
  7. package/package.json +56 -21
  8. package/scripts/tfx-route.sh +8 -11
  9. package/tui/codex-profile.mjs +457 -0
  10. package/tui/core.mjs +266 -0
  11. package/tui/doctor.mjs +375 -0
  12. package/tui/gemini-profile.mjs +299 -0
  13. package/tui/monitor-data.mjs +152 -0
  14. package/tui/monitor.mjs +339 -0
  15. package/tui/setup.mjs +598 -0
  16. package/CLAUDE.md +0 -212
  17. package/references/hosts.json +0 -46
  18. package/skills/tfx-workspace/async-tests/run-tests.sh +0 -203
  19. package/skills/tfx-workspace/evals/evals.json +0 -79
  20. package/skills/tfx-workspace/iteration-1/benchmark.json +0 -524
  21. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/eval_metadata.json +0 -11
  22. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/grading.json +0 -25
  23. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/outputs/analysis.md +0 -154
  24. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/timing.json +0 -5
  25. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/grading.json +0 -25
  26. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/outputs/analysis.md +0 -126
  27. package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/timing.json +0 -5
  28. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/eval_metadata.json +0 -11
  29. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/grading.json +0 -25
  30. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/outputs/analysis.md +0 -119
  31. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/timing.json +0 -5
  32. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/grading.json +0 -25
  33. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/outputs/analysis.md +0 -115
  34. package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/timing.json +0 -5
  35. package/skills/tfx-workspace/iteration-1/hub-start-sequence/eval_metadata.json +0 -10
  36. package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/grading.json +0 -20
  37. package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/outputs/analysis.md +0 -86
  38. package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/timing.json +0 -5
  39. package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/grading.json +0 -20
  40. package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/outputs/analysis.md +0 -81
  41. package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/timing.json +0 -5
  42. package/skills/tfx-workspace/iteration-1/multi-team-creation/eval_metadata.json +0 -12
  43. package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/grading.json +0 -30
  44. package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/outputs/analysis.md +0 -316
  45. package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/timing.json +0 -5
  46. package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/grading.json +0 -30
  47. package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/outputs/analysis.md +0 -352
  48. package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/timing.json +0 -5
  49. package/skills/tfx-workspace/iteration-1/review.html +0 -1325
  50. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/eval_metadata.json +0 -12
  51. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/grading.json +0 -30
  52. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/outputs/analysis.md +0 -97
  53. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/timing.json +0 -5
  54. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/grading.json +0 -30
  55. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/outputs/analysis.md +0 -94
  56. package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/timing.json +0 -5
  57. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/eval_metadata.json +0 -12
  58. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/grading.json +0 -30
  59. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/outputs/analysis.md +0 -209
  60. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/timing.json +0 -5
  61. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/grading.json +0 -30
  62. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/outputs/analysis.md +0 -193
  63. package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/timing.json +0 -5
  64. package/skills/tfx-workspace/iteration-2/benchmark.json +0 -144
  65. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/eval_metadata.json +0 -13
  66. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/grading.json +0 -35
  67. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/outputs/analysis.md +0 -382
  68. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/timing.json +0 -5
  69. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/grading.json +0 -35
  70. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/outputs/analysis.md +0 -333
  71. package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/timing.json +0 -5
  72. package/skills/tfx-workspace/iteration-2/review.html +0 -1325
  73. package/skills/tfx-workspace/skill-snapshot/tfx-auto/SKILL.md +0 -217
  74. package/skills/tfx-workspace/skill-snapshot/tfx-auto-codex/SKILL.md +0 -77
  75. package/skills/tfx-workspace/skill-snapshot/tfx-codex/SKILL.md +0 -65
  76. package/skills/tfx-workspace/skill-snapshot/tfx-doctor/SKILL.md +0 -94
  77. package/skills/tfx-workspace/skill-snapshot/tfx-gemini/SKILL.md +0 -82
  78. package/skills/tfx-workspace/skill-snapshot/tfx-hub/SKILL.md +0 -133
  79. package/skills/tfx-workspace/skill-snapshot/tfx-multi/SKILL.md +0 -426
  80. package/skills/tfx-workspace/skill-snapshot/tfx-setup/SKILL.md +0 -101
@@ -0,0 +1,34 @@
1
+ {
2
+ "$schema": "https://anthropic.com/claude-code/marketplace.schema.json",
3
+ "name": "triflux",
4
+ "description": "CLI-first multi-model orchestrator — Codex/Gemini/Claude routing with DAG execution, auto-triage, and cost optimization",
5
+ "owner": {
6
+ "name": "tellang"
7
+ },
8
+ "plugins": [
9
+ {
10
+ "name": "triflux",
11
+ "description": "Tri-CLI orchestrator for Claude Code. Routes tasks across Claude + Codex + Gemini with consensus intelligence, natural language routing, 42 skills, and cross-model review.",
12
+ "version": "10.9.6",
13
+ "author": {
14
+ "name": "tellang"
15
+ },
16
+ "source": {
17
+ "source": "npm",
18
+ "package": "triflux"
19
+ },
20
+ "category": "productivity",
21
+ "homepage": "https://github.com/tellang/triflux",
22
+ "tags": [
23
+ "multi-model",
24
+ "codex",
25
+ "gemini",
26
+ "cli-routing",
27
+ "orchestration",
28
+ "cost-optimization",
29
+ "dag-execution"
30
+ ]
31
+ }
32
+ ],
33
+ "version": "10.9.14"
34
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "triflux",
3
+ "version": "10.3.4",
4
+ "description": "CLI-first multi-model orchestrator for Claude Code — route tasks to Codex, Gemini, and Claude",
5
+ "author": {
6
+ "name": "tellang"
7
+ },
8
+ "repository": "https://github.com/tellang/triflux",
9
+ "homepage": "https://github.com/tellang/triflux",
10
+ "license": "MIT",
11
+ "keywords": [
12
+ "claude-code",
13
+ "plugin",
14
+ "codex",
15
+ "gemini",
16
+ "cli-routing",
17
+ "orchestration",
18
+ "multi-model"
19
+ ],
20
+ "skills": "./skills/",
21
+ "hooks": "./hooks/hooks.json"
22
+ }
@@ -0,0 +1,29 @@
1
+ {
2
+ "$schema": "mcp-registry-schema",
3
+ "version": 1,
4
+ "description": "MCP 서버 중앙 레지스트리 — 진실의 원천",
5
+ "defaults": {
6
+ "transport": "hub-url",
7
+ "hub_base": "http://127.0.0.1:27888"
8
+ },
9
+ "servers": {
10
+ "tfx-hub": {
11
+ "transport": "hub-url",
12
+ "url": "http://127.0.0.1:27888/mcp",
13
+ "safe": true,
14
+ "targets": ["claude", "gemini", "codex"],
15
+ "description": "triflux Hub MCP 서버"
16
+ }
17
+ },
18
+ "policies": {
19
+ "stdio_action": "replace-with-hub",
20
+ "unknown_server_action": "warn",
21
+ "watched_paths": [
22
+ "~/.gemini/settings.json",
23
+ "~/.codex/config.toml",
24
+ "~/.claude/settings.json",
25
+ "~/.claude/settings.local.json",
26
+ ".mcp.json"
27
+ ]
28
+ }
29
+ }
package/hub/server.mjs CHANGED
@@ -593,6 +593,20 @@ export async function startHub({
593
593
  locks: swarmLocks,
594
594
  });
595
595
 
596
+ // Synapse Layer 5: emitter subscribers — bridge events to hub logging
597
+ synapseEmitter.on("synapse.session.started", ({ sessionId }) => {
598
+ hubLog.info({ sessionId }, "synapse.session.started");
599
+ });
600
+ synapseEmitter.on("synapse.session.heartbeat", ({ sessionId }) => {
601
+ hubLog.debug({ sessionId }, "synapse.session.heartbeat");
602
+ });
603
+ synapseEmitter.on("synapse.session.stale", ({ sessionId }) => {
604
+ hubLog.warn({ sessionId }, "synapse.session.stale");
605
+ });
606
+ synapseEmitter.on("synapse.session.removed", ({ sessionId }) => {
607
+ hubLog.info({ sessionId }, "synapse.session.removed");
608
+ });
609
+
596
610
  const hitl = createHitlManager(store, router);
597
611
  const pipe = createPipeServer({
598
612
  router,
@@ -760,6 +774,33 @@ export async function startHub({
760
774
  return writeJson(res, 200, { ok: true, accounts });
761
775
  }
762
776
 
777
+ // ── Synapse Layer 5: session registry + locks + preflight routes ──
778
+ if (path === "/synapse/sessions" && req.method === "GET") {
779
+ return writeJson(res, 200, { ok: true, ...synapseRegistry.snapshot(), ts: Date.now() });
780
+ }
781
+
782
+ if (path === "/synapse/locks" && req.method === "GET") {
783
+ return writeJson(res, 200, { ok: true, locks: swarmLocks.snapshot(), ts: Date.now() });
784
+ }
785
+
786
+ if (path === "/synapse/preflight" && req.method === "POST") {
787
+ const VALID_OPS = new Set(["checkout", "rebase", "cherry-pick", "reset", "stash-pop", "worktree-remove"]);
788
+ try {
789
+ const body = await parseBody(req);
790
+ const { op, args = {}, sessionContext = {} } = body;
791
+ if (!op || typeof op !== "string") {
792
+ return writeJson(res, 400, { ok: false, error: "op 필수" });
793
+ }
794
+ if (!VALID_OPS.has(op)) {
795
+ return writeJson(res, 400, { ok: false, error: `invalid op: ${op}` });
796
+ }
797
+ const result = gitPreflight.check(op, args, sessionContext);
798
+ return writeJson(res, 200, { ok: true, ...result });
799
+ } catch (err) {
800
+ return writeJson(res, 400, { ok: false, error: String(err?.message || err) });
801
+ }
802
+ }
803
+
763
804
  if (path.startsWith("/bridge")) {
764
805
  const isBridgeStatusGet =
765
806
  path === "/bridge/status" && req.method === "GET";
@@ -66,6 +66,40 @@ const TERMINAL_STATES = new Set([STATES.DEAD, STATES.COMPLETED]);
66
66
  const DEFAULT_MAX_RESTARTS = 3;
67
67
  const DEFAULT_GRACE_MS = 10_000;
68
68
 
69
+ /**
70
+ * Auth 파일을 lease 소스에서 CLI 대상 경로로 복사.
71
+ * @param {object} lease — broker lease 객체 (mode, authFile 필수)
72
+ * @param {'codex'|'gemini'} agent
73
+ * @param {string} sessionId — 로깅용
74
+ * @param {object} eventLog — createEventLog 인스턴스
75
+ */
76
+ function swapAuthFile(lease, agent, sessionId, eventLog) {
77
+ if (lease?.mode !== "auth" || !lease.authFile) return true;
78
+ const dests =
79
+ agent === "codex"
80
+ ? [join(homedir(), ".codex", "auth.json")]
81
+ : [
82
+ join(homedir(), ".gemini", "oauth_creds.json"),
83
+ join(homedir(), ".gemini", "gemini-credentials.json"),
84
+ ];
85
+ let allOk = true;
86
+ for (const dest of dests) {
87
+ try {
88
+ mkdirSync(dirname(dest), { recursive: true });
89
+ copyFileSync(lease.authFile, dest);
90
+ eventLog.append("auth_copy", { session: sessionId, agent, dest });
91
+ } catch (err) {
92
+ allOk = false;
93
+ eventLog.append("auth_copy_error", {
94
+ session: sessionId,
95
+ dest,
96
+ error: err.message,
97
+ });
98
+ }
99
+ }
100
+ return allOk;
101
+ }
102
+
69
103
  /**
70
104
  * Conductor 팩토리.
71
105
  * @param {object} opts
@@ -73,6 +107,7 @@ const DEFAULT_GRACE_MS = 10_000;
73
107
  * @param {number} [opts.maxRestarts=3]
74
108
  * @param {number} [opts.graceMs=10000] — shutdown grace period
75
109
  * @param {object} [opts.probeOpts] — health-probe 옵션 오버라이드
110
+ * @param {object} [opts.broker] — AccountBroker 인스턴스 (tierFallback 구독용)
76
111
  * @returns {Conductor}
77
112
  */
78
113
  export function createConductor(opts = {}) {
@@ -81,6 +116,7 @@ export function createConductor(opts = {}) {
81
116
  maxRestarts = DEFAULT_MAX_RESTARTS,
82
117
  graceMs = DEFAULT_GRACE_MS,
83
118
  probeOpts = {},
119
+ broker: optsBroker,
84
120
  } = opts;
85
121
 
86
122
  if (!logsDir) throw new Error("logsDir is required");
@@ -739,32 +775,7 @@ export function createConductor(opts = {}) {
739
775
  : config;
740
776
 
741
777
  // auth file copy — broker resolved absolute path, conductor does the actual copy
742
- if (lease?.mode === "auth" && lease.authFile) {
743
- const dests =
744
- config.agent === "codex"
745
- ? [join(homedir(), ".codex", "auth.json")]
746
- : [
747
- join(homedir(), ".gemini", "oauth_creds.json"),
748
- join(homedir(), ".gemini", "gemini-credentials.json"),
749
- ];
750
- for (const dest of dests) {
751
- try {
752
- mkdirSync(dirname(dest), { recursive: true });
753
- copyFileSync(lease.authFile, dest);
754
- eventLog.append("auth_copy", {
755
- session: config.id,
756
- agent: config.agent,
757
- dest,
758
- });
759
- } catch (err) {
760
- eventLog.append("auth_copy_error", {
761
- session: config.id,
762
- dest,
763
- error: err.message,
764
- });
765
- }
766
- }
767
- }
778
+ swapAuthFile(lease, config.agent, config.id, eventLog);
768
779
 
769
780
  // 원격 세션은 launcher 불필요 (이미 원격에서 실행 중)
770
781
  const launcher = resolvedConfig.remote
@@ -892,12 +903,44 @@ export function createConductor(opts = {}) {
892
903
  });
893
904
 
894
905
  await Promise.allSettled(cleanups);
906
+ process.removeListener("SIGINT", onSignal);
907
+ process.removeListener("SIGTERM", onSignal);
908
+ if (brokerInstance && onTierFallback) {
909
+ brokerInstance.removeListener("tierFallback", onTierFallback);
910
+ }
895
911
  if (conductor._meshBridge) conductor._meshBridge.detach();
896
912
  await eventLog.flush();
897
913
  await eventLog.close();
898
914
  emitter.emit("shutdown");
899
915
  }
900
916
 
917
+ // ── broker tierFallback 구독 ──────────────────────────────────
918
+ // 토큰 만료 등으로 상위 tier 계정이 불가능해지면, 활성 세션의 auth를 새 lease로 교체.
919
+ const brokerInstance = optsBroker ?? null;
920
+ const onTierFallback = brokerInstance
921
+ ? ({ provider }) => {
922
+ for (const session of sessions.values()) {
923
+ if (TERMINAL_STATES.has(session.state)) continue;
924
+ if (session.config.agent !== provider) continue;
925
+ if (session.config.remote) continue;
926
+
927
+ const newLease = brokerInstance.lease({ provider });
928
+ if (!newLease) continue;
929
+
930
+ swapAuthFile(newLease, provider, session.id, eventLog);
931
+ eventLog.append("tier_fallback_swap", {
932
+ session: session.id,
933
+ agent: provider,
934
+ newAccount: newLease.id,
935
+ });
936
+ }
937
+ }
938
+ : null;
939
+
940
+ if (brokerInstance && onTierFallback) {
941
+ brokerInstance.on("tierFallback", onTierFallback);
942
+ }
943
+
901
944
  // Shutdown traps
902
945
  const onSignal = () => {
903
946
  void shutdown("signal");
@@ -69,6 +69,7 @@ export function createSynapseRegistry(opts = {}) {
69
69
  }
70
70
 
71
71
  let persistTimer = null;
72
+ let destroyed = false;
72
73
 
73
74
  function persist() {
74
75
  if (!persistPath) return;
@@ -84,10 +85,10 @@ export function createSynapseRegistry(opts = {}) {
84
85
  }
85
86
 
86
87
  function schedulePersist() {
87
- if (persistTimer) return;
88
+ if (destroyed || persistTimer) return;
88
89
  persistTimer = setTimeout(() => {
89
90
  persistTimer = null;
90
- persist();
91
+ if (!destroyed) persist();
91
92
  }, 200);
92
93
  if (typeof persistTimer.unref === "function") persistTimer.unref();
93
94
  }
@@ -277,6 +278,7 @@ export function createSynapseRegistry(opts = {}) {
277
278
  }
278
279
 
279
280
  function destroy() {
281
+ destroyed = true;
280
282
  for (const sessionId of monitors.keys()) {
281
283
  stopMonitor(sessionId);
282
284
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "triflux",
3
- "version": "10.9.14",
3
+ "version": "10.9.15",
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": {
@@ -13,26 +13,69 @@
13
13
  "tfx-doctor-tui": "bin/tfx-doctor-tui.mjs",
14
14
  "tfx-setup-tui": "bin/tfx-setup-tui.mjs"
15
15
  },
16
- "engines": {
17
- "node": ">=18.0.0"
18
- },
19
- "dependencies": {
20
- "@triflux/core": "10.0.1",
21
- "@triflux/remote": "^10.0.0-alpha.1"
22
- },
23
16
  "files": [
24
17
  "bin",
18
+ "tui",
19
+ "hub",
20
+ "config",
25
21
  "skills",
22
+ "!skills/tfx-workspace",
23
+ "!**/failure-reports",
24
+ "scripts",
26
25
  "hooks",
27
26
  "hud",
28
- "scripts",
29
- "hub",
30
27
  "mesh",
31
- "references",
32
- "CLAUDE.md",
28
+ ".claude-plugin",
33
29
  "README.md",
30
+ "README.ko.md",
34
31
  "LICENSE"
35
32
  ],
33
+ "workspaces": [
34
+ "packages/core",
35
+ "packages/remote",
36
+ "packages/triflux"
37
+ ],
38
+ "scripts": {
39
+ "pack": "node scripts/pack.mjs all",
40
+ "pack:core": "node scripts/pack.mjs core",
41
+ "pack:remote": "node scripts/pack.mjs remote",
42
+ "setup": "node scripts/setup.mjs",
43
+ "preinstall": "node scripts/preinstall.mjs",
44
+ "postinstall": "node scripts/setup.mjs",
45
+ "lint": "biome check .",
46
+ "lint:fix": "biome check --fix .",
47
+ "health": "npm test && npm run lint",
48
+ "test": "node scripts/test-lock.mjs --test --test-force-exit --test-concurrency=8 \"tests/**/*.test.mjs\" \"scripts/__tests__/**/*.test.mjs\"",
49
+ "test:unit": "node scripts/test-lock.mjs --test --test-force-exit --test-concurrency=8 tests/unit/**/*.test.mjs",
50
+ "test:integration": "node scripts/test-lock.mjs --test --test-force-exit --test-concurrency=8 tests/integration/**/*.test.mjs",
51
+ "test:route-smoke": "node scripts/test-lock.mjs --test scripts/test-tfx-route-no-claude-native.mjs",
52
+ "test:contract": "node scripts/test-lock.mjs --test --test-force-exit --test-concurrency=8 tests/contract/**/*.test.mjs",
53
+ "test:coverage": "node --experimental-test-coverage --test-coverage-lines=60 --test-coverage-functions=60 --test --test-force-exit --test-concurrency=8 \"tests/**/*.test.mjs\"",
54
+ "gen:skill-docs": "node scripts/gen-skill-docs.mjs",
55
+ "gen:skill-manifest": "node scripts/gen-skill-manifest.mjs"
56
+ },
57
+ "engines": {
58
+ "node": ">=18.0.0"
59
+ },
60
+ "repository": {
61
+ "type": "git",
62
+ "url": "git+https://github.com/tellang/triflux.git"
63
+ },
64
+ "homepage": "https://github.com/tellang/triflux#readme",
65
+ "author": "tellang",
66
+ "license": "MIT",
67
+ "dependencies": {
68
+ "@modelcontextprotocol/sdk": "^1.27.1",
69
+ "better-sqlite3": "^12.6.2",
70
+ "pino": "^10.3.1",
71
+ "pino-pretty": "^13.1.3",
72
+ "systray2": "^2.1.4",
73
+ "zod": "^4.0.0"
74
+ },
75
+ "devDependencies": {
76
+ "@biomejs/biome": "^2.0.0",
77
+ "knip": "^6.3.0"
78
+ },
36
79
  "keywords": [
37
80
  "claude-code",
38
81
  "plugin",
@@ -43,13 +86,5 @@
43
86
  "multi-model",
44
87
  "triflux",
45
88
  "tfx"
46
- ],
47
- "author": "tellang",
48
- "license": "MIT",
49
- "homepage": "https://github.com/tellang/triflux#readme",
50
- "repository": {
51
- "type": "git",
52
- "url": "git+https://github.com/tellang/triflux.git",
53
- "directory": "packages/triflux"
54
- }
89
+ ]
55
90
  }
@@ -105,17 +105,14 @@ if [[ -f "$_CODEX_CONFIG" ]] && awk '
105
105
  fi
106
106
 
107
107
  build_codex_base() {
108
- # Escape hatch: TFX_FORCE_CODEX_BYPASS=1이면 감지 결과와 무관하게 항상 bypass.
109
- # CI/디버깅/긴급 상황에서 config.toml 상태에 상관없이 non-TTY codex exec를 보장.
110
- if [[ "${TFX_FORCE_CODEX_BYPASS:-0}" == "1" ]]; then
111
- echo "--dangerously-bypass-approvals-and-sandbox --skip-git-repo-check"
112
- return
113
- fi
114
- if [[ -n "$_CODEX_HAS_SANDBOX" ]]; then
115
- echo "--skip-git-repo-check"
116
- else
117
- echo "--dangerously-bypass-approvals-and-sandbox --skip-git-repo-check"
118
- fi
108
+ # codex exec는 항상 non-TTY subprocess에서 실행되므로 --dangerously-bypass 필수.
109
+ # --dangerously-bypass는 config.toml approval_mode/sandbox와 충돌하지 않음
110
+ # (--full-auto와 달리 bypass는 config 값을 override할 뿐 에러를 던지지 않음).
111
+ # 검증: approval_mode="auto" config에서 --dangerously-bypass 동시 사용 → exit 0 확인.
112
+ #
113
+ # Note: 위의 _CODEX_HAS_SANDBOX awk 감지는 현재 미사용이지만, 향후 codex가
114
+ # bypass와 config.toml 충돌을 감지하면 분기 로직을 재활성화할 수 있으므로 유지.
115
+ echo "--dangerously-bypass-approvals-and-sandbox --skip-git-repo-check"
119
116
  }
120
117
 
121
118
  # ── Async Job 디렉토리 ──