Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 19 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -797,11 +797,25 @@ RUN dnf install -y clang gcc-c++ && dnf clean all \
&& mkdir -p /usr/lib/llvm-${CLANG_VERSION}/lib \
&& ln -sf /usr/lib/clang /usr/lib/llvm-${CLANG_VERSION}/lib/clang

# The `manylinux` image comes with multiple Python versions. We'll use
# 3.10 to match our main build environment. Set up symlinks so `python`
# and `python3` point to Python 3.10.
RUN ln -sf /opt/python/cp310-cp310/bin/python /usr/local/bin/python \
&& ln -sf /opt/python/cp310-cp310/bin/python /usr/local/bin/python3 \
# The `manylinux` image comes with multiple Python versions, but all
# of them are built `--disable-shared` with no `libpython` installed,
# and embedding Python — which building `reboot_native.node` does —
# needs `-lpython3.10` at link time. Point `python` and `python3` at a
# python-build-standalone CPython 3.10 instead, which ships
# `libpython3.10.so`; it is the same build
# `reboot/nodejs/prepare_environment.sh` uses. `pip` and `pip3` stay
# on the manylinux 3.10, whose layout `auditwheel` and the wheel
# builds expect, so `python3` and `pip` deliberately name different
# installations.
RUN set -e; \
if [ "${TARGETARCH}" = "amd64" ]; then ARCH=x86_64; else ARCH=aarch64; fi; \
mkdir /tmp/python-build-standalone; \
wget -qO- "https://github.com/indygreg/python-build-standalone/releases/download/20240814/cpython-3.10.14+20240814-${ARCH}-unknown-linux-gnu-install_only.tar.gz" \
| tar -xzf - -C /tmp/python-build-standalone \
&& mv /tmp/python-build-standalone/python /opt/reboot-python \
&& rmdir /tmp/python-build-standalone \
&& ln -sf /opt/reboot-python/bin/python3 /usr/local/bin/python \
&& ln -sf /opt/reboot-python/bin/python3 /usr/local/bin/python3 \
&& ln -sf /opt/python/cp310-cp310/bin/pip /usr/local/bin/pip \
&& ln -sf /opt/python/cp310-cp310/bin/pip /usr/local/bin/pip3

Expand Down
67 changes: 67 additions & 0 deletions rbt/dashboard/v1/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
load(
"@com_github_reboot_dev_reboot//reboot:rules.bzl",
"js_proto_library",
"js_reboot_library",
"js_reboot_react_library",
"py_reboot_library",
)
load("@com_google_protobuf//bazel:proto_library.bzl", "proto_library")

proto_library(
name = "dashboard_proto",
srcs = [
":dashboard.proto",
],
visibility = ["//visibility:public"],
deps = [
"@com_github_reboot_dev_reboot//rbt/v1alpha1:options_proto",
],
)

py_reboot_library(
name = "dashboard_py_reboot",
proto = "dashboard.proto",
proto_library = ":dashboard_proto",
visibility = ["//visibility:public"],
)

js_proto_library(
name = "dashboard_js_proto",
package_json = ":package.json",
proto = "dashboard.proto",
proto_deps = [
":dashboard_proto",
# ISSUE(https://github.com/reboot-dev/mono/issues/3218): Until we can
# use `create_protoc_plugin_rule` we need to repeat the dependencies of
# the `proto_libraries` here.
"@com_github_reboot_dev_reboot//rbt/v1alpha1:options_proto",
"@com_google_protobuf//:descriptor_proto",
],
visibility = ["//visibility:public"],
)

js_reboot_library(
name = "dashboard_js_reboot",
srcs = [
":dashboard_proto",
],
proto = "dashboard.proto",
visibility = ["//visibility:public"],
deps = [
":dashboard_js_proto",
],
)

js_reboot_react_library(
name = "dashboard_js_reboot_react",
srcs = [
":dashboard_js_proto",
],
proto = "dashboard.proto",
proto_deps = [
":dashboard_proto",
"@com_github_reboot_dev_reboot//rbt/v1alpha1:options_proto",
"@com_google_protobuf//:descriptor_proto",
],
visibility = ["//visibility:public"],
)
176 changes: 176 additions & 0 deletions rbt/dashboard/v1/dashboard.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
syntax = "proto3";

package rbt.dashboard.v1;

import "rbt/v1alpha1/options.proto";

////////////////////////////////////////////////////////////////////////

// The information the developer dashboard needs to display data
// about the Reboot application being developed.

message FieldInfo {
string name = 1;
string type = 2;
}

message MethodInfo {
string name = 1;
string kind = 2;
repeated FieldInfo arguments = 3;
repeated FieldInfo returns = 4;
repeated string errors = 5;
optional string description = 6;
bool factory = 7;
bool mcp = 8;
}

message StateTypeInfo {
string name = 1;

// The file the developer declared it in, e.g.
// "bank/v1/account.py".
string file = 2;
repeated FieldInfo fields = 3;
repeated MethodInfo methods = 4;

// What the state type does, in the author's own words.
optional string description = 5;
}

////////////////////////////////////////////////////////////////////////

// What the dashboard application has read of the developer's API
// files, so that a browser can read it without reaching the
// application itself.
message API {
option (rbt.v1alpha1.state) = {
};

// The state types the developer's API files declare, which exist
// before the application does.
repeated StateTypeInfo state_types = 1;

// Why the API files could not be read, if they could not be. A
// half-written file is the normal case while someone is typing, and
// saying so beats showing nothing.
string error = 2;
}

message APIGetRequest {}

message APIGetResponse {
repeated StateTypeInfo state_types = 1;
string error = 2;
}

message APIUpdateRequest {
repeated StateTypeInfo state_types = 1;
string error = 2;
}

