| 150 | } |
| 151 | |
| 152 | export class Session { |
| 153 | readonly rpc: SDKSessionRPC; |
| 154 | readonly telemetry: TelemetryClient; |
| 155 | readonly skills: SessionSkillRegistry; |
| 156 | readonly agents: Map<string, AgentEntry> = new Map(); |
| 157 | readonly mcp: McpConnectionManager; |
| 158 | readonly log: Logger; |
| 159 | private readonly logHandle: SessionLogHandle | undefined; |
| 160 | readonly hookEngine: HookEngine; |
| 161 | readonly experimentalFlags: ExperimentalFlagResolver; |
| 162 | private toolKaos: Kaos; |
| 163 | private persistenceKaos: Kaos; |
| 164 | private additionalDirs: readonly string[]; |
| 165 | private readonly pluginCommands: readonly PluginCommandDef[]; |
| 166 | private agentIdCounter = 0; |
| 167 | private readonly skillsReady: Promise<void>; |
| 168 | metadata: SessionMeta = { |
| 169 | createdAt: new Date().toISOString(), |
| 170 | updatedAt: new Date().toISOString(), |
| 171 | title: 'New Session', |
| 172 | isCustomTitle: false, |
| 173 | agents: {}, |
| 174 | custom: {}, |
| 175 | }; |
| 176 | private writeMetadataPromise = Promise.resolve(); |
| 177 | private agentsMdWarning: string | undefined; |
| 178 | |
| 179 | constructor(public readonly options: SessionOptions) { |
| 180 | // Attach the per-session log sink up front so the constructor's |
| 181 | // fire-and-forget `loadSkills` / `loadMcpServers` failures (and |
| 182 | // anything else that races) land in the session log, not just global. |
| 183 | this.logHandle = |
| 184 | options.id === undefined |
| 185 | ? undefined |
| 186 | : getRootLogger().attachSession({ |
| 187 | sessionId: options.id, |
| 188 | sessionDir: options.homedir, |
| 189 | }); |
| 190 | this.log = |
| 191 | this.logHandle?.logger ?? |
| 192 | (options.id === undefined ? log : log.createChild({ sessionId: options.id })); |
| 193 | this.rpc = options.rpc; |
| 194 | this.experimentalFlags = options.experimentalFlags ?? new FlagResolver(); |
| 195 | this.hookEngine = new HookEngine(options.hooks, { |
| 196 | cwd: options.kaos.getcwd(), |
| 197 | sessionId: options.id, |
| 198 | }); |
| 199 | this.telemetry = options.telemetry ?? noopTelemetryClient; |
| 200 | this.toolKaos = options.kaos; |
| 201 | this.persistenceKaos = options.persistenceKaos ?? options.kaos; |
| 202 | this.additionalDirs = normalizeAdditionalDirs(options.additionalDirs ?? []); |
| 203 | this.pluginCommands = options.pluginCommands ?? []; |
| 204 | this.skills = new SessionSkillRegistry({ |
| 205 | sessionId: options.id, |
| 206 | }); |
| 207 | this.mcp = new McpConnectionManager({ |
| 208 | oauthService: new McpOAuthService({ kimiHomeDir: options.kimiHomeDir }), |
| 209 | log: this.log, |