From ad777100245d2901ade9db08b3f607d5fda8b6a6 Mon Sep 17 00:00:00 2001 From: swethasukumarr Date: Mon, 3 Aug 2026 14:59:04 -0400 Subject: [PATCH 1/3] Restore develop firebolt-open-rpc.json --- docs/openrpc/the-spec/firebolt-open-rpc.json | 112 ++++++++++++++++--- 1 file changed, 98 insertions(+), 14 deletions(-) diff --git a/docs/openrpc/the-spec/firebolt-open-rpc.json b/docs/openrpc/the-spec/firebolt-open-rpc.json index 98fdd71..f628a67 100644 --- a/docs/openrpc/the-spec/firebolt-open-rpc.json +++ b/docs/openrpc/the-spec/firebolt-open-rpc.json @@ -76,13 +76,19 @@ "properties": { "intent": { "type": "object", - "required": ["action"], + "required": [ + "action" + ], "properties": { - "action": { "type": "string" }, + "action": { + "type": "string" + }, "context": { "type": "object", "properties": { - "source": { "type": "string" } + "source": { + "type": "string" + } } } } @@ -148,13 +154,19 @@ "properties": { "intent": { "type": "object", - "required": ["action"], + "required": [ + "action" + ], "properties": { - "action": { "type": "string" }, + "action": { + "type": "string" + }, "context": { "type": "object", "properties": { - "source": { "type": "string" } + "source": { + "type": "string" + } } } } @@ -208,13 +220,19 @@ "required": true, "schema": { "type": "object", - "required": ["action"], + "required": [ + "action" + ], "properties": { - "action": { "type": "string" }, + "action": { + "type": "string" + }, "context": { "type": "object", "properties": { - "source": { "type": "string" } + "source": { + "type": "string" + } } } } @@ -2380,10 +2398,10 @@ "name": "value", "description": "The memory usage information", "value": { - "userMemoryUsedKiB": 123456, - "userMemoryLimitKiB": 789012, - "gpuMemoryUsedKiB": 345678, - "gpuMemoryLimitKiB": 901234 + "userMemoryUsed": 126418944, + "userMemoryLimit": 807948288, + "gpuMemoryUsed": 353974272, + "gpuMemoryLimit": 922863616 } } } @@ -3327,6 +3345,39 @@ } } }, + { + "name": "Device.dolbyAtmosExperienceAvailable", + "summary": "Returns whether Dolby Atmos experience is available on the device", + "params": [], + "tags": [ + { + "name": "property:readonly" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:device:info" + ] + } + ], + "result": { + "name": "dolbyAtmosExperienceAvailable", + "summary": "Whether Dolby Atmos experience is available on the device", + "schema": { + "type": "boolean" + } + }, + "examples": [ + { + "name": "Getting Dolby Atmos experience availability", + "params": [], + "result": { + "name": "Default Result", + "value": true + } + } + ] + }, { "name": "Device.onHdrChanged", "summary": "Returns the HDR standards that are supported by the attached TV or the integral display", @@ -3373,6 +3424,39 @@ } } }, + { + "name": "Localization.timeZone", + "tags": [ + { + "name": "property:readonly" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:localization:time-zone" + ] + } + ], + "summary": "Get the IANA timezone of the device.", + "params": [], + "result": { + "name": "timeZone", + "summary": "The device timezone.", + "schema": { + "type": "string" + } + }, + "examples": [ + { + "name": "Default example", + "params": [], + "result": { + "name": "Default Result", + "value": "America/New_York" + } + } + ] + }, { "name": "Localization.onCountryChanged", "tags": [ @@ -4168,4 +4252,4 @@ } } } -} \ No newline at end of file +} From a60d8c51aaf63e1389c80eda718bfe6e2531b227 Mon Sep 17 00:00:00 2001 From: swethasukumarr Date: Tue, 4 Aug 2026 11:56:41 -0400 Subject: [PATCH 2/3] Fix firebolt-open-rpc.json --- docs/openrpc/the-spec/firebolt-open-rpc.json | 231 +++++++++++++------ 1 file changed, 163 insertions(+), 68 deletions(-) diff --git a/docs/openrpc/the-spec/firebolt-open-rpc.json b/docs/openrpc/the-spec/firebolt-open-rpc.json index f628a67..743e3fe 100644 --- a/docs/openrpc/the-spec/firebolt-open-rpc.json +++ b/docs/openrpc/the-spec/firebolt-open-rpc.json @@ -673,6 +673,39 @@ } ] }, + { + "name": "Device.dolbyAtmosExperienceAvailable", + "summary": "Returns whether Dolby Atmos experience is available on the device", + "params": [], + "tags": [ + { + "name": "property:readonly" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:device:info" + ] + } + ], + "result": { + "name": "dolbyAtmosExperienceAvailable", + "summary": "Whether Dolby Atmos experience is available on the device", + "schema": { + "type": "boolean" + } + }, + "examples": [ + { + "name": "Getting Dolby Atmos experience availability", + "params": [], + "result": { + "name": "Default Result", + "value": true + } + } + ] + }, { "name": "Discovery.watched", "summary": "Notify the platform that content was partially or completely watched", @@ -793,7 +826,7 @@ }, { "name": "Discovery.watchedV2", - "summary": "Notify the platform that content was partially or completely watched, returns whether the notification was accepted", + "summary": "Notify the platform that content was partially or completely watched", "tags": [ { "name": "polymorphic-reducer" @@ -847,9 +880,8 @@ ], "result": { "name": "result", - "summary": "Whether the platform accepted the watched notification", "schema": { - "type": "boolean" + "type": "null" } }, "examples": [ @@ -875,7 +907,7 @@ ], "result": { "name": "result", - "value": true + "value": null } }, { @@ -904,7 +936,7 @@ ], "result": { "name": "result", - "value": true + "value": null } } ] @@ -1233,6 +1265,39 @@ } ] }, + { + "name": "Localization.timeZone", + "tags": [ + { + "name": "property:readonly" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:localization:time-zone" + ] + } + ], + "summary": "Get the IANA timezone of the device.", + "params": [], + "result": { + "name": "timeZone", + "summary": "The device timezone.", + "schema": { + "type": "string" + } + }, + "examples": [ + { + "name": "Default example", + "params": [], + "result": { + "name": "Default Result", + "value": "America/New_York" + } + } + ] + }, { "name": "Metrics.ready", "tags": [ @@ -2374,7 +2439,7 @@ }, { "name": "Stats.memoryUsage", - "summary": "Returns information about container memory usage, in units of 1024 bytes.", + "summary": "Returns information about container memory usage in bytes.", "tags": [ { "name": "capabilities", @@ -3345,39 +3410,6 @@ } } }, - { - "name": "Device.dolbyAtmosExperienceAvailable", - "summary": "Returns whether Dolby Atmos experience is available on the device", - "params": [], - "tags": [ - { - "name": "property:readonly" - }, - { - "name": "capabilities", - "x-uses": [ - "xrn:firebolt:capability:device:info" - ] - } - ], - "result": { - "name": "dolbyAtmosExperienceAvailable", - "summary": "Whether Dolby Atmos experience is available on the device", - "schema": { - "type": "boolean" - } - }, - "examples": [ - { - "name": "Getting Dolby Atmos experience availability", - "params": [], - "result": { - "name": "Default Result", - "value": true - } - } - ] - }, { "name": "Device.onHdrChanged", "summary": "Returns the HDR standards that are supported by the attached TV or the integral display", @@ -3425,37 +3457,50 @@ } }, { - "name": "Localization.timeZone", + "name": "Device.onDolbyAtmosExperienceAvailableChanged", + "summary": "Returns whether Dolby Atmos experience is available on the device", + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], "tags": [ { - "name": "property:readonly" + "name": "event", + "x-notifier": "Device.onDolbyAtmosExperienceAvailableChanged", + "x-subscriber-for": "Device.dolbyAtmosExperienceAvailable" }, { "name": "capabilities", "x-uses": [ - "xrn:firebolt:capability:localization:time-zone" + "xrn:firebolt:capability:device:info" ] } ], - "summary": "Get the IANA timezone of the device.", - "params": [], - "result": { - "name": "timeZone", - "summary": "The device timezone.", - "schema": { - "type": "string" - } - }, "examples": [ { - "name": "Default example", - "params": [], + "name": "Getting Dolby Atmos experience availability", + "params": [ + { + "name": "listen", + "value": true + } + ], "result": { - "name": "Default Result", - "value": "America/New_York" + "name": "result", + "value": null } } - ] + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } }, { "name": "Localization.onCountryChanged", @@ -3608,6 +3653,52 @@ } } }, + { + "name": "Localization.onTimeZoneChanged", + "tags": [ + { + "name": "event", + "x-notifier": "Localization.onTimeZoneChanged", + "x-subscriber-for": "Localization.timeZone" + }, + { + "name": "capabilities", + "x-uses": [ + "xrn:firebolt:capability:localization:time-zone" + ] + } + ], + "summary": "Get the IANA timezone of the device.", + "params": [ + { + "name": "listen", + "schema": { + "type": "boolean" + } + } + ], + "examples": [ + { + "name": "Default example", + "params": [ + { + "name": "listen", + "value": true + } + ], + "result": { + "name": "result", + "value": null + } + } + ], + "result": { + "name": "result", + "schema": { + "type": "null" + } + } + }, { "name": "Network.onConnectedChanged", "summary": "Returns whether the device currently has a usable network connection.", @@ -3861,28 +3952,32 @@ "type": "object", "description": "Describes current and maximum memory usage of the container.", "properties": { - "userMemoryUsedKiB": { + "userMemoryUsed": { "type": "integer", - "description": "User memory currently used in 1024 bytes." + "description": "User memory currently used, in bytes.", + "minimum": 0 }, - "userMemoryLimitKiB": { + "userMemoryLimit": { "type": "integer", - "description": "Maximum user memory available in 1024 bytes." + "description": "Maximum user memory available, in bytes.", + "minimum": 0 }, - "gpuMemoryUsedKiB": { + "gpuMemoryUsed": { "type": "integer", - "description": "GPU memory currently used in 1024 bytes." + "description": "GPU memory currently used, in bytes.", + "minimum": 0 }, - "gpuMemoryLimitKiB": { + "gpuMemoryLimit": { "type": "integer", - "description": "Maximum GPU memory available in 1024 bytes." + "description": "Maximum GPU memory available, in bytes.", + "minimum": 0 } }, "required": [ - "userMemoryUsedKiB", - "userMemoryLimitKiB", - "gpuMemoryUsedKiB", - "gpuMemoryLimitKiB" + "userMemoryUsed", + "userMemoryLimit", + "gpuMemoryUsed", + "gpuMemoryLimit" ] }, "TTSEnabled": { From 5c0de8b50f2a902948efaf15aff3f8fbb085702f Mon Sep 17 00:00:00 2001 From: swethasukumarr Date: Wed, 5 Aug 2026 09:20:52 -0400 Subject: [PATCH 3/3] Add fmt.sh and clean up lint.sh clang-format tooling --- fmt.sh | 44 +++++++++++ include/firebolt/actions.h | 3 +- lint.sh | 103 ++----------------------- test/api_test_app/apis/actionsDemo.cpp | 12 ++- test/unit/actionsTest.cpp | 4 +- 5 files changed, 57 insertions(+), 109 deletions(-) create mode 100755 fmt.sh diff --git a/fmt.sh b/fmt.sh new file mode 100755 index 0000000..b3ec468 --- /dev/null +++ b/fmt.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# Check (default) or fix clang-format. Like `cargo fmt [--check]`. +# ./fmt.sh — check only (exit 1 if violations) +# ./fmt.sh --fix — reformat in place +# +# Uses Docker by default (matches CI exactly). If Docker is unavailable or +# SKIP_DOCKER=1 is set, falls back to the locally installed clang-format. +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# Minimal image — only clang-format, matches the Ubuntu version used in CI +IMAGE="firebolt-cpp-client-fmt:local" + +use_docker=true +if [[ "${SKIP_DOCKER:-0}" == "1" ]] || ! command -v docker &>/dev/null; then + use_docker=false +fi + +if [[ "$use_docker" == true ]]; then + if ! docker image inspect "$IMAGE" &>/dev/null; then + echo "Building clang-format Docker image (one-time, ~30s)..." + docker build -t "$IMAGE" - <<'DOCKERFILE' +FROM ubuntu:24.04 +RUN apt-get update && apt-get install -y --no-install-recommends clang-format git && rm -rf /var/lib/apt/lists/* +WORKDIR /workspace +DOCKERFILE + fi + RUN="docker run --rm --user $(id -u):$(id -g) -v $SCRIPT_DIR:/workspace $IMAGE bash -c" +else + if ! command -v clang-format &>/dev/null; then + echo "clang-format not found. Install it or run without SKIP_DOCKER=1." >&2 + exit 1 + fi + echo "[fmt] Using local clang-format ($(clang-format --version))" + RUN="bash -c" +fi + +if [[ "${1:-}" == "--fix" ]]; then + $RUN "set -e && git ls-files -- '*.cpp' '*.h' | xargs clang-format -i" + echo "Done. Files reformatted." +else + $RUN "set -e && git ls-files -- '*.cpp' '*.h' | xargs clang-format --dry-run --Werror" + echo "Formatting OK." +fi diff --git a/include/firebolt/actions.h b/include/firebolt/actions.h index dd93d7e..7d28222 100644 --- a/include/firebolt/actions.h +++ b/include/firebolt/actions.h @@ -64,8 +64,7 @@ class IActions virtual Result unsubscribe(SubscriptionId id) = 0; virtual void unsubscribeAll() = 0; - virtual Result start(const IntentData& intent, - std::optional handlerAppId = std::nullopt) const = 0; + virtual Result start(const IntentData& intent, std::optional handlerAppId = std::nullopt) const = 0; }; // class IActions diff --git a/lint.sh b/lint.sh index 552384d..a7dc561 100755 --- a/lint.sh +++ b/lint.sh @@ -24,30 +24,23 @@ NO_BUILD=false CLEAN=false RUN_CLANG_TIDY=true RUN_CPPCHECK=true -RUN_CLANG_FORMAT=true APPLY_FIXES=false -FORMAT_FIX=false CLANG_TIDY_PATHS=(src include test/unit test/component) -CLANG_FORMAT_PATHS=(src include test) usage() { cat < Build directory containing compile_commands.json (default: build-dev) --tidy-path

Add path for clang-tidy scan (repeatable) - --format-path

Add path for clang-format scan (repeatable) --fix Apply clang-tidy fix-its (clang-tidy only) - --format-fix Apply clang-format fixes in-place - --format-only Run clang-format only - --no-format Skip clang-format checks --tidy-only Run clang-tidy only --cppcheck-only Run cppcheck only --help Show this help @@ -56,10 +49,7 @@ Examples: ./lint.sh ./lint.sh --tidy-only ./lint.sh --tidy-only --fix - ./lint.sh --format-only - ./lint.sh --format-fix ./lint.sh --tidy-path test/api_test_app - ./lint.sh --format-path include/firebolt ./lint.sh --no-build --build-dir build-dev EOF } @@ -90,37 +80,14 @@ while [[ $# -gt 0 ]]; do CLANG_TIDY_PATHS+=("${2:-}") shift ;; - --format-path) - if [[ $# -lt 2 || -z "${2:-}" || "$2" == --* ]]; then - echo "Missing value for --format-path" >&2 - usage - exit 1 - fi - CLANG_FORMAT_PATHS+=("${2:-}") - shift - ;; --fix) APPLY_FIXES=true ;; - --format-fix) - FORMAT_FIX=true - RUN_CLANG_FORMAT=true - ;; - --format-only) - RUN_CLANG_FORMAT=true - RUN_CLANG_TIDY=false - RUN_CPPCHECK=false - ;; - --no-format) - RUN_CLANG_FORMAT=false - ;; --tidy-only) - RUN_CLANG_FORMAT=false RUN_CLANG_TIDY=true RUN_CPPCHECK=false ;; --cppcheck-only) - RUN_CLANG_FORMAT=false RUN_CLANG_TIDY=false RUN_CPPCHECK=true ;; @@ -144,8 +111,8 @@ if [[ "$RUN_CLANG_TIDY" == true && "$NO_BUILD" == false && "$BUILD_DIR" != "buil exit 1 fi -if [[ "$RUN_CLANG_FORMAT" == false && "$RUN_CLANG_TIDY" == false && "$RUN_CPPCHECK" == false ]]; then - echo "Nothing to run: clang-format, clang-tidy, and cppcheck are all disabled." >&2 +if [[ "$RUN_CLANG_TIDY" == false && "$RUN_CPPCHECK" == false ]]; then + echo "Nothing to run: clang-tidy and cppcheck are both disabled." >&2 exit 1 fi @@ -154,11 +121,6 @@ if [[ "$APPLY_FIXES" == true && "$RUN_CLANG_TIDY" == false ]]; then exit 1 fi -if [[ "$FORMAT_FIX" == true && "$RUN_CLANG_FORMAT" == false ]]; then - echo "--format-fix requires clang-format to be enabled (remove --no-format)." >&2 - exit 1 -fi - if [[ "$RUN_CLANG_TIDY" == true ]] && ! command -v clang-tidy >/dev/null 2>&1; then echo "clang-tidy not found. Install it (e.g. apt install clang-tidy)." >&2 exit 1 @@ -169,11 +131,6 @@ if [[ "$RUN_CPPCHECK" == true ]] && ! command -v cppcheck >/dev/null 2>&1; then exit 1 fi -if [[ "$RUN_CLANG_FORMAT" == true ]] && ! command -v clang-format >/dev/null 2>&1; then - echo "clang-format not found. Install it (e.g. apt install clang-format)." >&2 - exit 1 -fi - if [[ "$CLEAN" == true ]]; then rm -rf "$BUILD_DIR" fi @@ -187,56 +144,6 @@ if [[ "$RUN_CLANG_TIDY" == true && ! -f "$BUILD_DIR/compile_commands.json" ]]; t exit 1 fi -if [[ "$RUN_CLANG_FORMAT" == true ]]; then - if [[ "$FORMAT_FIX" == true ]]; then - echo "[lint] Running clang-format with fixes enabled" - else - echo "[lint] Running clang-format check" - fi - - format_paths=() - for p in "${CLANG_FORMAT_PATHS[@]}"; do - if [[ -e "$p" ]]; then - format_paths+=("$p") - fi - done - - if [[ ${#format_paths[@]} -eq 0 ]]; then - echo "No valid clang-format paths found." >&2 - exit 1 - fi - - mapfile -t format_files < <( - find "${format_paths[@]}" -type f \( -name "*.h" -o -name "*.hh" -o -name "*.hpp" -o -name "*.hxx" -o -name "*.c" -o -name "*.cc" -o -name "*.cpp" -o -name "*.cxx" \) | sort - ) - - if [[ ${#format_files[@]} -eq 0 ]]; then - echo "No C/C++ files found for clang-format." >&2 - exit 1 - fi - - clang_format_failed=0 - total_format_files=${#format_files[@]} - format_index=0 - for f in "${format_files[@]}"; do - format_index=$((format_index + 1)) - echo "[lint][clang-format] ${format_index}/${total_format_files}: $f" - if [[ "$FORMAT_FIX" == true ]]; then - clang-format -i "$f" - else - if ! clang-format --dry-run --Werror "$f"; then - clang_format_failed=1 - fi - fi - done - - if [[ "$FORMAT_FIX" == false && $clang_format_failed -ne 0 ]]; then - echo "clang-format reported issues." >&2 - echo "Run ./lint.sh --format-fix to apply formatting automatically." >&2 - exit 1 - fi -fi - if [[ "$RUN_CLANG_TIDY" == true ]]; then if [[ "$APPLY_FIXES" == true ]]; then echo "[lint] Running clang-tidy with fixes enabled" diff --git a/test/api_test_app/apis/actionsDemo.cpp b/test/api_test_app/apis/actionsDemo.cpp index bb1fd26..31b982f 100644 --- a/test/api_test_app/apis/actionsDemo.cpp +++ b/test/api_test_app/apis/actionsDemo.cpp @@ -44,8 +44,8 @@ void ActionsDemo::runOption(const std::string& method) auto r = Firebolt::IFireboltAccessor::Instance().ActionsInterface().intent(); if (succeed(r)) { - std::cout << "Current Intent - action: " << r->intent.action - << ", source: " << (r->intent.context && r->intent.context->source ? *r->intent.context->source : "(none)") + std::cout << "Current Intent - action: " << r->intent.action << ", source: " + << (r->intent.context && r->intent.context->source ? *r->intent.context->source : "(none)") << ", intentId: " << r->intentId << std::endl; } } @@ -70,11 +70,9 @@ void ActionsDemo::runOption(const std::string& method) { auto callback = [&](const Intent& payload) { - std::cout << "Intent received - action: " << payload.intent.action - << ", source: " - << (payload.intent.context && payload.intent.context->source - ? *payload.intent.context->source - : "(none)") + std::cout << "Intent received - action: " << payload.intent.action << ", source: " + << (payload.intent.context && payload.intent.context->source ? *payload.intent.context->source + : "(none)") << ", intentId: " << payload.intentId << std::endl; }; auto r = Firebolt::IFireboltAccessor::Instance().ActionsInterface().subscribeOnIntent(std::move(callback)); diff --git a/test/unit/actionsTest.cpp b/test/unit/actionsTest.cpp index 236cf91..12a9089 100644 --- a/test/unit/actionsTest.cpp +++ b/test/unit/actionsTest.cpp @@ -65,7 +65,7 @@ TEST_F(ActionsUTest, Start) .WillOnce(Invoke([&](const std::string& /*methodName*/, const nlohmann::json& /*parameters*/) { return Firebolt::Result{Firebolt::Error::None}; })); - auto result = actionsImpl_.start( - Firebolt::Actions::IntentData{"pre-load", Firebolt::Actions::IntentContext{{"system"}}}); + auto result = + actionsImpl_.start(Firebolt::Actions::IntentData{"pre-load", Firebolt::Actions::IntentContext{{"system"}}}); ASSERT_TRUE(result) << "ActionsImpl::start() returned an error"; }