@triflux/core 10.50.2 → 10.52.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 (84) hide show
  1. package/hooks/agy-session-hook.mjs +11 -56
  2. package/hooks/codex-session-hook.mjs +11 -101
  3. package/hub/bridge.mjs +65 -1250
  4. package/hub/cli-adapter-base.mjs +12 -90
  5. package/hub/codex-adapter.mjs +0 -1
  6. package/hub/codex-preflight.mjs +5 -28
  7. package/hub/index.mjs +3 -19
  8. package/hub/lib/process-utils.mjs +1 -156
  9. package/hub/lib/spawn-trace.mjs +3 -2
  10. package/hub/lib/timeout-defaults.mjs +0 -1
  11. package/hub/team/claude-daemon-control.mjs +1 -2
  12. package/hub/team/claude-session-projection.mjs +5 -73
  13. package/hub/team/nativeProxy.mjs +759 -0
  14. package/hub/team/session-context.mjs +1 -1
  15. package/hud/cli-policy.mjs +0 -22
  16. package/hud/constants.mjs +13 -26
  17. package/hud/hud-qos-status.mjs +42 -54
  18. package/hud/providers/gemini.mjs +125 -20
  19. package/hud/renderers.mjs +101 -122
  20. package/hud/utils.mjs +10 -6
  21. package/package.json +2 -6
  22. package/scripts/lib/agent-route-policy.mjs +143 -62
  23. package/scripts/lib/cli-claude.mjs +0 -14
  24. package/scripts/lib/env-probe.mjs +2 -131
  25. package/scripts/lib/gemini-profiles.mjs +2 -69
  26. package/scripts/lib/legacy-mcp-cleanup.mjs +283 -0
  27. package/scripts/lib/machine-profile.mjs +3 -17
  28. package/scripts/lib/mcp-filter.mjs +109 -53
  29. package/scripts/lib/mcp-guard-engine.mjs +40 -98
  30. package/scripts/lib/mcp-health.mjs +2 -2
  31. package/scripts/lib/mcp-server-catalog.mjs +2 -2
  32. package/scripts/lib/psmux-info.mjs +11 -59
  33. package/scripts/lib/session-presence.mjs +2 -100
  34. package/scripts/lib/skill-template.mjs +0 -245
  35. package/hub/adaptive-diagnostic.mjs +0 -350
  36. package/hub/adaptive-inject.mjs +0 -224
  37. package/hub/adaptive-memory.mjs +0 -277
  38. package/hub/adaptive.mjs +0 -172
  39. package/hub/assign-callbacks.mjs +0 -170
  40. package/hub/delegator/contracts.mjs +0 -38
  41. package/hub/delegator/index.mjs +0 -14
  42. package/hub/delegator/schema/delegator-tools.schema.json +0 -250
  43. package/hub/delegator/service.mjs +0 -336
  44. package/hub/delegator/tool-definitions.mjs +0 -35
  45. package/hub/dynamic-routing-engine.mjs +0 -511
  46. package/hub/hitl.mjs +0 -202
  47. package/hub/lib/known-errors.json +0 -72
  48. package/hub/lib/memory-store.mjs +0 -1001
  49. package/hub/lib/phase-manager.mjs +0 -493
  50. package/hub/lib/risk-tier.mjs +0 -53
  51. package/hub/lib/ssh-command.mjs +0 -231
  52. package/hub/lib/staged-file-detect.mjs +0 -43
  53. package/hub/lib/state-snapshot.mjs +0 -293
  54. package/hub/lib/tfx-route-args.mjs +0 -353
  55. package/hub/lib/trace-recorder.mjs +0 -153
  56. package/hub/lib/uuidv7.mjs +0 -45
  57. package/hub/memory-doctor.mjs +0 -640
  58. package/hub/middleware/quota-middleware.mjs +0 -70
  59. package/hub/middleware/request-logger.mjs +0 -191
  60. package/hub/paths.mjs +0 -24
  61. package/hub/pipeline/index.mjs +0 -163
  62. package/hub/pipeline/state.mjs +0 -191
  63. package/hub/pipeline/transitions.mjs +0 -131
  64. package/hub/reflexion.mjs +0 -290
  65. package/hub/role-contract.mjs +0 -314
  66. package/hub/router.mjs +0 -2026
  67. package/hub/routing-snapshot.mjs +0 -261
  68. package/hub/session-fingerprint.mjs +0 -418
  69. package/hub/state.mjs +0 -300
  70. package/hub/team/synapse-http.mjs +0 -311
  71. package/hub/team-bridge.mjs +0 -27
  72. package/mesh/index.mjs +0 -69
  73. package/mesh/mesh-budget.mjs +0 -137
  74. package/mesh/mesh-heartbeat.mjs +0 -100
  75. package/mesh/mesh-protocol.mjs +0 -96
  76. package/mesh/mesh-queue.mjs +0 -163
  77. package/mesh/mesh-registry.mjs +0 -78
  78. package/mesh/mesh-router.mjs +0 -77
  79. package/scripts/lib/claudemd-scanner.mjs +0 -223
  80. package/scripts/lib/context.mjs +0 -67
  81. package/scripts/lib/dynamic-route-cli.mjs +0 -107
  82. package/scripts/lib/handoff.mjs +0 -187
  83. package/scripts/lib/logger.mjs +0 -122
  84. package/scripts/lib/stealth-fetch.mjs +0 -176
