dsh-over-ssh 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +119 -2
- package/agents/agent-manifest.json +20 -0
- package/agents/linux-amd64/dsh-over-ssh-agent +0 -0
- package/agents/linux-arm64/dsh-over-ssh-agent +0 -0
- package/cordis.patch.yml +84 -0
- package/lib/client.js +6611 -0
- package/lib/file-references.js +366 -0
- package/lib/fs.js +1368 -0
- package/lib/index.js +19034 -0
- package/lib/local-bridge-refs.js +16 -0
- package/lib/local-bridge.js +16 -0
- package/lib/terminal-wrapper.js +294 -0
- package/lib/types/src/client/controls.d.ts +131 -0
- package/lib/types/src/client/core/card-focus-trap.d.ts +45 -0
- package/lib/types/src/client/core/controls.d.ts +164 -0
- package/lib/types/src/client/core/latest.d.ts +48 -0
- package/lib/types/src/client/core/locale.d.ts +38 -0
- package/lib/types/src/client/core/message.d.ts +37 -0
- package/lib/types/src/client/core/panel-model.d.ts +134 -0
- package/lib/types/src/client/core/portal.d.ts +266 -0
- package/lib/types/src/client/core/remote.d.ts +84 -0
- package/lib/types/src/client/core/styles.d.ts +458 -0
- package/lib/types/src/client/file-tree-io.d.ts +19 -0
- package/lib/types/src/client/file-tree.d.ts +271 -0
- package/lib/types/src/client/flows/directory-browser.d.ts +587 -0
- package/lib/types/src/client/flows/session-directory.d.ts +415 -0
- package/lib/types/src/client/flows/workspace-directory-flow.d.ts +480 -0
- package/lib/types/src/client/index.d.ts +49 -0
- package/lib/types/src/client/locale.d.ts +31 -0
- package/lib/types/src/client/panel-model.d.ts +37 -0
- package/lib/types/src/client/panel.d.ts +77 -0
- package/lib/types/src/client/roots/connection-test.d.ts +69 -0
- package/lib/types/src/client/roots/roots-panel-state.d.ts +307 -0
- package/lib/types/src/client/roots/roots-panel-view.d.ts +280 -0
- package/lib/types/src/client/roots/roots-panel.d.ts +364 -0
- package/lib/types/src/client/roots/transfer-panel-view.d.ts +35 -0
- package/lib/types/src/client/roots/transfer-panel.d.ts +241 -0
- package/lib/types/src/client/roots/transfer-progress.d.ts +67 -0
- package/lib/types/src/client/roots-panel-view.d.ts +236 -0
- package/lib/types/src/client/roots-panel.d.ts +347 -0
- package/lib/types/src/client/session/session-panel-view.d.ts +336 -0
- package/lib/types/src/client/session/session-panel.d.ts +322 -0
- package/lib/types/src/client/session/session-remote-mark.d.ts +110 -0
- package/lib/types/src/client/session/session-row-actions.d.ts +398 -0
- package/lib/types/src/client/session-panel.d.ts +152 -0
- package/lib/types/src/client/styles.d.ts +252 -0
- package/lib/types/src/client/workspace-directory-flow.d.ts +342 -0
- package/lib/types/src/config.d.ts +312 -0
- package/lib/types/src/file-references.d.ts +25 -0
- package/lib/types/src/fs.d.ts +46 -0
- package/lib/types/src/host/app/backend.d.ts +170 -0
- package/lib/types/src/host/app/recycle-bin/recycle-bin-contract.d.ts +247 -0
- package/lib/types/src/host/app/recycle-bin/recycle-bin-move.d.ts +18 -0
- package/lib/types/src/host/app/recycle-bin/recycle-bin-service.d.ts +45 -0
- package/lib/types/src/host/app/recycle-bin/recycle-bin-world.d.ts +38 -0
- package/lib/types/src/host/app/recycle-bin-contract.d.ts +215 -0
- package/lib/types/src/host/app/recycle-bin-move.d.ts +18 -0
- package/lib/types/src/host/app/recycle-bin-service.d.ts +45 -0
- package/lib/types/src/host/app/recycle-bin-world.d.ts +35 -0
- package/lib/types/src/host/app/roots/roots-api-connections.d.ts +49 -0
- package/lib/types/src/host/app/roots/roots-api-contract.d.ts +369 -0
- package/lib/types/src/host/app/roots/roots-api-directories.d.ts +13 -0
- package/lib/types/src/host/app/roots/roots-api-http.d.ts +77 -0
- package/lib/types/src/host/app/roots/roots-api-long-poll.d.ts +130 -0
- package/lib/types/src/host/app/roots/roots-api-projections.d.ts +102 -0
- package/lib/types/src/host/app/roots/roots-api-roots.d.ts +13 -0
- package/lib/types/src/host/app/roots/roots-api-state.d.ts +22 -0
- package/lib/types/src/host/app/roots/roots-api-transfers.d.ts +26 -0
- package/lib/types/src/host/app/roots/roots-api.d.ts +55 -0
- package/lib/types/src/host/app/roots/user-roots.d.ts +552 -0
- package/lib/types/src/host/app/roots-api-connections.d.ts +49 -0
- package/lib/types/src/host/app/roots-api-contract.d.ts +339 -0
- package/lib/types/src/host/app/roots-api-directories.d.ts +13 -0
- package/lib/types/src/host/app/roots-api-http.d.ts +77 -0
- package/lib/types/src/host/app/roots-api-projections.d.ts +102 -0
- package/lib/types/src/host/app/roots-api-roots.d.ts +13 -0
- package/lib/types/src/host/app/roots-api-state.d.ts +22 -0
- package/lib/types/src/host/app/roots-api-support.d.ts +182 -0
- package/lib/types/src/host/app/roots-api-transfers.d.ts +13 -0
- package/lib/types/src/host/app/roots-api.d.ts +55 -0
- package/lib/types/src/host/app/routed-fs.d.ts +239 -0
- package/lib/types/src/host/app/serialize.d.ts +37 -0
- package/lib/types/src/host/app/session-admin/session-admin-context.d.ts +36 -0
- package/lib/types/src/host/app/session-admin/session-admin-contract.d.ts +221 -0
- package/lib/types/src/host/app/session-admin/session-admin-delete.d.ts +34 -0
- package/lib/types/src/host/app/session-admin/session-admin-service.d.ts +40 -0
- package/lib/types/src/host/app/session-admin-context.d.ts +36 -0
- package/lib/types/src/host/app/session-admin-contract.d.ts +214 -0
- package/lib/types/src/host/app/session-admin-delete.d.ts +34 -0
- package/lib/types/src/host/app/session-admin-service.d.ts +38 -0
- package/lib/types/src/host/app/takeover/takeover-plan.d.ts +227 -0
- package/lib/types/src/host/app/takeover/takeover-rows.d.ts +55 -0
- package/lib/types/src/host/app/transport/transport-selector.d.ts +98 -0
- package/lib/types/src/host/app/transport/transport-service.d.ts +82 -0
- package/lib/types/src/host/app/transport-selector.d.ts +98 -0
- package/lib/types/src/host/app/transport-service.d.ts +75 -0
- package/lib/types/src/host/app/user-roots.d.ts +461 -0
- package/lib/types/src/host/domain/bin-location.d.ts +79 -0
- package/lib/types/src/host/domain/capability.d.ts +78 -0
- package/lib/types/src/host/domain/connection.d.ts +95 -0
- package/lib/types/src/host/domain/errors.d.ts +55 -0
- package/lib/types/src/host/domain/glob-pattern.d.ts +62 -0
- package/lib/types/src/host/domain/literal-text.d.ts +63 -0
- package/lib/types/src/host/domain/path-grammar.d.ts +84 -0
- package/lib/types/src/host/domain/recycle-bin.d.ts +337 -0
- package/lib/types/src/host/domain/root.d.ts +74 -0
- package/lib/types/src/host/domain/roots/bin-location.d.ts +91 -0
- package/lib/types/src/host/domain/roots/connection.d.ts +106 -0
- package/lib/types/src/host/domain/roots/root.d.ts +108 -0
- package/lib/types/src/host/domain/roots/route-table.d.ts +102 -0
- package/lib/types/src/host/domain/roots/session-roots.d.ts +151 -0
- package/lib/types/src/host/domain/roots/ssh-config.d.ts +73 -0
- package/lib/types/src/host/domain/route-table.d.ts +80 -0
- package/lib/types/src/host/domain/session/session-admin.d.ts +345 -0
- package/lib/types/src/host/domain/session/terminal-target.d.ts +136 -0
- package/lib/types/src/host/domain/session-admin.d.ts +330 -0
- package/lib/types/src/host/domain/shell.d.ts +47 -0
- package/lib/types/src/host/domain/ssh-config.d.ts +73 -0
- package/lib/types/src/host/domain/terminal-target.d.ts +132 -0
- package/lib/types/src/host/domain/tool-requests.d.ts +369 -0
- package/lib/types/src/host/domain/transfer/recycle-bin.d.ts +337 -0
- package/lib/types/src/host/domain/transfer/transfer.d.ts +260 -0
- package/lib/types/src/host/domain/transfer.d.ts +260 -0
- package/lib/types/src/host/infra/backend/local-backend.d.ts +84 -0
- package/lib/types/src/host/infra/backend/local-version.d.ts +43 -0
- package/lib/types/src/host/infra/backend/platform-local-backend.d.ts +89 -0
- package/lib/types/src/host/infra/backend/remote-backend.d.ts +239 -0
- package/lib/types/src/host/infra/cache/lru.d.ts +52 -0
- package/lib/types/src/host/infra/cache/versioned.d.ts +77 -0
- package/lib/types/src/host/infra/temp-name.d.ts +19 -0
- package/lib/types/src/host/infra/transport/agent/agent-installer.d.ts +121 -0
- package/lib/types/src/host/infra/transport/agent/agent-protocol-client.d.ts +132 -0
- package/lib/types/src/host/infra/transport/agent/agent-protocol-codec.d.ts +140 -0
- package/lib/types/src/host/infra/transport/agent/agent-protocol-errors.d.ts +41 -0
- package/lib/types/src/host/infra/transport/agent/agent-protocol-frames.d.ts +197 -0
- package/lib/types/src/host/infra/transport/agent/agent-protocol-types.d.ts +564 -0
- package/lib/types/src/host/infra/transport/agent/agent-transport.d.ts +418 -0
- package/lib/types/src/host/infra/transport/agent-installer.d.ts +121 -0
- package/lib/types/src/host/infra/transport/agent-protocol-client.d.ts +123 -0
- package/lib/types/src/host/infra/transport/agent-protocol-codec.d.ts +131 -0
- package/lib/types/src/host/infra/transport/agent-protocol-errors.d.ts +41 -0
- package/lib/types/src/host/infra/transport/agent-protocol-frames.d.ts +197 -0
- package/lib/types/src/host/infra/transport/agent-protocol-types.d.ts +509 -0
- package/lib/types/src/host/infra/transport/agent-transport.d.ts +353 -0
- package/lib/types/src/host/infra/transport/alias-transport.d.ts +206 -0
- package/lib/types/src/host/infra/transport/askpass-fs.d.ts +20 -0
- package/lib/types/src/host/infra/transport/askpass.d.ts +133 -0
- package/lib/types/src/host/infra/transport/command-pool.d.ts +61 -0
- package/lib/types/src/host/infra/transport/fs-commands.d.ts +140 -0
- package/lib/types/src/host/infra/transport/git-status-route.d.ts +63 -0
- package/lib/types/src/host/infra/transport/git-status.d.ts +101 -0
- package/lib/types/src/host/infra/transport/node-spawn.d.ts +26 -0
- package/lib/types/src/host/infra/transport/session-window.d.ts +51 -0
- package/lib/types/src/host/infra/transport/shell-quote.d.ts +59 -0
- package/lib/types/src/host/infra/transport/ssh/alias-transport.d.ts +206 -0
- package/lib/types/src/host/infra/transport/ssh/askpass-fs.d.ts +20 -0
- package/lib/types/src/host/infra/transport/ssh/askpass.d.ts +133 -0
- package/lib/types/src/host/infra/transport/ssh/shell-quote.d.ts +62 -0
- package/lib/types/src/host/infra/transport/ssh/ssh-argv.d.ts +43 -0
- package/lib/types/src/host/infra/transport/ssh/ssh2-transport.d.ts +328 -0
- package/lib/types/src/host/infra/transport/ssh-argv.d.ts +43 -0
- package/lib/types/src/host/infra/transport/ssh2-transport.d.ts +302 -0
- package/lib/types/src/host/infra/transport/transport-base.d.ts +34 -0
- package/lib/types/src/host/infra/transport/transport.d.ts +527 -0
- package/lib/types/src/host/integration/agent/agent-install-io.d.ts +33 -0
- package/lib/types/src/host/integration/agent/agent-preflight.d.ts +56 -0
- package/lib/types/src/host/integration/agent/askpass-registry.d.ts +66 -0
- package/lib/types/src/host/integration/agent-install-io.d.ts +33 -0
- package/lib/types/src/host/integration/agent-preflight.d.ts +56 -0
- package/lib/types/src/host/integration/anchor-directory.d.ts +56 -0
- package/lib/types/src/host/integration/askpass-registry.d.ts +59 -0
- package/lib/types/src/host/integration/bin-root-resolver.d.ts +81 -0
- package/lib/types/src/host/integration/connection-test.d.ts +73 -0
- package/lib/types/src/host/integration/file-reference-provider.d.ts +115 -0
- package/lib/types/src/host/integration/fs/file-reference-provider.d.ts +142 -0
- package/lib/types/src/host/integration/fs/fs-provider.d.ts +368 -0
- package/lib/types/src/host/integration/fs/git-status-wiring.d.ts +21 -0
- package/lib/types/src/host/integration/fs/platform-errors.d.ts +94 -0
- package/lib/types/src/host/integration/fs/remote-file-tools.d.ts +369 -0
- package/lib/types/src/host/integration/fs/remote-index.d.ts +177 -0
- package/lib/types/src/host/integration/fs-provider.d.ts +226 -0
- package/lib/types/src/host/integration/lsp/lsp-framing.d.ts +38 -0
- package/lib/types/src/host/integration/lsp/lsp-registry.d.ts +67 -0
- package/lib/types/src/host/integration/lsp/lsp-session.d.ts +130 -0
- package/lib/types/src/host/integration/management-tools.d.ts +64 -0
- package/lib/types/src/host/integration/recycle-bin-service.d.ts +247 -0
- package/lib/types/src/host/integration/remote/connection-test.d.ts +73 -0
- package/lib/types/src/host/integration/remote/remote-face.d.ts +127 -0
- package/lib/types/src/host/integration/remote/remote-tool-backend.d.ts +108 -0
- package/lib/types/src/host/integration/remote-face.d.ts +127 -0
- package/lib/types/src/host/integration/remote-file-tools.d.ts +241 -0
- package/lib/types/src/host/integration/remote-home.d.ts +69 -0
- package/lib/types/src/host/integration/remote-index.d.ts +165 -0
- package/lib/types/src/host/integration/remote-job-tools.d.ts +295 -0
- package/lib/types/src/host/integration/remote-tool-backend.d.ts +97 -0
- package/lib/types/src/host/integration/remote-tools.d.ts +206 -0
- package/lib/types/src/host/integration/root-registry.d.ts +115 -0
- package/lib/types/src/host/integration/roots/anchor-directory.d.ts +56 -0
- package/lib/types/src/host/integration/roots/bin-root-resolver.d.ts +81 -0
- package/lib/types/src/host/integration/roots/remote-home.d.ts +69 -0
- package/lib/types/src/host/integration/roots/root-registry.d.ts +144 -0
- package/lib/types/src/host/integration/roots/roots-wiring.d.ts +219 -0
- package/lib/types/src/host/integration/roots/session-root-index.d.ts +52 -0
- package/lib/types/src/host/integration/roots-api.d.ts +407 -0
- package/lib/types/src/host/integration/roots-wiring.d.ts +211 -0
- package/lib/types/src/host/integration/session/session-api.d.ts +88 -0
- package/lib/types/src/host/integration/session/session-bin-lock.d.ts +80 -0
- package/lib/types/src/host/integration/session/session-header.d.ts +151 -0
- package/lib/types/src/host/integration/session/session-labels.d.ts +56 -0
- package/lib/types/src/host/integration/session/session-route-wiring.d.ts +50 -0
- package/lib/types/src/host/integration/session-admin-service.d.ts +236 -0
- package/lib/types/src/host/integration/session-api.d.ts +81 -0
- package/lib/types/src/host/integration/session-bin-lock.d.ts +80 -0
- package/lib/types/src/host/integration/session-header.d.ts +118 -0
- package/lib/types/src/host/integration/session-labels.d.ts +56 -0
- package/lib/types/src/host/integration/session-route-wiring.d.ts +50 -0
- package/lib/types/src/host/integration/session-scope.d.ts +113 -0
- package/lib/types/src/host/integration/session-tools.d.ts +44 -0
- package/lib/types/src/host/integration/strict-arguments.d.ts +79 -0
- package/lib/types/src/host/integration/takeover/takeover-api.d.ts +62 -0
- package/lib/types/src/host/integration/takeover/takeover-route-wiring.d.ts +60 -0
- package/lib/types/src/host/integration/takeover/takeover-service.d.ts +167 -0
- package/lib/types/src/host/integration/terminal-manifest.d.ts +94 -0
- package/lib/types/src/host/integration/tools/management-tools.d.ts +245 -0
- package/lib/types/src/host/integration/tools/remote-job-tools.d.ts +316 -0
- package/lib/types/src/host/integration/tools/remote-lsp-tools.d.ts +43 -0
- package/lib/types/src/host/integration/tools/remote-tools.d.ts +236 -0
- package/lib/types/src/host/integration/tools/session-target.d.ts +52 -0
- package/lib/types/src/host/integration/tools/session-tools.d.ts +46 -0
- package/lib/types/src/host/integration/tools/strict-arguments.d.ts +79 -0
- package/lib/types/src/host/integration/tools/terminal-manifest.d.ts +94 -0
- package/lib/types/src/host/integration/transfer/remote-copy.d.ts +66 -0
- package/lib/types/src/host/integration/transfer/transfer-adapters.d.ts +48 -0
- package/lib/types/src/host/integration/transfer/transfer-service.d.ts +212 -0
- package/lib/types/src/host/integration/transfer/transfer-tracker.d.ts +106 -0
- package/lib/types/src/host/integration/transfer-adapters.d.ts +44 -0
- package/lib/types/src/host/integration/transfer-service.d.ts +164 -0
- package/lib/types/src/host/integration/transfer-tracker.d.ts +106 -0
- package/lib/types/src/host/integration/user-roots.d.ts +461 -0
- package/lib/types/src/index.d.ts +66 -0
- package/lib/types/src/local-bridge-refs.d.ts +26 -0
- package/lib/types/src/local-bridge.d.ts +36 -0
- package/lib/types/src/shared/format.d.ts +13 -0
- package/lib/types/src/wiring/connections.d.ts +189 -0
- package/lib/types/src/wiring/fs.d.ts +13 -0
- package/lib/types/src/wiring/helpers.d.ts +144 -0
- package/lib/types/src/wiring/install-memo.d.ts +32 -0
- package/lib/types/src/wiring/legacy-dirs.d.ts +62 -0
- package/lib/types/src/wiring/package-paths.d.ts +35 -0
- package/lib/types/src/wiring/roots.d.ts +21 -0
- package/lib/types/src/wiring/state-dir.d.ts +29 -0
- package/lib/types/src/wiring/tools.d.ts +35 -0
- package/package.json +120 -4
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The roots panel's whole decision surface: wire parsing, the HTTP calls to the host route, input validation
|
|
3
|
+
* and the view model. **No React, no DOM, no `@deepseek-ai/*`** — the component renders what this module
|
|
4
|
+
* returns and nothing else, which is what makes the panel testable without a browser (红线 2).
|
|
5
|
+
*
|
|
6
|
+
* Two rules this module owns:
|
|
7
|
+
*
|
|
8
|
+
* 1. **No credentials, ever.** {@link parseRootsSnapshot} copies field by field and drops anything else, so a
|
|
9
|
+
* host answer that leaked `keyPath` / `password` still cannot reach the DOM. The host route filters its
|
|
10
|
+
* side; this is the client's half of the same rule.
|
|
11
|
+
* 2. **Password authentication is not editable here.** A password must never round-trip through a browser
|
|
12
|
+
* form and a same-origin POST, so {@link validateConnectionDraft} refuses it outright rather than
|
|
13
|
+
* growing a field that leaks secrets into web storage.
|
|
14
|
+
*
|
|
15
|
+
* @module dsh-remote-workspace/client/roots-panel
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Where the host route lives, as the browser must request it.
|
|
19
|
+
*
|
|
20
|
+
* **Relative on purpose, and this is the platform's own convention.** The GUI is served from two different
|
|
21
|
+
* origins depending on the carrier, and only a relative path is correct in both:
|
|
22
|
+
*
|
|
23
|
+
* - `dsh web` (browser): the page origin *is* the host, so `/api/…` reaches
|
|
24
|
+
* `ctx.webServer` directly;
|
|
25
|
+
* - the Desktop shell: the page is `dsh-app://app/` and `/api/…` resolves to
|
|
26
|
+
* `dsh-app://app/api/…`, which Electron's `protocol.handle('dsh-app')` forwards to the owned host with
|
|
27
|
+
* the browser-session cookie the shell keeps out of the page
|
|
28
|
+
* (`resources/app.asar/lib/main.js`, `forwardWebRequest`: non-asset paths are proxied with
|
|
29
|
+
* `headers.set('cookie', cookie)`; `serveWebDocument` never sees `/api/…`).
|
|
30
|
+
*
|
|
31
|
+
* The absolute host origin (`globalThis.__DSH_TRANSPORT__.streamBaseUrl`) is deliberately **not** used here:
|
|
32
|
+
* the shell strips `set-cookie` from proxied responses and the session cookie is host-only + `HttpOnly`, so
|
|
33
|
+
* a direct fetch to the host origin cannot authenticate — it would turn a working request into a 401. The
|
|
34
|
+
* platform uses that origin for the WebSocket only (`dsh-api-gateway`, `REMOTE_STREAM_MUX_PATH`), and its
|
|
35
|
+
* own HTTP callers resolve against `document.baseURI` (`dsh-client-file-upload`, `new URL(request.path,
|
|
36
|
+
* document.baseURI)`).
|
|
37
|
+
*/
|
|
38
|
+
export declare const ROOTS_API_PATH = "/api/remote-workspace/roots";
|
|
39
|
+
/** A root either lives on this machine or behind a connection. */
|
|
40
|
+
export type RootLocation = 'local' | 'remote';
|
|
41
|
+
/** One root as the panel shows it. */
|
|
42
|
+
export interface RootRow {
|
|
43
|
+
/** Stable identity: `<location>:<connectionId or '-'>:<path>`. */
|
|
44
|
+
readonly key: string;
|
|
45
|
+
readonly location: RootLocation;
|
|
46
|
+
readonly path: string;
|
|
47
|
+
readonly connectionId?: string;
|
|
48
|
+
readonly label?: string;
|
|
49
|
+
readonly writable: boolean;
|
|
50
|
+
/** `config` rows come from the profile patch; `user` rows were added in this panel. */
|
|
51
|
+
readonly source: 'config' | 'user';
|
|
52
|
+
/** Whether this root also appears in the panel's own file — only those may be deleted. */
|
|
53
|
+
readonly inUserFile: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* The workspaces that list this root; absent means plugin-wide.
|
|
56
|
+
*
|
|
57
|
+
* The composer's card filters on it (one workspace must not inherit another's directories); the settings
|
|
58
|
+
* panel ignores it, because that panel manages the plugin-wide list.
|
|
59
|
+
*/
|
|
60
|
+
readonly workspaces?: readonly string[];
|
|
61
|
+
}
|
|
62
|
+
/** A connection, narrowed to what the panel may display. **No credential fields exist on this type.** */
|
|
63
|
+
export interface ConnectionSummary {
|
|
64
|
+
readonly id: string;
|
|
65
|
+
readonly host: string;
|
|
66
|
+
readonly user?: string;
|
|
67
|
+
readonly port?: number;
|
|
68
|
+
readonly authKind: 'agent' | 'key' | 'password';
|
|
69
|
+
/**
|
|
70
|
+
* The transport the record asks for, when it names one.
|
|
71
|
+
*
|
|
72
|
+
* The edit form prefills from this: a form that always showed the default would silently rewrite a
|
|
73
|
+
* connection the user had deliberately set to zero-install. Absent means "the reader's default" (the
|
|
74
|
+
* record carries no choice), which is a different fact from "the user chose the default".
|
|
75
|
+
*/
|
|
76
|
+
readonly transport?: ConnectionTransportChoice;
|
|
77
|
+
}
|
|
78
|
+
/** Everything one GET answers. */
|
|
79
|
+
export interface RootsSnapshot {
|
|
80
|
+
readonly roots: readonly RootRow[];
|
|
81
|
+
readonly connections: readonly ConnectionSummary[];
|
|
82
|
+
readonly warnings: readonly string[];
|
|
83
|
+
}
|
|
84
|
+
/** The outcome of one call: the panel never throws on a host failure, it shows it. */
|
|
85
|
+
export type ApiResult<T> = {
|
|
86
|
+
readonly ok: true;
|
|
87
|
+
readonly value: T;
|
|
88
|
+
} | {
|
|
89
|
+
readonly ok: false;
|
|
90
|
+
readonly error: string;
|
|
91
|
+
};
|
|
92
|
+
/** What this module needs from `fetch`; injected so tests run without a server (红线 3). */
|
|
93
|
+
export type FetchLike = (input: string, init?: {
|
|
94
|
+
readonly method?: string;
|
|
95
|
+
readonly headers?: Record<string, string>;
|
|
96
|
+
readonly body?: string;
|
|
97
|
+
readonly signal?: AbortSignal;
|
|
98
|
+
}) => Promise<{
|
|
99
|
+
readonly ok: boolean;
|
|
100
|
+
readonly status: number;
|
|
101
|
+
json: () => Promise<unknown>;
|
|
102
|
+
}>;
|
|
103
|
+
/** A message is a key plus its parameters; the component resolves it against the locale dictionaries. */
|
|
104
|
+
export interface MessageKey {
|
|
105
|
+
readonly key: string;
|
|
106
|
+
readonly params?: Readonly<Record<string, string | number>>;
|
|
107
|
+
}
|
|
108
|
+
/** A validated draft, or the reason it was refused. */
|
|
109
|
+
export type Validation<T> = {
|
|
110
|
+
readonly ok: true;
|
|
111
|
+
readonly value: T;
|
|
112
|
+
} | {
|
|
113
|
+
readonly ok: false;
|
|
114
|
+
readonly message: MessageKey;
|
|
115
|
+
};
|
|
116
|
+
/** The payload the panel sends to add a root. */
|
|
117
|
+
export interface RootDraft {
|
|
118
|
+
readonly location: RootLocation;
|
|
119
|
+
readonly path: string;
|
|
120
|
+
readonly connectionId?: string;
|
|
121
|
+
readonly label?: string;
|
|
122
|
+
readonly writable?: boolean;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Which transport a connection should use, as the form offers it.
|
|
126
|
+
*
|
|
127
|
+
* Spelled out here rather than imported from the host's `TransportKind` (`host/domain/connection.ts`): this
|
|
128
|
+
* module is the pure client half and imports nothing from the host (红线 2). The two unions must stay equal,
|
|
129
|
+
* and the host re-validates whatever arrives (`normalizeConnectionEntry`), so a drift cannot reach the file.
|
|
130
|
+
*
|
|
131
|
+
* **Not to be confused with `authKind: 'agent'`**, which names the *local* ssh-agent as a credential source.
|
|
132
|
+
* `transport: 'agent'` names the *remote* Tier 2 Go program this plugin uploads (ADR-0005/0007).
|
|
133
|
+
*/
|
|
134
|
+
export type ConnectionTransportChoice = 'alias' | 'ssh2' | 'agent';
|
|
135
|
+
/** Every transport the form may offer, in the order the selector lists them (the default first). */
|
|
136
|
+
export declare const CONNECTION_TRANSPORTS: readonly ConnectionTransportChoice[];
|
|
137
|
+
/** The transport a draft uses when it names none: the Tier 2 agent, matching the host's own default. */
|
|
138
|
+
export declare const DEFAULT_CONNECTION_TRANSPORT: ConnectionTransportChoice;
|
|
139
|
+
/**
|
|
140
|
+
* Narrow an untrusted value to a transport this build knows.
|
|
141
|
+
*
|
|
142
|
+
* Anything unrecognised degrades to the default rather than reaching the wire: the field is a closed union, and
|
|
143
|
+
* a value the host would reject as `CONNECTION_INVALID` is worse than the documented default.
|
|
144
|
+
*
|
|
145
|
+
* @param value - the raw field.
|
|
146
|
+
* @returns the transport, or {@link DEFAULT_CONNECTION_TRANSPORT}.
|
|
147
|
+
*/
|
|
148
|
+
export declare function toConnectionTransport(value: unknown): ConnectionTransportChoice;
|
|
149
|
+
/**
|
|
150
|
+
* The payload the panel sends to add a connection.
|
|
151
|
+
*
|
|
152
|
+
* `password` is the **only** secret this client ever holds, and only long enough to post it: the host writes
|
|
153
|
+
* it into `ctx.credentials` and answers with a projection that never contains it (FR-2.1.2).
|
|
154
|
+
*/
|
|
155
|
+
export interface ConnectionDraft {
|
|
156
|
+
readonly id: string;
|
|
157
|
+
readonly host: string;
|
|
158
|
+
readonly user: string;
|
|
159
|
+
readonly authKind: 'agent' | 'key' | 'password';
|
|
160
|
+
/**
|
|
161
|
+
* The transport to use. Optional on the way in (an omitted value means {@link DEFAULT_CONNECTION_TRANSPORT})
|
|
162
|
+
* and **always present on the way out**: the host persists the user's explicit choice, so "the default" is a
|
|
163
|
+
* decision the record carries rather than one every reader has to re-derive.
|
|
164
|
+
*/
|
|
165
|
+
readonly transport?: ConnectionTransportChoice;
|
|
166
|
+
readonly keyPath?: string;
|
|
167
|
+
readonly password?: string;
|
|
168
|
+
readonly port?: number;
|
|
169
|
+
}
|
|
170
|
+
/** The identity the host also uses, so removals address the same row the list shows. */
|
|
171
|
+
export declare function rootKey(location: RootLocation, path: string, connectionId?: string): string;
|
|
172
|
+
/**
|
|
173
|
+
* Narrow one GET answer to the panel's model, field by field.
|
|
174
|
+
*
|
|
175
|
+
* Unknown fields are dropped rather than copied: an answer carrying `keyPath` reaches the DOM only as a
|
|
176
|
+
* missing field, never as a value. A malformed answer becomes an empty snapshot with a warning instead of a
|
|
177
|
+
* throw — a broken channel must degrade the panel, not break the whole settings page.
|
|
178
|
+
*
|
|
179
|
+
* @param value - the parsed JSON the route answered with.
|
|
180
|
+
* @returns a snapshot that is safe to render.
|
|
181
|
+
*/
|
|
182
|
+
export declare function parseRootsSnapshot(value: unknown): RootsSnapshot;
|
|
183
|
+
/** True when a string is an absolute path this machine can open (drive letter, POSIX root, or UNC). */
|
|
184
|
+
export declare function isAbsoluteLocalPath(path: string): boolean;
|
|
185
|
+
/**
|
|
186
|
+
* Refuse a draft before it becomes a request.
|
|
187
|
+
*
|
|
188
|
+
* @param draft - what the form holds.
|
|
189
|
+
* @param existing - roots already shown, to reject a duplicate.
|
|
190
|
+
* @returns the wire payload, or the message key to show next to the field.
|
|
191
|
+
*/
|
|
192
|
+
export declare function validateRootDraft(draft: RootDraft, existing?: readonly RootRow[]): Validation<RootDraft>;
|
|
193
|
+
/**
|
|
194
|
+
* Refuse a connection draft before it becomes a request.
|
|
195
|
+
*
|
|
196
|
+
* The id rule is the **host's** rule (a user-chosen name, Chinese included), so the panel refuses exactly
|
|
197
|
+
* what `path-grammar.ts` would refuse instead of sending a request that comes back 400.
|
|
198
|
+
*
|
|
199
|
+
* Password auth is supported: the draft carries the password once, the host stores it in `ctx.credentials`,
|
|
200
|
+
* and nothing in any answer ever carries it back (FR-2.1.2).
|
|
201
|
+
*
|
|
202
|
+
* The transport is **always** in the returned value, even when the draft omits it: the form has a selector,
|
|
203
|
+
* and the host must receive the user's choice explicitly rather than re-deriving the default per reader.
|
|
204
|
+
*
|
|
205
|
+
* @param draft - what the form holds.
|
|
206
|
+
* @param existing - connections already shown, to reject a duplicate id.
|
|
207
|
+
* @returns the wire payload, or the message key to show next to the field.
|
|
208
|
+
*/
|
|
209
|
+
export declare function validateConnectionDraft(draft: ConnectionDraft, existing?: readonly ConnectionSummary[]): Validation<ConnectionDraft>;
|
|
210
|
+
/**
|
|
211
|
+
* Refuse an **edit** draft before it becomes a request.
|
|
212
|
+
*
|
|
213
|
+
* The same rules as {@link validateConnectionDraft} for every field, with the three differences an edit
|
|
214
|
+
* needs, and each one exists for a reason:
|
|
215
|
+
*
|
|
216
|
+
* 1. **A rename is allowed but must not collide with a *different* connection.** Uniqueness is checked
|
|
217
|
+
* against the rows except the one being edited - `validateConnectionDraft` cannot express that, and using
|
|
218
|
+
* it here would refuse every save that kept the id.
|
|
219
|
+
* 2. **An empty password means "do not touch the stored secret", not "refuse".** No answer ever carries a
|
|
220
|
+
* secret back, so the form's password box is always empty on render; requiring it would make it
|
|
221
|
+
* impossible to change a host without retyping the password, and treating empty as "clear" would delete
|
|
222
|
+
* the password on every unrelated edit. The field is therefore **omitted** from the payload unless the
|
|
223
|
+
* user typed one, which is exactly how the host reads it.
|
|
224
|
+
* 3. **`keyPath` follows the same rule as the password: blank means "keep the stored one".** The panel
|
|
225
|
+
* cannot prefill it, because the host's answer deliberately never carries a `keyPath` (it names a real
|
|
226
|
+
* file). Refusing a blank one would therefore make it impossible to edit a key connection's host without
|
|
227
|
+
* retyping its private-key path, and *filling* it with a guess would silently repoint the connection.
|
|
228
|
+
* So it is omitted unless the user typed one - the host's merge keeps what is stored.
|
|
229
|
+
*
|
|
230
|
+
* @param draft - what the form holds.
|
|
231
|
+
* @param originalId - the id of the connection being edited (the lookup key the host needs).
|
|
232
|
+
* @param existing - connections already shown, to reject a colliding rename.
|
|
233
|
+
* @returns the wire payload, or the message key to show next to the field.
|
|
234
|
+
*/
|
|
235
|
+
export declare function validateConnectionEdit(draft: ConnectionDraft, originalId: string, existing?: readonly ConnectionSummary[]): Validation<Record<string, unknown>>;
|
|
236
|
+
/** One row as the component renders it. */
|
|
237
|
+
export interface RootRowView {
|
|
238
|
+
readonly key: string;
|
|
239
|
+
readonly location: RootLocation;
|
|
240
|
+
readonly title: string;
|
|
241
|
+
readonly subtitle: string;
|
|
242
|
+
readonly badgeKey: string;
|
|
243
|
+
readonly removable: boolean;
|
|
244
|
+
}
|
|
245
|
+
/** The panel's complete render input. */
|
|
246
|
+
export interface RootsView {
|
|
247
|
+
readonly rows: readonly RootRowView[];
|
|
248
|
+
readonly connections: readonly ConnectionSummary[];
|
|
249
|
+
/** Set when the host did not answer, so the panel can say why instead of looking empty. */
|
|
250
|
+
readonly notice?: MessageKey;
|
|
251
|
+
/** False while a request is in flight, so the form cannot double-submit. */
|
|
252
|
+
readonly canEdit: boolean;
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Turn a snapshot (or the failure to get one) into render input.
|
|
256
|
+
*
|
|
257
|
+
* @param input - the last answer, or the last error, plus whether a request is running.
|
|
258
|
+
* @returns rows, connections, notice and the edit gate.
|
|
259
|
+
*/
|
|
260
|
+
export declare function buildRootsView(input: {
|
|
261
|
+
readonly snapshot?: RootsSnapshot;
|
|
262
|
+
readonly error?: string;
|
|
263
|
+
readonly pending?: boolean;
|
|
264
|
+
}): RootsView;
|
|
265
|
+
/** The calls the panel makes. */
|
|
266
|
+
export interface RootsApi {
|
|
267
|
+
load(signal?: AbortSignal): Promise<ApiResult<RootsSnapshot>>;
|
|
268
|
+
send(body: Record<string, unknown>): Promise<ApiResult<RootsSnapshot>>;
|
|
269
|
+
/**
|
|
270
|
+
* A POST whose answer is **not** a snapshot.
|
|
271
|
+
*
|
|
272
|
+
* The import actions answer a candidate list and an import report, neither of which is a roots snapshot. It
|
|
273
|
+
* is a separate method rather than a looser return type on {@link RootsApi.send} so that every existing call
|
|
274
|
+
* keeps the snapshot it already depends on: widening `send` would make `state` optional for all of them.
|
|
275
|
+
*/
|
|
276
|
+
sendRaw(body: Record<string, unknown>): Promise<ApiResult<Record<string, unknown>>>;
|
|
277
|
+
}
|
|
278
|
+
/** One importable `~/.ssh/config` alias, as the import dialog renders it. */
|
|
279
|
+
export interface SshConfigCandidate {
|
|
280
|
+
/** The literal alias; also the `ssh` target. Shown verbatim so the user recognises their own config. */
|
|
281
|
+
readonly alias: string;
|
|
282
|
+
/** Resolved host name. */
|
|
283
|
+
readonly host: string;
|
|
284
|
+
readonly user?: string;
|
|
285
|
+
readonly port?: number;
|
|
286
|
+
/** Whether the block named an identity file. The path itself never reaches the client. */
|
|
287
|
+
readonly hasIdentityFile: boolean;
|
|
288
|
+
readonly hasProxyJump: boolean;
|
|
289
|
+
/** The id the import would create. Editable in spirit: the user sees it before committing. */
|
|
290
|
+
readonly suggestedId: string;
|
|
291
|
+
}
|
|
292
|
+
/** One alias the host refused, with the machine-readable reason. */
|
|
293
|
+
export interface SshConfigSkipped {
|
|
294
|
+
readonly pattern: string;
|
|
295
|
+
readonly reason: string;
|
|
296
|
+
readonly line: number;
|
|
297
|
+
}
|
|
298
|
+
/** What `list-ssh-config` answers. */
|
|
299
|
+
export interface SshConfigListing {
|
|
300
|
+
readonly candidates: readonly SshConfigCandidate[];
|
|
301
|
+
readonly skipped: readonly SshConfigSkipped[];
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Narrow the host's `list-ssh-config` answer.
|
|
305
|
+
*
|
|
306
|
+
* Defensive in the same way {@link parseRootsSnapshot} is: the client never trusts the wire's shape, and a row
|
|
307
|
+
* without a usable alias or id is **dropped** rather than rendered as a checkbox that would import nothing.
|
|
308
|
+
*
|
|
309
|
+
* @param value - the parsed JSON body.
|
|
310
|
+
* @returns the listing, with unusable rows removed.
|
|
311
|
+
*/
|
|
312
|
+
export declare function parseSshConfigListing(value: unknown): SshConfigListing;
|
|
313
|
+
/**
|
|
314
|
+
* The human-readable reason one alias was refused.
|
|
315
|
+
*
|
|
316
|
+
* The mapping lives here rather than in the view so the reasons are testable without rendering, and an unknown
|
|
317
|
+
* reason from a newer host still produces a sentence instead of an empty cell.
|
|
318
|
+
*
|
|
319
|
+
* @param reason - the machine-readable reason.
|
|
320
|
+
* @returns a message key.
|
|
321
|
+
*/
|
|
322
|
+
export declare function sshConfigSkipKey(reason: string): string;
|
|
323
|
+
/** A candidate's one-line summary: `user@host:port`, with the flags that matter for the import. */
|
|
324
|
+
export declare function sshConfigCandidateSummary(candidate: SshConfigCandidate): string;
|
|
325
|
+
/**
|
|
326
|
+
* The reason a failed response reports, when the host did not name one.
|
|
327
|
+
*
|
|
328
|
+
* The path is part of the text on purpose: `http-404` alone cannot distinguish "this route is not
|
|
329
|
+
* registered" (the host half never claimed it — that was a real defect) from "the request never reached the
|
|
330
|
+
* host" (the shell's proxy or the composition is at fault). Both are shown verbatim in the panel's notice.
|
|
331
|
+
*
|
|
332
|
+
* @param status - the HTTP status.
|
|
333
|
+
* @param path - the exact URL that was requested.
|
|
334
|
+
* @returns the machine-readable reason.
|
|
335
|
+
*/
|
|
336
|
+
export declare function transportFailureReason(status: number, path: string): string;
|
|
337
|
+
/**
|
|
338
|
+
* Bind the route to the panel's two operations.
|
|
339
|
+
*
|
|
340
|
+
* @param fetchImpl - `window.fetch` in the app, a stub in tests.
|
|
341
|
+
* @param path - override for tests; defaults to {@link ROOTS_API_PATH}.
|
|
342
|
+
* @returns the calls the component uses.
|
|
343
|
+
*/
|
|
344
|
+
export declare function createRootsApi(fetchImpl: FetchLike, path?: string): RootsApi;
|
|
345
|
+
/** The field names the panel must never send, asserted by tests rather than trusted to reviewers. */
|
|
346
|
+
export declare function isForbiddenField(name: string): boolean;
|
|
347
|
+
//# sourceMappingURL=roots-panel.d.ts.map
|