message APIUpdateResponse {}

message APIWatchRequest {}

message APIWatchResponse {}

////////////////////////////////////////////////////////////////////////

// What the developer has told the dashboard about opening dashboards.
//
// Kept here rather than in a file under their project because it is a
// fact about their machine and their browser, not about their
// application, and nothing about it belongs in their repository. It
// survives a hot reload and an `rbt dev run` restart because the
// dashboard application's state store does.
message Preferences {
option (rbt.v1alpha1.state) = {
};

// Whether the developer has asked `rbt dev run` to stop opening a
// dashboard by itself. Recorded as the exception rather than as
// the rule, so that somebody who has never chosen gets a dashboard
// opened when nobody is looking at one.
//
// `--open-dashboard` opens one whatever this says.
bool suppress_open_on_restart = 1;

// The state types whose methods the developer has opened on the
// dashboard, by fully qualified name such as `bank.v1.Account`.
// Held as the set that is open rather than the set that is closed,
// so that somebody who has clicked nothing gets a page where every
// state type shows its methods but none of their detail.
//
// Kept sorted, so that clicking two state types open in one order
// and then the other stores the same thing both times.
repeated string expanded_state_types = 2;
}

message PreferencesGetRequest {}

message PreferencesGetResponse {
bool suppress_open_on_restart = 1;
repeated string expanded_state_types = 2;
}

message PreferencesSetSuppressOpenOnRestartRequest {
bool suppress_open_on_restart = 1;
}

message PreferencesSetSuppressOpenOnRestartResponse {}

message PreferencesSetExpandedRequest {
// The fully qualified name of one state type, spelled the way
// `StateTypeInfo` spells it.
string state_type = 1;

bool expanded = 2;
}

message PreferencesSetExpandedResponse {}

////////////////////////////////////////////////////////////////////////

service APIMethods {
rpc Get(APIGetRequest) returns (APIGetResponse) {
option (rbt.v1alpha1.method).reader = {
};
}

rpc Update(APIUpdateRequest) returns (APIUpdateResponse) {
option (rbt.v1alpha1.method).writer = {
};
}

// Watches the developer's API files for as long as the dashboard
// application runs, reading each one that changes.
rpc Watch(APIWatchRequest) returns (APIWatchResponse) {
option (rbt.v1alpha1.method).workflow = {
};
}
}

////////////////////////////////////////////////////////////////////////

service PreferencesMethods {
rpc Get(PreferencesGetRequest) returns (PreferencesGetResponse) {
option (rbt.v1alpha1.method).reader = {
};
}

rpc SetSuppressOpenOnRestart(PreferencesSetSuppressOpenOnRestartRequest)
returns (PreferencesSetSuppressOpenOnRestartResponse) {
option (rbt.v1alpha1.method).writer = {
};
}

// One state type per call rather than the whole set, so that two
// tabs opening two different state types at the same moment do not
// each write back a set that predates the other's click.
rpc SetExpanded(PreferencesSetExpandedRequest)
returns (PreferencesSetExpandedResponse) {
option (rbt.v1alpha1.method).writer = {
};
}
}
3 changes: 3 additions & 0 deletions rbt/dashboard/v1/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"type": "module"
}
16 changes: 16 additions & 0 deletions rbt/std/presence/v1/presence.proto
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ message Presence {
* `Subscriber` using the API described there.
*/
service PresenceMethods {
/**
* Constructs the `Presence` instance, empty, so that `List`
* answers before the first `Subscribe`.
*/
rpc Create(CreateRequest) returns (CreateResponse) {
option (rbt.v1alpha1.method).writer = {
};
}

/**
* Registers a subscriber as present.
*
Expand Down Expand Up @@ -54,6 +63,13 @@ service PresenceMethods {

////////////////////////////////////////////////////////////////////////

// See `Create`.
message CreateRequest {}

message CreateResponse {}

////////////////////////////////////////////////////////////////////////

// See `Subscribe`.
message SubscribeRequest {
// The subscriber to register as present.
Expand Down
14 changes: 12 additions & 2 deletions rbt/v1alpha1/options.proto
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,9 @@ message McpMethodOptions {
optional bool resource = 2;
// Custom name for the tool/resource (defaults to method name).
optional string name = 3;
// Description for the tool/resource.
optional string description = 4;
// Deprecated: write `MethodOptions.description` instead. Read as a
// fallback when it is the only description present.
optional string description = 4 [deprecated = true];
// Display title for the tool/resource.
optional string title = 5;
}
Expand Down Expand Up @@ -102,6 +103,9 @@ message MethodOptions {

// MCP options for exposing this method as a tool or resource.
optional McpMethodOptions mcp = 9;

// What this method does, in the author's own words.
optional string description = 10;
}

extend google.protobuf.MethodOptions {
Expand Down Expand Up @@ -159,6 +163,12 @@ message StateOptions {
// `RBT_VALIDATE_TRUSTED_EFFECTS` is set. See
// https://github.com/reboot-dev/mono/issues/4499.
bool trusted_effects = 4;

// What the state type does, in the author's own words. Worth
// writing about the parts a reader cannot derive, such as what it
// is the consistency boundary for, rather than restating the
// methods listed beside it.
optional string description = 5;
}

extend google.protobuf.MessageOptions {
Expand Down
1 change: 1 addition & 0 deletions reboot/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,7 @@ py_library(
":python_thirdparty",
"//reboot/aio:python",
"//reboot/cli:main_py",
"//reboot/dashboard:main_py",
"//reboot/mcp:python",
"//reboot/nodejs:python",
"@com_github_reboot_dev_reboot//protoc_gen_mypy_plugin:protoc-gen-mypy",
Expand Down
Loading
Loading