|
| 1 | +import {spawn} from 'node:child_process' |
1 | 2 | import {join} from 'node:path' |
2 | 3 |
|
3 | 4 | import type {ProjectLocationDTO} from '../../../../shared/transport/types/dto.js' |
4 | 5 | import type {IContextTreeService} from '../../../core/interfaces/context-tree/i-context-tree-service.js' |
5 | 6 | import type {IProjectRegistry} from '../../../core/interfaces/project/i-project-registry.js' |
6 | 7 | import type {ITransportServer} from '../../../core/interfaces/transport/i-transport-server.js' |
7 | 8 |
|
8 | | -import {LocationsEvents, type LocationsGetResponse} from '../../../../shared/transport/events/locations-events.js' |
| 9 | +import { |
| 10 | + LocationsEvents, |
| 11 | + type LocationsGetResponse, |
| 12 | + type LocationsRevealRequest, |
| 13 | + type LocationsRevealResponse, |
| 14 | +} from '../../../../shared/transport/events/locations-events.js' |
9 | 15 | import {BRV_DIR, CONTEXT_TREE_DIR} from '../../../constants.js' |
10 | 16 | import {type ProjectPathResolver} from './handler-types.js' |
| 17 | +import {resolveRevealCommand} from './reveal-command.js' |
11 | 18 |
|
12 | 19 | export interface LocationsHandlerDeps { |
13 | 20 | contextTreeService: IContextTreeService |
@@ -49,6 +56,11 @@ export class LocationsHandler { |
49 | 56 | return {locations: []} |
50 | 57 | } |
51 | 58 | }) |
| 59 | + |
| 60 | + this.transport.onRequest<LocationsRevealRequest, LocationsRevealResponse>( |
| 61 | + LocationsEvents.REVEAL, |
| 62 | + async (data) => this.handleReveal(data), |
| 63 | + ) |
52 | 64 | } |
53 | 65 |
|
54 | 66 | private async buildLocations(currentProjectPath?: string): Promise<ProjectLocationDTO[]> { |
@@ -96,4 +108,28 @@ export class LocationsHandler { |
96 | 108 | return (all.get(b.projectPath)?.registeredAt ?? 0) - (all.get(a.projectPath)?.registeredAt ?? 0) |
97 | 109 | }) |
98 | 110 | } |
| 111 | + |
| 112 | + private async handleReveal(data: LocationsRevealRequest): Promise<LocationsRevealResponse> { |
| 113 | + const {projectPath} = data |
| 114 | + if (!projectPath) throw new Error('projectPath is required') |
| 115 | + |
| 116 | + // Only allow revealing paths that are registered projects — the client |
| 117 | + // controls this argument, so we must not trust it blindly. |
| 118 | + const registered = this.projectRegistry.getAll() |
| 119 | + if (!registered.has(projectPath)) { |
| 120 | + throw new Error('Project is not registered.') |
| 121 | + } |
| 122 | + |
| 123 | + const exists = await this.pathExists(projectPath).catch(() => false) |
| 124 | + if (!exists) throw new Error('Project folder no longer exists.') |
| 125 | + |
| 126 | + const {args, command} = resolveRevealCommand(process.platform, projectPath) |
| 127 | + const child = spawn(command, args, {detached: true, stdio: 'ignore'}) |
| 128 | + child.on('error', () => { |
| 129 | + /* best-effort — nothing to report back once the ack resolved */ |
| 130 | + }) |
| 131 | + child.unref() |
| 132 | + |
| 133 | + return {projectPath} |
| 134 | + } |
99 | 135 | } |
0 commit comments