@@ -1,176 +1,137 @@
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: {
10
13
  profile: "gpt61_sol_high",
11
14
  timeoutSec: 1080,
12
- runMode: "fg",
13
- opusOversight: false,
14
15
  mcpHint: "implement",
15
16
  subcommand: "exec",
16
17
  },
17
18
  codex: {
18
19
  profile: "gpt61_sol_high",
19
20
  timeoutSec: 1080,
20
- runMode: "fg",
21
- opusOversight: false,
22
21
  mcpHint: "implement",
23
22
  subcommand: "exec",
24
23
  },
25
24
  "build-fixer": {
26
25
  profile: "gpt6_luna_high",
27
26
  timeoutSec: 540,
28
- runMode: "fg",
29
- opusOversight: false,
30
27
  mcpHint: "implement",
31
28
  subcommand: "exec",
32
29
  },
33
30
  cleanup: {
34
31
  profile: "gpt61_sol_med",
35
32
  timeoutSec: 540,
36
- runMode: "fg",
37
- opusOversight: false,
38
33
  mcpHint: "implement",
39
34
  subcommand: "exec",
40
35
  },
41
36
  deslop: {
42
37
  profile: "gpt61_sol_med",
43
38
  timeoutSec: 540,
44
- runMode: "fg",
45
- opusOversight: false,
46
39
  mcpHint: "implement",
47
40
  subcommand: "exec",
48
41
  },
49
42
  debugger: {
50
43
  profile: "gpt6_astra_xhigh",
51
44
  timeoutSec: 900,
52
- runMode: "bg",
53
- opusOversight: false,
54
45
  mcpHint: "implement",
55
46
  subcommand: "exec",
56
47
  },
57
48
  "deep-executor": {
58
49
  profile: "gpt6_astra_xhigh",
59
50
  timeoutSec: 3600,
60
- runMode: "bg",
61
- opusOversight: true,
62
51
  mcpHint: "implement",
63
52
  subcommand: "exec",
64
53
  },
65
54
  architect: {
66
55
  profile: "gpt6_astra_xhigh",
67
56
  timeoutSec: 3600,
68
- runMode: "bg",
69
- opusOversight: true,
70
57
  mcpHint: "analyze",
71
58
  subcommand: "exec",
72
59
  },
73
60
  critic: {
74
61
  profile: "gpt6_astra_xhigh",
75
62
  timeoutSec: 3600,
76
- runMode: "bg",
77
- opusOversight: true,
78
63
  mcpHint: "analyze",
79
64
  subcommand: "exec",
80
65
  },
81
66
  planner: {
82
67
  profile: "gpt6_astra_xhigh",
83
68
  timeoutSec: 3600,
84
- runMode: "fg",
85
- opusOversight: true,
86
69
  mcpHint: "analyze",
87
70
  subcommand: "exec",
88
71
  },
89
72
  analyst: {
90
73
  profile: "gpt6_astra_xhigh",
91
74
  timeoutSec: 3600,
92
- runMode: "fg",
93
- opusOversight: true,
94
75
  mcpHint: "analyze",
95
76
  subcommand: "exec",
96
77
  },
97
78
  "code-reviewer": {
98
79
  profile: "gpt61_sol_high",
99
80
  timeoutSec: 1800,
100
- runMode: "bg",
101
- opusOversight: false,
102
81
  mcpHint: "review",
103
82
  subcommand: "review",
104
83
  },
