@jsonstudio/rcc 0.90.1 → 0.90.91

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 (193) hide show
  1. package/README.md +1 -1
  2. package/dist/build-info.js +2 -2
  3. package/dist/cli/commands/claude.js +3 -8
  4. package/dist/cli/commands/claude.js.map +1 -1
  5. package/dist/cli/commands/codex.js +5 -3
  6. package/dist/cli/commands/codex.js.map +1 -1
  7. package/dist/cli/commands/launcher/index.d.ts +1 -1
  8. package/dist/cli/commands/launcher/types.d.ts +1 -1
  9. package/dist/cli/commands/launcher/utils.d.ts +4 -1
  10. package/dist/cli/commands/launcher/utils.js +22 -8
  11. package/dist/cli/commands/launcher/utils.js.map +1 -1
  12. package/dist/cli/commands/launcher-kernel.d.ts +1 -1
  13. package/dist/cli/commands/launcher-kernel.js +237 -203
  14. package/dist/cli/commands/launcher-kernel.js.map +1 -1
  15. package/dist/cli/commands/{clock-admin.d.ts → session-admin.d.ts} +2 -2
  16. package/dist/cli/commands/{clock-admin.js → session-admin.js} +17 -17
  17. package/dist/cli/commands/session-admin.js.map +1 -0
  18. package/dist/cli/commands/{tmux-inject.d.ts → session-inject.d.ts} +2 -2
  19. package/dist/cli/commands/{tmux-inject.js → session-inject.js} +12 -12
  20. package/dist/cli/commands/session-inject.js.map +1 -0
  21. package/dist/cli/commands/start-utils.d.ts +1 -0
  22. package/dist/cli/commands/start-utils.js +3 -0
  23. package/dist/cli/commands/start-utils.js.map +1 -1
  24. package/dist/cli/commands/start.js +14 -7
  25. package/dist/cli/commands/start.js.map +1 -1
  26. package/dist/cli/register/session-admin-command.d.ts +3 -0
  27. package/dist/cli/register/session-admin-command.js +5 -0
  28. package/dist/cli/register/session-admin-command.js.map +1 -0
  29. package/dist/cli/register/session-inject-command.d.ts +3 -0
  30. package/dist/cli/register/session-inject-command.js +5 -0
  31. package/dist/cli/register/session-inject-command.js.map +1 -0
  32. package/dist/cli.js +4 -4
  33. package/dist/cli.js.map +1 -1
  34. package/dist/config/provider-v2-loader.js +18 -3
  35. package/dist/config/provider-v2-loader.js.map +1 -1
  36. package/dist/config/routecodex-config-loader.js +136 -26
  37. package/dist/config/routecodex-config-loader.js.map +1 -1
  38. package/dist/config/unified-config-paths.js +22 -0
  39. package/dist/config/unified-config-paths.js.map +1 -1
  40. package/dist/config/virtual-router-builder.js +1 -6
  41. package/dist/config/virtual-router-builder.js.map +1 -1
  42. package/dist/docs/daemon-admin-ui.html +6 -6
  43. package/dist/index.js +1 -1
  44. package/dist/index.js.map +1 -1
  45. package/dist/manager/modules/quota/provider-key-normalization.js +1 -10
  46. package/dist/manager/modules/quota/provider-key-normalization.js.map +1 -1
  47. package/dist/manager/modules/quota/provider-quota-daemon.events.js +40 -49
  48. package/dist/manager/modules/quota/provider-quota-daemon.events.js.map +1 -1
  49. package/dist/manager/modules/quota/provider-quota-daemon.model-backoff.js +2 -16
  50. package/dist/manager/modules/quota/provider-quota-daemon.model-backoff.js.map +1 -1
  51. package/dist/manager/modules/token/index.d.ts +1 -0
  52. package/dist/manager/modules/token/index.js +6 -1
  53. package/dist/manager/modules/token/index.js.map +1 -1
  54. package/dist/manager/types.d.ts +1 -0
  55. package/dist/modules/llmswitch/bridge/state-integrations.js +1 -1
  56. package/dist/modules/llmswitch/bridge/state-integrations.js.map +1 -1
  57. package/dist/providers/auth/oauth-repair-cooldown.js +7 -2
  58. package/dist/providers/auth/oauth-repair-cooldown.js.map +1 -1
  59. package/dist/providers/core/config/camoufox-actions.js +11 -2
  60. package/dist/providers/core/config/camoufox-actions.js.map +1 -1
  61. package/dist/providers/core/config/camoufox-launcher.js +60 -24
  62. package/dist/providers/core/config/camoufox-launcher.js.map +1 -1
  63. package/dist/providers/core/config/service-profiles.js +2 -2
  64. package/dist/providers/core/config/service-profiles.js.map +1 -1
  65. package/dist/providers/core/runtime/base-provider-runtime-helpers.js +15 -2
  66. package/dist/providers/core/runtime/base-provider-runtime-helpers.js.map +1 -1
  67. package/dist/providers/core/strategies/oauth-device-flow.js +26 -3
  68. package/dist/providers/core/strategies/oauth-device-flow.js.map +1 -1
  69. package/dist/providers/core/utils/provider-error-reporter.js +51 -0
  70. package/dist/providers/core/utils/provider-error-reporter.js.map +1 -1
  71. package/dist/server/handlers/handler-response-utils.js +3 -6
  72. package/dist/server/handlers/handler-response-utils.js.map +1 -1
  73. package/dist/server/handlers/handler-utils.js +14 -8
  74. package/dist/server/handlers/handler-utils.js.map +1 -1
  75. package/dist/server/handlers/responses-handler.js +5 -3
  76. package/dist/server/handlers/responses-handler.js.map +1 -1
  77. package/dist/server/runtime/http-server/daemon-admin/providers-handler-routing-utils.d.ts +1 -1
  78. package/dist/server/runtime/http-server/daemon-admin/providers-handler-routing-utils.js +5 -5
  79. package/dist/server/runtime/http-server/daemon-admin/providers-handler-routing-utils.js.map +1 -1
  80. package/dist/server/runtime/http-server/daemon-admin/routing-policy.d.ts +1 -1
  81. package/dist/server/runtime/http-server/daemon-admin/routing-policy.js +4 -4
  82. package/dist/server/runtime/http-server/daemon-admin/routing-policy.js.map +1 -1
  83. package/dist/server/runtime/http-server/executor/client-injection-flow.js +20 -10
  84. package/dist/server/runtime/http-server/executor/client-injection-flow.js.map +1 -1
  85. package/dist/server/runtime/http-server/executor/provider-response-converter.js +54 -17
  86. package/dist/server/runtime/http-server/executor/provider-response-converter.js.map +1 -1
  87. package/dist/server/runtime/http-server/executor/provider-runtime-resolver.js +8 -6
  88. package/dist/server/runtime/http-server/executor/provider-runtime-resolver.js.map +1 -1
  89. package/dist/server/runtime/http-server/executor/request-retry-helpers.d.ts +1 -1
  90. package/dist/server/runtime/http-server/executor/request-retry-helpers.js +8 -8
  91. package/dist/server/runtime/http-server/executor/request-retry-helpers.js.map +1 -1
  92. package/dist/server/runtime/http-server/executor/retry-engine.d.ts +2 -2
  93. package/dist/server/runtime/http-server/executor/retry-engine.js +2 -2
  94. package/dist/server/runtime/http-server/executor/retry-engine.js.map +1 -1
  95. package/dist/server/runtime/http-server/executor/usage-aggregator.js +5 -2
  96. package/dist/server/runtime/http-server/executor/usage-aggregator.js.map +1 -1
  97. package/dist/server/runtime/http-server/executor-metadata.js +57 -77
  98. package/dist/server/runtime/http-server/executor-metadata.js.map +1 -1
  99. package/dist/server/runtime/http-server/executor-provider.d.ts +1 -0
  100. package/dist/server/runtime/http-server/executor-provider.js +5 -1
  101. package/dist/server/runtime/http-server/executor-provider.js.map +1 -1
  102. package/dist/server/runtime/http-server/http-server-lifecycle.js +2 -1
  103. package/dist/server/runtime/http-server/http-server-lifecycle.js.map +1 -1
  104. package/dist/server/runtime/http-server/http-server-runtime-setup.js +1 -1
  105. package/dist/server/runtime/http-server/http-server-runtime-setup.js.map +1 -1
  106. package/dist/server/runtime/http-server/http-server-session-daemon.d.ts +6 -0
  107. package/dist/server/runtime/http-server/{http-server-clock-daemon.js → http-server-session-daemon.js} +80 -73
  108. package/dist/server/runtime/http-server/http-server-session-daemon.js.map +1 -0
  109. package/dist/server/runtime/http-server/index.d.ts +11 -11
  110. package/dist/server/runtime/http-server/index.js +21 -21
  111. package/dist/server/runtime/http-server/index.js.map +1 -1
  112. package/dist/server/runtime/http-server/managed-process-probe.js +1 -1
  113. package/dist/server/runtime/http-server/managed-process-probe.js.map +1 -1
  114. package/dist/server/runtime/http-server/middleware.js +19 -11
  115. package/dist/server/runtime/http-server/middleware.js.map +1 -1
  116. package/dist/server/runtime/http-server/request-executor.js +13 -4
  117. package/dist/server/runtime/http-server/request-executor.js.map +1 -1
  118. package/dist/server/runtime/http-server/routes.js +3 -3
  119. package/dist/server/runtime/http-server/routes.js.map +1 -1
  120. package/dist/server/runtime/http-server/{clock-client-reaper.d.ts → session-client-reaper.d.ts} +6 -6
  121. package/dist/server/runtime/http-server/{clock-client-reaper.js → session-client-reaper.js} +23 -23
  122. package/dist/server/runtime/http-server/session-client-reaper.js.map +1 -0
  123. package/dist/server/runtime/http-server/{clock-client-registry-utils.d.ts → session-client-registry-utils.d.ts} +10 -10
  124. package/dist/server/runtime/http-server/{clock-client-registry-utils.js → session-client-registry-utils.js} +3 -3
  125. package/dist/server/runtime/http-server/session-client-registry-utils.js.map +1 -0
  126. package/dist/server/runtime/http-server/{clock-client-registry.d.ts → session-client-registry.d.ts} +12 -12
  127. package/dist/server/runtime/http-server/{clock-client-registry.js → session-client-registry.js} +9 -9
  128. package/dist/server/runtime/http-server/session-client-registry.js.map +1 -0
  129. package/dist/server/runtime/http-server/{clock-client-route-utils.d.ts → session-client-route-utils.d.ts} +1 -1
  130. package/dist/server/runtime/http-server/{clock-client-route-utils.js → session-client-route-utils.js} +4 -4
  131. package/dist/server/runtime/http-server/session-client-route-utils.js.map +1 -0
  132. package/dist/server/runtime/http-server/session-client-routes.d.ts +2 -0
  133. package/dist/server/runtime/http-server/{clock-client-routes.js → session-client-routes.js} +65 -47
  134. package/dist/server/runtime/http-server/session-client-routes.js.map +1 -0
  135. package/dist/server/runtime/http-server/session-daemon-inject-config.d.ts +1 -0
  136. package/dist/server/runtime/http-server/{clock-daemon-inject-config.js → session-daemon-inject-config.js} +2 -2
  137. package/dist/server/runtime/http-server/session-daemon-inject-config.js.map +1 -0
  138. package/dist/server/runtime/http-server/{clock-daemon-log-throttle.d.ts → session-daemon-log-throttle.d.ts} +7 -7
  139. package/dist/server/runtime/http-server/{clock-daemon-log-throttle.js → session-daemon-log-throttle.js} +5 -5
  140. package/dist/server/runtime/http-server/session-daemon-log-throttle.js.map +1 -0
  141. package/dist/server/runtime/http-server/{clock-scope-resolution.d.ts → session-scope-resolution.d.ts} +2 -2
  142. package/dist/server/runtime/http-server/{clock-scope-resolution.js → session-scope-resolution.js} +14 -18
  143. package/dist/server/runtime/http-server/session-scope-resolution.js.map +1 -0
  144. package/dist/server/runtime/http-server/stopmessage-scope-rebind.d.ts +8 -0
  145. package/dist/server/runtime/http-server/stopmessage-scope-rebind.js +29 -0
  146. package/dist/server/runtime/http-server/stopmessage-scope-rebind.js.map +1 -1
  147. package/dist/server/runtime/http-server/tmux-session-probe.js +1 -1
  148. package/dist/server/runtime/http-server/tmux-session-probe.js.map +1 -1
  149. package/dist/token-daemon/token-daemon.d.ts +2 -0
  150. package/dist/token-daemon/token-daemon.js +18 -10
  151. package/dist/token-daemon/token-daemon.js.map +1 -1
  152. package/dist/utils/log-helpers.js +46 -0
  153. package/dist/utils/log-helpers.js.map +1 -1
  154. package/dist/utils/session-client-token.d.ts +4 -0
  155. package/dist/utils/{clock-client-token.js → session-client-token.js} +19 -24
  156. package/dist/utils/session-client-token.js.map +1 -0
  157. package/dist/utils/session-scope-trace.d.ts +11 -0
  158. package/dist/utils/{clock-scope-trace.js → session-scope-trace.js} +9 -9
  159. package/dist/utils/session-scope-trace.js.map +1 -0
  160. package/docs/CLOCK.md +0 -1
  161. package/docs/PORTS.md +2 -2
  162. package/docs/ROUTING_POLICY_SCHEMA.md +1 -1
  163. package/docs/antigravity-routing-contract.md +2 -2
  164. package/docs/daemon-admin-ui.html +6 -6
  165. package/docs/{clock-client-daemon-design.md → session-client-daemon-design.md} +34 -34
  166. package/package.json +3 -3
  167. package/scripts/compare-responses-sse.mjs +267 -0
  168. package/scripts/replay-codex-sample.mjs +52 -6
  169. package/scripts/virtual-router-dryrun.mjs +7 -1
  170. package/dist/cli/commands/clock-admin.js.map +0 -1
  171. package/dist/cli/commands/tmux-inject.js.map +0 -1
  172. package/dist/cli/register/clock-admin-command.d.ts +0 -3
  173. package/dist/cli/register/clock-admin-command.js +0 -5
  174. package/dist/cli/register/clock-admin-command.js.map +0 -1
  175. package/dist/cli/register/tmux-inject-command.d.ts +0 -3
  176. package/dist/cli/register/tmux-inject-command.js +0 -5
  177. package/dist/cli/register/tmux-inject-command.js.map +0 -1
  178. package/dist/server/runtime/http-server/clock-client-reaper.js.map +0 -1
  179. package/dist/server/runtime/http-server/clock-client-registry-utils.js.map +0 -1
  180. package/dist/server/runtime/http-server/clock-client-registry.js.map +0 -1
  181. package/dist/server/runtime/http-server/clock-client-route-utils.js.map +0 -1
  182. package/dist/server/runtime/http-server/clock-client-routes.d.ts +0 -2
  183. package/dist/server/runtime/http-server/clock-client-routes.js.map +0 -1
  184. package/dist/server/runtime/http-server/clock-daemon-inject-config.d.ts +0 -1
  185. package/dist/server/runtime/http-server/clock-daemon-inject-config.js.map +0 -1
  186. package/dist/server/runtime/http-server/clock-daemon-log-throttle.js.map +0 -1
  187. package/dist/server/runtime/http-server/clock-scope-resolution.js.map +0 -1
  188. package/dist/server/runtime/http-server/http-server-clock-daemon.d.ts +0 -6
  189. package/dist/server/runtime/http-server/http-server-clock-daemon.js.map +0 -1
  190. package/dist/utils/clock-client-token.d.ts +0 -4
  191. package/dist/utils/clock-client-token.js.map +0 -1
  192. package/dist/utils/clock-scope-trace.d.ts +0 -11
  193. package/dist/utils/clock-scope-trace.js.map +0 -1
