or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

extension-points.mdindex.mdworkspace-commands.mdworkspace-file-handling.mdworkspace-preferences.mdworkspace-server.mdworkspace-service.md

workspace-server.mddocs/

0

# Workspace Server

1

2

The workspace server provides backend workspace management functionality including workspace persistence, recent workspace tracking, and server-side workspace operations. It operates over JSON-RPC and handles workspace state across application sessions.

3

4

## Capabilities

5

6

### Core Workspace Server Protocol

7

8

The main server interface for workspace operations exposed over JSON-RPC.

9

10

```typescript { .api }

11

/**

12

* JSON-RPC endpoint path for workspace service

13

*/

14

const workspacePath = '/services/workspace';

15

16

/**

17

* Workspace server interface for backend workspace operations

18

*/

19

interface WorkspaceServer {

20

/**

21

* Returns the most recently used workspace folder URI as a string

22

*/

23

getMostRecentlyUsedWorkspace(): Promise<string | undefined>;

24

25

/**

26

* Sets the desired URI as the most recently used workspace folder

27

* @param uri - String representation of the workspace URI

28

*/

29

setMostRecentlyUsedWorkspace(uri: string): Promise<void>;

30

31

/**

32

* Removes a workspace from the list of recently opened workspaces

33

* @param uri - The workspace URI to remove

34

*/

35

removeRecentWorkspace(uri: string): Promise<void>;

36

37

/**

38

* Returns list of recently opened workspaces as an array

39

*/

40

getRecentWorkspaces(): Promise<string[]>;

41

}

42

```

43

44

**Usage Example:**

45

46

```typescript

47

import { injectable, inject } from "@theia/core/shared/inversify";

48

import { WorkspaceServer } from "@theia/workspace/lib/common";

49

50

@injectable()

51

export class MyWorkspaceClient {

52

53

@inject(WorkspaceServer)

54

protected readonly workspaceServer: WorkspaceServer;

55

56

async displayRecentWorkspaces(): Promise<void> {

57

// Get recent workspaces

58

const recentWorkspaces = await this.workspaceServer.getRecentWorkspaces();

59

console.log("Recent workspaces:", recentWorkspaces);

60

61

// Get most recently used

62

const mostRecent = await this.workspaceServer.getMostRecentlyUsedWorkspace();

63

if (mostRecent) {

64

console.log("Most recent workspace:", mostRecent);

65

}

66

}

67

68

async setCurrentWorkspace(workspaceUri: string): Promise<void> {

69

// Set as most recently used

70

await this.workspaceServer.setMostRecentlyUsedWorkspace(workspaceUri);

71

console.log(`Set ${workspaceUri} as most recent workspace`);

72

}

73

74

async cleanupOldWorkspace(workspaceUri: string): Promise<void> {

75

// Remove from recent list

76

await this.workspaceServer.removeRecentWorkspace(workspaceUri);

77

console.log(`Removed ${workspaceUri} from recent workspaces`);

78

}

79

}

80

```

81

82

### Default Workspace Server Implementation

83

84

Backend implementation that handles persistence and workspace lifecycle management.

85

86

```typescript { .api }

87

class DefaultWorkspaceServer implements WorkspaceServer, BackendApplicationContribution {

88

/**

89

* Threshold for untitled workspace cleanup (days)

90

*/

91

protected readonly untitledWorkspaceStaleThreshold: number;

92

93

/**

94

* Backend application lifecycle - called on server start

95

*/

96

onStart(): void;

97

98

/**

99

* Get most recently used workspace (implements WorkspaceServer)

100

*/

101

getMostRecentlyUsedWorkspace(): Promise<string | undefined>;

102

103

/**

104

* Set most recently used workspace and persist to storage

105

*/

106

setMostRecentlyUsedWorkspace(rawUri: string): Promise<void>;

107

108

/**

109

* Remove workspace from recent list and update storage

110

*/

111

removeRecentWorkspace(rawUri: string): Promise<void>;

112

113

/**

114

* Get filtered list of recent workspaces that still exist

115

*/

116

getRecentWorkspaces(): Promise<string[]>;

117

}

118

```

119

120

**Usage Example:**

121

122