105
84
  "quality-reviewer": {
106
85
  profile: "gpt61_sol_high",
107
86
  timeoutSec: 1800,
108
- runMode: "bg",
109
- opusOversight: false,
110
87
  mcpHint: "review",
111
88
  subcommand: "review",
112
89
  },
113
90
  "security-reviewer": {
114
91
  profile: "gpt6_astra_xhigh",
115
92
  timeoutSec: 1800,
116
- runMode: "bg",
117
- opusOversight: true,
118
93
  mcpHint: "review",
119
94
  subcommand: "review",
120
95
  },
121
96
  scientist: {
122
97
  profile: "gpt61_sol_high",
123
98
  timeoutSec: 1440,
124
- runMode: "bg",
125
- opusOversight: false,
126
99
  mcpHint: "analyze",
127
100
  subcommand: "exec",
128
101
  },
129
102
  "document-specialist": {
130
103
  profile: "gpt61_sol_high",
131
104
  timeoutSec: 1440,
132
- runMode: "bg",
133
- opusOversight: false,
134
105
  mcpHint: "analyze",
135
106
  subcommand: "exec",
136
107
  },
137
108
  "scientist-deep": {
138
109
  profile: "gpt6_astra_xhigh",
139
110
  timeoutSec: 3600,
140
- runMode: "bg",
141
- opusOversight: false,
142
111
  mcpHint: "analyze",
143
112
  subcommand: "exec",
144
113
  },
145
114
  verifier: {
146
115
  profile: "gpt61_sol_high",
147
116
  timeoutSec: 1200,
148
- runMode: "fg",
149
- opusOversight: false,
150
117
  mcpHint: "review",
151
118
  subcommand: "review",
152
119
  },
153
120
  "test-engineer": {
154
121
  profile: "gpt61_sol_high",
155
122
  timeoutSec: 1200,
156
- runMode: "bg",
157
- opusOversight: false,
158
123
  mcpHint: "implement",
159
124
  subcommand: "exec",
160
125
  },
161
126
  "qa-tester": {
162
127
  profile: "gpt61_sol_high",
163
128
  timeoutSec: 1200,
164
- runMode: "bg",
165
- opusOversight: false,
166
129
  mcpHint: "review",
167
130
  subcommand: "review",
168
131
  },
169
132
  spark: {
170
133
  profile: "gpt6_luna_low",
171
134
  timeoutSec: 180,
172
- runMode: "fg",
173
- opusOversight: false,
174
135
  mcpHint: "implement",
175
136
  subcommand: "exec",
176
137
  },