@@ -4,10 +4,11 @@ import { spawnSync } from 'node:child_process';
4
4
  import { createServer } from 'node:http';
5
5
  import crypto from 'node:crypto';
6
6
  import { LOCAL_HOSTS } from '../../constants/index.js';
7
- import { encodeClockClientApiKey, extractClockClientDaemonIdFromApiKey, extractClockClientTmuxSessionIdFromApiKey } from '../../utils/clock-client-token.js';
8
- import { isClockScopeTraceEnabled, isClockScopeTraceVerbose } from '../../utils/clock-scope-trace.js';
7
+ import { encodeSessionClientApiKey, extractSessionClientDaemonIdFromApiKey, extractSessionClientScopeIdFromApiKey } from '../../utils/session-client-token.js';
8
+ import { isSessionScopeTraceEnabled, isSessionScopeTraceVerbose } from '../../utils/session-scope-trace.js';
9
9
  import { logProcessLifecycle } from '../../utils/process-lifecycle-logger.js';
10
10
  import { resolveBinary, parseServerUrl, resolveBoolFromEnv, resolveTmuxSelfHealPolicy, readConfigApiKey, normalizeConnectHost, toIntegerPort, tryReadConfigHostPort, resolveIntFromEnv } from './launcher/utils.js';
11
+ import { resolveRouteCodexConfigPath } from '../../config/config-paths.js';
11
12
  function shouldStopManagedTmuxOnShutdown(signal, env) {
12
13
  if (signal === 'SIGINT') {
13
14
  return true;
@@ -26,6 +27,37 @@ function shouldLogClientExitSummary(commandName) {
26
27
  const normalized = String(commandName || '').trim().toLowerCase();
27
28
  return normalized === 'codex' || normalized === 'claude' || normalized === 'routecodex';
28
29
  }
30
+ function resolveLauncherConfigPath(ctx, fsImpl, pathImpl, options) {
31
+ let configPath = typeof options.config === 'string' && options.config.trim() ? options.config.trim() : '';
32
+ if (!configPath) {
33
+ const resolved = resolveRouteCodexConfigPath();
34
+ configPath = resolved && resolved.trim()
35
+ ? resolved
36
+ : pathImpl.join(ctx.homedir(), '.routecodex', 'config.json');
37
+ }
38
+ return configPath;
39
+ }
40
+ function resolveLauncherApiKey(ctx, fsImpl, configPath, options) {
41
+ const fromOption = typeof options.apikey === 'string' && options.apikey.trim()
42
+ ? options.apikey.trim()
43
+ : null;
44
+ if (fromOption) {
45
+ return fromOption;
46
+ }
47
+ const fromRouteEnv = typeof ctx.env.ROUTECODEX_HTTP_APIKEY === 'string' && ctx.env.ROUTECODEX_HTTP_APIKEY.trim()
48
+ ? ctx.env.ROUTECODEX_HTTP_APIKEY.trim()
49
+ : null;
50
+ if (fromRouteEnv) {
51
+ return fromRouteEnv;
52
+ }
53
+ const fromRccEnv = typeof ctx.env.RCC_HTTP_APIKEY === 'string' && ctx.env.RCC_HTTP_APIKEY.trim()
54
+ ? ctx.env.RCC_HTTP_APIKEY.trim()
55
+ : null;
56
+ if (fromRccEnv) {
57
+ return fromRccEnv;
58
+ }
59
+ return readConfigApiKey(fsImpl, configPath);
60
+ }
29
61
  function readProcessPpidAndCommand(pid) {
30
62
  if (process.platform === 'win32') {
31
63
  return { ppid: null, command: '' };
@@ -95,11 +127,10 @@ function canSignalOwnedToolProcess(args) {
95
127
  }
96
128
  return { ok: true, reason: 'owned_child' };
97
129
  }
98
- function resolveServerConnection(ctx, fsImpl, pathImpl, options) {
99
- let configPath = typeof options.config === 'string' && options.config.trim() ? options.config.trim() : '';
100
- if (!configPath) {
101
- configPath = pathImpl.join(ctx.homedir(), '.routecodex', 'config.json');
102
- }
130
+ function resolveServerConnection(ctx, fsImpl, pathImpl, options, configPathOverride) {
131
+ const configPath = configPathOverride && configPathOverride.trim()
132
+ ? configPathOverride.trim()
133
+ : resolveLauncherConfigPath(ctx, fsImpl, pathImpl, options);
103
134
  let actualProtocol = 'http';
104
135
  let actualPort = toIntegerPort(options.port);
105
136
  let actualHost = typeof options.host === 'string' && options.host.trim() ? options.host.trim() : LOCAL_HOSTS.ANY;
@@ -135,12 +166,7 @@ function resolveServerConnection(ctx, fsImpl, pathImpl, options) {
135
166
  if (!(typeof options.url === 'string' && options.url.trim()) && !actualPort) {
136
167
  throw new Error('Invalid or missing port configuration for RouteCodex server');
137
168
  }
138
- const configuredApiKey = (typeof options.apikey === 'string' && options.apikey.trim() ? options.apikey.trim() : null) ??
139
- (typeof ctx.env.ROUTECODEX_APIKEY === 'string' && ctx.env.ROUTECODEX_APIKEY.trim()
140
- ? ctx.env.ROUTECODEX_APIKEY.trim()
141
- : null) ??
142
- (typeof ctx.env.RCC_APIKEY === 'string' && ctx.env.RCC_APIKEY.trim() ? ctx.env.RCC_APIKEY.trim() : null) ??
143
- readConfigApiKey(fsImpl, configPath);
169
+ const configuredApiKey = resolveLauncherApiKey(ctx, fsImpl, configPath, options);
144
170
  const connectHost = normalizeConnectHost(actualHost);
145
171
  const portPart = actualPort ? `:${actualPort}` : '';
146
172
  const serverUrl = `${actualProtocol}://${connectHost}${portPart}${actualBasePath}`;
@@ -602,64 +628,23 @@ function normalizePathForComparison(candidate) {
602
628
  return raw;
603
629
  }
604
630
  }
605
- function findReusableManagedTmuxSession(spawnSyncImpl, cwd, commandName) {
606
- const expectedCwd = normalizePathForComparison(cwd);
607
- const expectedSessionPrefix = `rcc_${normalizeSessionToken(commandName)}_`;
631
+ function formatHmms(value) {
632
+ const pad = (n) => String(n).padStart(2, '0');
633
+ return `${pad(value.getHours())}${pad(value.getMinutes())}${pad(value.getSeconds())}`;
634
+ }
635
+ function tmuxSessionExists(spawnSyncImpl, sessionName) {
608
636
  try {
609
- const listResult = spawnSyncImpl('tmux', ['list-sessions', '-F', '#S #{session_attached}'], { encoding: 'utf8' });
610
- if (listResult.status !== 0) {
611
- return null;
612
- }
613
- const lines = String(listResult.stdout || '')
614
- .split(/\r?\n/)
615
- .map((line) => line.trim())
616
- .filter(Boolean);
617
- for (const line of lines) {
618
- const [sessionName, attachedFlag] = line.split(' ');
619
- const normalizedName = String(sessionName || '').trim();
620
- if (!normalizedName.startsWith(expectedSessionPrefix)) {
621
- continue;
622
- }
623
- if (String(attachedFlag || '').trim() === '1') {
624
- continue;
625
- }
626
- const panesResult = spawnSyncImpl('tmux', [
627
- 'list-panes',
628
- '-t',
629
- normalizedName,
630
- '-F',
631
- '#{session_name}:#{window_index}.#{pane_index} #{pane_current_command} #{pane_current_path}'
632
- ], { encoding: 'utf8' });
633
- if (panesResult.status !== 0) {
634
- continue;
635
- }
636
- const panes = String(panesResult.stdout || '')
637
- .split(/\r?\n/)
638
- .map((paneLine) => paneLine.trim())
639
- .filter(Boolean);
640
- for (const pane of panes) {
641
- const [target, command, panePath] = pane.split(' ');
642
- const tmuxTarget = String(target || '').trim();
643
- const currentCommand = String(command || '').trim().toLowerCase();
644
- const normalizedPanePath = normalizePathForComparison(String(panePath || '').trim());
645
- if (!tmuxTarget) {
646
- continue;
647
- }
648
- if (!isReusableIdlePaneCommand(currentCommand)) {
649
- continue;
650
- }
651
- if (!normalizedPanePath || normalizedPanePath !== expectedCwd) {
652
- continue;
653
- }
654
- return { sessionName: normalizedName, tmuxTarget };
655
- }
656
- }
657
- return null;
637
+ const result = spawnSyncImpl('tmux', ['has-session', '-t', sessionName], { encoding: 'utf8' });
638
+ return result.status === 0;
658
639
  }
659
640
  catch {
660
- return null;
641
+ return false;
661
642
  }
662
643
  }
644
+ function buildManagedTmuxSessionName(nowMs, attempt) {
645
+ const stamp = formatHmms(new Date(nowMs + attempt * 1000));
646
+ return `rcc-tmux-${stamp}`;
647
+ }
663
648
  function requestManagedTmuxSessionExit(spawnSyncImpl, sessionName) {
664
649
  const target = String(sessionName || '').trim();
665
650
  if (!target) {
@@ -691,29 +676,33 @@ function requestManagedTmuxSessionExit(spawnSyncImpl, sessionName) {
691
676
  }
692
677
  }
693
678
  function createManagedTmuxSession(args) {
694
- const { spawnSyncImpl, cwd, commandName } = args;
695
- const sessionName = (() => {
696
- const token = normalizeSessionToken(commandName);
697
- return `rcc_${token}_${Date.now()}_${Math.random().toString(16).slice(2, 8)}`;
698
- })();
699
- try {
700
- const result = spawnSyncImpl('tmux', ['new-session', '-d', '-s', sessionName, '-c', cwd], { encoding: 'utf8' });
701
- if (result.status !== 0) {
702
- return null;
679
+ const { spawnSyncImpl, cwd } = args;
680
+ const baseNow = Date.now();
681
+ for (let attempt = 0; attempt < 6; attempt += 1) {
682
+ const sessionName = buildManagedTmuxSessionName(baseNow, attempt);
683
+ if (tmuxSessionExists(spawnSyncImpl, sessionName)) {
684
+ continue;
703
685
  }
704
- }
705
- catch {
706
- return null;
707
- }
708
- const tmuxTarget = `${sessionName}:0.0`;
709
- return {
710
- sessionName,
711
- tmuxTarget,
712
- reused: false,
713
- stop: () => {
714
- requestManagedTmuxSessionExit(spawnSyncImpl, sessionName);
686
+ try {
687
+ const result = spawnSyncImpl('tmux', ['new-session', '-d', '-s', sessionName, '-c', cwd], { encoding: 'utf8' });
688
+ if (result.status !== 0) {
689
+ continue;
690
+ }
715
691
  }
716
- };
692
+ catch {
693
+ continue;
694
+ }
695
+ const tmuxTarget = `${sessionName}:0.0`;
696
+ return {
697
+ sessionName,
698
+ tmuxTarget,
699
+ reused: false,
700
+ stop: () => {
701
+ requestManagedTmuxSessionExit(spawnSyncImpl, sessionName);
702
+ }
703
+ };
704
+ }
705
+ return null;
717
706
  }
718
707
  function launchCommandInTmuxPane(args) {
719
708
  const { spawnSyncImpl, tmuxTarget, cwd, command, commandName, commandArgs, envOverrides, selfHealPolicy } = args;
@@ -822,20 +811,20 @@ function normalizeTmuxInjectedText(raw) {
822
811
  .join(' ')
823
812
  .trim();
824
813
  }
825
- async function startClockClientService(args) {
814
+ async function startSessionClientService(args) {
826
815
  const { ctx, resolved, workdir, tmuxTarget, spawnSyncImpl, clientType, managedTmuxSession, getManagedProcessState } = args;
827
816
  const daemonId = (() => {
828
817
  try {
829
- return `clockd_${crypto.randomUUID()}`;
818
+ return `sessiond_${crypto.randomUUID()}`;
830
819
  }
831
820
  catch {
832
- return `clockd_${Date.now()}_${Math.random().toString(16).slice(2)}`;
821
+ return `sessiond_${Date.now()}_${Math.random().toString(16).slice(2)}`;
833
822
  }
834
823
  })();
835
824
  const normalizedTmuxTarget = String(tmuxTarget || '').trim();
836
825
  if (!normalizedTmuxTarget) {
837
826
  // No tmux target means no reliable stdin injection path.
838
- // Do not register a clock-client daemon with a synthetic session id.
827
+ // Do not register a session-client daemon with a synthetic session id.
839
828
  return null;
840
829
  }
841
830
  const tmuxSessionId = (() => {
@@ -888,7 +877,7 @@ async function startClockClientService(args) {
888
877
  server?.listen(0, '127.0.0.1', () => {
889
878
  const address = server?.address();
890
879
  if (!address || typeof address === 'string') {
891
- reject(new Error('failed to resolve clock daemon callback address'));
880
+ reject(new Error('failed to resolve session daemon callback address'));
892
881
  return;
893
882
  }
894
883
  resolve(address.port);
@@ -906,7 +895,7 @@ async function startClockClientService(args) {
906
895
  callbackUrl = `http://127.0.0.1:${port}/inject`;
907
896
  }
908
897
  const controlUrl = `${resolved.protocol}://127.0.0.1:${resolved.port}${resolved.basePath}`;
909
- const controlRequestTimeoutMs = resolveIntFromEnv(ctx.env.ROUTECODEX_CLOCK_CLIENT_CONTROL_TIMEOUT_MS ?? ctx.env.RCC_CLOCK_CLIENT_CONTROL_TIMEOUT_MS, 1500, 200, 30_000);
898
+ const controlRequestTimeoutMs = resolveIntFromEnv(ctx.env.ROUTECODEX_SESSION_CLIENT_CONTROL_TIMEOUT_MS ?? ctx.env.RCC_SESSION_CLIENT_CONTROL_TIMEOUT_MS, 1500, 200, 30_000);
910
899
  const normalizeManagedProcessPayload = () => {
911
900
  const state = typeof getManagedProcessState === 'function' ? getManagedProcessState() : undefined;
912
901
  const managedClientProcess = state?.managedClientProcess === true;
@@ -955,7 +944,7 @@ async function startClockClientService(args) {
955
944
  }
956
945
  }
957
946
  };
958
- const reRegisterBackoffMs = resolveIntFromEnv(ctx.env.ROUTECODEX_CLOCK_CLIENT_REREGISTER_BACKOFF_MS ?? ctx.env.RCC_CLOCK_CLIENT_REREGISTER_BACKOFF_MS, 1500, 200, 60_000);
947
+ const reRegisterBackoffMs = resolveIntFromEnv(ctx.env.ROUTECODEX_SESSION_CLIENT_REREGISTER_BACKOFF_MS ?? ctx.env.RCC_SESSION_CLIENT_REREGISTER_BACKOFF_MS, 1500, 200, 60_000);
959
948
  let registerInFlight = null;
960
949
  let lastRegisterAttemptAtMs = 0;
961
950
  const registerDaemon = async () => {
@@ -964,7 +953,7 @@ async function startClockClientService(args) {
964
953
  }
965
954
  registerInFlight = (async () => {
966
955
  lastRegisterAttemptAtMs = Date.now();
967
- const result = await post('/daemon/clock-client/register', {
956
+ const result = await post('/daemon/session-client/register', {
968
957
  daemonId,
969
958
  tmuxSessionId,
970
959
  sessionId: tmuxSessionId,
@@ -985,7 +974,7 @@ async function startClockClientService(args) {
985
974
  }
986
975
  };
987
976
  const syncHeartbeat = async () => {
988
- const heartbeat = await post('/daemon/clock-client/heartbeat', {
977
+ const heartbeat = await post('/daemon/session-client/heartbeat', {
989
978
  daemonId,
990
979
  tmuxSessionId,
991
980
  sessionId: tmuxSessionId,
@@ -1032,7 +1021,7 @@ async function startClockClientService(args) {
1032
1021
  syncHeartbeat,
1033
1022
  stop: async () => {
1034
1023
  clearInterval(heartbeat);
1035
- await post('/daemon/clock-client/unregister', { daemonId });
1024
+ await post('/daemon/session-client/unregister', { daemonId });
1036
1025
  if (!server) {
1037
1026
  return;
1038
1027
  }
@@ -1120,14 +1109,25 @@ export function createLauncherCommand(program, ctx, spec) {
1120
1109
  command.action(async (extraArgs = [], options) => {
1121
1110
  const spinner = await ctx.createSpinner(`Preparing ${spec.displayName} with RouteCodex...`);
1122
1111
  try {
1123
- const resolved = resolveServerConnection(ctx, fsImpl, pathImpl, options);
1124
- await ctx.ensureGuardianDaemon?.();
1125
- const ensureResult = await ensureServerReady(ctx, fsImpl, pathImpl, spinner, options, resolved, spec.allowAutoStartServer === true);
1126
- if (!ensureResult.ready) {
1127
- spinner.info('RouteCodex server is not running; launcher will continue and wait for your next requests.');
1112
+ const tmuxOnly = spec.commandName === 'codex';
1113
+ const configPath = resolveLauncherConfigPath(ctx, fsImpl, pathImpl, options);
1114
+ const resolved = tmuxOnly ? undefined : resolveServerConnection(ctx, fsImpl, pathImpl, options, configPath);
1115
+ const requireResolved = () => {
1116
+ if (!resolved) {
1117
+ throw new Error('RouteCodex server connection is not available for this launcher');
1118
+ }
1119
+ return resolved;
1120
+ };
1121
+ let ensureResult = null;
1122
+ if (!tmuxOnly) {
1123
+ const server = requireResolved();
1124
+ await ctx.ensureGuardianDaemon?.();
1125
+ ensureResult = await ensureServerReady(ctx, fsImpl, pathImpl, spinner, options, server, spec.allowAutoStartServer === true);
1126
+ if (!ensureResult.ready) {
1127
+ spinner.info('RouteCodex server is not running; launcher will continue and wait for your next requests.');
1128
+ }
1128
1129
  }
1129
1130
  spinner.text = `Launching ${spec.displayName}...`;
1130
- const baseUrl = `${resolved.protocol}://${resolved.connectHost}${resolved.portPart}${resolved.basePath}`;
1131
1131
  const currentCwd = resolveWorkingDirectory(ctx, fsImpl, pathImpl, options.cwd);
1132
1132
  const spawnSyncImpl = ctx.spawnSyncImpl ?? spawnSync;
1133
1133
  const tmuxSelfHealPolicy = resolveTmuxSelfHealPolicy(ctx.env);
@@ -1187,97 +1187,107 @@ export function createLauncherCommand(program, ctx, spec) {
1187
1187
  let managedTmuxSession = null;
1188
1188
  const tmuxEnabled = isTmuxAvailable(spawnSyncImpl);
1189
1189
  if (!tmuxEnabled) {
1190
- ctx.logger.warning('[clock-advanced] tmux not found; advanced clock client service disabled (launcher will continue).');
1190
+ ctx.logger.warning('[session-advanced] tmux not found; advanced session client service disabled (launcher will continue).');
1191
1191
  }
1192
- let tmuxTarget = tmuxEnabled ? resolveCurrentTmuxTarget(ctx.env, spawnSyncImpl) : null;
1193
- if (tmuxTarget && !isReusableTmuxPaneTarget(spawnSyncImpl, tmuxTarget, currentCwd)) {
1194
- tmuxTarget = null;
1192
+ let tmuxTarget = null;
1193
+ if (tmuxEnabled && !tmuxOnly) {
1194
+ tmuxTarget = resolveCurrentTmuxTarget(ctx.env, spawnSyncImpl);
1195
1195
  }
1196
- if (tmuxEnabled && !tmuxTarget) {
1196
+ if (tmuxEnabled && (tmuxOnly || !tmuxTarget)) {
1197
1197
  managedTmuxSession = createManagedTmuxSession({
1198
1198
  spawnSyncImpl,
1199
- cwd: currentCwd,
1200
- commandName: spec.commandName
1199
+ cwd: currentCwd
1201
1200
  });
1202
1201
  if (managedTmuxSession) {
1203
1202
  tmuxTarget = managedTmuxSession.tmuxTarget;
1204
- if (managedTmuxSession.reused) {
1205
- ctx.logger.info('[clock-advanced] reused existing managed tmux session and rebound launcher automatically.');
1206
- }
1207
- else {
1208
- ctx.logger.info('[clock-advanced] started managed tmux session automatically; no manual tmux setup needed.');
1209
- }
1203
+ ctx.logger.info('[session-advanced] started managed tmux session automatically; no manual tmux setup needed.');
1210
1204
  }
1211
1205
  else {
1212
- ctx.logger.warning('[clock-advanced] failed to start managed tmux session; launcher continues without advanced mode.');
1206
+ ctx.logger.warning('[session-advanced] failed to start managed tmux session; launcher continues without advanced mode.');
1213
1207
  }
1214
1208
  }
1215
1209
  const managedClientProcessEnabled = !managedTmuxSession;
1216
1210
  let managedClientPid = null;
1217
1211
  const managedClientCommandHint = managedClientProcessEnabled ? resolvedBinary : undefined;
1218
- const reclaimRequiredRaw = String(ctx.env.ROUTECODEX_CLOCK_RECLAIM_REQUIRED
1219
- ?? ctx.env.RCC_CLOCK_RECLAIM_REQUIRED
1212
+ const reclaimRequiredRaw = String(ctx.env.ROUTECODEX_SESSION_RECLAIM_REQUIRED
1213
+ ?? ctx.env.RCC_SESSION_RECLAIM_REQUIRED
1220
1214
  ?? '1')
1221
1215
  .trim()
1222
1216
  .toLowerCase();
1223
1217
  const reclaimRequired = reclaimRequiredRaw !== '0' && reclaimRequiredRaw !== 'false' && reclaimRequiredRaw !== 'no';
1224
- const clockClientService = await startClockClientService({
1225
- ctx,
1226
- resolved,
1227
- workdir: currentCwd,
1228
- tmuxTarget,
1229
- spawnSyncImpl,
1230
- clientType: spec.commandName,
1231
- managedTmuxSession: Boolean(managedTmuxSession),
1232
- getManagedProcessState: () => ({
1233
- managedClientProcess: managedClientProcessEnabled,
1234
- managedClientPid,
1235
- managedClientCommandHint
1236
- })
1237
- });
1238
- if (managedClientProcessEnabled && reclaimRequired && tmuxTarget && !clockClientService) {
1239
- throw new Error('clock client registration failed for managed child process; aborting launch to avoid orphan process');
1240
- }
1241
- if (tmuxTarget && !clockClientService) {
1242
- ctx.logger.warning('[clock-advanced] failed to start clock client daemon service; launcher continues without advanced mode.');
1243
- }
1244
- const clockAdvancedEnabled = Boolean(clockClientService && tmuxTarget);
1245
- const inferredTmuxSessionId = clockClientService?.tmuxSessionId ||
1246
- inferTmuxSessionIdFromTarget(tmuxTarget) ||
1247
- undefined;
1248
- const inferredDaemonId = clockClientService?.daemonId ||
1249
- (inferredTmuxSessionId ? `clockd_unbound_${process.pid}` : undefined);
1250
- const clockClientApiKey = inferredTmuxSessionId && inferredDaemonId
1251
- ? encodeClockClientApiKey(resolved.configuredApiKey || 'rcc-proxy-key', inferredDaemonId, inferredTmuxSessionId)
1252
- : (resolved.configuredApiKey || 'rcc-proxy-key');
1253
- if (isClockScopeTraceEnabled()) {
1254
- try {
1255
- const parsedDaemonId = extractClockClientDaemonIdFromApiKey(clockClientApiKey) || 'none';
1256
- const parsedTmuxSessionId = extractClockClientTmuxSessionIdFromApiKey(clockClientApiKey) || 'none';
1257
- const verbose = isClockScopeTraceVerbose();
1258
- ctx.logger.info(`[clock-scope][launch] command=${spec.commandName} advanced=${clockAdvancedEnabled ? 'on' : 'off'} ` +
1259
- `daemon=${parsedDaemonId} tmux=${parsedTmuxSessionId} tmuxTarget=${tmuxTarget || 'none'}` +
1260
- (verbose ? ` managedTmux=${managedTmuxSession ? 'yes' : 'no'} serverStarted=${ensureResult.started ? 'yes' : 'no'}` : ''));
1218
+ let sessionClientService = null;
1219
+ let sessionAdvancedEnabled = false;
1220
+ let inferredTmuxSessionId;
1221
+ let inferredDaemonId;
1222
+ let sessionClientApiKey;
1223
+ let tmuxOnlySessionId;
1224
+ if (!tmuxOnly) {
1225
+ const server = requireResolved();
1226
+ sessionClientService = await startSessionClientService({
1227
+ ctx,
1228
+ resolved: server,
1229
+ workdir: currentCwd,
1230
+ tmuxTarget,
1231
+ spawnSyncImpl,
1232
+ clientType: spec.commandName,
1233
+ managedTmuxSession: Boolean(managedTmuxSession),
1234
+ getManagedProcessState: () => ({
1235
+ managedClientProcess: managedClientProcessEnabled,
1236
+ managedClientPid,
1237
+ managedClientCommandHint
1238
+ })
1239
+ });
1240
+ if (managedClientProcessEnabled && reclaimRequired && tmuxTarget && !sessionClientService) {
1241
+ throw new Error('session client registration failed for managed child process; aborting launch to avoid orphan process');
1261
1242
  }
1262
- catch {
1263
- // best-effort diagnostics only
1243
+ if (tmuxTarget && !sessionClientService) {
1244
+ ctx.logger.warning('[session-advanced] failed to start session client daemon service; launcher continues without advanced mode.');
1264
1245
  }
1265
- }
1266
- await ctx.registerGuardianProcess?.({
1267
- source: spec.commandName,
1268
- pid: process.pid,
1269
- ppid: process.ppid,
1270
- port: resolved.port,
1271
- tmuxSessionId: clockClientService?.tmuxSessionId || inferTmuxSessionIdFromTarget(tmuxTarget) || undefined,
1272
- tmuxTarget: tmuxTarget || undefined,
1273
- metadata: {
1274
- workingDirectory: currentCwd,
1275
- binary: resolvedBinary,
1276
- managedTmuxSession: Boolean(managedTmuxSession),
1277
- autoStartedServer: ensureResult.started === true
1246
+ sessionAdvancedEnabled = Boolean(sessionClientService && tmuxTarget);
1247
+ inferredTmuxSessionId =
1248
+ sessionClientService?.tmuxSessionId ||
1249
+ inferTmuxSessionIdFromTarget(tmuxTarget) ||
1250
+ undefined;
1251
+ inferredDaemonId =
1252
+ sessionClientService?.daemonId ||
1253
+ (inferredTmuxSessionId ? `sessiond_unbound_${process.pid}` : undefined);
1254
+ sessionClientApiKey =
1255
+ inferredTmuxSessionId && inferredDaemonId
1256
+ ? encodeSessionClientApiKey(server.configuredApiKey || 'rcc-proxy-key', inferredDaemonId, inferredTmuxSessionId)
1257
+ : (server.configuredApiKey || 'rcc-proxy-key');
1258
+ if (isSessionScopeTraceEnabled()) {
1259
+ try {
1260
+ const parsedDaemonId = extractSessionClientDaemonIdFromApiKey(sessionClientApiKey) || 'none';
1261
+ const parsedTmuxSessionId = extractSessionClientScopeIdFromApiKey(sessionClientApiKey) || 'none';
1262
+ const verbose = isSessionScopeTraceVerbose();
1263
+ ctx.logger.info(`[session-scope][launch] command=${spec.commandName} advanced=${sessionAdvancedEnabled ? 'on' : 'off'} ` +
1264
+ `daemon=${parsedDaemonId} tmux=${parsedTmuxSessionId} tmuxTarget=${tmuxTarget || 'none'}` +
1265
+ (verbose ? ` managedTmux=${managedTmuxSession ? 'yes' : 'no'} serverStarted=${ensureResult?.started ? 'yes' : 'no'}` : ''));
1266
+ }
1267
+ catch {
1268
+ // best-effort diagnostics only
1269
+ }
1278
1270
  }
1279
- });
1271
+ await ctx.registerGuardianProcess?.({
1272
+ source: spec.commandName,
1273
+ pid: process.pid,
1274
+ ppid: process.ppid,
1275
+ port: server.port,
1276
+ tmuxSessionId: sessionClientService?.tmuxSessionId || inferTmuxSessionIdFromTarget(tmuxTarget) || undefined,
1277
+ tmuxTarget: tmuxTarget || undefined,
1278
+ metadata: {
1279
+ workingDirectory: currentCwd,
1280
+ binary: resolvedBinary,
1281
+ managedTmuxSession: Boolean(managedTmuxSession),
1282
+ autoStartedServer: ensureResult?.started === true
1283
+ }
1284
+ });
1285
+ }
1280
1286
  const applyLifecycleOrThrow = async (args) => {
1287
+ if (tmuxOnly || !resolved) {
1288
+ return;
1289
+ }
1290
+ const server = requireResolved();
1281
1291
  const accepted = await ctx.reportGuardianLifecycle?.({
1282
1292
  action: args.action,
1283
1293
  source: `cli.launcher.${spec.commandName}`,
@@ -1285,39 +1295,60 @@ export function createLauncherCommand(program, ctx, spec) {
1285
1295
  targetPid: args.targetPid && args.targetPid > 0 ? args.targetPid : undefined,
1286
1296
  signal: args.signal,
1287
1297
  metadata: {
1288
- port: resolved.port,
1289
- serverUrl: resolved.serverUrl
1298
+ port: server.port,
1299
+ serverUrl: server.serverUrl
1290
1300
  }
1291
1301
  });
1292
1302
  if (ctx.reportGuardianLifecycle && accepted !== true) {
1293
1303
  throw new Error(`guardian lifecycle apply rejected (${args.action})`);
1294
1304
  }
1295
1305
  };
1296
- const toolEnv = spec.buildEnv({
1297
- env: {
1298
- ...ctx.env,
1299
- PWD: currentCwd,
1300
- RCC_WORKDIR: currentCwd,
1301
- ROUTECODEX_WORKDIR: currentCwd,
1302
- OPENAI_BASE_URL: normalizeOpenAiBaseUrl(baseUrl),
1303
- OPENAI_API_BASE: normalizeOpenAiBaseUrl(baseUrl),
1304
- OPENAI_API_BASE_URL: normalizeOpenAiBaseUrl(baseUrl),
1305
- OPENAI_API_KEY: clockClientApiKey,
1306
- RCC_CLOCK_ADVANCED_ENABLED: clockAdvancedEnabled ? '1' : '0',
1307
- ...(inferredTmuxSessionId
1308
- ? {
1309
- RCC_CLOCK_CLIENT_SESSION_ID: inferredTmuxSessionId,
1310
- RCC_CLOCK_CLIENT_TMUX_SESSION_ID: inferredTmuxSessionId
1306
+ if (tmuxOnly) {
1307
+ const tmuxSessionId = inferTmuxSessionIdFromTarget(tmuxTarget) || '';
1308
+ tmuxOnlySessionId = tmuxSessionId || undefined;
1309
+ }
1310
+ const toolEnv = (() => {
1311
+ if (tmuxOnly) {
1312
+ const env = { ...ctx.env };
1313
+ if (tmuxOnlySessionId) {
1314
+ const baseKey = resolveLauncherApiKey(ctx, fsImpl, configPath, options);
1315
+ if (!baseKey) {
1316
+ throw new Error('Missing apikey for tmux scope. Set --apikey or ROUTECODEX_HTTP_APIKEY/RCC_HTTP_APIKEY or httpserver.apikey in config.');
1311
1317
  }
1312
- : {}),
1313
- ...(inferredDaemonId
1314
- ? { RCC_CLOCK_CLIENT_DAEMON_ID: inferredDaemonId }
1315
- : {})
1316
- },
1317
- baseUrl,
1318
- configuredApiKey: resolved.configuredApiKey,
1319
- cwd: currentCwd
1320
- });
1318
+ const scopedKey = encodeSessionClientApiKey(baseKey, '', tmuxOnlySessionId);
1319
+ env.ROUTECODEX_HTTP_APIKEY = scopedKey;
1320
+ env.OPENAI_API_KEY = scopedKey;
1321
+ env.ANTHROPIC_AUTH_TOKEN = scopedKey;
1322
+ }
1323
+ return env;
1324
+ }
1325
+ const server = requireResolved();
1326
+ return spec.buildEnv({
1327
+ env: {
1328
+ ...ctx.env,
1329
+ PWD: currentCwd,
1330
+ RCC_WORKDIR: currentCwd,
1331
+ ROUTECODEX_WORKDIR: currentCwd,
1332
+ OPENAI_BASE_URL: normalizeOpenAiBaseUrl(`${server.protocol}://${server.connectHost}${server.portPart}${server.basePath}`),
1333
+ OPENAI_API_BASE: normalizeOpenAiBaseUrl(`${server.protocol}://${server.connectHost}${server.portPart}${server.basePath}`),
1334
+ OPENAI_API_BASE_URL: normalizeOpenAiBaseUrl(`${server.protocol}://${server.connectHost}${server.portPart}${server.basePath}`),
1335
+ OPENAI_API_KEY: sessionClientApiKey,
1336
+ RCC_SESSION_ADVANCED_ENABLED: sessionAdvancedEnabled ? '1' : '0',
1337
+ ...(inferredTmuxSessionId
1338
+ ? {
1339
+ RCC_SESSION_CLIENT_SESSION_ID: inferredTmuxSessionId,
1340
+ RCC_SESSION_CLIENT_TMUX_SESSION_ID: inferredTmuxSessionId
1341
+ }
1342
+ : {}),
1343
+ ...(inferredDaemonId
1344
+ ? { RCC_SESSION_CLIENT_DAEMON_ID: inferredDaemonId }
1345
+ : {})
1346
+ },
1347
+ baseUrl: `${server.protocol}://${server.connectHost}${server.portPart}${server.basePath}`,
1348
+ configuredApiKey: server.configuredApiKey,
1349
+ cwd: currentCwd
1350
+ });
1351
+ })();
1321
1352
  const shouldUseShell = ctx.isWindows &&
1322
1353
  !pathImpl.extname(resolvedBinary) &&
1323
1354
  !resolvedBinary.includes('/') &&
@@ -1356,14 +1387,17 @@ export function createLauncherCommand(program, ctx, spec) {
1356
1387
  managedClientPid = typeof toolProcess.pid === 'number' && Number.isFinite(toolProcess.pid)
1357
1388
  ? Math.floor(toolProcess.pid)
1358
1389
  : null;
1359
- if (clockClientService && managedClientProcessEnabled && managedClientPid) {
1360
- void clockClientService.syncHeartbeat();
1390
+ if (sessionClientService && managedClientProcessEnabled && managedClientPid) {
1391
+ void sessionClientService.syncHeartbeat();
1361
1392
  }
1362
1393
  spinner.succeed(`${spec.displayName} launched with RouteCodex proxy`);
1363
1394
  if (!managedTmuxSession) {
1364
- ctx.logger.info(`Using RouteCodex server at: ${baseUrl}`);
1395
+ if (!tmuxOnly) {
1396
+ const server = requireResolved();
1397
+ ctx.logger.info(`Using RouteCodex server at: ${server.protocol}://${server.connectHost}${server.portPart}${server.basePath}`);
1398
+ }
1365
1399
  ctx.logger.info(`${spec.displayName} binary: ${resolvedBinary}`);
1366
- if (ensureResult.started && ensureResult.logPath) {
1400
+ if (!tmuxOnly && ensureResult?.started && ensureResult.logPath) {
1367
1401
  ctx.logger.info(`RouteCodex auto-start logs: ${ensureResult.logPath}`);
1368
1402
  }
1369
1403
  ctx.logger.info(`Working directory for ${spec.displayName}: ${currentCwd}`);
@@ -1393,7 +1427,7 @@ export function createLauncherCommand(program, ctx, spec) {
1393
1427
  toolProcessClosing = true;
1394
1428
  logClientExitSummary();
1395
1429
  try {
1396
- await clockClientService?.stop();
1430
+ await sessionClientService?.stop();
1397
1431
  }
1398
1432
  catch {
1399
1433
  // ignore