@triflux/remote 10.50.1 → 10.51.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 (120) hide show
  1. package/cto/brief.mjs +0 -12
  2. package/cto/collect.mjs +16 -247
  3. package/cto/current.schema.json +4 -20
  4. package/cto/events.mjs +13 -294
  5. package/cto/hygiene.mjs +26 -346
  6. package/cto/lake-root.mjs +114 -16
  7. package/cto/status.mjs +33 -128
  8. package/hub/index.mjs +0 -8
  9. package/hub/store-adapter.mjs +1 -1
  10. package/hub/team/agent-map.json +0 -1
  11. package/hub/team/ansi.mjs +1 -35
  12. package/hub/team/backend.mjs +9 -145
  13. package/hub/team/cli/commands/attach.mjs +1 -17
  14. package/hub/team/cli/commands/control.mjs +12 -38
  15. package/hub/team/cli/commands/debug.mjs +1 -37
  16. package/hub/team/cli/commands/focus.mjs +5 -31
  17. package/hub/team/cli/commands/interrupt.mjs +6 -25
  18. package/hub/team/cli/commands/kill.mjs +1 -30
  19. package/hub/team/cli/commands/list.mjs +0 -16
  20. package/hub/team/cli/commands/send.mjs +6 -26
  21. package/hub/team/cli/commands/start/index.mjs +41 -133
  22. package/hub/team/cli/commands/start/parse-args.mjs +15 -40
  23. package/hub/team/cli/commands/start/start-headless.mjs +138 -105
  24. package/hub/team/cli/commands/start/start-mux.mjs +0 -3
  25. package/hub/team/cli/commands/status.mjs +2 -57
  26. package/hub/team/cli/commands/stop.mjs +14 -19
  27. package/hub/team/cli/help.mjs +4 -5
  28. package/hub/team/cli/manifest.mjs +5 -1
  29. package/hub/team/cli/render.mjs +0 -12
  30. package/hub/team/cli/services/hub-client.mjs +2 -88
  31. package/hub/team/cli/services/runtime-mode.mjs +27 -98
  32. package/hub/team/handoff.mjs +3 -34
  33. package/hub/team/headless.mjs +14 -755
  34. package/hub/team/orchestrator.mjs +4 -30
  35. package/hub/team/pane.mjs +6 -28
  36. package/hub/team/psmux.mjs +16 -403
  37. package/hub/team/remote-session.mjs +1 -2
  38. package/hub/team/session.mjs +8 -119
  39. package/hub/team/swarm-intent.mjs +0 -198
  40. package/hub/team/terminal-opener.mjs +11 -35
  41. package/hub/team/tui-core.mjs +1 -1
  42. package/hub/team/tui-viewer.mjs +2 -2
  43. package/hub/team/tui.mjs +8 -269
  44. package/hub/team/wt-manager.mjs +2 -2
  45. package/hub/workers/factory.mjs +4 -37
  46. package/hub/workers/lib/jsonrpc-ws-uds.mjs +0 -2
  47. package/package.json +1 -1
  48. package/scripts/lib/agent-route-policy.mjs +162 -14
  49. package/scripts/lib/claudemd-scanner.mjs +2 -199
  50. package/scripts/lib/cli-claude.mjs +0 -2
  51. package/scripts/lib/context.mjs +3 -19
  52. package/scripts/lib/env-probe.mjs +5 -64
  53. package/scripts/lib/gemini-profiles.mjs +2 -69
  54. package/scripts/lib/legacy-mcp-cleanup.mjs +14 -3
  55. package/scripts/lib/machine-profile.mjs +3 -17
  56. package/scripts/lib/mcp-filter.mjs +109 -53
  57. package/scripts/lib/mcp-health.mjs +2 -2
  58. package/scripts/lib/mcp-server-catalog.mjs +2 -2
  59. package/scripts/lib/psmux-info.mjs +25 -104
  60. package/scripts/lib/skill-template.mjs +0 -271
  61. package/cto/hygiene-actions.mjs +0 -355
  62. package/cto/hygiene-notify.mjs +0 -170
  63. package/hub/team/build-worker-prompt.mjs +0 -92
  64. package/hub/team/check-mcp-hub.mjs +0 -49
  65. package/hub/team/claude-native-bridge.mjs +0 -987
  66. package/hub/team/cli/commands/start/start-in-process.mjs +0 -50
  67. package/hub/team/cli/commands/start/start-wt.mjs +0 -86
  68. package/hub/team/cli/services/native-control.mjs +0 -145
  69. package/hub/team/codex-review.mjs +0 -520
  70. package/hub/team/conductor-mesh-bridge.mjs +0 -122
  71. package/hub/team/conductor.mjs +0 -1529
  72. package/hub/team/consensus-meta.mjs +0 -176
  73. package/hub/team/cto-pull.mjs +0 -31
  74. package/hub/team/daemon-pty-tmux-bridge.mjs +0 -146
  75. package/hub/team/dashboard.mjs +0 -322
  76. package/hub/team/event-log.mjs +0 -84
  77. package/hub/team/execution-mode.mjs +0 -324
  78. package/hub/team/extract-completion-payload.mjs +0 -110
  79. package/hub/team/headless-bridge-session.mjs +0 -17
  80. package/hub/team/health-probe.mjs +0 -435
  81. package/hub/team/interactive-native-launcher.mjs +0 -119
  82. package/hub/team/interactive-native-worker.mjs +0 -80
  83. package/hub/team/interactive-tui-transport.mjs +0 -479
  84. package/hub/team/launcher-template.mjs +0 -144
  85. package/hub/team/mcp-selector.mjs +0 -145
  86. package/hub/team/native-supervisor.mjs +0 -460
  87. package/hub/team/native.mjs +0 -727
  88. package/hub/team/recovery-store.mjs +0 -149
  89. package/hub/team/remote-probe.mjs +0 -292
  90. package/hub/team/remote-watcher.mjs +0 -506
  91. package/hub/team/runtime-strategy.mjs +0 -200
  92. package/hub/team/schemas/worker-completion.json +0 -39
  93. package/hub/team/sentinel-capture.mjs +0 -127
  94. package/hub/team/swarm-cli.mjs +0 -390
  95. package/hub/team/swarm-hypervisor.mjs +0 -2206
  96. package/hub/team/swarm-locks.mjs +0 -335
  97. package/hub/team/swarm-planner.mjs +0 -371
  98. package/hub/team/swarm-preflight.mjs +0 -366
  99. package/hub/team/swarm-reconciler.mjs +0 -242
  100. package/hub/team/tui-remote-adapter.mjs +0 -377
  101. package/hub/team/worker-completion-validator.mjs +0 -79
  102. package/hub/team/worktree-lifecycle.mjs +0 -639
  103. package/hub/team/wt-templates.json +0 -43
  104. package/hub/workers/antigravity-route-worker.mjs +0 -179
  105. package/hub/workers/gemini-worker.mjs +0 -217
  106. package/scripts/lib/agent-json.mjs +0 -27
  107. package/scripts/lib/async.mjs +0 -174
  108. package/scripts/lib/cli-agy.mjs +0 -85
  109. package/scripts/lib/cli-codex.mjs +0 -62
  110. package/scripts/lib/cli-gemini.mjs +0 -37
  111. package/scripts/lib/dynamic-route-cli.mjs +0 -107
  112. package/scripts/lib/env.mjs +0 -14
  113. package/scripts/lib/hub.mjs +0 -48
  114. package/scripts/lib/pid.mjs +0 -63
  115. package/scripts/lib/quota.mjs +0 -47
  116. package/scripts/lib/skill-state.mjs +0 -220
  117. package/scripts/lib/team.mjs +0 -75
  118. package/scripts/lib/timeout.mjs +0 -66
  119. package/scripts/lib/tmp.mjs +0 -26
  120. package/scripts/lib/toml.mjs +0 -132