```typescript

123

import { injectable, inject } from "@theia/core/shared/inversify";

124

import { DefaultWorkspaceServer } from "@theia/workspace/lib/node";

125

126

@injectable()

127

export class MyWorkspaceManager {

128

129

@inject(DefaultWorkspaceServer)

130

protected readonly workspaceServer: DefaultWorkspaceServer;

131

132

async initializeWorkspace(): Promise<void> {

133

// The server automatically handles:

134

// - Loading recent workspaces from ~/.config/theia/recentworkspace.json

135

// - Validating that workspaces still exist

136

// - Cleaning up old untitled workspaces (older than 10 days by default)

137

// - Processing CLI workspace arguments

138

139

const mostRecent = await this.workspaceServer.getMostRecentlyUsedWorkspace();

140

if (mostRecent) {

141

console.log(`Restoring workspace: ${mostRecent}`);

142

}

143

}

144

}

145

```

146

147

### CLI Integration

148

149

Service for handling workspace arguments from the command line.

150

151

```typescript { .api }

152

class WorkspaceCliContribution implements CliContribution {

153

/**

154

* Deferred workspace root from CLI arguments

155

*/

156

readonly workspaceRoot: Deferred<string | undefined>;

157

158

/**

159

* Configure CLI argument parsing for workspace options

160

*/

161

configure(conf: yargs.Argv): void;

162

163

/**

164

* Process parsed CLI arguments and set workspace

165

*/

166

setArguments(args: yargs.Arguments): Promise<void>;

167

168

/**

169

* Normalize workspace argument to proper format

170

*/

171

protected normalizeWorkspaceArg(raw: string): string;

172

173

/**

174

* Build untitled workspace for multiple directory arguments

175

*/

176

protected buildWorkspaceForMultipleArguments(workspaceArguments: string[]): Promise<string | undefined>;

177

}

178

```

179

180

**Usage Example:**

181

182

```typescript

183

import { injectable, inject } from "@theia/core/shared/inversify";

184

import { WorkspaceCliContribution } from "@theia/workspace/lib/node";

185

186

@injectable()

187

export class MyApplicationContribution {

188

189

@inject(WorkspaceCliContribution)

190

protected readonly cliContribution: WorkspaceCliContribution;

191

192

async handleStartup(): Promise<void> {

193

// Wait for CLI processing to complete

194

const workspaceFromCli = await this.cliContribution.workspaceRoot.promise;

195

196

if (workspaceFromCli) {

197

console.log(`Opening workspace from CLI: ${workspaceFromCli}`);

198

// The CLI contribution handles:

199

// - Single directory arguments

200

// - Multiple directory arguments (creates untitled workspace)

201

// - Workspace file arguments

202

// - Legacy --root-dir flag

203

}

204

}

205

}

206

207

// CLI usage examples:

208

// theia /path/to/workspace

209

// theia /path/to/project1 /path/to/project2 # Creates untitled workspace

210

// theia workspace.theia-workspace

211

// theia --root-dir=/legacy/path # Deprecated but supported

212

```

213

214

### Extension Points

215

216

Interfaces for extending workspace server functionality with custom handlers.

217

218

```typescript { .api }

219

/**

220

* Extension point for custom workspace handlers

221

*/

222

interface WorkspaceHandlerContribution {

223

/**

224

* Check if this handler can handle the given URI scheme/format

225

*/

226

canHandle(uri: URI): boolean;

227

228

/**

229

* Check if the workspace still exists and is accessible

230

*/

231

workspaceStillExists(uri: URI): Promise<boolean>;

232

}

233

234

/**

235

* Default file system workspace handler

236

*/

237

class FileWorkspaceHandlerContribution implements WorkspaceHandlerContribution {

238

/**

239

* Handles file:// scheme URIs

240

*/

241

canHandle(uri: URI): boolean;

242

243

/**

244

* Check if file/directory exists on disk

245

*/

246

workspaceStillExists(uri: URI): Promise<boolean>;

247

}

248

```

249

250

**Usage Example:**

251

252

