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
1 change: 1 addition & 0 deletions docs/docs/config.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ wsh editconfig
| term:macoptionismeta | bool | on macOS, treat the Option key as Meta key for terminal keybindings (default false) |
| term:bellsound <VersionBadge version="v0.14" /> | bool | when enabled, plays the system beep sound when the terminal bell (BEL character) is received (default false) |
| term:bellindicator <VersionBadge version="v0.14" /> | bool | when enabled, shows a visual indicator in the tab when the terminal bell is received (default false) |
| term:exitindicator <VersionBadge version="v0.14" /> | bool | when enabled, shows a colored tab indicator when a process exits — green for success, red for error (default false) |
| term:durable <VersionBadge version="v0.14" /> | bool | makes remote terminal sessions durable across network disconnects (defaults to false) |
| editor:minimapenabled | bool | set to false to disable editor minimap |
| editor:stickyscrollenabled | bool | enables monaco editor's stickyScroll feature (pinning headers of current context, e.g. class names, method names, etc.), defaults to false |
Expand Down
54 changes: 54 additions & 0 deletions frontend/app/tab/tab.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,28 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0

// Animate a shared breathing phase on :root so all indicator tabs pulse in sync.
// Uses CSS @property for an animatable custom property (Chromium 78+).
@property --breathe-phase {
syntax: "<number>";
initial-value: 0;
inherits: true;
}

:root {
animation: indicatorBreathePhase 16s ease-in-out infinite;
}

@keyframes indicatorBreathePhase {
0%,
100% {
--breathe-phase: 0;
}
50% {
--breathe-phase: 1;
}
}
Comment on lines +6 to +24
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Rename keyframes to kebab-case to satisfy Stylelint.

indicatorBreathePhase triggers the keyframes-name-pattern rule. Rename to indicator-breathe-phase and update the reference on Line 13.

