Skip to content

fix: dispatch plugin CLI commands#591

Merged
intel352 merged 1 commit into
mainfrom
codex/wfctl-plugin-cli-compute
May 10, 2026
Merged

fix: dispatch plugin CLI commands#591
intel352 merged 1 commit into
mainfrom
codex/wfctl-plugin-cli-compute

Conversation

@intel352

Copy link
Copy Markdown
Contributor

Summary

  • dispatch unknown top-level wfctl commands through installed plugin cliCommands
  • use $WFCTL_PLUGIN_DIR or data/plugins for plugin command discovery
  • reserve every static wfctl command name when validating plugin CLI declarations

Verification

  • GOWORK=off go test ./cmd/wfctl -run 'TestPluginCLIRegistry|TestStaticCommandWins|TestRunValidatePluginDir'
  • GOWORK=off go test ./cmd/wfctl
  • live local smoke with workflow-plugin-compute: wfctl compute audit, pools, run, and enroll routed through the installed plugin path to a local compute-server

Review

  • Antagonistic/security review completed before commit; no blocking findings on the Workflow routing patch.
  • Plugin-side follow-up findings were fixed in workflow-plugin-compute before relying on this path.

Copilot AI review requested due to automatic review settings May 10, 2026 00:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Enables wfctl to route unknown top-level commands to installed external plugins that declare cliCommands, using $WFCTL_PLUGIN_DIR (or the default data/plugins) as the discovery root, and tightens validation so plugins cannot shadow any built-in wfctl command names.

Changes:

  • Treats all static wfctl command names as reserved during plugin CLI command validation (via commands map).
  • Adds main dispatch path to execute plugin binaries for unknown commands discovered from installed plugins.
  • Extends tests to cover the “all static commands are reserved” invariant.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
cmd/wfctl/plugin_cli_commands.go Expands reserved-name detection to include all static command names in commands.
cmd/wfctl/plugin_cli_commands_test.go Updates fixtures and adds coverage asserting every static command is reserved.
cmd/wfctl/main.go Adds runtime dispatch for unknown commands via plugin cliCommands and chooses plugin directory via env/default.