@@ -179,16 +140,12 @@ const policy = {
179
140
  designer: {
180
141
  profile: "gpt6_astra_xhigh",
181
142
  timeoutSec: 900,
182
- runMode: "bg",
183
- opusOversight: false,
184
143
  mcpHint: "implement",
185
144
  subcommand: "exec",
186
145
  },
187
146
  writer: {
188
147
  profile: "gpt6_luna_high",
189
148
  timeoutSec: 900,
190
- runMode: "bg",
191
- opusOversight: false,
192
149
  mcpHint: "implement",
193
150
  subcommand: "exec",
194
151
  },
@@ -198,7 +155,7 @@ function freezePolicy(entry) {
198
155
  return Object.freeze({ ...entry });
199
156
  }
200
157
 
201
- export const CODEX_AGENT_POLICY = Object.freeze(
158
+ const CODEX_AGENT_POLICY = Object.freeze(
202
159
  Object.fromEntries(
203
160
  Object.entries(policy).map(([agent, entry]) => [
204
161
  agent,
@@ -206,9 +163,9 @@ export const CODEX_AGENT_POLICY = Object.freeze(
206
163
  ]),
207
164
  ),
208
165
  );
209
- export const DEFAULT_CODEX_AGENT = "executor";
166
+ const DEFAULT_CODEX_AGENT = "executor";
210
167
 
211
- export const CANONICAL_CODEX_PROFILE_OVERRIDES = Object.freeze(
168
+ const CANONICAL_CODEX_PROFILE_OVERRIDES = Object.freeze(
212
169
  new Set([
213
170
  "gpt6_luna_low",
214
171
  "gpt6_luna_high",
@@ -219,7 +176,7 @@ export const CANONICAL_CODEX_PROFILE_OVERRIDES = Object.freeze(
219
176
  "gpt6_astra_ultra",
220
177
  ]),
221
178
  );
222
- export const ULTRA_ELIGIBLE_CODEX_AGENTS = Object.freeze(
179
+ const ULTRA_ELIGIBLE_CODEX_AGENTS = Object.freeze(
223
180
  new Set(["deep-executor", "scientist-deep"]),
224
181
  );
225
182
 
@@ -316,39 +273,163 @@ export function resolveNestedCodexAgentProfile(
316
273
  return effort.toLowerCase() === "ultra" ? "gpt6_astra_max" : candidate;
317
274
  }
318
275
 
319
- export function describeCodexAgentPolicy() {
320
- return {
321
- defaultAgent: DEFAULT_CODEX_AGENT,
322
- agents: Object.keys(CODEX_AGENT_POLICY),
323
- };
276
+ const EXPECTED_DURATION_BY_AGENT = Object.freeze({
277
+ writer: 90,
278
+ verifier: 90,
279
+ "qa-tester": 90,
280
+ executor: 300,
281
+ debugger: 300,
282
+ "test-engineer": 300,
283
+ "code-reviewer": 600,
284
+ "security-reviewer": 600,
285
+ architect: 600,
286
+ planner: 600,
287
+ critic: 600,
288
+ analyst: 600,
289
+ scientist: 900,
290
+ "scientist-deep": 900,
291
+ "deep-executor": 900,
292
+ "document-specialist": 900,
293
+ });
294
+
295
+ const NATIVE_CODEX_AGENTS = new Set([
296
+ "explore",
297
+ "verifier",
298
+ "test-engineer",
299
+ "qa-tester",
300
+ ]);
301
+
302
+ function resolveDirectCodexRoutePolicy(agent) {
303
+ if (agent === "explore") {
304
+ return { ...CODEX_AGENT_POLICY.spark, timeoutSec: 600, mcpHint: "analyze" };
305
+ }
306
+ if (agent === "antigravity" || agent === "agy") {
307
+ return CODEX_AGENT_POLICY.designer;
308
+ }
309
+ return resolveCodexAgentPolicy(agent);
310
+ }
311
+
312
+ export function resolveAgentRoute(
313
+ agent,
314
+ map,
315
+ profileOverride = "auto",
316
+ nested = false,
317
+ geminiProfileResolver = resolveGeminiProfileForPurpose,
318
+ ) {
319
+ if (!/^[A-Za-z0-9_.-]+$/.test(agent)) {
320
+ throw new Error(`invalid agent: ${agent}`);
321
+ }
322
+ if (!Object.hasOwn(map, agent)) {
323
+ throw new Error(
324
+ `알 수 없는 에이전트 타입: ${agent}; available: ${Object.keys(map).join(", ")}`,
325
+ );
326
+ }
327
+ const provider = map[agent];
328
+ if (!["codex", "antigravity", "claude"].includes(provider)) {
329
+ throw new Error(`invalid provider for ${agent}: ${provider}`);
330
+ }
331
+ const policy = resolveDirectCodexRoutePolicy(agent);
332
+ const normalizedOverride = normalizeCodexProfileName(profileOverride);
333
+ let resolvedOverride = policy.profile;
334
+ if (normalizedOverride !== "auto") {
335
+ try {
336
+ resolvedOverride = resolveCodexAgentProfile(agent, {
337
+ profileOverride: normalizedOverride,
338
+ nested,
339
+ });
340
+ } catch {
341
+ throw new Error(
342
+ `TFX_CODEX_PROFILE 값이 유효하지 않습니다: ${profileOverride}`,
343
+ );
344
+ }
345
+ }
346
+ return [
347
+ provider,
348
+ policy.profile,
349
+ policy.timeoutSec,
350
+ policy.mcpHint,
351
+ policy.subcommand,
352
+ normalizedOverride,
353
+ resolvedOverride,
354
+ geminiProfileResolver(agent),
355
+ EXPECTED_DURATION_BY_AGENT[agent] ?? 30,
356
+ NATIVE_CODEX_AGENTS.has(agent),
357
+ ];
324
358
  }
325
359
 
326
360
  function parseCliArgs(argv) {
327
361
  const args = [...argv];
328
362
  let format = "json";
329
363
  let agent = DEFAULT_CODEX_AGENT;
364
+ let mapFile = "";
365
+ let profileOverride = "auto";
366
+ let geminiProfilesModule = "";
367
+ let nested = false;
330
368
  while (args.length > 0) {
331
369
  const flag = args.shift();
332
370
  if (flag === "--format") format = args.shift() || "";
333
371
  else if (flag === "--agent") agent = args.shift() || "";
372
+ else if (flag === "--map-file") mapFile = args.shift() || "";
373
+ else if (flag === "--profile-override")
374
+ profileOverride = args.shift() || "";
375
+ else if (flag === "--gemini-profiles-module")
376
+ geminiProfilesModule = args.shift() || "";
377
+ else if (flag === "--nested") nested = true;
334
378
  else throw new Error(`unknown argument: ${flag}`);
335
379
  }
336
- if (!new Set(["json", "tsv"]).has(format)) {
380
+ if (!new Set(["json", "tsv", "route"]).has(format)) {
337
381
  throw new Error(`unsupported format: ${format}`);
338
382
  }
339
- return { format, agent };
383
+ return {
384
+ format,
385
+ agent,
386
+ mapFile,
387
+ profileOverride,
388
+ geminiProfilesModule,
389
+ nested,
390
+ };
340
391
  }
341
392
 
342
- function runCli() {
343
- const { format, agent } = parseCliArgs(process.argv.slice(2));
393
+ async function runCli() {
394
+ const {
395
+ format,
396
+ agent,
397
+ mapFile,
398
+ profileOverride,
399
+ geminiProfilesModule,
400
+ nested,
401
+ } = parseCliArgs(process.argv.slice(2));
402
+ if (format === "route") {
403
+ if (!mapFile) throw new Error("--map-file is required for route format");
404
+ const map = JSON.parse(readFileSync(mapFile, "utf8"));
405
+ let resolver = resolveGeminiProfileForPurpose;
406
+ if (geminiProfilesModule) {
407
+ try {
408
+ const module = await import(pathToFileURL(geminiProfilesModule).href);
409
+ resolver = (agent) => {
410
+ try {
411
+ return module.resolveGeminiProfileForPurpose(agent) || "flash38";
412
+ } catch {
413
+ return "flash38";
414
+ }
415
+ };
416
+ } catch {
417
+ resolver = () => "flash38";
418
+ }
419
+ }
420
+ process.stdout.write(
421
+ resolveAgentRoute(agent, map, profileOverride, nested, resolver).join(
422
+ "\x1e",
423
+ ),
424
+ );
425
+ return;
426
+ }
344
427
  const resolved = resolveCodexAgentPolicy(agent);
345
428
  if (format === "tsv") {
346
429
  process.stdout.write(
347
430
  [
348
431
  resolved.profile,
349
432
  resolved.timeoutSec,
350
- resolved.runMode,
351
- resolved.opusOversight,
352
433
  resolved.mcpHint,
353
434
  resolved.subcommand,
354
435
  ].join("\t"),
@@ -360,7 +441,7 @@ function runCli() {
360
441
 
361
442
  if (import.meta.url === new URL(process.argv[1], "file:").href) {
362
443
  try {
363
- runCli();
444
+ await runCli();
364
445
  } catch (error) {
365
446
  process.stderr.write(`[agent-route-policy] ${error.message}\n`);
366
447
  process.exitCode = 1;
@@ -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";
@@ -14,32 +12,22 @@ export const command = null;
14
12
  const AGENT_PROFILES = {
15
13
  explore: {
16
14
  timeoutSec: 600,
17
- runMode: "fg",
18
- opusOversight: false,
19
15
  model: "haiku",
20
16
  },
21
17
  claude: {
22
18
  timeoutSec: 600,
23
- runMode: "fg",
24
- opusOversight: false,
25
19
  model: "haiku",
26
20
  },
27
21
  "test-engineer": {
28
22
  timeoutSec: 1200,
29
- runMode: "bg",
30
- opusOversight: false,
31
23
  model: "sonnet",
32
24
  },
33
25
  "qa-tester": {
34
26
  timeoutSec: 1200,
35
- runMode: "bg",
36
- opusOversight: false,
37
27
  model: "sonnet",
38
28
  },
39
29
  verifier: {
40
30
  timeoutSec: 1200,
41
- runMode: "fg",
42
- opusOversight: false,
43
31
  model: "sonnet",
44
32
  },
45
33
  };
@@ -64,8 +52,6 @@ export function plan({
64
52
  profile: "claude-native",
65
53
  effort: "n/a",
66
54
  timeoutMs: effectiveTimeoutSec * 1000,
67
- runMode: cfg.runMode,
68
- opusOversight: cfg.opusOversight,
69
55
  model: cfg.model,
70
56
  mcpProfile: mcpProfile === "auto" ? null : mcpProfile,
71
57
  promptLength: prompt.length,
@@ -1,76 +1,12 @@
1
- import { execSync, spawn } from "node:child_process";
2
1
  import { createHash } from "node:crypto";
3
2
  import { existsSync, readFileSync } from "node:fs";
4
3
  import { homedir } from "node:os";
5
- import { dirname, join } from "node:path";
6
- import { fileURLToPath } from "node:url";
7
- import { resolveHubPortForContext } from "../../hub/hub-lifecycle.mjs";
4
+ import { join } from "node:path";
8
5
  import { whichCommand, whichCommandAsync } from "../../hub/platform.mjs";
9
6
 
10
- 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
7
  const CLI_PROBE_CACHE = new Map();
14
8
  const CLI_PROBE_PROMISES = new Map();
15
9
 
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
- function fetchHubStatus({
24
- execSyncFn = execSync,
25
- statusUrl = resolveDefaultStatusUrl(),
26
- timeout = 3000,
27
- } = {}) {
28
- const response = execSyncFn(`curl -sf ${statusUrl}`, {
29
- timeout,
30
- encoding: "utf8",
31
- windowsHide: true,
32
- });
33
- const data = JSON.parse(response);
34
- return {
35
- ok: true,
36
- state: data?.hub?.state || "unknown",
37
- pid: data?.pid,
38
- };
39
- }
40
-
41
- export function resolveDefaultStatusUrl(
42
- env = process.env,
43
- cwd = process.cwd(),
44
- ) {
45
- const port = resolveHubPortForContext({
46
- env,
47
- cwd,
48
- defaultPort: HUB_DEFAULT_PORT,
49
- });
50
- return `http://127.0.0.1:${port}/status`;
51
- }
52
-
53
- function resolveStatusUrlForContext({
54
- statusUrl,
55
- env = process.env,
56
- cwd = process.cwd(),
57
- } = {}) {
58
- try {
59
- const url = new URL(String(statusUrl));
60
- url.port = String(
61
- resolveHubPortForContext({
62
- port: url.port,
63
- env,
64
- cwd,
65
- defaultPort: HUB_DEFAULT_PORT,
66
- }),
67
- );
68
- return url.toString();
69
- } catch {
70
- return resolveDefaultStatusUrl(env, cwd);
71
- }
72
- }
73
-
74
10
  function normalizeCliName(name) {
75
11
  return String(name ?? "").trim() || null;
76
12
  }
@@ -125,7 +61,7 @@ async function resolveCliProbe(name, options = {}) {
125
61
  return toCliResult(path);
126
62
  }
127
63
 
128
- export async function checkCli(name, options = {}) {
64
+ async function checkCli(name, options = {}) {
129
65
  const cliName = normalizeCliName(name);
130
66
  if (!cliName) return { ok: false };
131
67
 
@@ -168,11 +104,6 @@ export async function probeClis(names, options = {}) {
168
104
  return mapCliResults(cliNames, results);
169
105
  }
170
106
 
171
- export function resetCliProbeCache() {
172
- CLI_PROBE_CACHE.clear();
173
- CLI_PROBE_PROMISES.clear();
174
- }
175
-
176
107
  export function detectCodexAuthState({
177
108
  homeDir = homedir(),
178
109
  existsSyncFn = existsSync,
@@ -237,63 +168,3 @@ export function detectCodexPlan(options = {}) {
237
168
  const { plan, source } = detectCodexAuthState(options);
238
169
  return { plan, source };
239
170
  }
240
-
241
- export function checkHub({
242
- env = process.env,
243
- cwd = process.cwd(),
244
- pkgRoot = DEFAULT_PKG_ROOT,
245
- statusUrl = resolveDefaultStatusUrl(env, cwd),
246
- restart = true,
247
- requestTimeoutMs = 3000,
248
- pollAttempts = 8,
249
- pollIntervalMs = 500,
250
- execSyncFn = execSync,
251
- spawnFn = spawn,
252
- existsSyncFn = existsSync,
253
- sleepSyncFn = sleepSync,
254
- } = {}) {
255
- const guardedStatusUrl = resolveStatusUrlForContext({ statusUrl, env, cwd });
256
- try {
257
- return fetchHubStatus({
258
- execSyncFn,
259
- statusUrl: guardedStatusUrl,
260
- timeout: requestTimeoutMs,
261
- });
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
- } catch {
279
- return { ok: false, state: "unreachable", restart: "spawn_failed" };
280
- }
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
- }
298
-
299
- export { DEFAULT_PKG_ROOT, DEFAULT_STATUS_URL };