From 7355de4b73d30641be44f9015c350dfbb5b5b527 Mon Sep 17 00:00:00 2001 From: techartdev Date: Sat, 26 Sep 2026 23:59:21 +0300 Subject: [PATCH 1/2] Offer hash-pinned FTP adapter in App Manager --- src/extensions/AdapterManager.tsx | 64 ++++++++++++++++++++++++++++++- src/extensions/ftp-adapter.ts | 37 ++++++++++++++++++ 2 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 src/extensions/ftp-adapter.ts diff --git a/src/extensions/AdapterManager.tsx b/src/extensions/AdapterManager.tsx index 5d86a1f..f81ddfd 100644 --- a/src/extensions/AdapterManager.tsx +++ b/src/extensions/AdapterManager.tsx @@ -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([]), [busy, setBusy] = useState(false), @@ -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; @@ -252,6 +281,39 @@ export function AdapterManager({ services }: { services: AdapterServices }) {

)} + {services.reviewRepository && + !items.some( + (item) => + item.id === ftpAdapterSource.id && + item.version === ftpAdapterSource.version, + ) && ( +
+
+
+

SUGGESTED ADAPTER

+

+ FTP files +

+

+ Browse and download files from FTP servers. Uses explicit FTPS + by default, with an option for plain FTP. +

+

+ Uploads and file changes are not available in this preview. +

+
+ +
+
+ )}

Updates and disabling apply to new connections. Running connections keep their installed version. diff --git a/src/extensions/ftp-adapter.ts b/src/extensions/ftp-adapter.ts new file mode 100644 index 0000000..50fc00c --- /dev/null +++ b/src/extensions/ftp-adapter.ts @@ -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", + }, + ], +}; From d503d295cf8242491514a32933beadcd65059707 Mon Sep 17 00:00:00 2001 From: techartdev Date: Sun, 27 Sep 2026 00:03:10 +0300 Subject: [PATCH 2/2] Document FTP adapter connection scope --- docs/adapter-packages.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/adapter-packages.md b/docs/adapter-packages.md index ccd6998..61dd1b2 100644 --- a/docs/adapter-packages.md +++ b/docs/adapter-packages.md @@ -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.