Skip to content
Source
Sign inSign up

server.ts

1,052 lines41.6 KB

1import * as Effect from "effect/Effect";
2import * as Schema from "effect/Schema";
3import { AcpRegistryUrlAuthAction } from "./acpRegistry.ts";
4import {
5 type EnvironmentMachineKind,
6 ExecutionEnvironmentDescriptor,
7 ServerSelfUpdateMethod,
8} from "./environment.ts";
9import { AuthClientPresentationMetadata, ServerAuthDescriptor } from "./auth.ts";
10import {
11 ForwardCompatibleArray,
12 ForwardCompatibleOptional,
13 IsoDateTime,
14 NonNegativeInt,
15 PositiveInt,
16 ProjectId,
17 ThreadId,
18 TrimmedNonEmptyString,
19} from "./baseSchemas.ts";
20import {
21 KeybindingCommand,
22 KeybindingValue,
23 KeybindingWhen,
24 ResolvedKeybindingsConfig,
25} from "./keybindings.ts";
26import { EditorId, FileManagerRevealKind, RemoteOpenTarget } from "./editor.ts";
27import { ManagedPolicySummary } from "./managedPolicy.ts";
28import { ModelCapabilities, ProviderOptionDescriptor } from "./model.ts";
29import { RuntimeMode } from "./providerPolicy.ts";
30import { ProviderDriverKind, ProviderInstanceId } from "./providerInstance.ts";
31import { ServerProviderUsageLimits, UsageLimitSourceSnapshots } from "./providerUsageLimits.ts";
32import { LayoutSettings, ServerSettings } from "./settings.ts";
33import { DesktopUpdateChannelSchema } from "./ipc.ts";
34​
35const KeybindingsMalformedConfigIssue = Schema.Struct({
36 kind: Schema.Literal("keybindings.malformed-config"),
37 message: TrimmedNonEmptyString,
38});
39​
40const KeybindingsInvalidEntryIssue = Schema.Struct({
41 kind: Schema.Literal("keybindings.invalid-entry"),
42 message: TrimmedNonEmptyString,
43 index: Schema.Number,
44});
45​
46export const ServerConfigIssue = Schema.Union([
47 KeybindingsMalformedConfigIssue,
48 KeybindingsInvalidEntryIssue,
49]);
50export type ServerConfigIssue = typeof ServerConfigIssue.Type;
51​
52const ServerConfigIssues = ForwardCompatibleArray(ServerConfigIssue);
53​
54export const ServerProviderState = Schema.Literals(["ready", "warning", "error", "disabled"]);
55export type ServerProviderState = typeof ServerProviderState.Type;
56​
57export const ServerProviderAuthStatus = Schema.Literals([
58 "authenticated",
59 "unauthenticated",
60 "unknown",
61]);
62export type ServerProviderAuthStatus = typeof ServerProviderAuthStatus.Type;
63​
64export const ServerProviderAuth = Schema.Struct({
65 status: ServerProviderAuthStatus,
66 type: Schema.optional(TrimmedNonEmptyString),
67 label: Schema.optional(TrimmedNonEmptyString),
68 email: Schema.optional(TrimmedNonEmptyString),
69 action: Schema.optional(AcpRegistryUrlAuthAction),
70 canLogout: Schema.optional(Schema.Boolean),
71 subscriptionSharing: Schema.optional(Schema.Boolean),
72 profileId: Schema.optional(TrimmedNonEmptyString),
73 workspaceId: Schema.optional(TrimmedNonEmptyString),
74});
75export type ServerProviderAuth = typeof ServerProviderAuth.Type;
76​
77export const ServerProviderModel = Schema.Struct({
78 slug: TrimmedNonEmptyString,
79 name: TrimmedNonEmptyString,
80 shortName: Schema.optional(TrimmedNonEmptyString),
81 subProvider: Schema.optional(TrimmedNonEmptyString),
82 aliases: Schema.optional(Schema.Array(TrimmedNonEmptyString)),
83 badge: Schema.optional(Schema.Literal("new")),
84 isCustom: Schema.Boolean,
85 isDefault: Schema.optional(Schema.Boolean),
86 isLegacy: Schema.optional(Schema.Boolean),
87 capabilities: Schema.NullOr(ModelCapabilities),
88});
89export type ServerProviderModel = typeof ServerProviderModel.Type;
90​
91export const ServerProviderUpdateRequiredModel = Schema.Struct({
92 slug: TrimmedNonEmptyString,
93 name: TrimmedNonEmptyString,
94 badge: Schema.optional(Schema.Literal("new")),
95 minVersion: TrimmedNonEmptyString,
96});
97export type ServerProviderUpdateRequiredModel = typeof ServerProviderUpdateRequiredModel.Type;
98​
99export const ServerProviderSlashCommandInput = Schema.Struct({
100 hint: TrimmedNonEmptyString,
101});
102export type ServerProviderSlashCommandInput = typeof ServerProviderSlashCommandInput.Type;
103​
104export const ServerProviderSlashCommand = Schema.Struct({
105 name: TrimmedNonEmptyString,
106 description: Schema.optional(TrimmedNonEmptyString),
107 input: Schema.optional(ServerProviderSlashCommandInput),
108});
109export type ServerProviderSlashCommand = typeof ServerProviderSlashCommand.Type;
110​
111export const ServerProviderSkill = Schema.Struct({
112 name: TrimmedNonEmptyString,
113 description: Schema.optional(TrimmedNonEmptyString),
114 path: TrimmedNonEmptyString,
115 scope: Schema.optional(TrimmedNonEmptyString),
116 enabled: Schema.Boolean,
117 displayName: Schema.optional(TrimmedNonEmptyString),
118 shortDescription: Schema.optional(TrimmedNonEmptyString),
119 /** Claude disable-model-invocation: only users can invoke; composers must offer a slash command. */
120 userInvocationOnly: Schema.optional(Schema.Boolean),
121 /** Claude user-invocable:false: only agents can invoke; composers must hide the slash command. */
122 userInvocable: Schema.optional(Schema.Boolean),
123});
124export type ServerProviderSkill = typeof ServerProviderSkill.Type;
125​
126export const ServerProviderWorkspaceSnapshot = Schema.Struct({
127 cwd: TrimmedNonEmptyString,
128 checkedAt: IsoDateTime,
129 slashCommands: Schema.Array(ServerProviderSlashCommand),
130 slashCommandsPending: Schema.optional(Schema.Boolean),
131 skills: Schema.Array(ServerProviderSkill),
132 optionDescriptors: Schema.optional(Schema.Array(ProviderOptionDescriptor)),
133 // Absent means the provider's machine `models`, which keeps most snapshots small.
134 models: Schema.optional(Schema.Array(ServerProviderModel)),
135 modelsPending: Schema.optional(Schema.Boolean),
136});
137export type ServerProviderWorkspaceSnapshot = typeof ServerProviderWorkspaceSnapshot.Type;
138​
139export const PROVIDER_WORKSPACE_SNAPSHOT_TTL_MS = 5 * 60_000;
140​
141export function isProviderWorkspaceSnapshotCurrent(
142 snapshot: Pick<ServerProviderWorkspaceSnapshot, "checkedAt">,
143 nowMs: number,
144): boolean {
145 return nowMs - Date.parse(snapshot.checkedAt) < PROVIDER_WORKSPACE_SNAPSHOT_TTL_MS;
147​
148/** A pending snapshot keeps what it found before and is rescanned before its TTL. */
149export function isProviderWorkspaceSnapshotPending(
150 snapshot: Pick<ServerProviderWorkspaceSnapshot, "slashCommandsPending" | "modelsPending">,
151): boolean {
152 return snapshot.slashCommandsPending === true || snapshot.modelsPending === true;
154​
155/** Unavailable snapshots must set installed and enabled false. */
156export const ServerProviderAvailability = Schema.Literals(["available", "unavailable"]);
157export type ServerProviderAvailability = typeof ServerProviderAvailability.Type;
158​
159export const ServerProviderContinuation = Schema.Struct({
160 groupKey: TrimmedNonEmptyString,
161});
162export type ServerProviderContinuation = typeof ServerProviderContinuation.Type;
163​
164export const ServerProviderCompatibilityStatus = Schema.Literals([
165 "unknown",
166 "supported",
167 "graceful",
168 "unsupported",
169 "broken",
170]);
171export const ServerProviderCompatibilityAdvisory = Schema.Struct({
172 status: ServerProviderCompatibilityStatus,
173 latestVersionStatus: Schema.optionalKey(ServerProviderCompatibilityStatus),
174 message: Schema.NullOr(TrimmedNonEmptyString),
175 recommendedVersion: Schema.NullOr(TrimmedNonEmptyString),
176 recommendedRange: Schema.NullOr(TrimmedNonEmptyString),
177});
178export type ServerProviderCompatibilityAdvisory = typeof ServerProviderCompatibilityAdvisory.Type;
179​
180export const ServerProviderVersionAdvisoryStatus = Schema.Literals([
181 "unknown",
182 "current",
183 "behind_latest",
184]);
185export type ServerProviderVersionAdvisoryStatus = typeof ServerProviderVersionAdvisoryStatus.Type;
186​
187export const ServerProviderVersionAdvisory = Schema.Struct({
188 status: ServerProviderVersionAdvisoryStatus,
189 currentVersion: Schema.NullOr(TrimmedNonEmptyString),
190 latestVersion: Schema.NullOr(TrimmedNonEmptyString),
191 updateCommand: Schema.NullOr(TrimmedNonEmptyString),
192 canUpdate: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(false))),
193 canInstallVersion: Schema.optionalKey(Schema.Boolean),
194 checkedAt: Schema.NullOr(IsoDateTime),
195 message: Schema.NullOr(TrimmedNonEmptyString),
196});
197export type ServerProviderVersionAdvisory = typeof ServerProviderVersionAdvisory.Type;
198​
199export const ServerProviderUpdateStatus = Schema.Literals([
200 "idle",
201 "queued",
202 "running",
203 "succeeded",
204 "failed",
205 "unchanged",
206]);
207export type ServerProviderUpdateStatus = typeof ServerProviderUpdateStatus.Type;
208​
209export const ServerProviderUpdateState = Schema.Struct({
210 status: ServerProviderUpdateStatus,
211 startedAt: Schema.NullOr(IsoDateTime),
212 finishedAt: Schema.NullOr(IsoDateTime),
213 message: Schema.NullOr(TrimmedNonEmptyString),
214 output: Schema.NullOr(Schema.String.check(Schema.isMaxLength(10_000))),
215});
216export type ServerProviderUpdateState = typeof ServerProviderUpdateState.Type;
217​
218export const ServerProvider = Schema.Struct({
219 // Only instanceId is stable enough for provider routing.
220 instanceId: ProviderInstanceId,
221 driver: ProviderDriverKind,
222 displayName: Schema.optional(TrimmedNonEmptyString),
223 accentColor: Schema.optional(TrimmedNonEmptyString),
224 // Validate driver-supplied remote icons against the driver's trusted origin.
225 iconUrl: Schema.optional(TrimmedNonEmptyString.check(Schema.isMaxLength(2_048))),
226 badgeLabel: Schema.optional(TrimmedNonEmptyString),
227 continuation: Schema.optional(ServerProviderContinuation),
228 showInteractionModeToggle: Schema.optional(Schema.Boolean),
229 reportsContextWindow: Schema.optional(Schema.Boolean),
230 supportedRuntimeModes: Schema.optional(ForwardCompatibleArray(RuntimeMode)),
231 supportsConversationRollback: Schema.optional(Schema.Boolean),
232 supportsTextGeneration: Schema.optional(Schema.Boolean),
233 setup: Schema.optional(
234 Schema.Struct({
235 canAuthenticate: Schema.Boolean,
236 canInstall: Schema.Boolean,
237 documentationUrl: Schema.optionalKey(TrimmedNonEmptyString.check(Schema.isMaxLength(2_048))),
238 }),
239 ),
240 nativeSessions: Schema.optional(
241 Schema.Struct({
242 canList: Schema.Boolean,
243 canLoad: Schema.Boolean,
244 canResume: Schema.Boolean,
245 canDelete: Schema.optional(Schema.Boolean),
246 }),
247 ),
248 configurableProviders: Schema.optional(Schema.Boolean),
249 runtimePaths: Schema.optionalKey(
250 Schema.Struct({
251 homePath: TrimmedNonEmptyString,
252 shadowHomePath: Schema.NullOr(TrimmedNonEmptyString),
253 }),
254 ),
255 enabled: Schema.Boolean,
256 installed: Schema.Boolean,
257 version: Schema.NullOr(TrimmedNonEmptyString),
258 // Version reported by the installed CLI for a local provider with a separate
259 // server. Null means unknown; absence keeps legacy snapshots on `version`.
260 installedVersion: Schema.optionalKey(Schema.NullOr(TrimmedNonEmptyString)),
261 status: ServerProviderState,
262 auth: ServerProviderAuth,
263 checkedAt: IsoDateTime,
264 message: Schema.optional(TrimmedNonEmptyString),
265 availability: Schema.optional(ServerProviderAvailability),
266 unavailableReason: Schema.optional(TrimmedNonEmptyString),
267 models: Schema.Array(ServerProviderModel),
268 // Kept apart from `models` so clients that predate it never offer them.
269 updateRequiredModels: Schema.optionalKey(Schema.Array(ServerProviderUpdateRequiredModel)),
270 slashCommands: Schema.Array(ServerProviderSlashCommand).pipe(
271 Schema.withDecodingDefault(Effect.succeed([])),
272 ),
273 skills: Schema.Array(ServerProviderSkill).pipe(Schema.withDecodingDefault(Effect.succeed([]))),
274 workspaceSnapshots: Schema.optionalKey(Schema.Array(ServerProviderWorkspaceSnapshot)),
275 usageLimits: Schema.optional(ServerProviderUsageLimits),
276 versionAdvisory: Schema.optionalKey(ServerProviderVersionAdvisory),
277 compatibilityAdvisory: Schema.optionalKey(ServerProviderCompatibilityAdvisory),
278 updateState: Schema.optionalKey(ServerProviderUpdateState),
279 /**
280 * Stands for the machine slash commands and skills, which are then left out. Sent to clients
281 * that ask for catalog digests; they load both lists with their next cwd snapshot.
282 */
283 catalogDigest: Schema.optionalKey(TrimmedNonEmptyString),
284 /** Set by the client, never sent: the `catalogDigest` its slash commands and skills belong to. */
285 loadedCatalogDigest: Schema.optionalKey(TrimmedNonEmptyString),
286});
287export type ServerProvider = typeof ServerProvider.Type;
288​
289/** A provider without the lists that equal the ones its reader already holds. */
290export const ServerProviderDelta = ServerProvider.mapFields((fields) => ({
291 ...fields,
292 models: Schema.optionalKey(fields.models),
293 // Declared again without the decoding default, which would read as a change to an empty list.
294 slashCommands: Schema.optionalKey(Schema.Array(ServerProviderSlashCommand)),
295 skills: Schema.optionalKey(Schema.Array(ServerProviderSkill)),
296}));
297export type ServerProviderDelta = typeof ServerProviderDelta.Type;
298​
299const sameJson = (left: unknown, right: unknown) =>
300 left === right || JSON.stringify(left) === JSON.stringify(right);
301​
302/** Leaves each provider's models, slash commands, and skills out when `previous` has the same. */
303export function serverProviderDeltas(
304 previous: ReadonlyArray<ServerProvider>,
305 next: ReadonlyArray<ServerProvider>,
306): ServerProviderDelta[] {
307 const held = new Map(previous.map((provider) => [provider.instanceId, provider]));
308 return next.map((provider) => {
309 const base = held.get(provider.instanceId);
310 if (base === undefined) return provider;
311 const { models, slashCommands, skills, ...rest } = provider;
312 return {
313 ...rest,
314 ...(sameJson(base.models, models) ? {} : { models }),
315 ...(sameJson(base.slashCommands, slashCommands) ? {} : { slashCommands }),
316 ...(sameJson(base.skills, skills) ? {} : { skills }),
317 };
318 });
320​
321/** Rebuilds the provider list `serverProviderDeltas` was made from. */
322export function applyServerProviderDeltas(
323 previous: ReadonlyArray<ServerProvider>,
324 deltas: ReadonlyArray<ServerProviderDelta>,
325): ServerProvider[] {
326 const held = new Map(previous.map((provider) => [provider.instanceId, provider]));
327 return deltas.flatMap((delta) => {
328 const base = held.get(delta.instanceId);
329 const models = delta.models ?? base?.models;
330 const slashCommands = delta.slashCommands ?? base?.slashCommands;
331 const skills = delta.skills ?? base?.skills;
332 // A list this reader never held cannot be rebuilt; drop the provider like an unreadable one.
333 return models && slashCommands && skills ? [{ ...delta, models, slashCommands, skills }] : [];
334 });
336​
337export const ServerProviders = ForwardCompatibleArray(ServerProvider);
338export type ServerProviders = typeof ServerProviders.Type;
339​
340export const isProviderAvailable = (snapshot: ServerProvider): boolean =>
341 snapshot.availability !== "unavailable";
342​
343/** Legacy producers omit this field and support text generation. */
344export const isProviderTextGenerationCapable = (snapshot: ServerProvider): boolean =>
345 snapshot.supportsTextGeneration !== false;
346​
347export const OtlpEndpointSource = Schema.Literals(["environment", "bootstrap", "settings"]);
348export type OtlpEndpointSource = typeof OtlpEndpointSource.Type;
349​
350export const ServerObservability = Schema.Struct({
351 logsDirectoryPath: TrimmedNonEmptyString,
352 localTracingEnabled: Schema.Boolean,
353 otlpTracesUrl: Schema.optional(TrimmedNonEmptyString),
354 otlpTracesSource: Schema.optional(OtlpEndpointSource),
355 otlpTracesVariable: Schema.optional(TrimmedNonEmptyString),
356 otlpTracesEnabled: Schema.Boolean,
357 otlpMetricsUrl: Schema.optional(TrimmedNonEmptyString),
358 otlpMetricsSource: Schema.optional(OtlpEndpointSource),
359 otlpMetricsVariable: Schema.optional(TrimmedNonEmptyString),
360 otlpMetricsEnabled: Schema.Boolean,
361 otlpLogsUrl: Schema.optional(TrimmedNonEmptyString),
362 otlpLogsSource: Schema.optional(OtlpEndpointSource),
363 otlpLogsVariable: Schema.optional(TrimmedNonEmptyString),
364 otlpLogsEnabled: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(false))),
365});
366export type ServerObservability = typeof ServerObservability.Type;
367​
368export const OtlpSignal = Schema.Literals(["traces", "metrics", "logs"]);
369export type OtlpSignal = typeof OtlpSignal.Type;
370​
371export const OtlpEndpointCheckInput = Schema.Struct({
372 signal: OtlpSignal,
373 url: TrimmedNonEmptyString.check(Schema.isPattern(/^https?:\/\/./i)),
374});
375export type OtlpEndpointCheckInput = typeof OtlpEndpointCheckInput.Type;
376​
377export const OtlpEndpointCheckResult = Schema.Union([
378 Schema.TaggedStruct("Accepted", { latencyMs: Schema.Number }),
379 Schema.TaggedStruct("Rejected", { status: Schema.Number }),
380 Schema.TaggedStruct("Unreachable", { timedOut: Schema.Boolean }),
381]);
382export type OtlpEndpointCheckResult = typeof OtlpEndpointCheckResult.Type;
383​
384/** The client tells the server what it is, so the triage context can name it. */
385export const ServerPrepareTriageInput = Schema.Struct({
386 client: AuthClientPresentationMetadata,
387});
388export type ServerPrepareTriageInput = typeof ServerPrepareTriageInput.Type;
389​
390export const ServerPrepareTriageResult = Schema.Struct({
391 /** Composer text that links the session's prompt file. */
392 prompt: Schema.String,
393});
394export type ServerPrepareTriageResult = typeof ServerPrepareTriageResult.Type;
395​
396/**
397 * The prompt file links as a chip in the user's message; clients spot a triage
398 * draft by it.
399 */
400export const TRIAGE_PROMPT_FILE_NAME = "triage-playbook.md";
401​
402export class ServerPrepareTriageError extends Schema.TaggedError<ServerPrepareTriageError>()(
403 "ServerPrepareTriageError",
404 { cause: Schema.optional(Schema.Defect()) },
405) {
406 override get message(): string {
407 return "Could not write the triage session files.";
408 }
410​
411export const ServerTraceDiagnosticsErrorKind = Schema.Literals([
412 "trace-file-not-found",
413 "trace-file-read-failed",
414]);
415export type ServerTraceDiagnosticsErrorKind = typeof ServerTraceDiagnosticsErrorKind.Type;
416​
417export const ServerTraceDiagnosticsSpanSummary = Schema.Struct({
418 name: TrimmedNonEmptyString,
419 count: NonNegativeInt,
420 failureCount: NonNegativeInt,
421 totalDurationMs: Schema.Number,
422 averageDurationMs: Schema.Number,
423 maxDurationMs: Schema.Number,
424});
425export type ServerTraceDiagnosticsSpanSummary = typeof ServerTraceDiagnosticsSpanSummary.Type;
426​
427export const ServerTraceDiagnosticsFailureSummary = Schema.Struct({
428 name: TrimmedNonEmptyString,
429 cause: TrimmedNonEmptyString,
430 count: NonNegativeInt,
431 lastSeenAt: Schema.DateTimeUtc,
432 traceId: TrimmedNonEmptyString,
433 spanId: TrimmedNonEmptyString,
434});
435export type ServerTraceDiagnosticsFailureSummary = typeof ServerTraceDiagnosticsFailureSummary.Type;
436​
437export const ServerTraceDiagnosticsRecentFailure = Schema.Struct({
438 name: TrimmedNonEmptyString,
439 cause: TrimmedNonEmptyString,
440 durationMs: Schema.Number,
441 endedAt: Schema.DateTimeUtc,
442 traceId: TrimmedNonEmptyString,
443 spanId: TrimmedNonEmptyString,
444});
445export type ServerTraceDiagnosticsRecentFailure = typeof ServerTraceDiagnosticsRecentFailure.Type;
446​
447export const ServerTraceDiagnosticsSpanOccurrence = Schema.Struct({
448 name: TrimmedNonEmptyString,
449 durationMs: Schema.Number,
450 endedAt: Schema.DateTimeUtc,
451 traceId: TrimmedNonEmptyString,
452 spanId: TrimmedNonEmptyString,
453});
454export type ServerTraceDiagnosticsSpanOccurrence = typeof ServerTraceDiagnosticsSpanOccurrence.Type;
455​
456export const ServerTraceDiagnosticsLogEvent = Schema.Struct({
457 spanName: TrimmedNonEmptyString,
458 level: TrimmedNonEmptyString,
459 message: TrimmedNonEmptyString,
460 seenAt: Schema.DateTimeUtc,
461 traceId: TrimmedNonEmptyString,
462 spanId: TrimmedNonEmptyString,
463});
464export type ServerTraceDiagnosticsLogEvent = typeof ServerTraceDiagnosticsLogEvent.Type;
465​
466export const ServerTraceDiagnosticsResult = Schema.Struct({
467 traceFilePath: TrimmedNonEmptyString,
468 scannedFilePaths: Schema.Array(TrimmedNonEmptyString),
469 readAt: Schema.DateTimeUtc,
470 recordCount: NonNegativeInt,
471 parseErrorCount: NonNegativeInt,
472 firstSpanAt: Schema.Option(Schema.DateTimeUtc),
473 lastSpanAt: Schema.Option(Schema.DateTimeUtc),
474 failureCount: NonNegativeInt,
475 interruptionCount: NonNegativeInt,
476 slowSpanThresholdMs: NonNegativeInt,
477 slowSpanCount: NonNegativeInt,
478 logLevelCounts: Schema.Record(TrimmedNonEmptyString, NonNegativeInt),
479 topSpansByCount: Schema.Array(ServerTraceDiagnosticsSpanSummary),
480 slowestSpans: Schema.Array(ServerTraceDiagnosticsSpanOccurrence),
481 commonFailures: Schema.Array(ServerTraceDiagnosticsFailureSummary),
482 latestFailures: Schema.Array(ServerTraceDiagnosticsRecentFailure),
483 latestWarningAndErrorLogs: Schema.Array(ServerTraceDiagnosticsLogEvent),
484 partialFailure: Schema.Option(Schema.Boolean),
485 error: Schema.Option(
486 Schema.Struct({
487 kind: ServerTraceDiagnosticsErrorKind,
488 message: TrimmedNonEmptyString,
489 }),
490 ),
491});
492export type ServerTraceDiagnosticsResult = typeof ServerTraceDiagnosticsResult.Type;
493​
494export const ServerProcessSignal = Schema.Literals(["SIGINT", "SIGKILL"]);
495export type ServerProcessSignal = typeof ServerProcessSignal.Type;
496​
497export const ServerProcessDiagnosticsEntry = Schema.Struct({
498 pid: PositiveInt,
499 startTimeMs: NonNegativeInt,
500 ppid: NonNegativeInt,
501 pgid: Schema.Option(Schema.Int),
502 status: TrimmedNonEmptyString,
503 cpuPercent: Schema.Number,
504 rssBytes: NonNegativeInt,
505 elapsed: TrimmedNonEmptyString,
506 command: TrimmedNonEmptyString,
507 depth: NonNegativeInt,
508 childPids: Schema.Array(PositiveInt),
509});
510export type ServerProcessDiagnosticsEntry = typeof ServerProcessDiagnosticsEntry.Type;
511​
512export const ServerProcessDiagnosticsResult = Schema.Struct({
513 serverPid: PositiveInt,
514 readAt: Schema.DateTimeUtc,
515 processCount: NonNegativeInt,
516 totalRssBytes: NonNegativeInt,
517 totalCpuPercent: Schema.Number,
518 processes: Schema.Array(ServerProcessDiagnosticsEntry),
519 error: Schema.Option(
520 Schema.Struct({
521 message: TrimmedNonEmptyString,
522 }),
523 ),
524});
525export type ServerProcessDiagnosticsResult = typeof ServerProcessDiagnosticsResult.Type;
526​
527export const ServerProcessResourceHistoryInput = Schema.Struct({
528 windowMs: NonNegativeInt,
529 bucketMs: NonNegativeInt,
530});
531export type ServerProcessResourceHistoryInput = typeof ServerProcessResourceHistoryInput.Type;
532​
533export const ServerProcessResourceHistoryBucket = Schema.Struct({
534 startedAt: Schema.DateTimeUtc,
535 endedAt: Schema.DateTimeUtc,
536 avgCpuPercent: Schema.Number,
537 maxCpuPercent: Schema.Number,
538 maxRssBytes: NonNegativeInt,
539 maxProcessCount: NonNegativeInt,
540});
541export type ServerProcessResourceHistoryBucket = typeof ServerProcessResourceHistoryBucket.Type;
542​
543export const ServerProcessResourceHistorySummary = Schema.Struct({
544 processKey: TrimmedNonEmptyString,
545 pid: PositiveInt,
546 ppid: NonNegativeInt,
547 command: TrimmedNonEmptyString,
548 depth: NonNegativeInt,
549 isServerRoot: Schema.Boolean,
550 firstSeenAt: Schema.DateTimeUtc,
551 lastSeenAt: Schema.DateTimeUtc,
552 currentCpuPercent: Schema.Number,
553 avgCpuPercent: Schema.Number,
554 maxCpuPercent: Schema.Number,
555 cpuSecondsApprox: Schema.Number,
556 currentRssBytes: NonNegativeInt,
557 maxRssBytes: NonNegativeInt,
558 sampleCount: NonNegativeInt,
559});
560export type ServerProcessResourceHistorySummary = typeof ServerProcessResourceHistorySummary.Type;
561​
562export const ServerProcessResourceHistoryFailureTag = Schema.Literals([
563 "ProcessDiagnosticsQueryTimeoutError",
564 "ProcessDiagnosticsQueryFailedError",
565 "ProcessDiagnosticsServerProcessSignalError",
566 "ProcessDiagnosticsNotDescendantError",
567 "ProcessDiagnosticsSignalFailedError",
568]);
569export type ServerProcessResourceHistoryFailureTag =
570 typeof ServerProcessResourceHistoryFailureTag.Type;
571​
572export const ServerProcessResourceHistoryResult = Schema.Struct({
573 readAt: Schema.DateTimeUtc,
574 windowMs: NonNegativeInt,
575 bucketMs: NonNegativeInt,
576 sampleIntervalMs: NonNegativeInt,
577 retainedSampleCount: NonNegativeInt,
578 totalCpuSecondsApprox: Schema.Number,
579 buckets: Schema.Array(ServerProcessResourceHistoryBucket),
580 topProcesses: Schema.Array(ServerProcessResourceHistorySummary),
581 error: Schema.Option(
582 Schema.Struct({
583 failureTag: ServerProcessResourceHistoryFailureTag,
584 message: TrimmedNonEmptyString,
585 }),
586 ),
587});
588export type ServerProcessResourceHistoryResult = typeof ServerProcessResourceHistoryResult.Type;
589​
590export const ServerSignalProcessInput = Schema.Struct({
591 pid: PositiveInt,
592 startTimeMs: NonNegativeInt,
593 signal: ServerProcessSignal,
594});
595export type ServerSignalProcessInput = typeof ServerSignalProcessInput.Type;
596​
597export const ServerSignalProcessResult = Schema.Struct({
598 pid: PositiveInt,
599 signal: ServerProcessSignal,
600 signaled: Schema.Boolean,
601 message: Schema.Option(TrimmedNonEmptyString),
602});
603export type ServerSignalProcessResult = typeof ServerSignalProcessResult.Type;
604​
605export const EnvironmentThemeColor = Schema.String.check(
606 Schema.isPattern(/^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/),
607);
608export type EnvironmentThemeColor = typeof EnvironmentThemeColor.Type;
609​
610/** Reserve appearance keywords so published themes cannot replace stock preferences. */
611export const EnvironmentThemeId = Schema.String.check(
612 Schema.isPattern(/^(?!(?:system|light|dark)$)[a-z0-9](?:[a-z0-9-]{0,47})$/),
613);
614export type EnvironmentThemeId = typeof EnvironmentThemeId.Type;
615​
616const EnvironmentThemeColors = Schema.Record(
617 Schema.String.check(Schema.isPattern(/^[a-zA-Z][a-zA-Z0-9]{0,63}$/)),
618 TrimmedNonEmptyString.check(Schema.isMaxLength(64)),
619);
620​
621const environmentThemeFields = {
622 version: Schema.optional(Schema.Literal(1)),
623 name: TrimmedNonEmptyString.check(Schema.isMaxLength(48)),
624 appearance: Schema.Literals(["light", "dark"]),
625 /** Derive the palette from canvas/accent, then overlay colors; without them, colors is the palette. */
626 canvas: Schema.optional(EnvironmentThemeColor),
627 accent: Schema.optional(EnvironmentThemeColor),
628 colors: Schema.optional(EnvironmentThemeColors),
629 variants: Schema.optional(
630 Schema.Struct({
631 light: Schema.optional(EnvironmentThemeColors),
632 dark: Schema.optional(EnvironmentThemeColors),
633 }),
634 ),
635};
636​
637export const EnvironmentThemeFile = Schema.Struct(environmentThemeFields);
638export type EnvironmentThemeFile = typeof EnvironmentThemeFile.Type;
639​
640export const EnvironmentTheme = Schema.Struct({
641 id: EnvironmentThemeId,
642 ...environmentThemeFields,
643});
644export type EnvironmentTheme = typeof EnvironmentTheme.Type;
645​
646export function environmentThemeFileHasColors(file: EnvironmentThemeFile): boolean {
647 return (
648 (file.canvas !== undefined && file.accent !== undefined) ||
649 (file.colors !== undefined && Object.keys(file.colors).length > 0)
650 );
652​
653/** tailnet means this machine's Tailscale interface; other private addresses are lan. */
654export const ServerDirectEndpointKind = Schema.Literals(["lan", "tailnet"]);
655export type ServerDirectEndpointKind = typeof ServerDirectEndpointKind.Type;
656​
657export const ServerDirectEndpoint = Schema.Struct({
658 kind: ServerDirectEndpointKind,
659 httpBaseUrl: TrimmedNonEmptyString,
660});
661export type ServerDirectEndpoint = typeof ServerDirectEndpoint.Type;
662​
663/**
664 * A stretch where the server's event loop could not run, so it answered
665 * nothing and clients may have dropped the connection.
666 */
667export const ServerEventLoopStall = Schema.Struct({
668 detectedAt: IsoDateTime,
669 durationMs: NonNegativeInt,
670 /** One-minute load average when the stall was seen. Absent on Windows, which has none. */
671 loadAverage: Schema.optionalKey(Schema.Number),
672 cpuCount: PositiveInt,
673});
674export type ServerEventLoopStall = typeof ServerEventLoopStall.Type;
675​
676export const ServerConfig = Schema.Struct({
677 environment: ExecutionEnvironmentDescriptor,
678 auth: ServerAuthDescriptor,
679 cwd: TrimmedNonEmptyString,
680 keybindingsConfigPath: TrimmedNonEmptyString,
681 keybindings: ResolvedKeybindingsConfig,
682 issues: ServerConfigIssues,
683 providers: ServerProviders,
684 availableEditors: ForwardCompatibleArray(EditorId),
685 remoteOpenTargets: Schema.optionalKey(ForwardCompatibleArray(RemoteOpenTarget)),
686 /** Hints only; verify each address answers as this environment. */
687 directEndpoints: Schema.optionalKey(ForwardCompatibleArray(ServerDirectEndpoint)),
688 observability: ServerObservability,
689 // Read-only migration source, using the same field older servers send.
690 settings: Schema.Struct({
691 ...ServerSettings.fields,
692 layout: ForwardCompatibleOptional(LayoutSettings),
693 }),
694 /** Present when an administrator's policy file manages this environment. */
695 managedPolicy: Schema.optionalKey(ManagedPolicySummary),
696 shellResumeCompletionMarker: Schema.optionalKey(Schema.Boolean),
697 /**
698 * The shell can leave idle subagent children out of snapshots (`omitIdleSubagents`), and
699 * `getThreadFamily` and `getWorktreeThreadIds` serve the rows it leaves out.
700 */
701 shellThreadFamilies: Schema.optionalKey(Schema.Boolean),
702 threadLinkMetadata: Schema.optionalKey(Schema.Boolean),
703 /**
704 * The shell can leave older settled threads out of snapshots (`omitOlderSettled`), and
705 * `getOlderSettledThreads` serves them. Only servers that also advertise `shellThreadFamilies`.
706 */
707 shellOlderSettled: Schema.optionalKey(Schema.Boolean),
708 shellRevealInFileManager: Schema.optionalKey(Schema.Boolean),
709 shellRevealInFileManagerKind: Schema.optionalKey(FileManagerRevealKind),
710 threadResumeCompletionMarker: Schema.optionalKey(Schema.Boolean),
711 /** Send window fields only when advertised. */
712 threadSnapshotPagination: Schema.optionalKey(Schema.Boolean),
713 threadFind: Schema.optionalKey(Schema.Boolean),
714 threadFindProgressive: Schema.optionalKey(Schema.Boolean),
715 /** Settings patches may carry `secretProviders`; older servers drop the key without an error. */
716 secretProviderSettings: Schema.optionalKey(Schema.Boolean),
717 /** Secret settings may point at a secret provider; older servers drop the reference. */
718 secretReferences: Schema.optionalKey(Schema.Boolean),
719 /** A secret request card may be answered with a secret provider reference. */
720 secretRequestReferences: Schema.optionalKey(Schema.Boolean),
721 scratchWorkspaceRoot: Schema.optionalKey(TrimmedNonEmptyString),
722 newProjectsRoot: Schema.optionalKey(TrimmedNonEmptyString),
723 /**
724 * The latest stall long enough to notice, sent only for a few minutes after
725 * it. A client that reconnects reads it to say why the host stopped
726 * answering. Clients do not cache it, since it describes the host at connect.
727 */
728 lastEventLoopStall: Schema.optionalKey(ServerEventLoopStall),
729 /**
730 * The server user's home folder, where surfaces opened without a project
731 * (a terminal, the file browser) work. Absent on servers that predate it.
732 */
733 homeDirectory: Schema.optionalKey(TrimmedNonEmptyString),
734 /**
735 * Never sent in a config snapshot: the theme stream emits the current set
736 * before any change, so a snapshot carrying it too would hand every
737 * subscriber the same array twice per connect.
738 */
739 environmentThemes: Schema.optional(Schema.Array(EnvironmentTheme)),
740 /** Stream-only and opt-in; the source stream emits the current set on subscribe. */
741 usageLimitSources: Schema.optional(UsageLimitSourceSnapshots),
742});
743export type ServerConfig = typeof ServerConfig.Type;
744​
745export function resolveEnvironmentMachineKind(
746 config: {
747 readonly environment: Pick<ExecutionEnvironmentDescriptor, "platform">;
748 readonly settings?: Pick<ServerSettings, "environmentIcon">;
749 } | null,
750): EnvironmentMachineKind {
751 return config?.settings?.environmentIcon ?? config?.environment.platform.machine ?? "server";
753​
754const ServerUpsertKeybindingReplaceTarget = Schema.Struct({
755 key: KeybindingValue,
756 command: KeybindingCommand,
757 when: Schema.optional(KeybindingWhen),
758});
759​
760export const ServerUpsertKeybindingInput = Schema.Struct({
761 key: KeybindingValue,
762 command: KeybindingCommand,
763 when: Schema.optional(KeybindingWhen),
764 replace: Schema.optional(ServerUpsertKeybindingReplaceTarget),
765});
766export type ServerUpsertKeybindingInput = typeof ServerUpsertKeybindingInput.Type;
767​
768export const ServerRemoveKeybindingInput = ServerUpsertKeybindingReplaceTarget;
769export type ServerRemoveKeybindingInput = typeof ServerRemoveKeybindingInput.Type;
770​
771export const ServerUpsertKeybindingResult = Schema.Struct({
772 keybindings: ResolvedKeybindingsConfig,
773 issues: ServerConfigIssues,
774});
775export type ServerUpsertKeybindingResult = typeof ServerUpsertKeybindingResult.Type;
776​
777export const ServerRemoveKeybindingResult = ServerUpsertKeybindingResult;
778export type ServerRemoveKeybindingResult = typeof ServerRemoveKeybindingResult.Type;
779​
780export const ServerConfigUpdatedPayload = Schema.Struct({
781 issues: ServerConfigIssues,
782 providers: ServerProviders,
783 settings: Schema.optional(ServerSettings),
784});
785export type ServerConfigUpdatedPayload = typeof ServerConfigUpdatedPayload.Type;
786​
787export const ServerConfigKeybindingsUpdatedPayload = Schema.Struct({
788 keybindings: ResolvedKeybindingsConfig,
789 issues: ServerConfigIssues,
790});
791export type ServerConfigKeybindingsUpdatedPayload =
792 typeof ServerConfigKeybindingsUpdatedPayload.Type;
793​
794export const ServerConfigProviderStatusesPayload = Schema.Struct({
795 providers: ServerProviders,
796});
797export type ServerConfigProviderStatusesPayload = typeof ServerConfigProviderStatusesPayload.Type;
798​
799export const ServerConfigProviderStatusDeltasPayload = Schema.Struct({
800 /** Every provider in order, as `serverProviderDeltas` from the list this client last received. */
801 providers: ForwardCompatibleArray(ServerProviderDelta),
802});
803export type ServerConfigProviderStatusDeltasPayload =
804 typeof ServerConfigProviderStatusDeltasPayload.Type;
805​
806export const ServerConfigSettingsUpdatedPayload = Schema.Struct({
807 settings: ServerSettings,
808});
809export type ServerConfigSettingsUpdatedPayload = typeof ServerConfigSettingsUpdatedPayload.Type;
810​
811export const ServerConfigStreamSnapshotEvent = Schema.Struct({
812 version: Schema.Literal(1),
813 type: Schema.Literal("snapshot"),
814 config: ServerConfig,
815});
816export type ServerConfigStreamSnapshotEvent = typeof ServerConfigStreamSnapshotEvent.Type;
817​
818export const ServerConfigStreamKeybindingsUpdatedEvent = Schema.Struct({
819 version: Schema.Literal(1),
820 type: Schema.Literal("keybindingsUpdated"),
821 payload: ServerConfigKeybindingsUpdatedPayload,
822});
823export type ServerConfigStreamKeybindingsUpdatedEvent =
824 typeof ServerConfigStreamKeybindingsUpdatedEvent.Type;
825​
826export const ServerConfigStreamProviderStatusesEvent = Schema.Struct({
827 version: Schema.Literal(1),
828 type: Schema.Literal("providerStatuses"),
829 payload: ServerConfigProviderStatusesPayload,
830});
831export type ServerConfigStreamProviderStatusesEvent =
832 typeof ServerConfigStreamProviderStatusesEvent.Type;
833​
834export const ServerConfigStreamProviderStatusDeltasEvent = Schema.Struct({
835 version: Schema.Literal(1),
836 type: Schema.Literal("providerStatusDeltas"),
837 payload: ServerConfigProviderStatusDeltasPayload,
838});
839export type ServerConfigStreamProviderStatusDeltasEvent =
840 typeof ServerConfigStreamProviderStatusDeltasEvent.Type;
841​
842export const ServerConfigStreamSettingsUpdatedEvent = Schema.Struct({
843 version: Schema.Literal(1),
844 type: Schema.Literal("settingsUpdated"),
845 payload: ServerConfigSettingsUpdatedPayload,
846});
847export type ServerConfigStreamSettingsUpdatedEvent =
848 typeof ServerConfigStreamSettingsUpdatedEvent.Type;
849​
850export const ServerConfigEnvironmentThemesUpdatedPayload = Schema.Struct({
851 themes: Schema.Array(EnvironmentTheme),
852});
853export type ServerConfigEnvironmentThemesUpdatedPayload =
854 typeof ServerConfigEnvironmentThemesUpdatedPayload.Type;
855​
856export const ServerConfigStreamEnvironmentThemesUpdatedEvent = Schema.Struct({
857 version: Schema.Literal(1),
858 type: Schema.Literal("environmentThemesUpdated"),
859 payload: ServerConfigEnvironmentThemesUpdatedPayload,
860});
861export type ServerConfigStreamEnvironmentThemesUpdatedEvent =
862 typeof ServerConfigStreamEnvironmentThemesUpdatedEvent.Type;
863​
864export const ServerConfigUsageLimitSourcesUpdatedPayload = Schema.Struct({
865 sources: UsageLimitSourceSnapshots,
866});
867export type ServerConfigUsageLimitSourcesUpdatedPayload =
868 typeof ServerConfigUsageLimitSourcesUpdatedPayload.Type;
869​
870export const ServerConfigStreamUsageLimitSourcesUpdatedEvent = Schema.Struct({
871 version: Schema.Literal(1),
872 type: Schema.Literal("usageLimitSourcesUpdated"),
873 payload: ServerConfigUsageLimitSourcesUpdatedPayload,
874});
875export type ServerConfigStreamUsageLimitSourcesUpdatedEvent =
876 typeof ServerConfigStreamUsageLimitSourcesUpdatedEvent.Type;
877​
878export const ServerConfigStreamEvent = Schema.Union([
879 ServerConfigStreamSnapshotEvent,
880 ServerConfigStreamKeybindingsUpdatedEvent,
881 ServerConfigStreamProviderStatusesEvent,
882 ServerConfigStreamProviderStatusDeltasEvent,
883 ServerConfigStreamSettingsUpdatedEvent,
884 ServerConfigStreamEnvironmentThemesUpdatedEvent,
885 ServerConfigStreamUsageLimitSourcesUpdatedEvent,
886]);
887export type ServerConfigStreamEvent = typeof ServerConfigStreamEvent.Type;
888​
889export const ServerSelfUpdateOutcome = Schema.Struct({
890 id: TrimmedNonEmptyString,
891 fromVersion: TrimmedNonEmptyString,
892 targetVersion: TrimmedNonEmptyString,
893 status: Schema.Literals(["committed", "rolled-back", "failed"]),
894 reason: Schema.optionalKey(TrimmedNonEmptyString),
895});
896export type ServerSelfUpdateOutcome = typeof ServerSelfUpdateOutcome.Type;
897​
898export const ServerLifecycleReadyPayload = Schema.Struct({
899 at: IsoDateTime,
900 environment: ExecutionEnvironmentDescriptor,
901 updateOutcome: Schema.optionalKey(ServerSelfUpdateOutcome),
902});
903export type ServerLifecycleReadyPayload = typeof ServerLifecycleReadyPayload.Type;
904​
905export const ServerLifecycleWelcomePayload = Schema.Struct({
906 environment: ExecutionEnvironmentDescriptor,
907 cwd: TrimmedNonEmptyString,
908 projectName: TrimmedNonEmptyString,
909 bootstrapStatus: Schema.optional(Schema.Literals(["pending", "complete"])),
910 bootstrapProjectId: Schema.optional(ProjectId),
911 bootstrapThreadId: Schema.optional(ThreadId),
912 bootstrapProjectCreated: Schema.optional(Schema.Boolean),
913 bootstrapThreadCreated: Schema.optional(Schema.Boolean),
914});
915export type ServerLifecycleWelcomePayload = typeof ServerLifecycleWelcomePayload.Type;
916​
917export const ServerLifecycleLegacyThreadMigrationPayload = Schema.Struct({
918 status: Schema.Union([Schema.Literal("running"), Schema.Literal("complete")]),
919 totalThreadCount: NonNegativeInt,
920});
921export type ServerLifecycleLegacyThreadMigrationPayload =
922 typeof ServerLifecycleLegacyThreadMigrationPayload.Type;
923​
924export const ServerLifecycleStreamWelcomeEvent = Schema.Struct({
925 version: Schema.Literal(1),
926 sequence: NonNegativeInt,
927 type: Schema.Literal("welcome"),
928 payload: ServerLifecycleWelcomePayload,
929});
930export type ServerLifecycleStreamWelcomeEvent = typeof ServerLifecycleStreamWelcomeEvent.Type;
931​
932export const ServerLifecycleStreamReadyEvent = Schema.Struct({
933 version: Schema.Literal(1),
934 sequence: NonNegativeInt,
935 type: Schema.Literal("ready"),
936 payload: ServerLifecycleReadyPayload,
937});
938export type ServerLifecycleStreamReadyEvent = typeof ServerLifecycleStreamReadyEvent.Type;
939​
940export const ServerLifecycleStreamLegacyThreadMigrationEvent = Schema.Struct({
941 version: Schema.Literal(1),
942 sequence: NonNegativeInt,
943 type: Schema.Literal("legacyThreadMigration"),
944 payload: ServerLifecycleLegacyThreadMigrationPayload,
945});
946export type ServerLifecycleStreamLegacyThreadMigrationEvent =
947 typeof ServerLifecycleStreamLegacyThreadMigrationEvent.Type;
948​
949export const ServerLifecycleStreamEvent = Schema.Union([
950 ServerLifecycleStreamWelcomeEvent,
951 ServerLifecycleStreamReadyEvent,
952 ServerLifecycleStreamLegacyThreadMigrationEvent,
953]);
954export type ServerLifecycleStreamEvent = typeof ServerLifecycleStreamEvent.Type;
955​
956export const ServerProviderUpdatedPayload = Schema.Struct({
957 providers: ServerProviders,
958});
959export type ServerProviderUpdatedPayload = typeof ServerProviderUpdatedPayload.Type;
960​
961export const ServerProviderUpdateInput = Schema.Struct({
962 provider: ProviderDriverKind,
963 targetVersion: Schema.optionalKey(TrimmedNonEmptyString),
964 instanceId: Schema.optionalKey(ProviderInstanceId),
965});
966export type ServerProviderUpdateInput = typeof ServerProviderUpdateInput.Type;
967​
968export class ServerProviderUpdateError extends Schema.TaggedError<ServerProviderUpdateError>()(
969 "ServerProviderUpdateError",
970 {
971 provider: ProviderDriverKind,
972 reason: TrimmedNonEmptyString,
973 cause: Schema.optional(Schema.Defect()),
974 },
975) {
976 override get message(): string {
977 return `Provider update failed for ${this.provider}: ${this.reason}`;
978 }
980​
981export const ServerNpmReleaseInput = Schema.Struct({
982 spec: Schema.String.check(
983 Schema.isMaxLength(64),
984 Schema.isPattern(/^(?:latest|nightly|\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?)$/),
985 ),
986});
987export type ServerNpmReleaseInput = typeof ServerNpmReleaseInput.Type;
988​
989export const ServerNpmRelease = Schema.Struct({
990 version: Schema.String,
991 databaseMigration: Schema.optionalKey(Schema.Int),
992});
993export type ServerNpmRelease = typeof ServerNpmRelease.Type;
994​
995export class ServerNpmReleaseError extends Schema.TaggedError<ServerNpmReleaseError>()(
996 "ServerNpmReleaseError",
997 { reason: Schema.String },
998) {
999 override get message(): string {
1000 return `Could not check the configured npm registry: ${this.reason}`;
1003​
1004export const ServerSelfUpdateInput = Schema.Struct({
1005 /** Exact npm version, never a dist-tag, so server and client agree on the request. */
1006 targetVersion: TrimmedNonEmptyString,
1007 /** Desktop-managed hosts move their app to this update track first. Sent only for a track switch. */
1008 channel: Schema.optionalKey(DesktopUpdateChannelSchema),
1009 /** The target release's highest migration; the host refuses to leave Nightly without it. */
1010 targetDatabaseMigration: Schema.optionalKey(Schema.Int),
1011});
1012export type ServerSelfUpdateInput = typeof ServerSelfUpdateInput.Type;
1013​
1014export const ServerSelfUpdateResult = Schema.Struct({
1015 targetVersion: TrimmedNonEmptyString,
1016 method: ServerSelfUpdateMethod,
1017 updateId: Schema.optionalKey(TrimmedNonEmptyString),
1018 desktopUpdateToken: Schema.optionalKey(TrimmedNonEmptyString),
1019});
1020export type ServerSelfUpdateResult = typeof ServerSelfUpdateResult.Type;
1021​
1022export const DesktopUpdateCommitInput = Schema.Struct({
1023 requestId: TrimmedNonEmptyString,
1024});
1025export type DesktopUpdateCommitInput = typeof DesktopUpdateCommitInput.Type;
1026​
1027export const ServerSelfUpdateProgressStage = Schema.Literals(["downloading", "installing"]);
1028export type ServerSelfUpdateProgressStage = typeof ServerSelfUpdateProgressStage.Type;
1029​
1030export const ServerSelfUpdateProgressEvent = Schema.Union([
1031 Schema.Struct({
1032 type: Schema.Literal("progress"),
1033 stage: ServerSelfUpdateProgressStage,
1034 }),
1035 Schema.Struct({
1036 type: Schema.Literal("complete"),
1037 result: ServerSelfUpdateResult,
1038 }),
1039]);
1040export type ServerSelfUpdateProgressEvent = typeof ServerSelfUpdateProgressEvent.Type;
1041​
1042export class ServerSelfUpdateError extends Schema.TaggedError<ServerSelfUpdateError>()(
1043 "ServerSelfUpdateError",
1045 reason: TrimmedNonEmptyString,
1046 cause: Schema.optional(Schema.Defect()),
1047 },
1048) {
1049 override get message(): string {
1050 return `Server update failed: ${this.reason}`;