@jsonstudio/rcc 0.90.1 → 0.90.89
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 +18 -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 +208 -196
- 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;
|
|
@@ -98,7 +99,10 @@ function canSignalOwnedToolProcess(args) {
|
|
|
98
99
|
function resolveServerConnection(ctx, fsImpl, pathImpl, options) {
|
|
99
100
|
let configPath = typeof options.config === 'string' && options.config.trim() ? options.config.trim() : '';
|
|
100
101
|
if (!configPath) {
|
|
101
|
-
|
|
102
|
+
const resolved = resolveRouteCodexConfigPath();
|
|
103
|
+
configPath = resolved && resolved.trim()
|
|
104
|
+
? resolved
|
|
105
|
+
: pathImpl.join(ctx.homedir(), '.routecodex', 'config.json');
|
|
102
106
|
}
|
|
103
107
|
let actualProtocol = 'http';
|
|
104
108
|
let actualPort = toIntegerPort(options.port);
|
|
@@ -136,10 +140,9 @@ function resolveServerConnection(ctx, fsImpl, pathImpl, options) {
|
|
|
136
140
|
throw new Error('Invalid or missing port configuration for RouteCodex server');
|
|
137
141
|
}
|
|
138
142
|
const configuredApiKey = (typeof options.apikey === 'string' && options.apikey.trim() ? options.apikey.trim() : null) ??
|
|
139
|
-
(typeof ctx.env.
|
|
140
|
-
? ctx.env.
|
|
143
|
+
(typeof ctx.env.ROUTECODEX_HTTP_APIKEY === 'string' && ctx.env.ROUTECODEX_HTTP_APIKEY.trim()
|
|
144
|
+
? ctx.env.ROUTECODEX_HTTP_APIKEY.trim()
|
|
141
145
|
: null) ??
|
|
142
|
-
(typeof ctx.env.RCC_APIKEY === 'string' && ctx.env.RCC_APIKEY.trim() ? ctx.env.RCC_APIKEY.trim() : null) ??
|
|
143
146
|
readConfigApiKey(fsImpl, configPath);
|
|
144
147
|
const connectHost = normalizeConnectHost(actualHost);
|
|
145
148
|
const portPart = actualPort ? `:${actualPort}` : '';
|
|
@@ -602,64 +605,23 @@ function normalizePathForComparison(candidate) {
|
|
|
602
605
|
return raw;
|
|
603
606
|
}
|
|
604
607
|
}
|
|
605
|
-
function
|
|
606
|
-
const
|
|
607
|
-
|
|
608
|
+
function formatHmms(value) {
|
|
609
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
610
|
+
return `${pad(value.getHours())}${pad(value.getMinutes())}${pad(value.getSeconds())}`;
|
|
611
|
+
}
|
|
612
|
+
function tmuxSessionExists(spawnSyncImpl, sessionName) {
|
|
608
613
|
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;
|
|
614
|
+
const result = spawnSyncImpl('tmux', ['has-session', '-t', sessionName], { encoding: 'utf8' });
|
|
615
|
+
return result.status === 0;
|
|
658
616
|
}
|
|
659
617
|
catch {
|
|
660
|
-
return
|
|
618
|
+
return false;
|
|
661
619
|
}
|
|
662
620
|
}
|
|
621
|
+
function buildManagedTmuxSessionName(nowMs, attempt) {
|
|
622
|
+
const stamp = formatHmms(new Date(nowMs + attempt * 1000));
|
|
623
|
+
return `rcc-tmux-${stamp}`;
|
|
624
|
+
}
|
|
663
625
|
function requestManagedTmuxSessionExit(spawnSyncImpl, sessionName) {
|
|
664
626
|
const target = String(sessionName || '').trim();
|
|
665
627
|
if (!target) {
|
|
@@ -691,29 +653,33 @@ function requestManagedTmuxSessionExit(spawnSyncImpl, sessionName) {
|
|
|
691
653
|
}
|
|
692
654
|
}
|
|
693
655
|
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;
|
|
656
|
+
const { spawnSyncImpl, cwd } = args;
|
|
657
|
+
const baseNow = Date.now();
|
|
658
|
+
for (let attempt = 0; attempt < 6; attempt += 1) {
|
|
659
|
+
const sessionName = buildManagedTmuxSessionName(baseNow, attempt);
|
|
660
|
+
if (tmuxSessionExists(spawnSyncImpl, sessionName)) {
|
|
661
|
+
continue;
|
|
703
662
|
}
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
return {
|
|
710
|
-
sessionName,
|
|
711
|
-
tmuxTarget,
|
|
712
|
-
reused: false,
|
|
713
|
-
stop: () => {
|
|
714
|
-
requestManagedTmuxSessionExit(spawnSyncImpl, sessionName);
|
|
663
|
+
try {
|
|
664
|
+
const result = spawnSyncImpl('tmux', ['new-session', '-d', '-s', sessionName, '-c', cwd], { encoding: 'utf8' });
|
|
665
|
+
if (result.status !== 0) {
|
|
666
|
+
continue;
|
|
667
|
+
}
|
|
715
668
|
}
|
|
716
|
-
|
|
669
|
+
catch {
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
const tmuxTarget = `${sessionName}:0.0`;
|
|
673
|
+
return {
|
|
674
|
+
sessionName,
|
|
675
|
+
tmuxTarget,
|
|
676
|
+
reused: false,
|
|
677
|
+
stop: () => {
|
|
678
|
+
requestManagedTmuxSessionExit(spawnSyncImpl, sessionName);
|
|
679
|
+
}
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
return null;
|
|
717
683
|
}
|
|
718
684
|
function launchCommandInTmuxPane(args) {
|
|
719
685
|
const { spawnSyncImpl, tmuxTarget, cwd, command, commandName, commandArgs, envOverrides, selfHealPolicy } = args;
|
|
@@ -822,20 +788,20 @@ function normalizeTmuxInjectedText(raw) {
|
|
|
822
788
|
.join(' ')
|
|
823
789
|
.trim();
|
|
824
790
|
}
|
|
825
|
-
async function
|
|
791
|
+
async function startSessionClientService(args) {
|
|
826
792
|
const { ctx, resolved, workdir, tmuxTarget, spawnSyncImpl, clientType, managedTmuxSession, getManagedProcessState } = args;
|
|
827
793
|
const daemonId = (() => {
|
|
828
794
|
try {
|
|
829
|
-
return `
|
|
795
|
+
return `sessiond_${crypto.randomUUID()}`;
|
|
830
796
|
}
|
|
831
797
|
catch {
|
|
832
|
-
return `
|
|
798
|
+
return `sessiond_${Date.now()}_${Math.random().toString(16).slice(2)}`;
|
|
833
799
|
}
|
|
834
800
|
})();
|
|
835
801
|
const normalizedTmuxTarget = String(tmuxTarget || '').trim();
|
|
836
802
|
if (!normalizedTmuxTarget) {
|
|
837
803
|
// No tmux target means no reliable stdin injection path.
|
|
838
|
-
// Do not register a
|
|
804
|
+
// Do not register a session-client daemon with a synthetic session id.
|
|
839
805
|
return null;
|
|
840
806
|
}
|
|
841
807
|
const tmuxSessionId = (() => {
|
|
@@ -888,7 +854,7 @@ async function startClockClientService(args) {
|
|
|
888
854
|
server?.listen(0, '127.0.0.1', () => {
|
|
889
855
|
const address = server?.address();
|
|
890
856
|
if (!address || typeof address === 'string') {
|
|
891
|
-
reject(new Error('failed to resolve
|
|
857
|
+
reject(new Error('failed to resolve session daemon callback address'));
|
|
892
858
|
return;
|
|
893
859
|
}
|
|
894
860
|
resolve(address.port);
|
|
@@ -906,7 +872,7 @@ async function startClockClientService(args) {
|
|
|
906
872
|
callbackUrl = `http://127.0.0.1:${port}/inject`;
|
|
907
873
|
}
|
|
908
874
|
const controlUrl = `${resolved.protocol}://127.0.0.1:${resolved.port}${resolved.basePath}`;
|
|
909
|
-
const controlRequestTimeoutMs = resolveIntFromEnv(ctx.env.
|
|
875
|
+
const controlRequestTimeoutMs = resolveIntFromEnv(ctx.env.ROUTECODEX_SESSION_CLIENT_CONTROL_TIMEOUT_MS ?? ctx.env.RCC_SESSION_CLIENT_CONTROL_TIMEOUT_MS, 1500, 200, 30_000);
|
|
910
876
|
const normalizeManagedProcessPayload = () => {
|
|
911
877
|
const state = typeof getManagedProcessState === 'function' ? getManagedProcessState() : undefined;
|
|
912
878
|
const managedClientProcess = state?.managedClientProcess === true;
|
|
@@ -955,7 +921,7 @@ async function startClockClientService(args) {
|
|
|
955
921
|
}
|
|
956
922
|
}
|
|
957
923
|
};
|
|
958
|
-
const reRegisterBackoffMs = resolveIntFromEnv(ctx.env.
|
|
924
|
+
const reRegisterBackoffMs = resolveIntFromEnv(ctx.env.ROUTECODEX_SESSION_CLIENT_REREGISTER_BACKOFF_MS ?? ctx.env.RCC_SESSION_CLIENT_REREGISTER_BACKOFF_MS, 1500, 200, 60_000);
|
|
959
925
|
let registerInFlight = null;
|
|
960
926
|
let lastRegisterAttemptAtMs = 0;
|
|
961
927
|
const registerDaemon = async () => {
|
|
@@ -964,7 +930,7 @@ async function startClockClientService(args) {
|
|
|
964
930
|
}
|
|
965
931
|
registerInFlight = (async () => {
|
|
966
932
|
lastRegisterAttemptAtMs = Date.now();
|
|
967
|
-
const result = await post('/daemon/
|
|
933
|
+
const result = await post('/daemon/session-client/register', {
|
|
968
934
|
daemonId,
|
|
969
935
|
tmuxSessionId,
|
|
970
936
|
sessionId: tmuxSessionId,
|
|
@@ -985,7 +951,7 @@ async function startClockClientService(args) {
|
|
|
985
951
|
}
|
|
986
952
|
};
|
|
987
953
|
const syncHeartbeat = async () => {
|
|
988
|
-
const heartbeat = await post('/daemon/
|
|
954
|
+
const heartbeat = await post('/daemon/session-client/heartbeat', {
|
|
989
955
|
daemonId,
|
|
990
956
|
tmuxSessionId,
|
|
991
957
|
sessionId: tmuxSessionId,
|
|
@@ -1032,7 +998,7 @@ async function startClockClientService(args) {
|
|
|
1032
998
|
syncHeartbeat,
|
|
1033
999
|
stop: async () => {
|
|
1034
1000
|
clearInterval(heartbeat);
|
|
1035
|
-
await post('/daemon/
|
|
1001
|
+
await post('/daemon/session-client/unregister', { daemonId });
|
|
1036
1002
|
if (!server) {
|
|
1037
1003
|
return;
|
|
1038
1004
|
}
|
|
@@ -1120,14 +1086,24 @@ export function createLauncherCommand(program, ctx, spec) {
|
|
|
1120
1086
|
command.action(async (extraArgs = [], options) => {
|
|
1121
1087
|
const spinner = await ctx.createSpinner(`Preparing ${spec.displayName} with RouteCodex...`);
|
|
1122
1088
|
try {
|
|
1123
|
-
const
|
|
1124
|
-
|
|
1125
|
-
const
|
|
1126
|
-
|
|
1127
|
-
|
|
1089
|
+
const tmuxOnly = spec.commandName === 'codex';
|
|
1090
|
+
const resolved = tmuxOnly ? undefined : resolveServerConnection(ctx, fsImpl, pathImpl, options);
|
|
1091
|
+
const requireResolved = () => {
|
|
1092
|
+
if (!resolved) {
|
|
1093
|
+
throw new Error('RouteCodex server connection is not available for this launcher');
|
|
1094
|
+
}
|
|
1095
|
+
return resolved;
|
|
1096
|
+
};
|
|
1097
|
+
let ensureResult = null;
|
|
1098
|
+
if (!tmuxOnly) {
|
|
1099
|
+
const server = requireResolved();
|
|
1100
|
+
await ctx.ensureGuardianDaemon?.();
|
|
1101
|
+
ensureResult = await ensureServerReady(ctx, fsImpl, pathImpl, spinner, options, server, spec.allowAutoStartServer === true);
|
|
1102
|
+
if (!ensureResult.ready) {
|
|
1103
|
+
spinner.info('RouteCodex server is not running; launcher will continue and wait for your next requests.');
|
|
1104
|
+
}
|
|
1128
1105
|
}
|
|
1129
1106
|
spinner.text = `Launching ${spec.displayName}...`;
|
|
1130
|
-
const baseUrl = `${resolved.protocol}://${resolved.connectHost}${resolved.portPart}${resolved.basePath}`;
|
|
1131
1107
|
const currentCwd = resolveWorkingDirectory(ctx, fsImpl, pathImpl, options.cwd);
|
|
1132
1108
|
const spawnSyncImpl = ctx.spawnSyncImpl ?? spawnSync;
|
|
1133
1109
|
const tmuxSelfHealPolicy = resolveTmuxSelfHealPolicy(ctx.env);
|
|
@@ -1187,97 +1163,107 @@ export function createLauncherCommand(program, ctx, spec) {
|
|
|
1187
1163
|
let managedTmuxSession = null;
|
|
1188
1164
|
const tmuxEnabled = isTmuxAvailable(spawnSyncImpl);
|
|
1189
1165
|
if (!tmuxEnabled) {
|
|
1190
|
-
ctx.logger.warning('[
|
|
1166
|
+
ctx.logger.warning('[session-advanced] tmux not found; advanced session client service disabled (launcher will continue).');
|
|
1191
1167
|
}
|
|
1192
|
-
let tmuxTarget =
|
|
1193
|
-
if (
|
|
1194
|
-
tmuxTarget =
|
|
1168
|
+
let tmuxTarget = null;
|
|
1169
|
+
if (tmuxEnabled && !tmuxOnly) {
|
|
1170
|
+
tmuxTarget = resolveCurrentTmuxTarget(ctx.env, spawnSyncImpl);
|
|
1195
1171
|
}
|
|
1196
|
-
if (tmuxEnabled && !tmuxTarget) {
|
|
1172
|
+
if (tmuxEnabled && (tmuxOnly || !tmuxTarget)) {
|
|
1197
1173
|
managedTmuxSession = createManagedTmuxSession({
|
|
1198
1174
|
spawnSyncImpl,
|
|
1199
|
-
cwd: currentCwd
|
|
1200
|
-
commandName: spec.commandName
|
|
1175
|
+
cwd: currentCwd
|
|
1201
1176
|
});
|
|
1202
1177
|
if (managedTmuxSession) {
|
|
1203
1178
|
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
|
-
}
|
|
1179
|
+
ctx.logger.info('[session-advanced] started managed tmux session automatically; no manual tmux setup needed.');
|
|
1210
1180
|
}
|
|
1211
1181
|
else {
|
|
1212
|
-
ctx.logger.warning('[
|
|
1182
|
+
ctx.logger.warning('[session-advanced] failed to start managed tmux session; launcher continues without advanced mode.');
|
|
1213
1183
|
}
|
|
1214
1184
|
}
|
|
1215
1185
|
const managedClientProcessEnabled = !managedTmuxSession;
|
|
1216
1186
|
let managedClientPid = null;
|
|
1217
1187
|
const managedClientCommandHint = managedClientProcessEnabled ? resolvedBinary : undefined;
|
|
1218
|
-
const reclaimRequiredRaw = String(ctx.env.
|
|
1219
|
-
?? ctx.env.
|
|
1188
|
+
const reclaimRequiredRaw = String(ctx.env.ROUTECODEX_SESSION_RECLAIM_REQUIRED
|
|
1189
|
+
?? ctx.env.RCC_SESSION_RECLAIM_REQUIRED
|
|
1220
1190
|
?? '1')
|
|
1221
1191
|
.trim()
|
|
1222
1192
|
.toLowerCase();
|
|
1223
1193
|
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'}` : ''));
|
|
1194
|
+
let sessionClientService = null;
|
|
1195
|
+
let sessionAdvancedEnabled = false;
|
|
1196
|
+
let inferredTmuxSessionId;
|
|
1197
|
+
let inferredDaemonId;
|
|
1198
|
+
let sessionClientApiKey;
|
|
1199
|
+
let tmuxOnlySessionId;
|
|
1200
|
+
if (!tmuxOnly) {
|
|
1201
|
+
const server = requireResolved();
|
|
1202
|
+
sessionClientService = await startSessionClientService({
|
|
1203
|
+
ctx,
|
|
1204
|
+
resolved: server,
|
|
1205
|
+
workdir: currentCwd,
|
|
1206
|
+
tmuxTarget,
|
|
1207
|
+
spawnSyncImpl,
|
|
1208
|
+
clientType: spec.commandName,
|
|
1209
|
+
managedTmuxSession: Boolean(managedTmuxSession),
|
|
1210
|
+
getManagedProcessState: () => ({
|
|
1211
|
+
managedClientProcess: managedClientProcessEnabled,
|
|
1212
|
+
managedClientPid,
|
|
1213
|
+
managedClientCommandHint
|
|
1214
|
+
})
|
|
1215
|
+
});
|
|
1216
|
+
if (managedClientProcessEnabled && reclaimRequired && tmuxTarget && !sessionClientService) {
|
|
1217
|
+
throw new Error('session client registration failed for managed child process; aborting launch to avoid orphan process');
|
|
1261
1218
|
}
|
|
1262
|
-
|
|
1263
|
-
|
|
1219
|
+
if (tmuxTarget && !sessionClientService) {
|
|
1220
|
+
ctx.logger.warning('[session-advanced] failed to start session client daemon service; launcher continues without advanced mode.');
|
|
1264
1221
|
}
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1222
|
+
sessionAdvancedEnabled = Boolean(sessionClientService && tmuxTarget);
|
|
1223
|
+
inferredTmuxSessionId =
|
|
1224
|
+
sessionClientService?.tmuxSessionId ||
|
|
1225
|
+
inferTmuxSessionIdFromTarget(tmuxTarget) ||
|
|
1226
|
+
undefined;
|
|
1227
|
+
inferredDaemonId =
|
|
1228
|
+
sessionClientService?.daemonId ||
|
|
1229
|
+
(inferredTmuxSessionId ? `sessiond_unbound_${process.pid}` : undefined);
|
|
1230
|
+
sessionClientApiKey =
|
|
1231
|
+
inferredTmuxSessionId && inferredDaemonId
|
|
1232
|
+
? encodeSessionClientApiKey(server.configuredApiKey || 'rcc-proxy-key', inferredDaemonId, inferredTmuxSessionId)
|
|
1233
|
+
: (server.configuredApiKey || 'rcc-proxy-key');
|
|
1234
|
+
if (isSessionScopeTraceEnabled()) {
|
|
1235
|
+
try {
|
|
1236
|
+
const parsedDaemonId = extractSessionClientDaemonIdFromApiKey(sessionClientApiKey) || 'none';
|
|
1237
|
+
const parsedTmuxSessionId = extractSessionClientScopeIdFromApiKey(sessionClientApiKey) || 'none';
|
|
1238
|
+
const verbose = isSessionScopeTraceVerbose();
|
|
1239
|
+
ctx.logger.info(`[session-scope][launch] command=${spec.commandName} advanced=${sessionAdvancedEnabled ? 'on' : 'off'} ` +
|
|
1240
|
+
`daemon=${parsedDaemonId} tmux=${parsedTmuxSessionId} tmuxTarget=${tmuxTarget || 'none'}` +
|
|
1241
|
+
(verbose ? ` managedTmux=${managedTmuxSession ? 'yes' : 'no'} serverStarted=${ensureResult?.started ? 'yes' : 'no'}` : ''));
|
|
1242
|
+
}
|
|
1243
|
+
catch {
|
|
1244
|
+
// best-effort diagnostics only
|
|
1245
|
+
}
|
|
1278
1246
|
}
|
|
1279
|
-
|
|
1247
|
+
await ctx.registerGuardianProcess?.({
|
|
1248
|
+
source: spec.commandName,
|
|
1249
|
+
pid: process.pid,
|
|
1250
|
+
ppid: process.ppid,
|
|
1251
|
+
port: server.port,
|
|
1252
|
+
tmuxSessionId: sessionClientService?.tmuxSessionId || inferTmuxSessionIdFromTarget(tmuxTarget) || undefined,
|
|
1253
|
+
tmuxTarget: tmuxTarget || undefined,
|
|
1254
|
+
metadata: {
|
|
1255
|
+
workingDirectory: currentCwd,
|
|
1256
|
+
binary: resolvedBinary,
|
|
1257
|
+
managedTmuxSession: Boolean(managedTmuxSession),
|
|
1258
|
+
autoStartedServer: ensureResult?.started === true
|
|
1259
|
+
}
|
|
1260
|
+
});
|
|
1261
|
+
}
|
|
1280
1262
|
const applyLifecycleOrThrow = async (args) => {
|
|
1263
|
+
if (tmuxOnly || !resolved) {
|
|
1264
|
+
return;
|
|
1265
|
+
}
|
|
1266
|
+
const server = requireResolved();
|
|
1281
1267
|
const accepted = await ctx.reportGuardianLifecycle?.({
|
|
1282
1268
|
action: args.action,
|
|
1283
1269
|
source: `cli.launcher.${spec.commandName}`,
|
|
@@ -1285,39 +1271,62 @@ export function createLauncherCommand(program, ctx, spec) {
|
|
|
1285
1271
|
targetPid: args.targetPid && args.targetPid > 0 ? args.targetPid : undefined,
|
|
1286
1272
|
signal: args.signal,
|
|
1287
1273
|
metadata: {
|
|
1288
|
-
port:
|
|
1289
|
-
serverUrl:
|
|
1274
|
+
port: server.port,
|
|
1275
|
+
serverUrl: server.serverUrl
|
|
1290
1276
|
}
|
|
1291
1277
|
});
|
|
1292
1278
|
if (ctx.reportGuardianLifecycle && accepted !== true) {
|
|
1293
1279
|
throw new Error(`guardian lifecycle apply rejected (${args.action})`);
|
|
1294
1280
|
}
|
|
1295
1281
|
};
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
RCC_CLOCK_CLIENT_SESSION_ID: inferredTmuxSessionId,
|
|
1310
|
-
RCC_CLOCK_CLIENT_TMUX_SESSION_ID: inferredTmuxSessionId
|
|
1282
|
+
if (tmuxOnly) {
|
|
1283
|
+
const tmuxSessionId = inferTmuxSessionIdFromTarget(tmuxTarget) || '';
|
|
1284
|
+
tmuxOnlySessionId = tmuxSessionId || undefined;
|
|
1285
|
+
}
|
|
1286
|
+
const toolEnv = (() => {
|
|
1287
|
+
if (tmuxOnly) {
|
|
1288
|
+
const env = { ...ctx.env };
|
|
1289
|
+
if (tmuxOnlySessionId) {
|
|
1290
|
+
const baseKey = (typeof env.ROUTECODEX_HTTP_APIKEY === 'string' && env.ROUTECODEX_HTTP_APIKEY.trim())
|
|
1291
|
+
|| '';
|
|
1292
|
+
if (!baseKey) {
|
|
1293
|
+
ctx.logger.warning('[session-scope] ROUTECODEX_HTTP_APIKEY is empty; tmux scope not injected.');
|
|
1294
|
+
return env;
|
|
1311
1295
|
}
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1296
|
+
const scopedKey = encodeSessionClientApiKey(baseKey, '', tmuxOnlySessionId);
|
|
1297
|
+
env.ROUTECODEX_HTTP_APIKEY = scopedKey;
|
|
1298
|
+
env.OPENAI_API_KEY = scopedKey;
|
|
1299
|
+
env.ANTHROPIC_AUTH_TOKEN = scopedKey;
|
|
1300
|
+
}
|
|
1301
|
+
return env;
|
|
1302
|
+
}
|
|
1303
|
+
const server = requireResolved();
|
|
1304
|
+
return spec.buildEnv({
|
|
1305
|
+
env: {
|
|
1306
|
+
...ctx.env,
|
|
1307
|
+
PWD: currentCwd,
|
|
1308
|
+
RCC_WORKDIR: currentCwd,
|
|
1309
|
+
ROUTECODEX_WORKDIR: currentCwd,
|
|
1310
|
+
OPENAI_BASE_URL: normalizeOpenAiBaseUrl(`${server.protocol}://${server.connectHost}${server.portPart}${server.basePath}`),
|
|
1311
|
+
OPENAI_API_BASE: normalizeOpenAiBaseUrl(`${server.protocol}://${server.connectHost}${server.portPart}${server.basePath}`),
|
|
1312
|
+
OPENAI_API_BASE_URL: normalizeOpenAiBaseUrl(`${server.protocol}://${server.connectHost}${server.portPart}${server.basePath}`),
|
|
1313
|
+
OPENAI_API_KEY: sessionClientApiKey,
|
|
1314
|
+
RCC_SESSION_ADVANCED_ENABLED: sessionAdvancedEnabled ? '1' : '0',
|
|
1315
|
+
...(inferredTmuxSessionId
|
|
1316
|
+
? {
|
|
1317
|
+
RCC_SESSION_CLIENT_SESSION_ID: inferredTmuxSessionId,
|
|
1318
|
+
RCC_SESSION_CLIENT_TMUX_SESSION_ID: inferredTmuxSessionId
|
|
1319
|
+
}
|
|
1320
|
+
: {}),
|
|
1321
|
+
...(inferredDaemonId
|
|
1322
|
+
? { RCC_SESSION_CLIENT_DAEMON_ID: inferredDaemonId }
|
|
1323
|
+
: {})
|
|
1324
|
+
},
|
|
1325
|
+
baseUrl: `${server.protocol}://${server.connectHost}${server.portPart}${server.basePath}`,
|
|
1326
|
+
configuredApiKey: server.configuredApiKey,
|
|
1327
|
+
cwd: currentCwd
|
|
1328
|
+
});
|
|
1329
|
+
})();
|
|
1321
1330
|
const shouldUseShell = ctx.isWindows &&
|
|
1322
1331
|
!pathImpl.extname(resolvedBinary) &&
|
|
1323
1332
|
!resolvedBinary.includes('/') &&
|
|
@@ -1356,14 +1365,17 @@ export function createLauncherCommand(program, ctx, spec) {
|
|
|
1356
1365
|
managedClientPid = typeof toolProcess.pid === 'number' && Number.isFinite(toolProcess.pid)
|
|
1357
1366
|
? Math.floor(toolProcess.pid)
|
|
1358
1367
|
: null;
|
|
1359
|
-
if (
|
|
1360
|
-
void
|
|
1368
|
+
if (sessionClientService && managedClientProcessEnabled && managedClientPid) {
|
|
1369
|
+
void sessionClientService.syncHeartbeat();
|
|
1361
1370
|
}
|
|
1362
1371
|
spinner.succeed(`${spec.displayName} launched with RouteCodex proxy`);
|
|
1363
1372
|
if (!managedTmuxSession) {
|
|
1364
|
-
|
|
1373
|
+
if (!tmuxOnly) {
|
|
1374
|
+
const server = requireResolved();
|
|
1375
|
+
ctx.logger.info(`Using RouteCodex server at: ${server.protocol}://${server.connectHost}${server.portPart}${server.basePath}`);
|
|
1376
|
+
}
|
|
1365
1377
|
ctx.logger.info(`${spec.displayName} binary: ${resolvedBinary}`);
|
|
1366
|
-
if (ensureResult
|
|
1378
|
+
if (!tmuxOnly && ensureResult?.started && ensureResult.logPath) {
|
|
1367
1379
|
ctx.logger.info(`RouteCodex auto-start logs: ${ensureResult.logPath}`);
|
|
1368
1380
|
}
|
|
1369
1381
|
ctx.logger.info(`Working directory for ${spec.displayName}: ${currentCwd}`);
|
|
@@ -1393,7 +1405,7 @@ export function createLauncherCommand(program, ctx, spec) {
|
|
|
1393
1405
|
toolProcessClosing = true;
|
|
1394
1406
|
logClientExitSummary();
|
|
1395
1407
|
try {
|
|
1396
|
-
await
|
|
1408
|
+
await sessionClientService?.stop();
|
|
1397
1409
|
}
|
|
1398
1410
|
catch {
|
|
1399
1411
|
// ignore
|