@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.
- package/README.md +1 -1
- package/dist/build-info.js +2 -2
- package/dist/cli/commands/claude.js +3 -8
- package/dist/cli/commands/claude.js.map +1 -1
- package/dist/cli/commands/codex.js +5 -3
- package/dist/cli/commands/codex.js.map +1 -1
- package/dist/cli/commands/launcher/index.d.ts +1 -1
- package/dist/cli/commands/launcher/types.d.ts +1 -1
- package/dist/cli/commands/launcher/utils.d.ts +4 -1
- package/dist/cli/commands/launcher/utils.js +22 -8
- package/dist/cli/commands/launcher/utils.js.map +1 -1
- package/dist/cli/commands/launcher-kernel.d.ts +1 -1
- package/dist/cli/commands/launcher-kernel.js +237 -203
- package/dist/cli/commands/launcher-kernel.js.map +1 -1
- package/dist/cli/commands/{clock-admin.d.ts → session-admin.d.ts} +2 -2
- package/dist/cli/commands/{clock-admin.js → session-admin.js} +17 -17
- package/dist/cli/commands/session-admin.js.map +1 -0
- package/dist/cli/commands/{tmux-inject.d.ts → session-inject.d.ts} +2 -2
- package/dist/cli/commands/{tmux-inject.js → session-inject.js} +12 -12
- package/dist/cli/commands/session-inject.js.map +1 -0
- package/dist/cli/commands/start-utils.d.ts +1 -0
- package/dist/cli/commands/start-utils.js +3 -0
- package/dist/cli/commands/start-utils.js.map +1 -1
- package/dist/cli/commands/start.js +14 -7
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/register/session-admin-command.d.ts +3 -0
- package/dist/cli/register/session-admin-command.js +5 -0
- package/dist/cli/register/session-admin-command.js.map +1 -0
- package/dist/cli/register/session-inject-command.d.ts +3 -0
- package/dist/cli/register/session-inject-command.js +5 -0
- package/dist/cli/register/session-inject-command.js.map +1 -0
- package/dist/cli.js +4 -4
- package/dist/cli.js.map +1 -1
- package/dist/config/provider-v2-loader.js +18 -3
- package/dist/config/provider-v2-loader.js.map +1 -1
- package/dist/config/routecodex-config-loader.js +136 -26
- package/dist/config/routecodex-config-loader.js.map +1 -1
- package/dist/config/unified-config-paths.js +22 -0
- package/dist/config/unified-config-paths.js.map +1 -1
- package/dist/config/virtual-router-builder.js +1 -6
- package/dist/config/virtual-router-builder.js.map +1 -1
- package/dist/docs/daemon-admin-ui.html +6 -6
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/manager/modules/quota/provider-key-normalization.js +1 -10
- package/dist/manager/modules/quota/provider-key-normalization.js.map +1 -1
- package/dist/manager/modules/quota/provider-quota-daemon.events.js +40 -49
- package/dist/manager/modules/quota/provider-quota-daemon.events.js.map +1 -1
- package/dist/manager/modules/quota/provider-quota-daemon.model-backoff.js +2 -16
- package/dist/manager/modules/quota/provider-quota-daemon.model-backoff.js.map +1 -1
- package/dist/manager/modules/token/index.d.ts +1 -0
- package/dist/manager/modules/token/index.js +6 -1
- package/dist/manager/modules/token/index.js.map +1 -1
- package/dist/manager/types.d.ts +1 -0
- package/dist/modules/llmswitch/bridge/state-integrations.js +1 -1
- package/dist/modules/llmswitch/bridge/state-integrations.js.map +1 -1
- package/dist/providers/auth/oauth-repair-cooldown.js +7 -2
- package/dist/providers/auth/oauth-repair-cooldown.js.map +1 -1
- package/dist/providers/core/config/camoufox-actions.js +11 -2
- package/dist/providers/core/config/camoufox-actions.js.map +1 -1
- package/dist/providers/core/config/camoufox-launcher.js +60 -24
- package/dist/providers/core/config/camoufox-launcher.js.map +1 -1
- package/dist/providers/core/config/service-profiles.js +2 -2
- package/dist/providers/core/config/service-profiles.js.map +1 -1
- package/dist/providers/core/runtime/base-provider-runtime-helpers.js +15 -2
- package/dist/providers/core/runtime/base-provider-runtime-helpers.js.map +1 -1
- package/dist/providers/core/strategies/oauth-device-flow.js +26 -3
- package/dist/providers/core/strategies/oauth-device-flow.js.map +1 -1
- package/dist/providers/core/utils/provider-error-reporter.js +51 -0
- package/dist/providers/core/utils/provider-error-reporter.js.map +1 -1
- package/dist/server/handlers/handler-response-utils.js +3 -6
- package/dist/server/handlers/handler-response-utils.js.map +1 -1
- package/dist/server/handlers/handler-utils.js +14 -8
- package/dist/server/handlers/handler-utils.js.map +1 -1
- package/dist/server/handlers/responses-handler.js +5 -3
- package/dist/server/handlers/responses-handler.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/providers-handler-routing-utils.d.ts +1 -1
- package/dist/server/runtime/http-server/daemon-admin/providers-handler-routing-utils.js +5 -5
- package/dist/server/runtime/http-server/daemon-admin/providers-handler-routing-utils.js.map +1 -1
- package/dist/server/runtime/http-server/daemon-admin/routing-policy.d.ts +1 -1
- package/dist/server/runtime/http-server/daemon-admin/routing-policy.js +4 -4
- package/dist/server/runtime/http-server/daemon-admin/routing-policy.js.map +1 -1
- package/dist/server/runtime/http-server/executor/client-injection-flow.js +20 -10
- package/dist/server/runtime/http-server/executor/client-injection-flow.js.map +1 -1
- package/dist/server/runtime/http-server/executor/provider-response-converter.js +54 -17
- package/dist/server/runtime/http-server/executor/provider-response-converter.js.map +1 -1
- package/dist/server/runtime/http-server/executor/provider-runtime-resolver.js +8 -6
- package/dist/server/runtime/http-server/executor/provider-runtime-resolver.js.map +1 -1
- package/dist/server/runtime/http-server/executor/request-retry-helpers.d.ts +1 -1
- package/dist/server/runtime/http-server/executor/request-retry-helpers.js +8 -8
- package/dist/server/runtime/http-server/executor/request-retry-helpers.js.map +1 -1
- package/dist/server/runtime/http-server/executor/retry-engine.d.ts +2 -2
- package/dist/server/runtime/http-server/executor/retry-engine.js +2 -2
- package/dist/server/runtime/http-server/executor/retry-engine.js.map +1 -1
- package/dist/server/runtime/http-server/executor/usage-aggregator.js +5 -2
- package/dist/server/runtime/http-server/executor/usage-aggregator.js.map +1 -1
- package/dist/server/runtime/http-server/executor-metadata.js +57 -77
- package/dist/server/runtime/http-server/executor-metadata.js.map +1 -1
- package/dist/server/runtime/http-server/executor-provider.d.ts +1 -0
- package/dist/server/runtime/http-server/executor-provider.js +5 -1
- package/dist/server/runtime/http-server/executor-provider.js.map +1 -1
- package/dist/server/runtime/http-server/http-server-lifecycle.js +2 -1
- package/dist/server/runtime/http-server/http-server-lifecycle.js.map +1 -1
- package/dist/server/runtime/http-server/http-server-runtime-setup.js +1 -1
- package/dist/server/runtime/http-server/http-server-runtime-setup.js.map +1 -1
- package/dist/server/runtime/http-server/http-server-session-daemon.d.ts +6 -0
- package/dist/server/runtime/http-server/{http-server-clock-daemon.js → http-server-session-daemon.js} +80 -73
- package/dist/server/runtime/http-server/http-server-session-daemon.js.map +1 -0
- package/dist/server/runtime/http-server/index.d.ts +11 -11
- package/dist/server/runtime/http-server/index.js +21 -21
- package/dist/server/runtime/http-server/index.js.map +1 -1
- package/dist/server/runtime/http-server/managed-process-probe.js +1 -1
- package/dist/server/runtime/http-server/managed-process-probe.js.map +1 -1
- package/dist/server/runtime/http-server/middleware.js +19 -11
- package/dist/server/runtime/http-server/middleware.js.map +1 -1
- package/dist/server/runtime/http-server/request-executor.js +13 -4
- package/dist/server/runtime/http-server/request-executor.js.map +1 -1
- package/dist/server/runtime/http-server/routes.js +3 -3
- package/dist/server/runtime/http-server/routes.js.map +1 -1
- package/dist/server/runtime/http-server/{clock-client-reaper.d.ts → session-client-reaper.d.ts} +6 -6
- package/dist/server/runtime/http-server/{clock-client-reaper.js → session-client-reaper.js} +23 -23
- package/dist/server/runtime/http-server/session-client-reaper.js.map +1 -0
- package/dist/server/runtime/http-server/{clock-client-registry-utils.d.ts → session-client-registry-utils.d.ts} +10 -10
- package/dist/server/runtime/http-server/{clock-client-registry-utils.js → session-client-registry-utils.js} +3 -3
- package/dist/server/runtime/http-server/session-client-registry-utils.js.map +1 -0
- package/dist/server/runtime/http-server/{clock-client-registry.d.ts → session-client-registry.d.ts} +12 -12
- package/dist/server/runtime/http-server/{clock-client-registry.js → session-client-registry.js} +9 -9
- package/dist/server/runtime/http-server/session-client-registry.js.map +1 -0
- package/dist/server/runtime/http-server/{clock-client-route-utils.d.ts → session-client-route-utils.d.ts} +1 -1
- package/dist/server/runtime/http-server/{clock-client-route-utils.js → session-client-route-utils.js} +4 -4
- package/dist/server/runtime/http-server/session-client-route-utils.js.map +1 -0
- package/dist/server/runtime/http-server/session-client-routes.d.ts +2 -0
- package/dist/server/runtime/http-server/{clock-client-routes.js → session-client-routes.js} +65 -47
- package/dist/server/runtime/http-server/session-client-routes.js.map +1 -0
- package/dist/server/runtime/http-server/session-daemon-inject-config.d.ts +1 -0
- package/dist/server/runtime/http-server/{clock-daemon-inject-config.js → session-daemon-inject-config.js} +2 -2
- package/dist/server/runtime/http-server/session-daemon-inject-config.js.map +1 -0
- package/dist/server/runtime/http-server/{clock-daemon-log-throttle.d.ts → session-daemon-log-throttle.d.ts} +7 -7
- package/dist/server/runtime/http-server/{clock-daemon-log-throttle.js → session-daemon-log-throttle.js} +5 -5
- package/dist/server/runtime/http-server/session-daemon-log-throttle.js.map +1 -0
- package/dist/server/runtime/http-server/{clock-scope-resolution.d.ts → session-scope-resolution.d.ts} +2 -2
- package/dist/server/runtime/http-server/{clock-scope-resolution.js → session-scope-resolution.js} +14 -18
- package/dist/server/runtime/http-server/session-scope-resolution.js.map +1 -0
- package/dist/server/runtime/http-server/stopmessage-scope-rebind.d.ts +8 -0
- package/dist/server/runtime/http-server/stopmessage-scope-rebind.js +29 -0
- package/dist/server/runtime/http-server/stopmessage-scope-rebind.js.map +1 -1
- package/dist/server/runtime/http-server/tmux-session-probe.js +1 -1
- package/dist/server/runtime/http-server/tmux-session-probe.js.map +1 -1
- package/dist/token-daemon/token-daemon.d.ts +2 -0
- package/dist/token-daemon/token-daemon.js +18 -10
- package/dist/token-daemon/token-daemon.js.map +1 -1
- package/dist/utils/log-helpers.js +46 -0
- package/dist/utils/log-helpers.js.map +1 -1
- package/dist/utils/session-client-token.d.ts +4 -0
- package/dist/utils/{clock-client-token.js → session-client-token.js} +19 -24
- package/dist/utils/session-client-token.js.map +1 -0
- package/dist/utils/session-scope-trace.d.ts +11 -0
- package/dist/utils/{clock-scope-trace.js → session-scope-trace.js} +9 -9
- package/dist/utils/session-scope-trace.js.map +1 -0
- package/docs/CLOCK.md +0 -1
- package/docs/PORTS.md +2 -2
- package/docs/ROUTING_POLICY_SCHEMA.md +1 -1
- package/docs/antigravity-routing-contract.md +2 -2
- package/docs/daemon-admin-ui.html +6 -6
- package/docs/{clock-client-daemon-design.md → session-client-daemon-design.md} +34 -34
- package/package.json +3 -3
- package/scripts/compare-responses-sse.mjs +267 -0
- package/scripts/replay-codex-sample.mjs +52 -6
- package/scripts/virtual-router-dryrun.mjs +7 -1
- package/dist/cli/commands/clock-admin.js.map +0 -1
- package/dist/cli/commands/tmux-inject.js.map +0 -1
- package/dist/cli/register/clock-admin-command.d.ts +0 -3
- package/dist/cli/register/clock-admin-command.js +0 -5
- package/dist/cli/register/clock-admin-command.js.map +0 -1
- package/dist/cli/register/tmux-inject-command.d.ts +0 -3
- package/dist/cli/register/tmux-inject-command.js +0 -5
- package/dist/cli/register/tmux-inject-command.js.map +0 -1
- package/dist/server/runtime/http-server/clock-client-reaper.js.map +0 -1
- package/dist/server/runtime/http-server/clock-client-registry-utils.js.map +0 -1
- package/dist/server/runtime/http-server/clock-client-registry.js.map +0 -1
- package/dist/server/runtime/http-server/clock-client-route-utils.js.map +0 -1
- package/dist/server/runtime/http-server/clock-client-routes.d.ts +0 -2
- package/dist/server/runtime/http-server/clock-client-routes.js.map +0 -1
- package/dist/server/runtime/http-server/clock-daemon-inject-config.d.ts +0 -1
- package/dist/server/runtime/http-server/clock-daemon-inject-config.js.map +0 -1
- package/dist/server/runtime/http-server/clock-daemon-log-throttle.js.map +0 -1
- package/dist/server/runtime/http-server/clock-scope-resolution.js.map +0 -1
- package/dist/server/runtime/http-server/http-server-clock-daemon.d.ts +0 -6
- package/dist/server/runtime/http-server/http-server-clock-daemon.js.map +0 -1
- package/dist/utils/clock-client-token.d.ts +0 -4
- package/dist/utils/clock-client-token.js.map +0 -1
- package/dist/utils/clock-scope-trace.d.ts +0 -11
- 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 {
|
|
8
|
-
import {
|
|
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
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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 = (
|
|
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
|
|
606
|
-
const
|
|
607
|
-
|
|
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
|
|
610
|
-
|
|
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
|
|
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
|
|
695
|
-
const
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
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
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
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
|
|
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 `
|
|
818
|
+
return `sessiond_${crypto.randomUUID()}`;
|
|
830
819
|
}
|
|
831
820
|
catch {
|
|
832
|
-
return `
|
|
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
|
|
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
|
|
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.
|
|
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.
|
|
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/
|
|
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/
|
|
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/
|
|
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
|
|
1124
|
-
|
|
1125
|
-
const
|
|
1126
|
-
|
|
1127
|
-
|
|
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('[
|
|
1190
|
+
ctx.logger.warning('[session-advanced] tmux not found; advanced session client service disabled (launcher will continue).');
|
|
1191
1191
|
}
|
|
1192
|
-
let tmuxTarget =
|
|
1193
|
-
if (
|
|
1194
|
-
tmuxTarget =
|
|
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
|
-
|
|
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('[
|
|
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.
|
|
1219
|
-
?? ctx.env.
|
|
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
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
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
|
-
|
|
1263
|
-
|
|
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
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
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:
|
|
1289
|
-
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
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
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
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
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 (
|
|
1360
|
-
void
|
|
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
|
-
|
|
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
|
|
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
|
|
1430
|
+
await sessionClientService?.stop();
|
|
1397
1431
|
}
|
|
1398
1432
|
catch {
|
|
1399
1433
|
// ignore
|