```typescript

253

import { injectable } from "@theia/core/shared/inversify";

254

import { WorkspaceHandlerContribution } from "@theia/workspace/lib/node";

255

import URI from "@theia/core/lib/common/uri";

256

257

@injectable()

258

export class RemoteWorkspaceHandler implements WorkspaceHandlerContribution {

259

260

canHandle(uri: URI): boolean {

261

// Handle custom remote workspace schemes

262

return uri.scheme === 'ssh' || uri.scheme === 'ftp';

263

}

264

265

async workspaceStillExists(uri: URI): Promise<boolean> {

266

// Custom logic to check remote workspace availability

267

if (uri.scheme === 'ssh') {

268

return this.checkSshWorkspace(uri);

269

} else if (uri.scheme === 'ftp') {

270

return this.checkFtpWorkspace(uri);

271

}

272

return false;

273

}

274

275

private async checkSshWorkspace(uri: URI): Promise<boolean> {

276

// Implementation for SSH workspace validation

277

try {

278

// SSH connection logic here

279

return true;

280

} catch {

281

return false;

282

}

283

}

284

285

private async checkFtpWorkspace(uri: URI): Promise<boolean> {

286

// Implementation for FTP workspace validation

287

try {

288

// FTP connection logic here

289

return true;

290

} catch {

291

return false;

292

}

293

}

294

}

295

296

// Register the custom handler in your module:

297

// bind(WorkspaceHandlerContribution).to(RemoteWorkspaceHandler).inSingletonScope();

298

```

299

300

### Recent Workspace Data Management

301

302

Data structures and utilities for managing workspace persistence.

303

304

```typescript { .api }

305

interface RecentWorkspacePathsData {

306

/** Array of recent workspace URI strings */

307

recentRoots: string[];

308

}

309

310

namespace RecentWorkspacePathsData {

311

/**

312

* Create RecentWorkspacePathsData from unknown data with validation

313

*/

314

function create(data: unknown): RecentWorkspacePathsData | undefined;

315

}

316

```

317

318

**Usage Example:**

319

320

```typescript

321

import { RecentWorkspacePathsData } from "@theia/workspace/lib/node";

322

import * as fs from "fs-extra";

323

324

export class WorkspaceStorageManager {

325

326

private readonly recentWorkspacesPath = "~/.config/theia/recentworkspace.json";

327

328

async loadRecentWorkspaces(): Promise<string[]> {

329

try {

330

const data = await fs.readJson(this.recentWorkspacesPath);

331

const workspaceData = RecentWorkspacePathsData.create(data);

332

return workspaceData?.recentRoots || [];

333

} catch {

334

return [];

335

}

336

}

337

338

async saveRecentWorkspaces(workspaces: string[]): Promise<void> {

339

const data: RecentWorkspacePathsData = {

340

recentRoots: workspaces

341

};

342

await fs.ensureDir(path.dirname(this.recentWorkspacesPath));

343

await fs.writeJson(this.recentWorkspacesPath, data, { spaces: 2 });

344

}

345

346

async addRecentWorkspace(workspace: string): Promise<void> {

347

const recent = await this.loadRecentWorkspaces();

348

349

// Remove if already exists (to move to front)

350

const filtered = recent.filter(w => w !== workspace);

351

352

// Add to front and limit to reasonable number

353

const updated = [workspace, ...filtered].slice(0, 10);

354

355

await this.saveRecentWorkspaces(updated);

356

}

357

}

358

```

359

360

### Server Configuration and Lifecycle

361

362

The workspace server integrates with Theia's backend application lifecycle and provides automatic cleanup and maintenance.

363

364

**Key Features:**

365

366

- **Automatic Cleanup**: Removes untitled workspaces older than configurable threshold (default: 10 days)

367

- **Persistence**: Stores recent workspaces in user config directory

368

- **Validation**: Checks workspace existence before returning in recent list

369

- **CLI Integration**: Processes command-line workspace arguments

370

- **Extension Support**: Pluggable workspace handlers for different URI schemes

371

372

## Types

373

374

```typescript { .api }

375

interface RecentWorkspacePathsData {

376

recentRoots: string[];

377

}

378

379

interface WorkspaceHandlerContribution {

380

canHandle(uri: URI): boolean;

381

workspaceStillExists(uri: URI): Promise<boolean>;

382

}

383

384

interface CliContribution {

385

configure(conf: yargs.Argv): void;

386

setArguments(args: yargs.Arguments): Promise<void>;

387

}

388

389

interface BackendApplicationContribution {

390

initialize?(): void;

391

configure?(app: Application): void;

392

onStart?(server?: http.Server): void;

393

onStop?(app?: Application): void;

394

}

395

396

const workspacePath: string; // '/services/workspace'

397

const WorkspaceServer: symbol;

398

const WorkspaceHandlerContribution: symbol;

399

400

type Deferred<T> = {

401

readonly promise: Promise<T>;

402

resolve(value: T): void;

403

reject(reason?: any): void;

404

};

405

```