Repository navigation
feat(extensions): add provider-less terminal connections - #419
Merged
Merged
Conversation
A connection contribution can now declare `terminal` (command, args, env, title) instead of a provider runtime. The host resolves the templates against the saved non-secret form values and opens a regular local terminal tab, so extensions like tsh-ssh need nothing but an extension.json. - Manifest: runtimeId/resourceType become optional; `terminal` is mutually exclusive with runtimeId, resourceType, shellViewId and workbench bindings. The command is fixed (no placeholders) and placeholders may only reference existing non-secret fields. - Host-side guard: an argument whose template does not start with '-' is rejected if the substituted value does, so shared or synced connection data cannot inject command-line options. Empty optional args/env entries are dropped, control characters are rejected. - Terminal: launched sessions get a fixed tab title, can be duplicated, and restart on Enter after the child process exits. - Connection form hides the Test button for terminal connections. - Docs: describe terminal connections in the extension development guide. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds provider-less terminal connections to the extension system. A connection contribution can now declare a
terminalblock (command,args,env,title) instead of a provider runtime. When the user opens such a connection, the host starts a regular local terminal tab from the declared template, using the non-secret values saved in the connection form.Problem: an extension whose only job is "run a local command with a few saved parameters" (e.g.
tsh ssh <target>for Teleport) still had to ship and spawn a native provider process plus a resource workbench. Sessions are tied to a live provider client, so this could not be simplified without a large rework. With this change, such an extension is a singleextension.jsonwith noruntime, nobin/, and no Rust.What changed:
extension-runtime):runtimeIdandresourceTypebecome optional.terminalis mutually exclusive withruntimeId,resourceType,shellViewId, and workbench bindings.commandis fixed (no placeholders). Placeholders ({{fieldId}})in
args,envvalues andtitlemay only reference existing non-secret form fields. Secret fields are rejected for terminal connections.terminal_launch.rs): substitutes placeholders from the saved connection values. Optional args/env entries that resolve to an empty string are dropped. Control characters in values are rejected.-but the substituted value does, the open is rejected (e.g.target = "-oProxyCommand=..."cannot become ansshoption).terminal,terminal_view): launched sessions get a fixed tab title, can be duplicated, and restart on Enter after the child process exits instead of leaving a dead tab.home_strategy.rs): new branch that opens a terminal tab for contributions withterminal, independent of theshell-pluginsfeature.The companion extension (
tsh-ssh, static composite,engines.onetcli >= 0.20.3) lives innavop-extensionsand is submitted separately. The submodule pointer is intentionally not part of this PR.Break Changes
No behavior change for existing extensions. Two API-level notes:
ResourceConnectionContrib.runtime_id/resource_typenow default to empty on deserialization. Registration still rejects a non-terminal connection that leaves them empty, with the same error as before.RegisteredResourceConnectionContributiongains a publicterminal: Option<ResourceConnectionTerminal>field, so Rust code constructing it by struct literal must addterminal: None.RegisteredResourceConnectionContribution { ... shell_view_id: None, + terminal: None, form: Default::default(), }How to Test
Automated:
cargo test -p extension-runtime --lib -- terminal # template resolution, option-injection guard, registration rules
cargo test -p terminal_view --lib duplicate # duplicate source for launched terminals
cargo test -p terminal --lib restart # restart-after-exit for local sessions
cargo test -p main home
cargo check --workspace --tests
Checklist