diff --git a/src/management/instance-manager.ts b/src/management/instance-manager.ts index 8fa15198..ba39c65c 100644 --- a/src/management/instance-manager.ts +++ b/src/management/instance-manager.ts @@ -13,6 +13,9 @@ import ProfileContextSyncLock from './profile-context-sync-lock'; import { DEFAULT_ACCOUNT_CONTEXT_MODE } from '../auth/account-context'; import type { AccountContextPolicy } from '../auth/account-context'; import { getCcsDir, getCcsHome } from '../utils/config-manager'; +import { createLogger } from '../services/logging'; + +const logger = createLogger('management:instance-manager'); const MANAGED_MCP_SERVER_NAMES = new Set(['ccs-websearch', 'ccs-image-analysis', 'ccs-browser']); @@ -52,6 +55,10 @@ class InstanceManager { await this.contextSyncLock.withLock(profileName, async () => { // Lazy initialization if (!fs.existsSync(instancePath)) { + logger.stage('route', 'instance.init', 'Initializing new profile instance', { + profile: profileName, + bare: options.bare === true, + }); this.initializeInstance(profileName, instancePath, options); } @@ -170,6 +177,9 @@ class InstanceManager { } fs.rmSync(instancePath, { recursive: true, force: true }); + logger.stage('cleanup', 'instance.deleted', 'Profile instance deleted', { + profile: profileName, + }); }); }); } diff --git a/src/targets/claude-adapter.ts b/src/targets/claude-adapter.ts index 397ce6e1..750a301d 100644 --- a/src/targets/claude-adapter.ts +++ b/src/targets/claude-adapter.ts @@ -21,6 +21,9 @@ import { getWebSearchHookEnv } from '../utils/websearch-manager'; import { appendBrowserToolArgs } from '../utils/browser'; import { wireChildProcessSignals } from '../utils/signal-forwarder'; import { runCleanup } from '../errors'; +import { createLogger } from '../services/logging'; + +const adapterLogger = createLogger('targets:claude'); export class ClaudeAdapter implements TargetAdapter { readonly type: TargetType = 'claude'; @@ -101,6 +104,13 @@ export class ClaudeAdapter implements TargetAdapter { const isPowerShellScript = isWindows && /\.ps1$/i.test(claudeCli); const needsShell = isWindows && /\.(cmd|bat)$/i.test(claudeCli); + const spawnStartedAt = Date.now(); + adapterLogger.stage('dispatch', 'target.spawn', 'Spawning Claude CLI child process', { + target: 'claude', + claudeCli, + argCount: args.length, + }); + let child: ChildProcess; if (isPowerShellScript) { child = spawn( @@ -128,6 +138,16 @@ export class ClaudeAdapter implements TargetAdapter { }); } + child.on('exit', (code, signal) => { + adapterLogger.stage( + 'respond', + 'target.exit', + 'Claude CLI child process exited', + { target: 'claude', exitCode: code, signal }, + { latencyMs: Date.now() - spawnStartedAt } + ); + }); + wireChildProcessSignals(child, async (err: NodeJS.ErrnoException) => { if (err.code === 'EACCES') { console.error(`[X] Claude CLI is not executable: ${claudeCli}`); diff --git a/src/targets/codex-adapter.ts b/src/targets/codex-adapter.ts index f82aa23b..31cf2104 100644 --- a/src/targets/codex-adapter.ts +++ b/src/targets/codex-adapter.ts @@ -23,6 +23,9 @@ import { getCodexBinaryInfo, readCodexVersion, } from './codex-detector'; +import { createLogger } from '../services/logging'; + +const adapterLogger = createLogger('targets:codex'); const CODEX_RUNTIME_PROVIDER_ID = 'ccs_runtime'; const CODEX_RUNTIME_ENV_KEY = 'CCS_CODEX_API_KEY'; @@ -310,6 +313,13 @@ export class CodexAdapter implements TargetAdapter { const isPowerShellScript = isWindows && /\.ps1$/i.test(codexPath); const needsShell = isWindows && /\.(cmd|bat)$/i.test(codexPath); + const spawnStartedAt = Date.now(); + adapterLogger.stage('dispatch', 'target.spawn', 'Spawning Codex CLI child process', { + target: 'codex', + codexPath, + argCount: args.length, + }); + let child: ChildProcess; if (isPowerShellScript) { child = spawn( @@ -329,6 +339,16 @@ export class CodexAdapter implements TargetAdapter { child = spawn(codexPath, args, { stdio: 'inherit', windowsHide: true, env: launchEnv }); } + child.on('exit', (code, signal) => { + adapterLogger.stage( + 'respond', + 'target.exit', + 'Codex CLI child process exited', + { target: 'codex', exitCode: code, signal }, + { latencyMs: Date.now() - spawnStartedAt } + ); + }); + wireChildProcessSignals(child, (err: NodeJS.ErrnoException) => { if (err.code === 'EACCES') { console.error(`[X] Codex CLI is not executable: ${codexPath}`); diff --git a/src/targets/droid-adapter.ts b/src/targets/droid-adapter.ts index c162f7f3..025875a9 100644 --- a/src/targets/droid-adapter.ts +++ b/src/targets/droid-adapter.ts @@ -19,6 +19,9 @@ import { } from '../utils/shell-executor'; import { wireChildProcessSignals } from '../utils/signal-forwarder'; import { runCleanup } from '../errors'; +import { createLogger } from '../services/logging'; + +const adapterLogger = createLogger('targets:droid'); export class DroidAdapter implements TargetAdapter { readonly type: TargetType = 'droid'; @@ -122,6 +125,13 @@ export class DroidAdapter implements TargetAdapter { const isPowerShellScript = isWindows && /\.ps1$/i.test(droidPath); const needsShell = isWindows && /\.(cmd|bat)$/i.test(droidPath); + const spawnStartedAt = Date.now(); + adapterLogger.stage('dispatch', 'target.spawn', 'Spawning Droid CLI child process', { + target: 'droid', + droidPath, + argCount: args.length, + }); + let child: ChildProcess; if (isPowerShellScript) { child = spawn( @@ -149,6 +159,16 @@ export class DroidAdapter implements TargetAdapter { }); } + child.on('exit', (code, signal) => { + adapterLogger.stage( + 'respond', + 'target.exit', + 'Droid CLI child process exited', + { target: 'droid', exitCode: code, signal }, + { latencyMs: Date.now() - spawnStartedAt } + ); + }); + wireChildProcessSignals(child, (err: NodeJS.ErrnoException) => { if (err.code === 'EACCES') { console.error(`[X] Droid CLI is not executable: ${droidPath}`);