Skip to content
Closed
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
2 changes: 2 additions & 0 deletions docs/adapter-packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Adapters run with the user's OS permissions. They are different from isolated de

Choose **Connect a host → Use connection adapters**. Select an installed, enabled adapter and complete its configuration fields. A connection may provide both Files and Terminal, or use **Add another connection** to assign those roles to separate adapter processes. Roles are explicit: an unavailable service is disabled rather than silently routed elsewhere.

The [ShellCanvas FTP adapter](https://github.com/techartdev/ShellCanvas-FTP) is suggested in App Manager. It supplies Files over explicit FTPS by default, with an opt-in plain FTP mode for restricted servers. The current preview browses folders, previews text, and downloads files; it does not offer uploads or file changes. FTP connects to the named server independently of SSH and needs the server's passive data ports reachable from this PC.

The bridges provide file browsing/previews and console byte streams, with optional resize. Optional file methods enable text reading/creation/saving, folder creation, rename, move, removal, and streaming uploads/downloads/copies. Optional directory readers enable folder transfers without collecting a whole tree in memory. **Remote settings** is a separate role with provider-defined fields and optional revision-checked changes. Unsupported desktop actions remain unavailable. A device that advertises only files can still open a workspace. Failure to initialize any selected source currently fails the initial composite connection; after connection, source availability is tracked independently.

Adapter connection settings survive whole-workspace reconnect in memory and can be explicitly saved through the connection dialog's **Saved workspace** controls. [Saved workspace profiles](workspace-profiles.md) persist public settings and explicit service assignments, omit password fields, and use revision-checked updates/removal. Reconnect preserves the desktop windows and creates fresh native session/console handles. It can use the currently installed version of the same adapter, while preserving the original service assignments and non-secret configuration. **SSH (built in)** can supply services alongside installed adapters and participates in source replacement with the existing host-key review. It is offered by the connection chooser, not installed or removed through the package manager. The existing saved SSH profiles continue to use their own connection flow.
Expand Down
64 changes: 63 additions & 1 deletion src/extensions/AdapterManager.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
// SPDX-License-Identifier: MPL-2.0
import { useEffect, useRef, useState } from "react";
import { Cable, Plus, RefreshCw, ShieldAlert, X } from "lucide-react";
import {
Cable,
FolderDown,
Plus,
RefreshCw,
ShieldAlert,
X,
} from "lucide-react";
import type { AdapterInfo, AdapterReview, AdapterServices } from "../adapters";
import { AdapterDiagnosticsPanel } from "../components/AdapterDiagnosticsPanel";
import { ftpAdapterSource } from "./ftp-adapter";
export function AdapterManager({ services }: { services: AdapterServices }) {
const [items, setItems] = useState<AdapterInfo[]>([]),
[busy, setBusy] = useState(false),
Expand Down Expand Up @@ -63,6 +71,27 @@ export function AdapterManager({ services }: { services: AdapterServices }) {
if (!result) pending.current = null;
});
}
async function inspectFtp() {
if (!services.reviewRepository) return;
const id = crypto.randomUUID();
pending.current = id;
setTrusted(false);
await run(async () => {
let result: AdapterReview;
try {
result = await services.reviewRepository!(id, ftpAdapterSource);
} catch (error) {
if (pending.current !== id) return;
pending.current = null;
throw error;
}
if (!active.current || pending.current !== id) {
await services.cancelReview(id);
return;
}
setReview(result);
});
}
async function cancel() {
const id = pending.current;
pending.current = null;
Expand Down Expand Up @@ -252,6 +281,39 @@ export function AdapterManager({ services }: { services: AdapterServices }) {
</p>
</div>
)}
{services.reviewRepository &&
!items.some(
(item) =>
item.id === ftpAdapterSource.id &&
item.version === ftpAdapterSource.version,
) && (
<article
className="extension-card"
aria-label="Suggested FTP adapter"
>
<div className="extension-review-heading">
<div>
<p className="extension-eyebrow">SUGGESTED ADAPTER</p>
<h3>
<FolderDown size={17} /> FTP files
</h3>
<p>
Browse and download files from FTP servers. Uses explicit FTPS
by default, with an option for plain FTP.
</p>
<p>
Uploads and file changes are not available in this preview.
</p>
</div>
<button
disabled={busy || !!review}
onClick={() => void inspectFtp()}
>
Review adapter
</button>
</div>
</article>
)}
<p className="extension-footnote">
Updates and disabling apply to new connections. Running connections keep
their installed version.
Expand Down
37 changes: 37 additions & 0 deletions src/extensions/ftp-adapter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: MPL-2.0
import type { RepositoryAdapterSource } from "../adapters";

/** The manifest hashes are pinned to the reviewed v0.1.0 repository tag. */
export const ftpAdapterSource: RepositoryAdapterSource = {
owner: "techartdev",
repository: "ShellCanvas-FTP",
reference: "v0.1.0",
id: "dev.shellcanvas.ftp",
version: "0.1.0",
packages: [
{
platform: "windows-x86_64",
path: "dist/windows-x86_64/adapter.json",
sha256:
"74f1c81b25e4c93e54c73e1a53cf9ee403bb9917afe752240b206f12b9be1e89",
},
{
platform: "linux-x86_64",
path: "dist/linux-x86_64/adapter.json",
sha256:
"709f183f80367b9fc67b3e76d7182d4de0d31d2d9c1b0c9d8712017ac3af1d77",
},
{
platform: "macos-x86_64",
path: "dist/macos-x86_64/adapter.json",
sha256:
"34c6c43b15b1fd8f93b7272b9e86a8f02fed52085d5339c2e059a7be4a3a539f",
},
{
platform: "macos-aarch64",
path: "dist/macos-aarch64/adapter.json",
sha256:
"280ccd267a8129de232f7bd6c6e7e0299345e21611d38964f73959e7d1d26d5b",
},
],
};