@@ -1,9 +1,12 @@
1
1
  // Canonical Codex role policy. Concrete model IDs stay in profile config files.
2
2
 
3
+ import { readFileSync } from "node:fs";
4
+ import { pathToFileURL } from "node:url";
3
5
  import {
4
6
  normalizeCodexProfileName,
5
7
  resolveCodexProfileConfigValues,
6
8
  } from "./codex-profile-config.mjs";
9
+ import { resolveGeminiProfileForPurpose } from "./gemini-profiles.mjs";
7
10
 
8
11
  const policy = {
9
12
  executor: {
@@ -198,7 +201,7 @@ function freezePolicy(entry) {
198
201
  return Object.freeze({ ...entry });
199
202
  }
200
203
 
201
- export const CODEX_AGENT_POLICY = Object.freeze(
204
+ const CODEX_AGENT_POLICY = Object.freeze(
202
205
  Object.fromEntries(
203
206
  Object.entries(policy).map(([agent, entry]) => [
204
207
  agent,
@@ -206,9 +209,9 @@ export const CODEX_AGENT_POLICY = Object.freeze(
206
209
  ]),
207
210
  ),
208
211
  );
209
- export const DEFAULT_CODEX_AGENT = "executor";
212
+ const DEFAULT_CODEX_AGENT = "executor";
210
213
 
211
- export const CANONICAL_CODEX_PROFILE_OVERRIDES = Object.freeze(
214
+ const CANONICAL_CODEX_PROFILE_OVERRIDES = Object.freeze(
212
215
  new Set([
213
216
  "gpt6_luna_low",
214
217
  "gpt6_luna_high",
@@ -219,7 +222,7 @@ export const CANONICAL_CODEX_PROFILE_OVERRIDES = Object.freeze(
219
222
  "gpt6_astra_ultra",
220
223
  ]),
221
224
  );
222
- export const ULTRA_ELIGIBLE_CODEX_AGENTS = Object.freeze(
225
+ const ULTRA_ELIGIBLE_CODEX_AGENTS = Object.freeze(
223
226
  new Set(["deep-executor", "scientist-deep"]),
224
227
  );
225
228
 
@@ -316,31 +319,176 @@ export function resolveNestedCodexAgentProfile(
316
319
  return effort.toLowerCase() === "ultra" ? "gpt6_astra_max" : candidate;
317
320
  }
318
321
 
319
- export function describeCodexAgentPolicy() {
320
- return {
321
- defaultAgent: DEFAULT_CODEX_AGENT,
322
- agents: Object.keys(CODEX_AGENT_POLICY),
323
- };
322
+ const MIN_TIMEOUT_BY_AGENT = Object.freeze({
323
+ "deep-executor": 900,
324
+ architect: 900,
325
+ planner: 900,
326
+ critic: 900,
327
+ analyst: 900,
328
+ "document-specialist": 900,
329
+ scientist: 900,
330
+ "scientist-deep": 900,
331
+ "code-reviewer": 600,
332
+ "security-reviewer": 600,
333
+ "quality-reviewer": 600,
334
+ executor: 300,
335
+ debugger: 300,
336
+ });
337
+
338
+ const EXPECTED_DURATION_BY_AGENT = Object.freeze({
339
+ writer: 90,
340
+ verifier: 90,
341
+ "qa-tester": 90,
342
+ executor: 300,
343
+ debugger: 300,
344
+ "test-engineer": 300,
345
+ "code-reviewer": 600,
346
+ "security-reviewer": 600,
347
+ architect: 600,
348
+ planner: 600,
349
+ critic: 600,
350
+ analyst: 600,
351
+ scientist: 900,
352
+ "scientist-deep": 900,
353
+ "deep-executor": 900,
354
+ "document-specialist": 900,
355
+ });
356
+
357
+ const NATIVE_CODEX_AGENTS = new Set([
358
+ "explore",
359
+ "verifier",
360
+ "test-engineer",
361
+ "qa-tester",
362
+ ]);
363
+
364
+ function resolveDirectCodexRoutePolicy(agent) {
365
+ if (agent === "explore") {
366
+ return { ...CODEX_AGENT_POLICY.spark, timeoutSec: 600, mcpHint: "analyze" };
367
+ }
368
+ if (agent === "antigravity" || agent === "agy") {
369
+ return CODEX_AGENT_POLICY.designer;
370
+ }
371
+ return resolveCodexAgentPolicy(agent);
372
+ }
373
+
374
+ export function resolveAgentRoute(
375
+ agent,
376
+ map,
377
+ profileOverride = "auto",
378
+ nested = false,
379
+ geminiProfileResolver = resolveGeminiProfileForPurpose,
380
+ ) {
381
+ if (!/^[A-Za-z0-9_.-]+$/.test(agent)) {
382
+ throw new Error(`invalid agent: ${agent}`);
383
+ }
384
+ if (!Object.hasOwn(map, agent)) {
385
+ throw new Error(
386
+ `알 수 없는 에이전트 타입: ${agent}; available: ${Object.keys(map).join(", ")}`,
387
+ );
388
+ }
389
+ const provider = map[agent];
390
+ if (!["codex", "antigravity", "claude"].includes(provider)) {
391
+ throw new Error(`invalid provider for ${agent}: ${provider}`);
392
+ }
393
+ const policy = resolveDirectCodexRoutePolicy(agent);
394
+ const normalizedOverride = normalizeCodexProfileName(profileOverride);
395
+ let resolvedOverride = policy.profile;
396
+ if (normalizedOverride !== "auto") {
397
+ try {
398
+ resolvedOverride = resolveCodexAgentProfile(agent, {
399
+ profileOverride: normalizedOverride,
400
+ nested,
401
+ });
402
+ } catch {
403
+ throw new Error(
404
+ `TFX_CODEX_PROFILE 값이 유효하지 않습니다: ${profileOverride}`,
405
+ );
406
+ }
407
+ }
408
+ return [
409
+ provider,
410
+ policy.profile,
411
+ policy.timeoutSec,
412
+ policy.runMode,
413
+ policy.opusOversight,
414
+ policy.mcpHint,
415
+ policy.subcommand,
416
+ normalizedOverride,
417
+ resolvedOverride,
418
+ geminiProfileResolver(agent),
419
+ MIN_TIMEOUT_BY_AGENT[agent] ?? 120,
420
+ EXPECTED_DURATION_BY_AGENT[agent] ?? 30,
421
+ NATIVE_CODEX_AGENTS.has(agent),
422
+ ];
324
423
  }
325
424
 
326
425
  function parseCliArgs(argv) {
327
426
  const args = [...argv];
328
427
  let format = "json";
329
428
  let agent = DEFAULT_CODEX_AGENT;
429
+ let mapFile = "";
430
+ let profileOverride = "auto";
431
+ let geminiProfilesModule = "";
432
+ let nested = false;
330
433
  while (args.length > 0) {
331
434
  const flag = args.shift();
332
435
  if (flag === "--format") format = args.shift() || "";
333
436
  else if (flag === "--agent") agent = args.shift() || "";
437
+ else if (flag === "--map-file") mapFile = args.shift() || "";
438
+ else if (flag === "--profile-override")
439
+ profileOverride = args.shift() || "";
440
+ else if (flag === "--gemini-profiles-module")
441
+ geminiProfilesModule = args.shift() || "";
442
+ else if (flag === "--nested") nested = true;
334
443
  else throw new Error(`unknown argument: ${flag}`);
335
444
  }
336
- if (!new Set(["json", "tsv"]).has(format)) {
445
+ if (!new Set(["json", "tsv", "route"]).has(format)) {
337
446
  throw new Error(`unsupported format: ${format}`);
338
447
  }
339
- return { format, agent };
448
+ return {
449
+ format,
450
+ agent,
451
+ mapFile,
452
+ profileOverride,
453
+ geminiProfilesModule,
454
+ nested,
455
+ };
340
456
  }
341
457
 
342
- function runCli() {
343
- const { format, agent } = parseCliArgs(process.argv.slice(2));
458
+ async function runCli() {
459
+ const {
460
+ format,
461
+ agent,
462
+ mapFile,
463
+ profileOverride,
464
+ geminiProfilesModule,
465
+ nested,
466
+ } = parseCliArgs(process.argv.slice(2));
467
+ if (format === "route") {
468
+ if (!mapFile) throw new Error("--map-file is required for route format");
469
+ const map = JSON.parse(readFileSync(mapFile, "utf8"));
470
+ let resolver = resolveGeminiProfileForPurpose;
471
+ if (geminiProfilesModule) {
472
+ try {
473
+ const module = await import(pathToFileURL(geminiProfilesModule).href);
474
+ resolver = (agent) => {
475
+ try {
476
+ return module.resolveGeminiProfileForPurpose(agent) || "flash38";
477
+ } catch {
478
+ return "flash38";
479
+ }
480
+ };
481
+ } catch {
482
+ resolver = () => "flash38";
483
+ }
484
+ }
485
+ process.stdout.write(
486
+ resolveAgentRoute(agent, map, profileOverride, nested, resolver).join(
487
+ "\x1e",
488
+ ),
489
+ );
490
+ return;
491
+ }
344
492
  const resolved = resolveCodexAgentPolicy(agent);
345
493
  if (format === "tsv") {
346
494
  process.stdout.write(
@@ -360,7 +508,7 @@ function runCli() {
360
508
 
361
509
  if (import.meta.url === new URL(process.argv[1], "file:").href) {
362
510
  try {
363
- runCli();
511
+ await runCli();
364
512
  } catch (error) {
365
513
  process.stderr.write(`[agent-route-policy] ${error.message}\n`);
366
514
  process.exitCode = 1;
@@ -1,114 +1,6 @@
1
- import { existsSync, readFileSync, writeFileSync } from "node:fs";
1
+ import { existsSync } from "node:fs";
2
2
  import { homedir } from "node:os";
3
- import { dirname, join, resolve } from "node:path";
4
- import { fileURLToPath } from "node:url";
5
-
6
- export const TFX_START = "<!-- TFX:START -->";
7
- export const TFX_END = "<!-- TFX:END -->";
8
- export const OMC_END = "<!-- OMC:END -->";
9
- const TFX_VERSION_RE = /<!-- TFX:VERSION:([\d.]+) -->/u;
10
-
11
- const LEGACY_PATTERNS = [
12
- /<user_cli_routing>/u,
13
- /Codex Pro 무료 기간/u,
14
- /codex exec --dangerously-bypass.*skip-git-repo-check/u,
15
- /OMC 에이전트 → CLI 매핑/u,
16
- /Spark 가드레일/u,
17
- ];
18
-
19
- const DEFAULT_TFX_TEMPLATE = [
20
- "### triflux CLI routing (managed)",
21
- "- 이 블록은 triflux setup에서 자동으로 관리됩니다.",
22
- "- 직접 수정이 필요하면 블록 바깥에 사용자 섹션을 추가하세요.",
23
- ].join("\n");
24
-
25
- const SCRIPT_DIR = dirname(fileURLToPath(import.meta.url));
26
- const DEFAULT_TEMPLATE_PATH = join(
27
- SCRIPT_DIR,
28
- "..",
29
- "templates",
30
- "claudemd-tfx-section.md",
31
- );
32
-
33
- function resolveVersion(version) {
34
- if (version) return version;
35
- try {
36
- const pkgPath = join(SCRIPT_DIR, "..", "..", "package.json");
37
- const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
38
- return pkg.version || "0.0.0";
39
- } catch {
40
- return "0.0.0";
41
- }
42
- }
43
-
44
- function resolveTemplate(template, templatePath = DEFAULT_TEMPLATE_PATH) {
45
- if (typeof template === "string" && template.trim()) {
46
- return template.trim();
47
- }
48
- if (existsSync(templatePath)) {
49
- const raw = readFileSync(templatePath, "utf8").trim();
50
- if (raw) return raw;
51
- }
52
- return DEFAULT_TFX_TEMPLATE;
53
- }
54
-
55
- function findManagedSection(rawText) {
56
- const raw = String(rawText || "");
57
- const startIdx = raw.indexOf(TFX_START);
58
- const endMarkerIdx = raw.indexOf(TFX_END);
59
- if (startIdx === -1 || endMarkerIdx === -1 || endMarkerIdx <= startIdx) {
60
- return {
61
- found: false,
62
- content: null,
63
- version: null,
64
- startIdx: -1,
65
- endIdx: -1,
66
- };
67
- }
68
-
69
- const endIdx = endMarkerIdx + TFX_END.length;
70
- const content = raw.slice(startIdx, endIdx);
71
- const versionMatch = content.match(TFX_VERSION_RE);
72
-
73
- return {
74
- found: true,
75
- content,
76
- version: versionMatch ? versionMatch[1] : null,
77
- startIdx,
78
- endIdx,
79
- };
80
- }
81
-
82
- function detectLegacyRange(rawText) {
83
- const raw = String(rawText || "");
84
- const matches = LEGACY_PATTERNS.some((pattern) => pattern.test(raw));
85
- if (!matches) {
86
- return { found: false, startIdx: -1, endIdx: -1 };
87
- }
88
-
89
- const startTag = raw.indexOf("<user_cli_routing>");
90
- const endTag = raw.indexOf("</user_cli_routing>");
91
- if (startTag === -1 || endTag === -1 || endTag <= startTag) {
92
- return { found: true, startIdx: -1, endIdx: -1 };
93
- }
94
-
95
- let removeStart = startTag;
96
- const userOverridesComment = "<!-- USER OVERRIDES";
97
- const commentIdx = raw.lastIndexOf(userOverridesComment, startTag);
98
- if (commentIdx !== -1 && startTag - commentIdx < 200) {
99
- removeStart = commentIdx;
100
- }
101
-
102
- return {
103
- found: true,
104
- startIdx: removeStart,
105
- endIdx: endTag + "</user_cli_routing>".length,
106
- };
107
- }
108
-
109
- function normalizeSpacing(text) {
110
- return String(text || "").replace(/\n{3,}/gu, "\n\n");
111
- }
3
+ import { join, resolve } from "node:path";
112
4
 
113
5
  export function findAllClaudeMdPaths(options = {}) {
114
6
  const cwd = options.cwd ? resolve(options.cwd) : process.cwd();
@@ -132,92 +24,3 @@ export function findAllClaudeMdPaths(options = {}) {
132
24
  }
133
25
  return paths;
134
26
  }
135
-
136
- export function writeSection(filePath, options = {}) {
137
- const absolutePath = resolve(filePath);
138
- const version = resolveVersion(options.version);
139
- const template = resolveTemplate(options.template, options.templatePath);
140
- const block = [
141
- TFX_START,
142
- `<!-- TFX:VERSION:${version} -->`,
143
- template,
144
- TFX_END,
145
- ].join("\n");
146
-
147
- if (!existsSync(absolutePath)) {
148
- writeFileSync(absolutePath, `${block}\n`, "utf8");
149
- return { action: "created", version, path: absolutePath };
150
- }
151
-
152
- const raw = readFileSync(absolutePath, "utf8");
153
- const existing = findManagedSection(raw);
154
-
155
- if (existing.found) {
156
- const nextContent = `${raw.slice(0, existing.startIdx)}${block}${raw.slice(existing.endIdx)}`;
157
- writeFileSync(absolutePath, nextContent, "utf8");
158
- return {
159
- action: "updated",
160
- oldVersion: existing.version,
161
- version,
162
- path: absolutePath,
163
- };
164
- }
165
-
166
- const omcEndIdx = raw.indexOf(OMC_END);
167
- if (omcEndIdx !== -1) {
168
- const insertAt = omcEndIdx + OMC_END.length;
169
- const before = raw.slice(0, insertAt);
170
- const after = raw.slice(insertAt);
171
- const nextContent = `${before}\n${block}${after}`;
172
- writeFileSync(absolutePath, nextContent, "utf8");
173
- return { action: "inserted_after_omc", version, path: absolutePath };
174
- }
175
-
176
- const separator = raw.endsWith("\n") ? "" : "\n";
177
- writeFileSync(absolutePath, `${raw}${separator}${block}\n`, "utf8");
178
- return { action: "appended", version, path: absolutePath };
179
- }
180
-
181
- export function migrateClaudeMd(filePath, options = {}) {
182
- const absolutePath = resolve(filePath);
183
- if (!existsSync(absolutePath)) {
184
- return { action: "no_file", removed: [], path: absolutePath };
185
- }
186
-
187
- const raw = readFileSync(absolutePath, "utf8");
188
- const existing = findManagedSection(raw);
189
- const legacy = detectLegacyRange(raw);
190
-
191
- if (existing.found && !legacy.found) {
192
- return {
193
- action: "already_managed",
194
- removed: [],
195
- version: existing.version,
196
- path: absolutePath,
197
- };
198
- }
199
-
200
- const removed = [];
201
- let nextContent = raw;
202
-
203
- if (legacy.found && legacy.startIdx !== -1 && legacy.endIdx !== -1) {
204
- nextContent = `${nextContent.slice(0, legacy.startIdx)}${nextContent.slice(legacy.endIdx)}`;
205
- removed.push("<user_cli_routing> block");
206
- }
207
-
208
- const existingAfterLegacy = findManagedSection(nextContent);
209
- if (existingAfterLegacy.found) {
210
- nextContent = `${nextContent.slice(0, existingAfterLegacy.startIdx)}${nextContent.slice(existingAfterLegacy.endIdx)}`;
211
- removed.push("old TFX block");
212
- }
213
-
214
- writeFileSync(absolutePath, normalizeSpacing(nextContent), "utf8");
215
- const writeResult = writeSection(absolutePath, options);
216
-
217
- return {
218
- action: "migrated",
219
- removed,
220
- version: writeResult.version,
221
- path: absolutePath,
222
- };
223
- }
@@ -3,8 +3,6 @@
3
3
  // 책임: Claude 는 외부 CLI 가 아닌 Claude Code Agent 도구로 dispatch 된다. plan() 은
4
4
  // command=null 을 반환하고 호출자가 Agent() 로 라우팅하도록 신호한다.
5
5
  //
6
- // 출처: scripts/tfx-route.sh route_agent() L1062-L1063 (explore|claude),
7
- // L1196-L1203 (TFX_CLI_MODE=gemini fallback), TFX_VERIFIER_OVERRIDE=claude.
8
6
  // timeoutSec은 lane 예상 소요 시간(advisory)이다. hard ceiling 집행은 Bash route가 소유한다.
9
7
 
10
8
  export const id = "claude";
@@ -5,19 +5,13 @@
5
5
  * 하나의 요청에서 발생한 모든 로그를 추적할 수 있다.
6
6
  *
7
7
  * 사용법:
8
- * import { getLogger, getCorrelationId, withRequestContext } from './lib/context.mjs';
8
+ * import { getCorrelationId, withRequestContext } from './lib/context.mjs';
9
9
  *
10
10
  * // 미들웨어에서 컨텍스트 생성
11
11
  * withRequestContext({ method: 'POST', path: '/bridge/result' }, () => {
12
- * const log = getLogger();
13
- * log.info({ agentId }, 'bridge.result_received');
12
+ * const correlationId = getCorrelationId();
14
13
  * });
15
14
  *
16
- * // 내부 함수에서 자동 상관 ID
17
- * function processResult() {
18
- * const log = getLogger();
19
- * log.info('result.processed'); // correlationId 자동 포함
20
- * }
21
15
  */
22
16
  import { AsyncLocalStorage } from "node:async_hooks";
23
17
  import { randomUUID } from "node:crypto";
@@ -25,17 +19,7 @@ import { randomUUID } from "node:crypto";
25
19
  import { logger } from "./logger.mjs";
26
20
 
27
21
  /** @type {AsyncLocalStorage<{logger: import('pino').Logger, correlationId: string}>} */
28
- export const asyncLocalStorage = new AsyncLocalStorage();
29
-
30
- /**
31
- * 현재 요청 컨텍스트의 로거를 반환한다.
32
- * 요청 컨텍스트 밖에서 호출하면 기본 로거를 반환한다.
33
- *
34
- * @returns {import('pino').Logger}
35
- */
36
- export function getLogger() {
37
- return asyncLocalStorage.getStore()?.logger || logger;
38
- }
22
+ const asyncLocalStorage = new AsyncLocalStorage();
39
23
 
40
24
  /**
41
25
  * 현재 요청의 상관 ID를 반환한다.
@@ -1,25 +1,15 @@
1
- import { execSync, spawn } from "node:child_process";
1
+ import { execSync } from "node:child_process";
2
2
  import { createHash } from "node:crypto";
3
3
  import { existsSync, readFileSync } from "node:fs";
4
4
  import { homedir } from "node:os";
5
- import { dirname, join } from "node:path";
6
- import { fileURLToPath } from "node:url";
5
+ import { join } from "node:path";
7
6
  import { resolveHubPortForContext } from "../../hub/hub-lifecycle.mjs";
8
7
  import { whichCommand, whichCommandAsync } from "@triflux/core/hub/platform.mjs";
9
8
 
10
9
  const HUB_DEFAULT_PORT = 27888;
11
- const DEFAULT_STATUS_URL = "http://127.0.0.1:27888/status";
12
- const _sab = new Int32Array(new SharedArrayBuffer(4));
13
10
  const CLI_PROBE_CACHE = new Map();
14
11
  const CLI_PROBE_PROMISES = new Map();
15
12
 
16
- const __filename = fileURLToPath(import.meta.url);
17
- const DEFAULT_PKG_ROOT = join(dirname(__filename), "..", "..");
18
-
19
- function sleepSync(ms) {
20
- Atomics.wait(_sab, 0, 0, ms);
21
- }
22
-
23
13
  function fetchHubStatus({
24
14
  execSyncFn = execSync,
25
15
  statusUrl = resolveDefaultStatusUrl(),
@@ -38,10 +28,7 @@ function fetchHubStatus({
38
28
  };
39
29
  }
40
30
 
41
- export function resolveDefaultStatusUrl(
42
- env = process.env,
43
- cwd = process.cwd(),
44
- ) {
31
+ function resolveDefaultStatusUrl(env = process.env, cwd = process.cwd()) {
45
32
  const port = resolveHubPortForContext({
46
33
  env,
47
34
  cwd,
@@ -125,7 +112,7 @@ async function resolveCliProbe(name, options = {}) {
125
112
  return toCliResult(path);
126
113
  }
127
114
 
128
- export async function checkCli(name, options = {}) {
115
+ async function checkCli(name, options = {}) {
129
116
  const cliName = normalizeCliName(name);
130
117
  if (!cliName) return { ok: false };
131
118
 
@@ -168,11 +155,6 @@ export async function probeClis(names, options = {}) {
168
155
  return mapCliResults(cliNames, results);
169
156
  }
170
157
 
171
- export function resetCliProbeCache() {
172
- CLI_PROBE_CACHE.clear();
173
- CLI_PROBE_PROMISES.clear();
174
- }
175
-
176
158
  export function detectCodexAuthState({
177
159
  homeDir = homedir(),
178
160
  existsSyncFn = existsSync,
@@ -241,16 +223,9 @@ export function detectCodexPlan(options = {}) {
241
223
  export function checkHub({
242
224
  env = process.env,
243
225
  cwd = process.cwd(),
244
- pkgRoot = DEFAULT_PKG_ROOT,
245
226
  statusUrl = resolveDefaultStatusUrl(env, cwd),
246
- restart = true,
247
227
  requestTimeoutMs = 3000,
248
- pollAttempts = 8,
249
- pollIntervalMs = 500,
250
228
  execSyncFn = execSync,
251
- spawnFn = spawn,
252
- existsSyncFn = existsSync,
253
- sleepSyncFn = sleepSync,
254
229
  } = {}) {
255
230
  const guardedStatusUrl = resolveStatusUrlForContext({ statusUrl, env, cwd });
256
231
  try {
@@ -259,41 +234,7 @@ export function checkHub({
259
234
  statusUrl: guardedStatusUrl,
260
235
  timeout: requestTimeoutMs,
261
236
  });
262
- } catch {}
263
-
264
- if (!restart) return { ok: false, state: "unreachable", restart: "disabled" };
265
-
266
- const serverPath = join(pkgRoot, "hub", "server.mjs");
267
- if (!existsSyncFn(serverPath))
268
- return { ok: false, state: "unreachable", restart: "no_server" };
269
-
270
- try {
271
- const child = spawnFn(process.execPath, [serverPath], {
272
- env: { ...env, TFX_HUB_PORT: String(new URL(guardedStatusUrl).port) },
273
- detached: true,
274
- stdio: "ignore",
275
- windowsHide: true,
276
- });
277
- child.unref();
278
237
  } catch {
279
- return { ok: false, state: "unreachable", restart: "spawn_failed" };
238
+ return { ok: false, state: "unreachable", restart: "disabled" };
280
239
  }
281
-
282
- for (let i = 0; i < pollAttempts; i++) {
283
- sleepSyncFn(pollIntervalMs);
284
- try {
285
- const status = fetchHubStatus({
286
- execSyncFn,
287
- statusUrl: guardedStatusUrl,
288
- timeout: Math.min(requestTimeoutMs, 1000),
289
- });
290
- if (status.state === "healthy") {
291
- return { ...status, restarted: true };
292
- }
293
- } catch {}
294
- }
295
-
296
- return { ok: false, state: "unreachable", restart: "timeout" };
297
240
  }
298
-
299
- export { DEFAULT_PKG_ROOT, DEFAULT_STATUS_URL };