(request: JsonRpcRequest)
| 183 | } |
| 184 | |
| 185 | private async handleInitialize(request: JsonRpcRequest): Promise<void> { |
| 186 | const params = request.params as { |
| 187 | rootUri?: string; |
| 188 | workspaceFolders?: Array<{ uri: string; name: string }>; |
| 189 | capabilities?: { roots?: unknown }; |
| 190 | clientInfo?: { name?: unknown; version?: unknown }; |
| 191 | } | undefined; |
| 192 | |
| 193 | this.clientSupportsRoots = !!params?.capabilities?.roots; |
| 194 | if (params?.clientInfo) { |
| 195 | this.clientInfo = { |
| 196 | name: typeof params.clientInfo.name === 'string' ? params.clientInfo.name : undefined, |
| 197 | version: typeof params.clientInfo.version === 'string' ? params.clientInfo.version : undefined, |
| 198 | }; |
| 199 | } |
| 200 | |
| 201 | // Explicit project signal, strongest first: client-provided rootUri / |
| 202 | // workspaceFolders (LSP-style), else the --path the server was launched |
| 203 | // with. cwd is NOT used here — we defer it so a roots/list answer can |
| 204 | // win over it. See issue #196. |
| 205 | let explicitPath: string | null = null; |
| 206 | if (params?.rootUri) { |
| 207 | explicitPath = fileUriToPath(params.rootUri); |
| 208 | } else if (params?.workspaceFolders?.[0]?.uri) { |
| 209 | explicitPath = fileUriToPath(params.workspaceFolders[0].uri); |
| 210 | } else if (this.explicitProjectPath) { |
| 211 | explicitPath = this.explicitProjectPath; |
| 212 | } |
| 213 | |
| 214 | // Pick the instructions variant by the root's index state — a cheap |
| 215 | // synchronous walk-up (existsSync loop only, no DB open, so the #172 |
| 216 | // respond-fast contract holds). When the root IS indexed, send the full |
| 217 | // single-project playbook. When it ISN'T, send the per-project variant |
| 218 | // (tools are still exposed — see handleToolsList): it tells the agent there |
| 219 | // is no default project and to pass `projectPath` to any project that has a |
| 220 | // `.codegraph/`. Gating tool AVAILABILITY on whether `./` is indexed was the |
| 221 | // #964 bug — it broke monorepos (only sub-projects indexed) and never |
| 222 | // surfaced the tools after a mid-session `codegraph init`. When no explicit |
| 223 | // path is known yet (roots/list dance pending), cwd is the best predictor of |
| 224 | // where the default project will resolve. |
| 225 | const indexed = findNearestCodeGraphRoot(explicitPath ?? process.cwd()) !== null; |
| 226 | |
| 227 | // Respond to the handshake BEFORE doing any heavy init — see issue #172. |
| 228 | this.transport.sendResult(request.id, { |
| 229 | protocolVersion: PROTOCOL_VERSION, |
| 230 | capabilities: { tools: {} }, |
| 231 | serverInfo: SERVER_INFO, |
| 232 | instructions: initializeInstructions(indexed ? SERVER_INSTRUCTIONS : SERVER_INSTRUCTIONS_NO_ROOT_INDEX), |
| 233 | }); |
| 234 | |
| 235 | if (explicitPath) { |
| 236 | // Kick off engine init in the background. If another session in the |
| 237 | // same daemon already opened the project, `ensureInitialized` is a |
| 238 | // ~free no-op — N concurrent clients pay exactly one open. |
| 239 | this.resolvePromise = this.engine.ensureInitialized(explicitPath); |
| 240 | } |
| 241 | } |
| 242 |
no test coverage detected