Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
df59c51
chore: introduce non-blocking .NET quality analysis (#16)
paulcam206 Sep 10, 2026
87bb5c8
chore: enforce C# formatting and style (#17)
paulcam206 Sep 10, 2026
b3d98ae
improve: harden native library loading (#18)
paulcam206 Sep 10, 2026
c3e1810
improve: make validation and comparisons deterministic (#19)
paulcam206 Sep 10, 2026
2904bd8
improve: remove blocking work from async paths (#20)
paulcam206 Sep 10, 2026
5624168
improve: tighten resource ownership and type boundaries (#21)
paulcam206 Sep 10, 2026
51969c7
chore: enforce the complete .NET quality gate (#22)
paulcam206 Sep 10, 2026
8251626
docs: align guidance with immutable package execution
Sep 10, 2026
bf2ce9f
docs: remove obsolete cleanup callout
Sep 10, 2026
52f2a53
Merge pull request #27 from xlinush/docs/refresh-current-behavior
xlinush Sep 11, 2026
27cc6b8
feat: bundle Node.js runtime in gateway MSIX
Sep 11, 2026
fa303bf
fix: fail loudly when test MSIX signing has no inputs (#31)
paulcam206 Sep 11, 2026
6f89905
refactor(clawctl): parse management arguments with System.CommandLine…
paulcam206 Sep 11, 2026
5208c1d
fix: follow upstream Node selection and repair bundled runtimes
Sep 11, 2026
5baa5e6
Merge current main into bundled runtime PR
Sep 11, 2026
cc1d833
chore(ci): finalize Artifact Signing setup (#24)
RomneyDa Sep 12, 2026
54d4c43
feat(ci): publish signed Gateway MSIX releases (#33)
RomneyDa Sep 12, 2026
735bd4e
fix(ci): authorize MakeAppx zero-version bundles (#34)
RomneyDa Sep 12, 2026
4bd8a55
Merge main and preserve bundled runtime release validation
Sep 14, 2026
df917ac
docs: make PR descriptions plain-language first (#35)
roboclaw-bot Sep 14, 2026
ba1a1e3
fix: keep dashboard and gateway builds aligned
anna-dingler Sep 14, 2026
bf02d02
test: validate emitted dashboard build identity
anna-dingler Sep 14, 2026
e4fee8a
docs: clarify build identity validation
anna-dingler Sep 14, 2026
f1071a1
Merge pull request #30 from xlinush/feature/bundle-node-runtime
xlinush Sep 14, 2026
59707e8
Merge pull request #37 from anna-dingler/fix/control-ui-build-identity
anna-dingler Sep 14, 2026
9a8cd4a
fix: preserve build identity validator in pipeline (#39)
anna-dingler Sep 14, 2026
bfc2664
Add Gateway isolation status plugin
Sep 11, 2026
d6855d0
docs: attach Gateway isolation local E2E evidence
Sep 11, 2026
db2b16c
test: expand Gateway isolation contract proof
Sep 11, 2026
ecc3a57
feat(plugin): follow Control UI theme
Sep 12, 2026
b732945
feat(plugin): inherit host theme styling
Sep 12, 2026
301b8cf
feat(plugin): label tab Windows Launcher
Sep 12, 2026
0b3a6d4
feat(plugin): consume forwarded Control UI themes
Sep 14, 2026
97c19ae
fix: align launcher plugin with current quality gates
Sep 14, 2026
742c939
build: require merged plugin theme forwarding
Sep 14, 2026
253f5a6
Rename launcher isolation status label
Sep 14, 2026
cc707aa
Restore launcher CLI control
Sep 14, 2026
dbb141f
Add final themed launcher proof
Sep 14, 2026
13cded5
Revert "Restore launcher CLI control"
Sep 14, 2026
1d44895
Reapply "Restore launcher CLI control"
Sep 14, 2026
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
268 changes: 268 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
root = true

# Repository-wide defaults. `.gitattributes` normalizes tracked text to LF, so
# `end_of_line` must stay `lf`; otherwise `dotnet format` rewrites files with
# CRLF and every formatted line shows up as a spurious diff.
[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true

[*.{json,jsonc,yml,yaml}]
indent_size = 2

[*.md]
# Markdown uses trailing double-space for hard line breaks.
trim_trailing_whitespace = false

[*.{appxmanifest,csproj,props,targets,slnx,xml}]
indent_size = 2

[*.ps1]
indent_size = 4

[*.cs]
indent_size = 4
max_line_length = 100

#### .NET code style ####

# `this.` qualification is not used anywhere in this repository.
dotnet_style_qualification_for_field = false:error
dotnet_style_qualification_for_property = false:error
dotnet_style_qualification_for_method = false:error
dotnet_style_qualification_for_event = false:error

dotnet_style_predefined_type_for_locals_parameters_members = true:error
dotnet_style_predefined_type_for_member_access = true:error

dotnet_style_object_initializer = true:suggestion
dotnet_style_collection_initializer = true:suggestion
dotnet_style_prefer_auto_properties = true:suggestion
dotnet_style_explicit_tuple_names = true:error
dotnet_style_prefer_inferred_tuple_names = true:suggestion
dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
# IDE0045/IDE0046: collapsing guard clauses into conditional expressions hurts
# readability in this codebase, which uses early-return validation throughout.
dotnet_style_prefer_conditional_expression_over_assignment = false:silent
dotnet_style_prefer_conditional_expression_over_return = false:silent
dotnet_style_prefer_compound_assignment = true:error
dotnet_style_prefer_simplified_boolean_expressions = true:error
dotnet_style_prefer_simplified_interpolation = true:error
dotnet_style_null_propagation = true:error
dotnet_style_coalesce_expression = true:error
dotnet_style_prefer_is_null_check_over_reference_equality_method = true:error
dotnet_style_readonly_field = true:error
dotnet_style_operator_placement_when_wrapping = beginning_of_line
dotnet_style_namespace_match_folder = true:suggestion

dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:suggestion
dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:suggestion
dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:suggestion
dotnet_style_parentheses_in_other_operators = never_if_unnecessary:suggestion

# Accessibility modifiers are written explicitly, except where C# requires
# them to be omitted (for example interface members).
dotnet_style_require_accessibility_modifiers = for_non_interface_members:error

#### C# code style ####

# `var` versus explicit types is left to the author. Both forms are idiomatic,
# this codebase deliberately mixes them, and enforcing either direction is
# churn that catches no defects.
csharp_style_var_for_built_in_types = false:silent
csharp_style_var_when_type_is_apparent = true:silent
csharp_style_var_elsewhere = false:silent

csharp_style_expression_bodied_methods = when_on_single_line:suggestion
csharp_style_expression_bodied_constructors = false:suggestion
csharp_style_expression_bodied_operators = when_on_single_line:suggestion
csharp_style_expression_bodied_properties = true:suggestion
csharp_style_expression_bodied_indexers = true:suggestion
csharp_style_expression_bodied_accessors = true:suggestion
csharp_style_expression_bodied_lambdas = true:suggestion
csharp_style_expression_bodied_local_functions = when_on_single_line:suggestion

csharp_style_pattern_matching_over_is_with_cast_check = true:error
csharp_style_pattern_matching_over_as_with_null_check = true:error
csharp_style_prefer_not_pattern = true:error
csharp_style_prefer_pattern_matching = true:suggestion
csharp_style_prefer_switch_expression = true:suggestion
csharp_style_prefer_extended_property_pattern = true:suggestion

csharp_style_inlined_variable_declaration = true:error
csharp_style_deconstructed_variable_declaration = true:suggestion
# Guard clauses that throw read better than ternary `throw` expressions, and
# this codebase already uses them consistently.
csharp_style_throw_expression = false:silent
csharp_style_conditional_delegate_call = true:error
csharp_style_prefer_index_operator = true:suggestion
csharp_style_prefer_range_operator = true:suggestion
csharp_style_prefer_null_check_over_type_check = true:error
csharp_style_prefer_tuple_swap = true:suggestion
csharp_style_prefer_utf8_string_literals = true:suggestion
csharp_style_prefer_readonly_struct = true:suggestion
csharp_style_prefer_readonly_struct_member = true:suggestion
csharp_style_prefer_primary_constructors = false:suggestion

csharp_prefer_simple_using_statement = true:suggestion
csharp_prefer_static_local_function = true:error
csharp_prefer_static_anonymous_function = true:suggestion
csharp_prefer_braces = true:error
csharp_style_namespace_declarations = file_scoped:error
csharp_style_prefer_method_group_conversion = true:suggestion
csharp_style_prefer_top_level_statements = false:suggestion
# IDE0058: requiring `_ =` on every ignored return value is noise. Ignoring the
# result of calls such as `Directory.CreateDirectory` is ordinary C#.
csharp_style_unused_value_expression_statement_preference = discard_variable:silent
# IDE0059 catches dead stores, which are a real defect signal.
csharp_style_unused_value_assignment_preference = discard_variable:error

csharp_using_directive_placement = outside_namespace:error

#### C# formatting ####

csharp_new_line_before_open_brace = all
csharp_new_line_before_else = true
csharp_new_line_before_catch = true
csharp_new_line_before_finally = true
csharp_new_line_before_members_in_object_initializers = true
csharp_new_line_before_members_in_anonymous_types = true
csharp_new_line_between_query_expression_clauses = true

csharp_indent_case_contents = true
csharp_indent_case_contents_when_block = false
csharp_indent_switch_labels = true
csharp_indent_labels = one_less_than_current
csharp_indent_block_contents = true
csharp_indent_braces = false

csharp_space_after_cast = false
csharp_space_after_keywords_in_control_flow_statements = true
csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
csharp_space_between_method_declaration_name_and_open_parenthesis = false
csharp_space_between_method_call_parameter_list_parentheses = false
csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_space_between_method_call_name_and_opening_parenthesis = false
csharp_space_after_comma = true
csharp_space_before_comma = false
csharp_space_after_dot = false
csharp_space_before_dot = false
csharp_space_after_semicolon_in_for_statement = true
csharp_space_before_semicolon_in_for_statement = false
csharp_space_around_declaration_statements = false
csharp_space_before_open_square_brackets = false
csharp_space_between_empty_square_brackets = false
csharp_space_between_square_brackets = false
csharp_space_around_binary_operators = before_and_after

csharp_preserve_single_line_statements = false
csharp_preserve_single_line_blocks = true

#### Naming conventions ####

dotnet_naming_style.pascal_case.capitalization = pascal_case
dotnet_naming_style.camel_case.capitalization = camel_case

dotnet_naming_style.interface_prefix.capitalization = pascal_case
dotnet_naming_style.interface_prefix.required_prefix = I

dotnet_naming_style.type_parameter_prefix.capitalization = pascal_case
dotnet_naming_style.type_parameter_prefix.required_prefix = T

dotnet_naming_style.underscore_camel_case.capitalization = camel_case
dotnet_naming_style.underscore_camel_case.required_prefix = _

dotnet_naming_symbols.interfaces.applicable_kinds = interface
dotnet_naming_symbols.interfaces.applicable_accessibilities = *

dotnet_naming_symbols.type_parameters.applicable_kinds = type_parameter
dotnet_naming_symbols.type_parameters.applicable_accessibilities = *

dotnet_naming_symbols.types_and_members.applicable_kinds = class, struct, enum, property, method, event, delegate, local_function
dotnet_naming_symbols.types_and_members.applicable_accessibilities = *

dotnet_naming_symbols.constants.applicable_kinds = field
dotnet_naming_symbols.constants.applicable_accessibilities = *
dotnet_naming_symbols.constants.required_modifiers = const

dotnet_naming_symbols.static_readonly_fields.applicable_kinds = field
dotnet_naming_symbols.static_readonly_fields.applicable_accessibilities = *
dotnet_naming_symbols.static_readonly_fields.required_modifiers = static, readonly

dotnet_naming_symbols.instance_fields.applicable_kinds = field
dotnet_naming_symbols.instance_fields.applicable_accessibilities = private, private_protected

dotnet_naming_symbols.parameters_and_locals.applicable_kinds = parameter, local

dotnet_naming_rule.interfaces_are_prefixed.symbols = interfaces
dotnet_naming_rule.interfaces_are_prefixed.style = interface_prefix
dotnet_naming_rule.interfaces_are_prefixed.severity = error

dotnet_naming_rule.type_parameters_are_prefixed.symbols = type_parameters
dotnet_naming_rule.type_parameters_are_prefixed.style = type_parameter_prefix
dotnet_naming_rule.type_parameters_are_prefixed.severity = error

dotnet_naming_rule.constants_are_pascal_case.symbols = constants
dotnet_naming_rule.constants_are_pascal_case.style = pascal_case
dotnet_naming_rule.constants_are_pascal_case.severity = error

dotnet_naming_rule.static_readonly_fields_are_pascal_case.symbols = static_readonly_fields
dotnet_naming_rule.static_readonly_fields_are_pascal_case.style = pascal_case
dotnet_naming_rule.static_readonly_fields_are_pascal_case.severity = error

dotnet_naming_rule.instance_fields_are_underscore_camel_case.symbols = instance_fields
dotnet_naming_rule.instance_fields_are_underscore_camel_case.style = underscore_camel_case
dotnet_naming_rule.instance_fields_are_underscore_camel_case.severity = error

dotnet_naming_rule.parameters_and_locals_are_camel_case.symbols = parameters_and_locals
dotnet_naming_rule.parameters_and_locals_are_camel_case.style = camel_case
dotnet_naming_rule.parameters_and_locals_are_camel_case.severity = error

dotnet_naming_rule.types_and_members_are_pascal_case.symbols = types_and_members
dotnet_naming_rule.types_and_members_are_pascal_case.style = pascal_case
dotnet_naming_rule.types_and_members_are_pascal_case.severity = error

#### Analyzer severities ####
#
# IDE style and naming rules above are errors: the tree is clean of them and
# CI must reject new drift.
#
# The CA rules below are still a known backlog and report as warnings. Later
# PRs in this stack promote one cohesive family at a time to `error` in the
# same change that clears it.

# Unnecessary usings. Requires `GenerateDocumentationFile` to run at build time.
dotnet_diagnostic.IDE0005.severity = error

# Style rules cleared by the formatting layer.
dotnet_diagnostic.IDE0305.severity = error
dotnet_diagnostic.IDE0330.severity = error

# Interop and security.
dotnet_diagnostic.CA5392.severity = error
dotnet_diagnostic.CA1838.severity = error

# Public contracts and globalization.
dotnet_diagnostic.CA1062.severity = error
dotnet_diagnostic.CA1307.severity = error
dotnet_diagnostic.CA1308.severity = error

# Asynchronous code.
dotnet_diagnostic.CA2007.severity = error
dotnet_diagnostic.CA1849.severity = error

# Lifetime and design.
dotnet_diagnostic.CA2000.severity = error
dotnet_diagnostic.CA1031.severity = error
dotnet_diagnostic.CA1515.severity = error
dotnet_diagnostic.CA1859.severity = error

[tests/**/*.cs]
# xUnit theory and member data intentionally expose public members, and test
# names describe scenarios rather than following production naming.
dotnet_diagnostic.CA1515.severity = none
70 changes: 55 additions & 15 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ Run commands from the repository root in PowerShell 7 (`pwsh`).
dotnet restore .\OpenClaw.Gateway.MSIX.slnx
dotnet build .\OpenClaw.Gateway.MSIX.slnx --configuration Release --no-restore

# Canonical quality gate: restore plus a Release rebuild with static analysis.
# Used by local development, CI, and the optional pre-push hook.
.\scripts\Test-DotNetQuality.ps1

# Publish the launcher through the NativeAOT toolchain without MSIX content.
$vsInstaller = Join-Path `
([Environment]::GetFolderPath([Environment+SpecialFolder]::ProgramFilesX86)) `
Expand Down Expand Up @@ -53,52 +57,88 @@ and ARM64 separately.
app execution alias and declares the `OpenClaw.Gateway` MSIX identity.
- The package contains an expanded, read-only OpenClaw application tree.
`HostOptions` resolves `app\openclaw.mjs` directly from the package.
- `openclaw` resolves device-installed Node.js, confirms the packaged entry
point exists, and forwards every argument unchanged to `openclaw.mjs`.
- `clawctl setup` is a read-only readiness check for compatible Node.js and the
packaged entry point. Runtime launches do not hash or walk package files.
- `openclaw` resolves the Node.js executable extracted into package LocalState,
confirms the packaged entry point exists, and forwards every argument
unchanged to `openclaw.mjs`.
- `clawctl setup` validates and reuses or repairs the architecture-specific
bundled Node.js runtime in versioned package LocalState and verifies the
packaged entry point. Runtime launches do not hash or walk application files.
- `clawctl` parses its own arguments with System.CommandLine
(`ClawCtlCommandLine` builds the tree; `Program.RunControlAsync` invokes it).
Help, usage, version, and completion are library behavior; parse errors exit
`1`. Response-file expansion is disabled, so `@file` is an ordinary
unrecognized argument. The library is scoped to `clawctl` only and must never
see `openclaw` arguments.
- `GatewayLauncher` starts Node without a shell, uses `ArgumentList`, inherits
the console streams, and sets `OPENCLAW_SUPERVISOR_MODE=external` plus
`OPENCLAW_NO_AUTO_UPDATE=1`. The child process exit code is the launcher exit
code.
code. Only the child environment prepends the bundled runtime to `PATH`.
- Diagnostics are written to packaged LocalState (or
`%LOCALAPPDATA%\OpenClawGatewayMSIX` outside an MSIX context) with a named
mutex so concurrent processes append complete records.
- The GitHub workflow first builds and packs a pinned
`openclaw/openclaw` revision on Linux. Windows matrix jobs use
`Build-Payload.ps1` to produce x64/ARM64 expanded trees and build metadata,
then `Build-MSIX.ps1` to reject bundled Node.js, build the application
inventory, publish the NativeAOT host, validate package contents, and emit
MSIX metadata.
- The GitHub workflow first builds and packs a pinned `openclaw/openclaw`
revision on Linux using that revision's `setup-node-env` action. The resolved
Node.js version flows through `source.json` and `payload-metadata.json`;
Windows payload builds use the same version. `Build-MSIX.ps1` downloads its
matching official archive, rejects Node.js from the application payload,
builds the application inventory, publishes the NativeAOT host, validates
package contents, and emits MSIX metadata including the runtime hash.
- Unsigned artifacts are the normal PR/push output. Test signing uses a
temporary runner-local certificate. Official signing is gated to `main` and
the immutable upstream commit in `release-policy.json`; signing inputs are
validated before Azure credentials are requested.

## Repository conventions

- Static analysis uses only the analyzers shipped by the pinned SDK.
`Directory.Build.props` sets `AnalysisMode=All`, `EnforceCodeStyleInBuild`,
and `GenerateDocumentationFile` (required for build-time `IDE0005`), and
suppresses `CS1591`. Rule severity belongs in the root `.editorconfig`, not
in the project files. `TreatWarningsAsErrors` is on and the build is
warning-free, so any new warning fails the build; only NuGet audit
advisories (`NU1901`-`NU1904`) are excluded, because a new advisory can break
an unchanged dependency graph. Do not commit a generated suppression
baseline; fix the diagnostic or add a narrow suppression with a written
rationale.
- The pre-push hook is opt in. `scripts\Install-GitHooks.ps1` copies the
tracked `hooks\pre-push` into the current clone and `-Remove` deletes it.
Never change `core.hooksPath` or global Git configuration, and never
overwrite a hook the repository did not write.
- `.gitattributes` normalizes tracked text to LF and `.editorconfig` sets
`end_of_line = lf`. Avoid whole-file rewrites through `Set-Content` or
`Out-File`, which reintroduce CRLF.
- Ordinary builds and tests must leave `IncludePackagingContent` unset.
Packaging builds set it to `true`, supply a runtime identifier and platform,
and use `obj\packaging` through `Directory.Build.props` to isolate MSIX
intermediates.
- Treat launcher arguments as OpenClaw-owned. Do not add host-only switches,
consume `--`, rewrite arguments, or block upstream commands; tests explicitly
protect transparent forwarding.
- Preserve direct execution from the immutable package and the caller's
working directory. Do not add runtime extraction, copying, hashing, or
inventory walks.
- Preserve direct execution of `app\openclaw.mjs` from the immutable package
and the caller's working directory. Node.js extraction belongs only to
`clawctl setup` and targets versioned package LocalState; do not copy the
OpenClaw application payload.
- The build-time inventory is a release trust boundary. Keep safe unique paths,
lengths, and SHA-256 values synchronized across composition and signing
validation.
- Keep x64 and ARM64 behavior synchronized across the workflow matrix, scripts,
project runtime identifiers, manifest content, payload metadata, and signing
validation.
- Do not add a packaging-side Node.js version pin or support-range policy.
The selected upstream toolchain owns version selection; package composition
supplies `NodeRuntimeArchiveFileName`, and the host reads the archive name.
- Official releases combine the x64 and ARM64 packages into one signed
`.msixbundle` while retaining signed standalone packages for explicit
architecture-specific deployment. Compose the bundle before signing; bundle
signing recursively covers its contained packages.
- Metadata files are part of the release trust chain, not incidental build
output. Changes to their fields must be coordinated across payload creation,
MSIX creation, signing validation, workflow artifacts, and tests.
- Keep the workflow's manual `openclaw_ref` default and automatic
`env.OPENCLAW_REF` fallback identical. Official-release changes also update
the reviewed immutable commit in `release-policy.json`.
the reviewed immutable commit and stable or correction tag in
`release-policy.json`. The tag determines the four-part MSIX identity
version and the permanent GitHub Release tag.
- The launcher is NativeAOT. `dotnet build` and the xUnit suite exercise a JIT
build, so run the NativeAOT publish path when changing reflection, interop,
or trimming-sensitive code.
Expand Down
Loading
Loading