docs/language-server/protocol-project-manager.md
This document contains the specification of the Enso protocol messages that pertain to the project manager component. Please familiarise yourself with the common features of the protocol before reading this document.
For information on the design and architecture of the protocol, as well as its transport formats, please look here.
<!-- MarkdownTOC levels="2,3" autolink="true" -->MissingComponentErrorBrokenComponentErrorProjectManagerUpgradeRequiredComponentInstallationErrorComponentUninstallationErrorComponentRepositoryUnavailableProjectNameValidationErrorProjectDataStoreErrorProjectExistsErrorProjectNotFoundErrorProjectOpenErrorProjectNotOpenErrorProjectOpenByOtherPeersErrorCannotRemoveOpenProjectErrorProjectCloseErrorLanguageServerErrorGlobalConfigurationAccessErrorProjectCreateErrorLoggingServiceUnavailableThere are a number of types that are used only within the project server's protocol messages. These are specified here.
ProjectMetadataThis type represents information about a project.
interface ProjectMetadata {
/**
* The name of the project.
*/
name: String;
/**
* The namespace of the project.
*/
namespace: String;
/**
* The project id.
*/
id: UUID;
/**
* Enso Engine version to use for the project, represented by a semver version
* string.
*
* If the edition associated with the project could not be resolved, the
* engine version may be missing.
*/
engineVersion?: String;
/**
* The project creation time.
*/
created: UTCDateTime;
/**
* The last opened datetime.
*/
lastOpened?: UTCDateTime;
}
MissingComponentActionThis type specifies what action should be taken if a component required to complete an operation is missing.
Fail will make the operation fail if any components are missing.Install will try to install any missing components, unless they are marked
as broken.ForceInstallBroken will try to install all missing components, even if some
of them are marked as broken.type MissingComponentAction = Fail | Install | ForceInstallBroken;
ProgressUnitThis type specifies the unit of progress updates related to a task.
type ProgressUnit = Bytes | Other;
EngineVersionThis type represents an installed or available engine version.
interface EngineVersion {
/** Semver string of engine version. */
version: String;
/** Specifies if that version is marked as broken. */
markedAsBroken: bool;
}
RunningStateThis type represents information about a state of the (potentially) running project.
interface RunningStatus {
/**
* If true, the project is open and (still) accepting new connections.
* False, if the project is currently shutdown.
*/
open: bool;
/**
* If true, the project is currently running but in a soft shutdown mode.
* False, if the project is either not running or it is not shutting down.
*/
shuttingDown: bool;
}
FileSystemEntryA directory entry in the fileystem operations.
type FileSystemEntry = FileEntry | DirectoryEntry | ProjectEntry;
interface FileEntry {
path: string;
attributes: Attributes;
}
interface DirectoryEntry {
path: string;
attributes: Attributes;
}
interface ProjectEntry {
path: string;
attributes: Attributes;
metadata: ProjectMetadata;
}
AttributesBasic attributes of a filesystem entry.
interface Attributes {
creationTime: UTCDateTime;
lastAccessTime: UTCDateTime;
lastModifiedTime: UTCDateTime;
byteSize: number;
}
UTCDateTimeTime in UTC time zone represented as ISO-8601 string.
type UTCDateTime = string;
The project-manager binary provides Cli interface to do basic filesystem operations.
List directory returning information about filesystem entries together with the project metadata if the listed directory contains a project.
project-manager --filesystem-list {path}
{
entries: FileSystemEntry[];
}
ProjectDataStoreError to signal problems with
underlying data store.Create directory with the specified path.
project-manager --filesystem-create-directory {path}
null;
ProjectDataStoreError to signal problems with
underlying data store.Deletes directory with the specified path.
project-manager --filesystem-delete-directory {path}
null;
ProjectDataStoreError to signal problems with
underlying data store.Moves file or directory from target path to the destination path.
project-manager --filesystem-move-from {path} --filesystem-move-to {path}
null;
ProjectDataStoreError to signal problems with
underlying data store.Read the provided path and return the contents to stdout.
project-manager --filesystem-read-path {path}
null;
ProjectDataStoreError to signal problems with
underlying data store.Writes bytes from stdin to the provided path.
echo 'Hello World!' | project-manager --filesystem-write-path {path}
null;
ProjectDataStoreError to signal problems with
underlying data store.The primary responsibility of the project managers is to allow users to manage their projects.
project/openThis message requests that the project manager open a specified project. This operation also includes spawning an instance of the language server open on the specified project.
To open a project, an engine version that is specified in project settings needs
to be installed. If missingComponentAction is set to Install or
ForceInstallBroken, this action will install any missing components,
otherwise, an error will be reported if a component is missing. A typical usage
scenario may consist of first trying to open the project without installing
missing components. If that fails with the MissingComponentError, the client
can ask the user if they want to install the missing components and re-attempt
the action.
/**
* Extra parameters required for cloud projects.
*/
interface CloudParams {
cloudProjectDirectoryPath: string;
cloudProjectId: string;
cloudProjectSessionId: string;
}
interface OpenProjectParams {
projectId: UUID;
/**
* Specifies how to handle missing components.
*
* If not provided, defaults to `Fail`.
*/
missingComponentAction?: MissingComponentAction;
/**
* Custom directory with the user projects.
*/
projectsDirectory?: string;
/**
* Extra cloud parameters required when running in hybrid mode.
*/
cloud?: CloudParams;
}
{
/**
* The version of the started language server represented by a semver version
* string.
*/
engineVersion: String;
/**
* The endpoint used for JSON-RPC protocol.
*/
languageServerJsonAddress: IPWithSocket;
/**
* The optional endpoint used for secure JSON-RPC protocol.
*/
languageServerSecureJsonAddress?: IPWithSocket;
/**
* The endpoint used for binary protocol.
*/
languageServerBinaryAddress: IPWithSocket;
/**
* The optional endpoint used for secure binary protocol.
*/
languageServerSecureBinaryAddress?: IPWithSocket;
// The name of the project as it is opened.
projectName: String;
// The normalized name of the project.
projectNormalizedName: String;
// The namespace of the project.
projectNamespace: String;
}
ProjectNotFoundError to signal that the project
doesn't exist.ProjectDataStoreError to signal problems with
underlying data store.ProjectOpenError to signal failures during server boot.MissingComponentError to signal that the component
required to open the project was missing (only in case
missingComponentAction was set to fail).BrokenComponentError to signal that the component
required to open the project was being installed but is marked as broken (only
in case missingComponentAction was set to install).ComponentInstallationError to signal that the
installation of a missing component has failed.ProjectManagerUpgradeRequired to signal
that the requested engine version requires a more recent project manager, so
an upgrade has to be performed before continuing.project/closeThis message requests that the project manager close a specified project. This operation includes shutting down the language server gracefully so that it can persist state to disk as needed.
interface ProjectCloseRequest {
projectId: UUID;
}
{
}
ProjectNotFoundError to signal that the project
doesn't exist.ProjectDataStoreError to signal problems with
underlying data store.ProjectCloseError to signal failures that occurred
during language server stoppage.ProjectNotOpenError to signal cannot close a project
that is not open.ProjectOpenByOtherPeersError to signal that
cannot close a project that is open by other clients.project/listThis message requests that the project manager lists all user's projects. The list of projects is sorted by the open time.
interface ProjectListRequest {
numberOfProjects?: Int;
}
interface ProjectListResponse {
projects: [ProjectMetadata];
}
ProjectDataStoreError to signal problems with
underlying data store.GlobalConfigurationAccessError to signal
that the global configuration file could not be accessed or parsed.project/createThis message requests the creation of a new project.
To create a project, an engine version associated with it needs to be installed.
Depending on missingComponentAction, any components required to complete the
operation are missing will be installed or a failure will be reported.
interface ProjectCreateRequest {
/** Name of the project to create. */
name: String;
/** The name of the project template to create. */
projectTemplate?: String;
/**
* Enso Engine version to use for the project.
*
* Possible values are:
* - a semver version string identifying an Enso engine version,
* - `default` to use the current default.
*
* The field is optional - if it is missing, it is treated as `default`.
*/
version?: String;
/**
* Specifies how to handle missing components.
*
* If not provided, defaults to `Fail`.
*/
missingComponentAction?: MissingComponentAction;
/**
* Custom directory with the user projects.
*/
projectsDirectory?: string;
}
interface ProjectCreateResponse {
projectId: UUID;
projectName: string;
projectNormalizedName: string;
}
ProjectNameValidationError to signal
validation failures.ProjectDataStoreError to signal problems with
underlying data store.ProjectExistsError to signal that the project already
exists.MissingComponentError to signal that the component
required to create the project was missing (only in case
missingComponentAction was set to fail).BrokenComponentError to signal that the component
required to create the project was being installed but is marked as broken
(only in case missingComponentAction was set to install).ComponentInstallationError to signal that the
installation of a missing component has failed.ProjectManagerUpgradeRequired to signal
that the requested engine version requires a more recent project manager, so
an upgrade has to be performed before continuing.project/renameThis message requests the renaming of a project.
interface ProjectRenameRequest {
projectId: UUID;
name: String;
/**
* Custom directory with the user projects.
*/
projectsDirectory?: string;
}
null
ProjectNameValidationError to signal
validation failures.ProjectDataStoreError to signal problems with
underlying data store.ProjectExistsError to signal that the project with
the provided name already exists.ServiceError to signal that the the
operation timed out.LanguageServerError to signal generic language
server failures.project/deleteThis message requests the deletion of a project.
interface ProjectDeleteRequest {
projectId: UUID;
/**
* Custom directory with the user projects.
*/
projectsDirectory?: string;
}
{
}
ProjectDataStoreError to signal problems with
underlying data store.ProjectNotFoundError to signal that the project
doesn't exist.CannotRemoveOpenProjectError to signal that
the project cannot be removed, because is open by at least one user.project/listSampleThis request lists the sample projects that are available to the user.
interface ProjectListSampleRequest {
numProjects: Int;
}
interface ProjectListSampleResponse {
projects: [ProjectMetadata];
}
TBC
project/statusThis request asks for the current state of the project.
interface ProjectStatusRequest {
projectID: UUID;
}
interface ProjectStatusResponse {
status: RunningStatus;
}
project/duplicateThis message requests to make a copy of the project.
interface ProjectDuplicateRequest {
/**
* The project to duplicate.
*/
projectId: UUID;
/**
* Custom directory with the user projects.
*/
projectsDirectory?: string;
}
interface ProjectDuplicateResponse {
projectId: UUID;
projectName: string;
projectNormalizedName: string;
}
ProjectDataStoreError to signal problems with
underlying data store.ProjectNotFoundError to signal that the project
doesn't exist.ServiceError to signal that the the
operation timed out.Some actions, especially those related to installation of new components may take a long time (for example because big packages need to be downloaded).
The protocol includes notifications tied to such actions that can be used to display progress bars.
Each task has a lifecycle of being initialized with a task/started
notification (which contains a UUID that identifies that task), being updated
with task/progress-update and finalized with task/finished. task/finished
may include an error (but please note that regardless of the task-related error,
the error will also be reported for the original request associated with the
task, for example as ComponentInstallationError returned for the
project/open request that triggered the installation).
Tasks are sent while an operation is being processed and a single operation may consist of several (sub)tasks.
For example, when opening a project the flow may be following:
project/open request sent to the servertask/started (downloading the archive)task/progress-update related to that tasktask/finishedtask/started (extracting the archive)task/progress-update related to that tasktask/finishedproject/open requestAll task progress updates happen within the response/request flow (up to a possible reordering of messages).
task/startedIndicates that a long running task has been started.
Currently only used when components are being installed to show installation progress.
interface TaskStartNotification {
/**
* Unique identifier of the task, used to correlate progress updates and the
* finished notification.
*/
taskId: UUID;
/**
* Name of the operation this task is related to, for example
* `project/open`.
*/
relatedOperation: String;
/** Unit in which progress of this task is measured. */
unit: ProgressUnit;
/**
* Indicates total expected progress.
*
* May be missing, as it is not always known, for example when downloading a
* file of unknown size or waiting on a lock.
*/
total?: Long;
}
task/progress-updateIndicates a progress update for a specific task.
interface TaskUpdateNotification {
taskId: UUID;
/** Optional message explaining current status of the task. */
message?: String;
/** Indicates amount of progress, for example: count of processed bytes. */
done: Long;
}
task/finishedIndicates that a task has been finished, either successfully or with an error.
interface TaskFinishedNotification {
taskId: UUID;
/** Optional message informing about task completion. */
message?: String;
/** Specifies if the task succeeded or failed. */
success: bool;
}
engine/list-installedLists engine versions currently installed.
Please note that the broken marks associated with each engine currently represent the state at the moment of installation. As of now, if the broken mark has been added later, it is not updated automatically.
null;
interface EngineVersionListResponse {
/** List of installed engines. */
versions: [EngineVersion];
}
TBC
engine/list-availableQueries the repository to list all engine versions that are available to be installed.
null;
interface EngineVersionListResponse {
/** List of available engines. */
versions: [EngineVersion];
}
ComponentRepositoryUnavailable to signal
that the component repository could not be reached.engine/installRequests to install the specified engine version. If that version is already installed, it has no effect.
interface EngineInstallRequest {
/** Semver string of engine version that should be installed. */
version: String;
/**
* Specifies whether the engine should be installed even if it is marked as
* broken.
*
* If not provided, defaults to `false`.
*/
forceInstallBroken?: bool;
}
null;
BrokenComponentError to signal that the requested
engine version is marked as broken (only in case forceInstallBroken was set
to false).ComponentInstallationError to signal that the
installation of a missing component has failed.ProjectManagerUpgradeRequired to signal
that the requested engine version requires a more recent project manager, so
an upgrade has to be performed before continuing.engine/uninstallRequests to uninstall the specified engine version.
If that version was not installed, it has no effect.
interface EngineUninstallRequest {
/** Semver string of engine version that should be uninstalled. */
version: String;
}
null;
ComponentUninstallationError to signal that
the component could not have been uninstalled.logging-service/get-endpointRequests the endpoint for connecting to the logging service.
null;
interface LoggingServiceEndpointResponse {
uri: String;
}
LoggingServiceUnavailable to signal that the
logging service is unavailable.The project manager is also responsible for managing the language server. This means that it needs to be able to spawn the process, but also tell the process when to shut down.
A language server process is spawned within the project/open call. That call
returns endpoints that the client can use to connect to the language server.
When project/close is called, the language server is shutdown. Moreover,
between these two calls, the project manager sends heartbeat messages to the
language server to check if it is still running. In case that it has crashed, a
restart is attempted.
The project manager component has its own set of errors. This section is not a complete specification and will be updated as new errors are added.
Besides the required code and message fields, the errors may have a data
field which can store additional error-specific payload.
MissingComponentErrorSignals that a component required to complete the action was missing, but the action did not ask for it to be automatically installed.
"error" : {
"code" : 4020,
"message" : "Engine 1.2.3 is required to complete the action but it is not installed."
}
BrokenComponentErrorSignals that a component that was being installed is marked as broken, but the option to forcibly install broken components was not set.
This error may handled by warning the user about the broken version or suggesting to upgrade the project and asking to confirm using the broken version. If the user wants to ignore the warning, the operation can be reattempted with the option to forcibly install broken components.
"error" : {
"code" : 4021,
"message" : "Engine 1.2.3 is marked as broken."
}
ProjectManagerUpgradeRequiredSignals that installation of a missing compoment has been attempted, but the required engine version requires a newer version of project manager than what is currently running.
This error type includes the optional data field which is an object with a
field minimumRequiredVersion that is a semver string of the project manager
version that is required to complete the related action.
"error" : {
"code" : 4022,
"message" : "Project manager 1.2.3 is required to install the requested engine. Please upgrade.",
"payload": {
"minimumRequiredVersion": "1.2.3"
}
}
ComponentInstallationErrorSignals that installation of a missing component has been attempted but it has failed.
"error" : {
"code" : 4023,
"message" : "A problem occurred when trying to find the release: Cannot find release `enso-1.2.3-not-published`."
}
ComponentUninstallationErrorSignals that uninstallation of a component has failed.
"error" : {
"code" : 4024,
"message" : "The requested engine version is not installed."
}
ComponentRepositoryUnavailableSignals that the repository is unavailable and could not be queried (usually caused by lack of internet connection).
"error" : {
"code" : 4025,
"message" : "Could not connect to github.com"
}
ProjectNameValidationErrorSignals validation failures.
"error" : {
"code" : 4001,
"message" : "Cannot create project with empty name"
}
ProjectDataStoreErrorSignals problems with underlying data store.
"error" : {
"code" : 4002,
"message" : "Cannot load project index"
}
ProjectExistsErrorSignals that the project already exists.
"error" : {
"code" : 4003,
"message" : "Project with the provided name exists"
}
ProjectNotFoundErrorSignals that the project doesn't exist.
"error" : {
"code" : 4004,
"message" : "Project with the provided id does not exist"
}
ProjectOpenErrorSignals that the project cannot be open due to boot failures.
"error" : {
"code" : 4005,
"message" : "A boot failure."
}
ProjectNotOpenErrorSignals that cannot close project that is not open.
"error" : {
"code" : 4006,
"message" : "Cannot close project that is not open"
}
ProjectOpenByOtherPeersErrorSignals that cannot close a project that is open by other clients.
"error" : {
"code" : 4007,
"message" : "Cannot close project because it is open by other peers"
}
CannotRemoveOpenProjectErrorSignals that cannot remove open project.
"error" : {
"code" : 4008,
"message" : "Cannot remove open project"
}
ProjectCloseErrorSignals failures during shutdown of a server.
"error" : {
"code" : 4009,
"message" : "A shutdown failure."
}
LanguageServerErrorSignals generic language server errors.
"error" : {
"code" : 4010,
"message" : "The language server is unresponsive"
}
GlobalConfigurationAccessErrorSignals that the global configuration file could not be accessed or parsed.
"error" : {
"code" : 4011,
"message" : "The global configuration file is malformed."
}
ProjectCreateErrorSignals that an error occurred when creating the project.
"error" : {
"code" : 4012,
"message" : "Could not create the project."
}
LoggingServiceUnavailableSignals that the logging service is not available.
"error" : {
"code" : 4013,
"message" : "The logging service has failed to boot."
}