Proposed fix
-@property --breathe-phase {
+@property --breathe-phase {
     syntax: "<number>";
     initial-value: 0;
     inherits: true;
 }
 
 :root {
-    animation: indicatorBreathePhase 16s ease-in-out infinite;
+    animation: indicator-breathe-phase 16s ease-in-out infinite;
 }
 
-@keyframes indicatorBreathePhase {
+@keyframes indicator-breathe-phase {
     0%,
     100% {
         --breathe-phase: 0;
     }
+
     50% {
         --breathe-phase: 1;
     }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@property --breathe-phase {
syntax: "<number>";
initial-value: 0;
inherits: true;
}
:root {
animation: indicatorBreathePhase 16s ease-in-out infinite;
}
@keyframes indicatorBreathePhase {
0%,
100% {
--breathe-phase: 0;
}
50% {
--breathe-phase: 1;
}
}
`@property` --breathe-phase {
syntax: "<number>";
initial-value: 0;
inherits: true;
}
:root {
animation: indicator-breathe-phase 16s ease-in-out infinite;
}
`@keyframes` indicator-breathe-phase {
0%,
100% {
--breathe-phase: 0;
}
50% {
--breathe-phase: 1;
}
}
🧰 Tools
🪛 Stylelint (17.2.0)

[error] 16-16: Expected keyframe name "indicatorBreathePhase" to be kebab-case (keyframes-name-pattern)

(keyframes-name-pattern)


[error] 21-23: Expected empty line before rule (rule-empty-line-before)

(rule-empty-line-before)

🤖 Prompt for AI Agents
In `@frontend/app/tab/tab.scss` around lines 6 - 24, Rename the keyframes
identifier from indicatorBreathePhase to kebab-case indicator-breathe-phase and
update its usage: change the `@keyframes` rule name (indicatorBreathePhase →
indicator-breathe-phase) and update the animation declaration on :root
(animation: indicatorBreathePhase → animation: indicator-breathe-phase) so the
keyframes-name-pattern Stylelint rule is satisfied.


.tab {
position: absolute;
width: 130px;
Expand Down Expand Up @@ -46,6 +68,8 @@

.name {
color: var(--main-text-color);
font-weight: 700;
filter: brightness(1.15);
}

& + .tab::after,
Expand Down Expand Up @@ -96,6 +120,24 @@
transition: none !important;
}

&.has-indicator {
.tab-inner {
background: rgb(from var(--tab-indicator-color) r g b / 0.15);
}
&.active .tab-inner {
background: rgb(from var(--tab-indicator-color) r g b / 0.2);
}
}

&.indicator-breathing {
.tab-inner {
background: rgb(from var(--tab-indicator-color) r g b / calc(0.08 + var(--breathe-phase) * 0.14));
}
&.active .tab-inner {
background: rgb(from var(--tab-indicator-color) r g b / calc(0.12 + var(--breathe-phase) * 0.14));
}
}
Comment on lines +123 to +139
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Stylelint: use percentage alpha notation and add empty lines before nested rules.

Static analysis flags alpha-value-notation (use 15%/20% instead of 0.15/0.2) and missing empty lines before the &.active rules. The calc() expressions in .indicator-breathing can't easily use % notation, so those are fine as-is, but the static values on Lines 125 and 128 should use percentages.

Proposed fix
     &.has-indicator {
         .tab-inner {
-            background: rgb(from var(--tab-indicator-color) r g b / 0.15);
+            background: rgb(from var(--tab-indicator-color) r g b / 15%);
         }
+
         &.active .tab-inner {
-            background: rgb(from var(--tab-indicator-color) r g b / 0.2);
+            background: rgb(from var(--tab-indicator-color) r g b / 20%);
         }
     }
 
     &.indicator-breathing {
         .tab-inner {
             background: rgb(from var(--tab-indicator-color) r g b / calc(0.08 + var(--breathe-phase) * 0.14));
         }
+
         &.active .tab-inner {
             background: rgb(from var(--tab-indicator-color) r g b / calc(0.12 + var(--breathe-phase) * 0.14));
         }
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
&.has-indicator {
.tab-inner {
background: rgb(from var(--tab-indicator-color) r g b / 0.15);
}
&.active .tab-inner {
background: rgb(from var(--tab-indicator-color) r g b / 0.2);
}
}
&.indicator-breathing {
.tab-inner {
background: rgb(from var(--tab-indicator-color) r g b / calc(0.08 + var(--breathe-phase) * 0.14));
}
&.active .tab-inner {
background: rgb(from var(--tab-indicator-color) r g b / calc(0.12 + var(--breathe-phase) * 0.14));
}
}
&.has-indicator {
.tab-inner {
background: rgb(from var(--tab-indicator-color) r g b / 15%);
}
&.active .tab-inner {
background: rgb(from var(--tab-indicator-color) r g b / 20%);
}
}
&.indicator-breathing {
.tab-inner {
background: rgb(from var(--tab-indicator-color) r g b / calc(0.08 + var(--breathe-phase) * 0.14));
}
&.active .tab-inner {
background: rgb(from var(--tab-indicator-color) r g b / calc(0.12 + var(--breathe-phase) * 0.14));
}
}
🧰 Tools
🪛 Stylelint (17.2.0)

[error] 125-125: Expected "0.15" to be "15%" (alpha-value-notation)

(alpha-value-notation)


[error] 128-128: Expected "0.2" to be "20%" (alpha-value-notation)

(alpha-value-notation)


[error] 127-129: Expected empty line before rule (rule-empty-line-before)

(rule-empty-line-before)


[error] 136-138: Expected empty line before rule (rule-empty-line-before)

(rule-empty-line-before)

🤖 Prompt for AI Agents
In `@frontend/app/tab/tab.scss` around lines 123 - 139, Change the hardcoded alpha
decimals to percentage notation and add blank lines before the nested active
rules: update the .has-indicator .tab-inner background alpha from 0.15 to 15%
and the .has-indicator &.active .tab-inner from 0.2 to 20%; ensure there is an
empty line separating the .tab-inner block and the &.active .tab-inner block;
leave the .indicator-breathing calc(...) alpha expressions unchanged but also
add the empty line before its &.active .tab-inner rule for consistency.


.wave-button {
position: absolute;
top: 50%;
Expand Down Expand Up @@ -129,6 +171,18 @@ body:not(.nohover) .tab.dragging {
border-color: transparent;
background: rgb(from var(--main-text-color) r g b / 0.1);
}
&.has-indicator .tab-inner {
background: rgb(from var(--tab-indicator-color) r g b / 0.15);
}
&.has-indicator.active .tab-inner {
background: rgb(from var(--tab-indicator-color) r g b / 0.2);
}
&.indicator-breathing .tab-inner {
background: rgb(from var(--tab-indicator-color) r g b / calc(0.08 + var(--breathe-phase) * 0.14));
}
&.indicator-breathing.active .tab-inner {
background: rgb(from var(--tab-indicator-color) r g b / calc(0.12 + var(--breathe-phase) * 0.14));
}
Comment on lines +174 to +185
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Same Stylelint fixes needed in the hover/drag block.

The same alpha-value-notation and rule-empty-line-before violations apply here. Apply the matching percentage notation and empty-line fixes.

Proposed fix
+
     &.has-indicator .tab-inner {
-        background: rgb(from var(--tab-indicator-color) r g b / 0.15);
+        background: rgb(from var(--tab-indicator-color) r g b / 15%);
     }
+
     &.has-indicator.active .tab-inner {
-        background: rgb(from var(--tab-indicator-color) r g b / 0.2);
+        background: rgb(from var(--tab-indicator-color) r g b / 20%);
     }
+
     &.indicator-breathing .tab-inner {
         background: rgb(from var(--tab-indicator-color) r g b / calc(0.08 + var(--breathe-phase) * 0.14));
     }
+
     &.indicator-breathing.active .tab-inner {
         background: rgb(from var(--tab-indicator-color) r g b / calc(0.12 + var(--breathe-phase) * 0.14));
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
&.has-indicator .tab-inner {
background: rgb(from var(--tab-indicator-color) r g b / 0.15);
}
&.has-indicator.active .tab-inner {
background: rgb(from var(--tab-indicator-color) r g b / 0.2);
}
&.indicator-breathing .tab-inner {
background: rgb(from var(--tab-indicator-color) r g b / calc(0.08 + var(--breathe-phase) * 0.14));
}
&.indicator-breathing.active .tab-inner {
background: rgb(from var(--tab-indicator-color) r g b / calc(0.12 + var(--breathe-phase) * 0.14));
}
&.has-indicator .tab-inner {
background: rgb(from var(--tab-indicator-color) r g b / 15%);
}
&.has-indicator.active .tab-inner {
background: rgb(from var(--tab-indicator-color) r g b / 20%);
}
&.indicator-breathing .tab-inner {
background: rgb(from var(--tab-indicator-color) r g b / calc(0.08 + var(--breathe-phase) * 0.14));
}
&.indicator-breathing.active .tab-inner {
background: rgb(from var(--tab-indicator-color) r g b / calc(0.12 + var(--breathe-phase) * 0.14));
}
🧰 Tools
🪛 Stylelint (17.2.0)

[error] 175-175: Expected "0.15" to be "15%" (alpha-value-notation)

(alpha-value-notation)


[error] 178-178: Expected "0.2" to be "20%" (alpha-value-notation)

(alpha-value-notation)


[error] 174-176: Expected empty line before rule (rule-empty-line-before)

(rule-empty-line-before)


[error] 177-179: Expected empty line before rule (rule-empty-line-before)

(rule-empty-line-before)


[error] 180-182: Expected empty line before rule (rule-empty-line-before)

(rule-empty-line-before)


[error] 183-185: Expected empty line before rule (rule-empty-line-before)

(rule-empty-line-before)

🤖 Prompt for AI Agents
In `@frontend/app/tab/tab.scss` around lines 174 - 185, The hover/drag block uses
the wrong alpha notation and misses required empty lines: for the selectors like
`.has-indicator .tab-inner`, `.has-indicator.active .tab-inner`,
`.indicator-breathing .tab-inner`, and `.indicator-breathing.active .tab-inner`
replace the fractional alpha values (e.g. 0.15, 0.2, calc(...) with fractional)
with percentage-style alpha values (e.g. 15%, 20%, calc(... * 100% or
equivalent) to satisfy the alpha-value-notation rule) and ensure there is a
blank line inserted between these rule blocks to satisfy rule-empty-line-before.

.close {
visibility: visible;
&:hover {
Expand Down
11 changes: 9 additions & 2 deletions frontend/app/tab/tab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,14 @@ const Tab = memo(
dragging: isDragging,
"before-active": isBeforeActive,
"new-tab": isNew,
"has-indicator": indicator != null,
"indicator-breathing": indicator != null && indicator.icon === "none",
})}
style={
indicator != null
? ({ "--tab-indicator-color": indicator.color || "#f59e0b" } as React.CSSProperties)
: undefined
}
onMouseDown={onDragStart}
onClick={handleTabClick}
onContextMenu={handleContextMenu}
Expand All @@ -242,10 +249,10 @@ const Tab = memo(
>
{tabData?.name}
</div>
{indicator && (
{indicator && indicator.icon !== "none" && (
<div
className="tab-indicator pointer-events-none"
style={{ color: indicator.color || "#fbbf24" }}
style={{ color: indicator.color || "#f59e0b" }}
title="Activity notification"
>
<i className={makeIconClass(indicator.icon, true, { defaultIcon: "bell" })} />
Expand Down
2 changes: 2 additions & 0 deletions frontend/types/gotypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1098,6 +1098,7 @@ declare global {
"term:conndebug"?: string;
"term:bellsound"?: boolean;
"term:bellindicator"?: boolean;
"term:exitindicator"?: boolean;
"term:durable"?: boolean;
"web:zoom"?: number;
"web:hidenav"?: boolean;
Expand Down Expand Up @@ -1287,6 +1288,7 @@ declare global {
"term:macoptionismeta"?: boolean;
"term:bellsound"?: boolean;
"term:bellindicator"?: boolean;
"term:exitindicator"?: boolean;
"term:durable"?: boolean;
"editor:minimapenabled"?: boolean;
"editor:stickyscrollenabled"?: boolean;
Expand Down
101 changes: 100 additions & 1 deletion pkg/blockcontroller/shellcontroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ func (bc *ShellController) getConnUnion(logCtx context.Context, remoteName strin
if err != nil {
return ConnUnion{}, fmt.Errorf("invalid ssh remote name (%s): %w", remoteName, err)
}
conn := conncontroller.MaybeGetConn(opts)
conn := conncontroller.GetConn(opts)
if conn == nil {
return ConnUnion{}, fmt.Errorf("ssh connection not found: %s", remoteName)
}
Expand Down Expand Up @@ -526,6 +526,34 @@ func (bc *ShellController) manageRunningShellProcess(shellProc *shellexec.ShellP
shellInputCh := make(chan *BlockInputUnion, 32)
bc.ShellInputCh = shellInputCh

// Fire amber "running" indicator for cmd blocks
if bc.ControllerType == BlockController_Cmd {
exitIndicatorEnabled := blockMeta.GetBool(waveobj.MetaKey_TermExitIndicator, false)
if !blockMeta.HasKey(waveobj.MetaKey_TermExitIndicator) {
if globalVal := wconfig.GetWatcher().GetFullConfig().Settings.TermExitIndicator; globalVal != nil {
exitIndicatorEnabled = *globalVal
}
}
if exitIndicatorEnabled {
indicator := wshrpc.TabIndicator{
Icon: "spinner+spin",
Color: "#f59e0b",
Priority: 1.5,
ClearOnFocus: false,
}
eventData := wshrpc.TabIndicatorEventData{
TabId: bc.TabId,
Indicator: &indicator,
}
event := wps.WaveEvent{
Event: wps.Event_TabIndicator,
Scopes: []string{waveobj.MakeORef(waveobj.OType_Tab, bc.TabId).String()},
Data: eventData,
}
wps.Broker.Publish(event)
}
}
Comment on lines +529 to +555
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Running indicator logic looks good. Global settings fallback is correctly implemented, and the indicator is appropriately scoped to BlockController_Cmd blocks only.

One edge case: if the user disables term:exitindicator while a command is still running, the exit goroutine (line 664) returns early without clearing this amber spinner—leaving it stuck on the tab. Consider unconditionally clearing the running indicator for Cmd blocks before the exitIndicatorEnabled early-return:

Proposed fix
+			// Always clear the running indicator for cmd blocks
+			if blockData.Meta.GetString(waveobj.MetaKey_Controller, "") == BlockController_Cmd {
+				clearEvent := wps.WaveEvent{
+					Event:  wps.Event_TabIndicator,
+					Scopes: []string{waveobj.MakeORef(waveobj.OType_Tab, bc.TabId).String()},
+					Data:   wshrpc.TabIndicatorEventData{TabId: bc.TabId, Indicator: nil},
+				}
+				wps.Broker.Publish(clearEvent)
+			}
 			if !exitIndicatorEnabled {
 				return
 			}


go func() {
// handles regular output from the pty (goes to the blockfile and xterm)
defer func() {
Expand Down Expand Up @@ -616,6 +644,77 @@ func (bc *ShellController) manageRunningShellProcess(shellProc *shellexec.ShellP
msg = fmt.Sprintf("%s (exit code %d)", baseMsg, exitCode)
}
bc.writeMutedMessageToTerminal("[" + msg + "]")
go func(exitCode int, exitSignal string) {
defer func() {
panichandler.PanicHandler("blockcontroller:exit-indicator", recover())
}()
ctx, cancelFn := context.WithTimeout(context.Background(), DefaultTimeout)
defer cancelFn()
blockData, err := wstore.DBMustGet[*waveobj.Block](ctx, bc.BlockId)
if err != nil {
log.Printf("error getting block data for exit indicator: %v\n", err)
return
}
exitIndicatorEnabled := blockData.Meta.GetBool(waveobj.MetaKey_TermExitIndicator, false)
if !blockData.Meta.HasKey(waveobj.MetaKey_TermExitIndicator) {
if globalVal := wconfig.GetWatcher().GetFullConfig().Settings.TermExitIndicator; globalVal != nil {
exitIndicatorEnabled = *globalVal
}
}
if !exitIndicatorEnabled {
return
}
closeOnExit := blockData.Meta.GetBool(waveobj.MetaKey_CmdCloseOnExit, false)
closeOnExitForce := blockData.Meta.GetBool(waveobj.MetaKey_CmdCloseOnExitForce, false)
if closeOnExitForce || (closeOnExit && exitCode == 0) {
// Clear running indicator before block gets deleted
if bc.ControllerType == BlockController_Cmd {
clearEvent := wps.WaveEvent{
Event: wps.Event_TabIndicator,
Scopes: []string{waveobj.MakeORef(waveobj.OType_Tab, bc.TabId).String()},
Data: wshrpc.TabIndicatorEventData{TabId: bc.TabId, Indicator: nil},
}
wps.Broker.Publish(clearEvent)
}
return
}
// Clear running indicator before exit indicator to prevent
// PersistentIndicator from resurrecting the amber glow
if bc.ControllerType == BlockController_Cmd {
clearEvent := wps.WaveEvent{
Event: wps.Event_TabIndicator,
Scopes: []string{waveobj.MakeORef(waveobj.OType_Tab, bc.TabId).String()},
Data: wshrpc.TabIndicatorEventData{TabId: bc.TabId, Indicator: nil},
}
wps.Broker.Publish(clearEvent)
}
var indicator wshrpc.TabIndicator
if exitCode == 0 && exitSignal == "" {
indicator = wshrpc.TabIndicator{
Icon: "check",
Color: "#4ade80",
Priority: 2,
ClearOnFocus: true,
}
} else {
indicator = wshrpc.TabIndicator{
Icon: "xmark-large",
Color: "#f87171",
Priority: 2,
ClearOnFocus: true,
}
}
eventData := wshrpc.TabIndicatorEventData{
TabId: bc.TabId,
Indicator: &indicator,
}
event := wps.WaveEvent{
Event: wps.Event_TabIndicator,
Scopes: []string{waveobj.MakeORef(waveobj.OType_Tab, bc.TabId).String()},
Data: eventData,
}
wps.Broker.Publish(event)
}(exitCode, exitSignal)
go checkCloseOnExit(bc.BlockId, exitCode)
}()
return nil
Expand Down
1 change: 1 addition & 0 deletions pkg/waveobj/metaconsts.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ const (
MetaKey_TermConnDebug = "term:conndebug"
MetaKey_TermBellSound = "term:bellsound"
MetaKey_TermBellIndicator = "term:bellindicator"
MetaKey_TermExitIndicator = "term:exitindicator"
MetaKey_TermDurable = "term:durable"

MetaKey_WebZoom = "web:zoom"
Expand Down
1 change: 1 addition & 0 deletions pkg/waveobj/wtypemeta.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ type MetaTSType struct {
TermConnDebug string `json:"term:conndebug,omitempty"` // null, info, debug
TermBellSound *bool `json:"term:bellsound,omitempty"`
TermBellIndicator *bool `json:"term:bellindicator,omitempty"`
TermExitIndicator *bool `json:"term:exitindicator,omitempty"`
TermDurable *bool `json:"term:durable,omitempty"`

WebZoom float64 `json:"web:zoom,omitempty"`
Expand Down
1 change: 1 addition & 0 deletions pkg/wconfig/defaultconfig/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"telemetry:enabled": true,
"term:bellsound": false,
"term:bellindicator": false,
"term:exitindicator": false,
"term:copyonselect": true,
"term:durable": false,
"waveai:showcloudmodes": true,
Expand Down
1 change: 1 addition & 0 deletions pkg/wconfig/metaconsts.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ const (
ConfigKey_TermMacOptionIsMeta = "term:macoptionismeta"
ConfigKey_TermBellSound = "term:bellsound"
ConfigKey_TermBellIndicator = "term:bellindicator"
ConfigKey_TermExitIndicator = "term:exitindicator"
ConfigKey_TermDurable = "term:durable"

ConfigKey_EditorMinimapEnabled = "editor:minimapenabled"
Expand Down
1 change: 1 addition & 0 deletions pkg/wconfig/settingsconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ type SettingsType struct {
TermMacOptionIsMeta *bool `json:"term:macoptionismeta,omitempty"`
TermBellSound *bool `json:"term:bellsound,omitempty"`
TermBellIndicator *bool `json:"term:bellindicator,omitempty"`
TermExitIndicator *bool `json:"term:exitindicator,omitempty"`
TermDurable *bool `json:"term:durable,omitempty"`

EditorMinimapEnabled bool `json:"editor:minimapenabled,omitempty"`
Expand Down
3 changes: 3 additions & 0 deletions schema/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@
"term:bellindicator": {
"type": "boolean"
},
"term:exitindicator": {
"type": "boolean"
},
"term:durable": {
"type": "boolean"
},
Expand Down