Comment thread cmd/wfctl/main.go
Comment on lines +189 to +193
if _, isStatic := commands[cmd]; !isStatic {
registry, err := BuildCLIRegistry(defaultPluginCommandDir())
if err != nil {
fmt.Fprintf(os.Stderr, "error: load plugin CLI commands: %v\n", err) //nolint:gosec // G705
os.Exit(1)
Comment thread cmd/wfctl/main.go
Comment on lines +190 to +197
registry, err := BuildCLIRegistry(defaultPluginCommandDir())
if err != nil {
fmt.Fprintf(os.Stderr, "error: load plugin CLI commands: %v\n", err) //nolint:gosec // G705
os.Exit(1)
}
if entry := registry.LookupCLICommand(cmd); entry != nil {
if err := DispatchCLICommand(entry, os.Args[1:]); err != nil {
fmt.Fprintf(os.Stderr, "error: %v\n", err) //nolint:gosec // G705
@github-actions

Copy link
Copy Markdown

⏱ Benchmark Results

No significant performance regressions detected.

benchstat comparison (baseline → PR)
## benchstat: baseline → PR
baseline-bench.txt:262: parsing iteration count: invalid syntax
baseline-bench.txt:299828: parsing iteration count: invalid syntax
baseline-bench.txt:580278: parsing iteration count: invalid syntax
baseline-bench.txt:878929: parsing iteration count: invalid syntax
baseline-bench.txt:1180127: parsing iteration count: invalid syntax
baseline-bench.txt:1565637: parsing iteration count: invalid syntax
benchmark-results.txt:262: parsing iteration count: invalid syntax
benchmark-results.txt:337721: parsing iteration count: invalid syntax
benchmark-results.txt:625917: parsing iteration count: invalid syntax
benchmark-results.txt:932884: parsing iteration count: invalid syntax
benchmark-results.txt:1244354: parsing iteration count: invalid syntax
benchmark-results.txt:1549302: parsing iteration count: invalid syntax
goos: linux
goarch: amd64
pkg: github.com/GoCodeAlone/workflow/dynamic
cpu: AMD EPYC 7763 64-Core Processor                
                            │ benchmark-results.txt │
                            │        sec/op         │
InterpreterCreation-4                 3.303m ± 191%
ComponentLoad-4                       3.557m ±   1%
ComponentExecute-4                    1.925µ ±   0%
PoolContention/workers-1-4            1.079µ ±   2%
PoolContention/workers-2-4            1.087µ ±   2%
PoolContention/workers-4-4            1.085µ ±   2%
PoolContention/workers-8-4            1.098µ ±   2%
PoolContention/workers-16-4           1.085µ ±   1%
ComponentLifecycle-4                  3.653m ±   1%
SourceValidation-4                    2.328µ ±   1%
RegistryConcurrent-4                  809.0n ±   2%
LoaderLoadFromString-4                3.617m ±   1%
geomean                               17.55µ

                            │ benchmark-results.txt │
                            │         B/op          │
InterpreterCreation-4                  2.027Mi ± 0%
ComponentLoad-4                        2.180Mi ± 0%
ComponentExecute-4                     1.203Ki ± 0%
PoolContention/workers-1-4             1.203Ki ± 0%
PoolContention/workers-2-4             1.203Ki ± 0%
PoolContention/workers-4-4             1.203Ki ± 0%
PoolContention/workers-8-4             1.203Ki ± 0%
PoolContention/workers-16-4            1.203Ki ± 0%
ComponentLifecycle-4                   2.183Mi ± 0%
SourceValidation-4                     1.984Ki ± 0%
RegistryConcurrent-4                   1.133Ki ± 0%
LoaderLoadFromString-4                 2.182Mi ± 0%
geomean                                15.25Ki

                            │ benchmark-results.txt │
                            │       allocs/op       │
InterpreterCreation-4                   15.68k ± 0%
ComponentLoad-4                         18.02k ± 0%
ComponentExecute-4                       25.00 ± 0%
PoolContention/workers-1-4               25.00 ± 0%
PoolContention/workers-2-4               25.00 ± 0%
PoolContention/workers-4-4               25.00 ± 0%
PoolContention/workers-8-4               25.00 ± 0%
PoolContention/workers-16-4              25.00 ± 0%
ComponentLifecycle-4                    18.07k ± 0%
SourceValidation-4                       32.00 ± 0%
RegistryConcurrent-4                     2.000 ± 0%
LoaderLoadFromString-4                  18.06k ± 0%
geomean                                  183.3

cpu: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz
                            │ baseline-bench.txt │
                            │       sec/op       │
InterpreterCreation-4               6.817m ± 56%
ComponentLoad-4                     3.450m ± 14%
ComponentExecute-4                  1.855µ ±  1%
PoolContention/workers-1-4          1.188µ ±  0%
PoolContention/workers-2-4          1.183µ ±  1%
PoolContention/workers-4-4          1.182µ ±  1%
PoolContention/workers-8-4          1.189µ ±  1%
PoolContention/workers-16-4         1.202µ ±  3%
ComponentLifecycle-4                3.483m ±  1%
SourceValidation-4                  2.245µ ±  1%
RegistryConcurrent-4                962.9n ±  6%
LoaderLoadFromString-4              3.620m ±  1%
geomean                             19.39µ

                            │ baseline-bench.txt │
                            │        B/op        │
InterpreterCreation-4               2.027Mi ± 0%
ComponentLoad-4                     2.180Mi ± 0%
ComponentExecute-4                  1.203Ki ± 0%
PoolContention/workers-1-4          1.203Ki ± 0%
PoolContention/workers-2-4          1.203Ki ± 0%
PoolContention/workers-4-4          1.203Ki ± 0%
PoolContention/workers-8-4          1.203Ki ± 0%
PoolContention/workers-16-4         1.203Ki ± 0%
ComponentLifecycle-4                2.183Mi ± 0%
SourceValidation-4                  1.984Ki ± 0%
RegistryConcurrent-4                1.133Ki ± 0%
LoaderLoadFromString-4              2.182Mi ± 0%
geomean                             15.25Ki

                            │ baseline-bench.txt │
                            │     allocs/op      │
InterpreterCreation-4                15.68k ± 0%
ComponentLoad-4                      18.02k ± 0%
ComponentExecute-4                    25.00 ± 0%
PoolContention/workers-1-4            25.00 ± 0%
PoolContention/workers-2-4            25.00 ± 0%
PoolContention/workers-4-4            25.00 ± 0%
PoolContention/workers-8-4            25.00 ± 0%
PoolContention/workers-16-4           25.00 ± 0%
ComponentLifecycle-4                 18.07k ± 0%
SourceValidation-4                    32.00 ± 0%
RegistryConcurrent-4                  2.000 ± 0%
LoaderLoadFromString-4               18.06k ± 0%
geomean                               183.3

pkg: github.com/GoCodeAlone/workflow/middleware
cpu: AMD EPYC 7763 64-Core Processor                
                                  │ benchmark-results.txt │
                                  │        sec/op         │
CircuitBreakerDetection-4                     285.8n ± 6%
CircuitBreakerExecution_Success-4             21.55n ± 0%
CircuitBreakerExecution_Failure-4             66.38n ± 1%
geomean                                       74.22n

                                  │ benchmark-results.txt │
                                  │         B/op          │
CircuitBreakerDetection-4                    144.0 ± 0%
CircuitBreakerExecution_Success-4            0.000 ± 0%
CircuitBreakerExecution_Failure-4            0.000 ± 0%
geomean                                                 ¹
¹ summaries must be >0 to compute geomean

                                  │ benchmark-results.txt │
                                  │       allocs/op       │
CircuitBreakerDetection-4                    1.000 ± 0%
CircuitBreakerExecution_Success-4            0.000 ± 0%
CircuitBreakerExecution_Failure-4            0.000 ± 0%
geomean                                                 ¹
¹ summaries must be >0 to compute geomean

cpu: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz
                                  │ baseline-bench.txt │
                                  │       sec/op       │
CircuitBreakerDetection-4                  455.2n ± 3%
CircuitBreakerExecution_Success-4          59.76n ± 1%
CircuitBreakerExecution_Failure-4          64.86n ± 1%
geomean                                    120.8n

                                  │ baseline-bench.txt │
                                  │        B/op        │
CircuitBreakerDetection-4                 144.0 ± 0%
CircuitBreakerExecution_Success-4         0.000 ± 0%
CircuitBreakerExecution_Failure-4         0.000 ± 0%
geomean                                              ¹
¹ summaries must be >0 to compute geomean

                                  │ baseline-bench.txt │
                                  │     allocs/op      │
CircuitBreakerDetection-4                 1.000 ± 0%
CircuitBreakerExecution_Success-4         0.000 ± 0%
CircuitBreakerExecution_Failure-4         0.000 ± 0%
geomean                                              ¹
¹ summaries must be >0 to compute geomean

pkg: github.com/GoCodeAlone/workflow/module
cpu: AMD EPYC 7763 64-Core Processor                
                                 │ benchmark-results.txt │
                                 │        sec/op         │
JQTransform_Simple-4                        880.2n ± 28%
JQTransform_ObjectConstruction-4            1.453µ ±  1%
JQTransform_ArraySelect-4                   3.350µ ±  1%
JQTransform_Complex-4                       38.65µ ±  1%
JQTransform_Throughput-4                    1.806µ ±  1%
SSEPublishDelivery-4                        63.62n ±  2%
geomean                                     1.634µ

                                 │ benchmark-results.txt │
                                 │         B/op          │
JQTransform_Simple-4                      1.273Ki ± 0%
JQTransform_ObjectConstruction-4          1.773Ki ± 0%
JQTransform_ArraySelect-4                 2.625Ki ± 0%
JQTransform_Complex-4                     16.22Ki ± 0%
JQTransform_Throughput-4                  1.984Ki ± 0%
SSEPublishDelivery-4                        0.000 ± 0%
geomean                                                ¹
¹ summaries must be >0 to compute geomean

                                 │ benchmark-results.txt │
                                 │       allocs/op       │
JQTransform_Simple-4                        10.00 ± 0%
JQTransform_ObjectConstruction-4            15.00 ± 0%
JQTransform_ArraySelect-4                   30.00 ± 0%
JQTransform_Complex-4                       324.0 ± 0%
JQTransform_Throughput-4                    17.00 ± 0%
SSEPublishDelivery-4                        0.000 ± 0%
geomean                                                ¹
¹ summaries must be >0 to compute geomean

cpu: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz
                                 │ baseline-bench.txt │
                                 │       sec/op       │
JQTransform_Simple-4                     909.2n ± 27%
JQTransform_ObjectConstruction-4         1.484µ ±  1%
JQTransform_ArraySelect-4                3.264µ ±  1%
JQTransform_Complex-4                    36.34µ ±  1%
JQTransform_Throughput-4                 1.840µ ±  2%
SSEPublishDelivery-4                     77.36n ±  1%
geomean                                  1.684µ

                                 │ baseline-bench.txt │
                                 │        B/op        │
JQTransform_Simple-4                   1.273Ki ± 0%
JQTransform_ObjectConstruction-4       1.773Ki ± 0%
JQTransform_ArraySelect-4              2.625Ki ± 0%
JQTransform_Complex-4                  16.22Ki ± 0%
JQTransform_Throughput-4               1.984Ki ± 0%
SSEPublishDelivery-4                     0.000 ± 0%
geomean                                             ¹
¹ summaries must be >0 to compute geomean

                                 │ baseline-bench.txt │
                                 │     allocs/op      │
JQTransform_Simple-4                     10.00 ± 0%
JQTransform_ObjectConstruction-4         15.00 ± 0%
JQTransform_ArraySelect-4                30.00 ± 0%
JQTransform_Complex-4                    324.0 ± 0%
JQTransform_Throughput-4                 17.00 ± 0%
SSEPublishDelivery-4                     0.000 ± 0%
geomean                                             ¹
¹ summaries must be >0 to compute geomean

pkg: github.com/GoCodeAlone/workflow/schema
cpu: AMD EPYC 7763 64-Core Processor                
                                    │ benchmark-results.txt │
                                    │        sec/op         │
SchemaValidation_Simple-4                      1.121µ ± 17%
SchemaValidation_AllFields-4                   1.705µ ±  4%
SchemaValidation_FormatValidation-4            1.599µ ±  2%
SchemaValidation_ManySchemas-4                 1.833µ ±  4%
geomean                                        1.538µ

                                    │ benchmark-results.txt │
                                    │         B/op          │
SchemaValidation_Simple-4                      0.000 ± 0%
SchemaValidation_AllFields-4                   0.000 ± 0%
SchemaValidation_FormatValidation-4            0.000 ± 0%
SchemaValidation_ManySchemas-4                 0.000 ± 0%
geomean                                                   ¹
¹ summaries must be >0 to compute geomean

                                    │ benchmark-results.txt │
                                    │       allocs/op       │
SchemaValidation_Simple-4                      0.000 ± 0%
SchemaValidation_AllFields-4                   0.000 ± 0%
SchemaValidation_FormatValidation-4            0.000 ± 0%
SchemaValidation_ManySchemas-4                 0.000 ± 0%
geomean                                                   ¹
¹ summaries must be >0 to compute geomean

cpu: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz
                                    │ baseline-bench.txt │
                                    │       sec/op       │
SchemaValidation_Simple-4                   1.045µ ± 28%
SchemaValidation_AllFields-4                1.546µ ±  7%
SchemaValidation_FormatValidation-4         1.501µ ±  1%
SchemaValidation_ManySchemas-4              1.509µ ±  3%
geomean                                     1.383µ

                                    │ baseline-bench.txt │
                                    │        B/op        │
SchemaValidation_Simple-4                   0.000 ± 0%
SchemaValidation_AllFields-4                0.000 ± 0%
SchemaValidation_FormatValidation-4         0.000 ± 0%
SchemaValidation_ManySchemas-4              0.000 ± 0%
geomean                                                ¹
¹ summaries must be >0 to compute geomean

                                    │ baseline-bench.txt │
                                    │     allocs/op      │
SchemaValidation_Simple-4                   0.000 ± 0%
SchemaValidation_AllFields-4                0.000 ± 0%
SchemaValidation_FormatValidation-4         0.000 ± 0%
SchemaValidation_ManySchemas-4              0.000 ± 0%
geomean                                                ¹
¹ summaries must be >0 to compute geomean

pkg: github.com/GoCodeAlone/workflow/store
cpu: AMD EPYC 7763 64-Core Processor                
                                   │ benchmark-results.txt │
                                   │        sec/op         │
EventStoreAppend_InMemory-4                   1.122µ ± 18%
EventStoreAppend_SQLite-4                     1.323m ±  6%
GetTimeline_InMemory/events-10-4              14.12µ ±  6%
GetTimeline_InMemory/events-50-4              76.96µ ± 19%
GetTimeline_InMemory/events-100-4             124.5µ ±  2%
GetTimeline_InMemory/events-500-4             638.2µ ±  1%
GetTimeline_InMemory/events-1000-4            1.300m ±  2%
GetTimeline_SQLite/events-10-4                109.7µ ±  1%
GetTimeline_SQLite/events-50-4                251.1µ ±  2%
GetTimeline_SQLite/events-100-4               421.0µ ±  3%
GetTimeline_SQLite/events-500-4               1.806m ±  2%
GetTimeline_SQLite/events-1000-4              3.537m ±  1%
geomean                                       219.3µ

                                   │ benchmark-results.txt │
                                   │         B/op          │
EventStoreAppend_InMemory-4                     814.0 ± 8%
EventStoreAppend_SQLite-4                     1.985Ki ± 2%
GetTimeline_InMemory/events-10-4              7.953Ki ± 0%
GetTimeline_InMemory/events-50-4              46.62Ki ± 0%
GetTimeline_InMemory/events-100-4             94.48Ki ± 0%
GetTimeline_InMemory/events-500-4             472.8Ki ± 0%
GetTimeline_InMemory/events-1000-4            944.3Ki ± 0%
GetTimeline_SQLite/events-10-4                16.74Ki ± 0%
GetTimeline_SQLite/events-50-4                87.14Ki ± 0%
GetTimeline_SQLite/events-100-4               175.4Ki ± 0%
GetTimeline_SQLite/events-500-4               846.1Ki ± 0%
GetTimeline_SQLite/events-1000-4              1.639Mi ± 0%
geomean                                       67.51Ki

                                   │ benchmark-results.txt │
                                   │       allocs/op       │
EventStoreAppend_InMemory-4                     7.000 ± 0%
EventStoreAppend_SQLite-4                       53.00 ± 0%
GetTimeline_InMemory/events-10-4                125.0 ± 0%
GetTimeline_InMemory/events-50-4                653.0 ± 0%
GetTimeline_InMemory/events-100-4              1.306k ± 0%
GetTimeline_InMemory/events-500-4              6.514k ± 0%
GetTimeline_InMemory/events-1000-4             13.02k ± 0%
GetTimeline_SQLite/events-10-4                  382.0 ± 0%
GetTimeline_SQLite/events-50-4                 1.852k ± 0%
GetTimeline_SQLite/events-100-4                3.681k ± 0%
GetTimeline_SQLite/events-500-4                18.54k ± 0%
GetTimeline_SQLite/events-1000-4               37.29k ± 0%
geomean                                        1.162k

cpu: Intel(R) Xeon(R) Platinum 8370C CPU @ 2.80GHz
                                   │ baseline-bench.txt │
                                   │       sec/op       │
EventStoreAppend_InMemory-4                1.123µ ±  2%
EventStoreAppend_SQLite-4                  978.7µ ±  3%
GetTimeline_InMemory/events-10-4           13.96µ ±  2%
GetTimeline_InMemory/events-50-4           73.72µ ± 19%
GetTimeline_InMemory/events-100-4          120.6µ ±  2%
GetTimeline_InMemory/events-500-4          620.8µ ±  1%
GetTimeline_InMemory/events-1000-4         1.264m ±  1%
GetTimeline_SQLite/events-10-4             84.35µ ±  1%
GetTimeline_SQLite/events-50-4             244.4µ ±  2%
GetTimeline_SQLite/events-100-4            438.3µ ±  1%
GetTimeline_SQLite/events-500-4            1.993m ±  3%
GetTimeline_SQLite/events-1000-4           3.889m ±  2%
geomean                                    210.3µ

                                   │ baseline-bench.txt │
                                   │        B/op        │
EventStoreAppend_InMemory-4                  787.0 ± 7%
EventStoreAppend_SQLite-4                  1.987Ki ± 2%
GetTimeline_InMemory/events-10-4           7.953Ki ± 0%
GetTimeline_InMemory/events-50-4           46.62Ki ± 0%
GetTimeline_InMemory/events-100-4          94.48Ki ± 0%
GetTimeline_InMemory/events-500-4          472.8Ki ± 0%
GetTimeline_InMemory/events-1000-4         944.3Ki ± 0%
GetTimeline_SQLite/events-10-4             16.74Ki ± 0%
GetTimeline_SQLite/events-50-4             87.14Ki ± 0%
GetTimeline_SQLite/events-100-4            175.4Ki ± 0%
GetTimeline_SQLite/events-500-4            846.1Ki ± 0%
GetTimeline_SQLite/events-1000-4           1.639Mi ± 0%
geomean                                    67.33Ki

                                   │ baseline-bench.txt │
                                   │     allocs/op      │
EventStoreAppend_InMemory-4                  7.000 ± 0%
EventStoreAppend_SQLite-4                    53.00 ± 0%
GetTimeline_InMemory/events-10-4             125.0 ± 0%
GetTimeline_InMemory/events-50-4             653.0 ± 0%
GetTimeline_InMemory/events-100-4           1.306k ± 0%
GetTimeline_InMemory/events-500-4           6.514k ± 0%
GetTimeline_InMemory/events-1000-4          13.02k ± 0%
GetTimeline_SQLite/events-10-4               382.0 ± 0%
GetTimeline_SQLite/events-50-4              1.852k ± 0%
GetTimeline_SQLite/events-100-4             3.681k ± 0%
GetTimeline_SQLite/events-500-4             18.54k ± 0%
GetTimeline_SQLite/events-1000-4            37.29k ± 0%
geomean                                     1.162k

Benchmarks run with go test -bench=. -benchmem -count=6.
Regressions ≥ 20% are flagged. Results compared via benchstat.

@intel352 intel352 merged commit 2864eee into main May 10, 2026
22 checks passed
@intel352 intel352 deleted the codex/wfctl-plugin-cli-compute branch May 10, 2026 00:49
intel352 added a commit that referenced this pull request May 10, 2026
…name (#595)

PR #591 wired BuildCLIRegistry into main.go's dispatch fallback, but the
binary-path computation joined manifest.Name twice:

  binaryPath := filepath.Join(pluginsDir, pluginName, pluginName)

where pluginName comes from the manifest map key (= manifest.Name).

This works only when the install directory name matches the manifest
name. In practice setup-plugins composite + `wfctl plugin install` both
extract tarballs to short directory names — `data/plugins/payments`,
`data/plugins/digitalocean`, etc. — while the binary inside is named
after the manifest (`workflow-plugin-payments`). The path therefore
resolved to:

  data/plugins/workflow-plugin-payments/workflow-plugin-payments

which doesn't exist, so DispatchCLICommand reported a fork/exec
failure. Worse, when LookupCLICommand succeeded but Dispatch failed,
operators got a confusing "no such file" error rather than the
plugin's own help.

Refactor BuildCLIRegistry to walk the plugins directory once and
capture both the dir name (for the install path) and the manifest name
(for the binary file name):

  binaryPath := filepath.Join(pluginsDir, dirEntry, manifest.Name)

LoadPluginManifests is no longer used by this path because its keyed
return collapses on manifest.Name and loses the dir name.

Reproducer + regression tests:
  TestPluginCLIRegistry_DirVsManifestNameMismatch — short dir +
    full manifest name (the bug from buymywishlist#260 retrigger).
  TestPluginCLIRegistry_EmptyManifestNameUsesDirName — covers the
    fallback when manifest.Name is empty.

Local repro (pre-fix) reported:
  fork/exec /tmp/test-plugins/workflow-plugin-payments/workflow-plugin-payments:
  no such file or directory

Same plugin tree post-fix dispatches correctly (binary lives at
/tmp/test-plugins/payments/workflow-plugin-payments).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants