host-execution-mcp 1.0.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.
Files changed (126) hide show
  1. package/CHANGELOG.md +330 -0
  2. package/LICENSE +21 -0
  3. package/README.md +92 -0
  4. package/SECURITY.md +72 -0
  5. package/dist/access/docker-runtime.d.ts +38 -0
  6. package/dist/access/docker-runtime.js +61 -0
  7. package/dist/access/docker-runtime.js.map +1 -0
  8. package/dist/access/index.d.ts +110 -0
  9. package/dist/access/index.js +174 -0
  10. package/dist/access/index.js.map +1 -0
  11. package/dist/access/paradi-auth.d.ts +33 -0
  12. package/dist/access/paradi-auth.js +89 -0
  13. package/dist/access/paradi-auth.js.map +1 -0
  14. package/dist/access/paradi-transport.d.ts +10 -0
  15. package/dist/access/paradi-transport.js +39 -0
  16. package/dist/access/paradi-transport.js.map +1 -0
  17. package/dist/access/paradi-username.d.ts +5 -0
  18. package/dist/access/paradi-username.js +14 -0
  19. package/dist/access/paradi-username.js.map +1 -0
  20. package/dist/access/probe.d.ts +14 -0
  21. package/dist/access/probe.js +63 -0
  22. package/dist/access/probe.js.map +1 -0
  23. package/dist/access/session-pool.d.ts +25 -0
  24. package/dist/access/session-pool.js +46 -0
  25. package/dist/access/session-pool.js.map +1 -0
  26. package/dist/access/ssh-transport.d.ts +16 -0
  27. package/dist/access/ssh-transport.js +74 -0
  28. package/dist/access/ssh-transport.js.map +1 -0
  29. package/dist/access/types.d.ts +43 -0
  30. package/dist/access/types.js +21 -0
  31. package/dist/access/types.js.map +1 -0
  32. package/dist/config.d.ts +52 -0
  33. package/dist/config.js +179 -0
  34. package/dist/config.js.map +1 -0
  35. package/dist/index.d.ts +2 -0
  36. package/dist/index.js +19 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/instructions.d.ts +4 -0
  39. package/dist/instructions.js +93 -0
  40. package/dist/instructions.js.map +1 -0
  41. package/dist/kubectl/runner.d.ts +32 -0
  42. package/dist/kubectl/runner.js +79 -0
  43. package/dist/kubectl/runner.js.map +1 -0
  44. package/dist/server.d.ts +3 -0
  45. package/dist/server.js +24 -0
  46. package/dist/server.js.map +1 -0
  47. package/dist/ssh/access-client.d.ts +62 -0
  48. package/dist/ssh/access-client.js +470 -0
  49. package/dist/ssh/access-client.js.map +1 -0
  50. package/dist/ssh/access-errors.d.ts +53 -0
  51. package/dist/ssh/access-errors.js +180 -0
  52. package/dist/ssh/access-errors.js.map +1 -0
  53. package/dist/ssh/access-sftp.d.ts +14 -0
  54. package/dist/ssh/access-sftp.js +456 -0
  55. package/dist/ssh/access-sftp.js.map +1 -0
  56. package/dist/ssh/bastion-client.d.ts +60 -0
  57. package/dist/ssh/bastion-client.js +423 -0
  58. package/dist/ssh/bastion-client.js.map +1 -0
  59. package/dist/ssh/bastion-errors.d.ts +62 -0
  60. package/dist/ssh/bastion-errors.js +190 -0
  61. package/dist/ssh/bastion-errors.js.map +1 -0
  62. package/dist/ssh/hop1-sftp.d.ts +14 -0
  63. package/dist/ssh/hop1-sftp.js +437 -0
  64. package/dist/ssh/hop1-sftp.js.map +1 -0
  65. package/dist/tools/copy-job-schemas.d.ts +709 -0
  66. package/dist/tools/copy-job-schemas.js +48 -0
  67. package/dist/tools/copy-job-schemas.js.map +1 -0
  68. package/dist/tools/register.d.ts +14 -0
  69. package/dist/tools/register.js +619 -0
  70. package/dist/tools/register.js.map +1 -0
  71. package/dist/tools/remote-schemas.d.ts +879 -0
  72. package/dist/tools/remote-schemas.js +214 -0
  73. package/dist/tools/remote-schemas.js.map +1 -0
  74. package/dist/utils/copy-executor.d.ts +41 -0
  75. package/dist/utils/copy-executor.js +231 -0
  76. package/dist/utils/copy-executor.js.map +1 -0
  77. package/dist/utils/copy-job-manager.d.ts +34 -0
  78. package/dist/utils/copy-job-manager.js +400 -0
  79. package/dist/utils/copy-job-manager.js.map +1 -0
  80. package/dist/utils/copy-job-store.d.ts +18 -0
  81. package/dist/utils/copy-job-store.js +104 -0
  82. package/dist/utils/copy-job-store.js.map +1 -0
  83. package/dist/utils/copy-job-types.d.ts +133 -0
  84. package/dist/utils/copy-job-types.js +37 -0
  85. package/dist/utils/copy-job-types.js.map +1 -0
  86. package/dist/utils/copy-transfer.d.ts +59 -0
  87. package/dist/utils/copy-transfer.js +86 -0
  88. package/dist/utils/copy-transfer.js.map +1 -0
  89. package/dist/utils/remote-copy.d.ts +14 -0
  90. package/dist/utils/remote-copy.js +115 -0
  91. package/dist/utils/remote-copy.js.map +1 -0
  92. package/dist/utils/remote-executor.d.ts +15 -0
  93. package/dist/utils/remote-executor.js +34 -0
  94. package/dist/utils/remote-executor.js.map +1 -0
  95. package/dist/utils/remote-target.d.ts +22 -0
  96. package/dist/utils/remote-target.js +75 -0
  97. package/dist/utils/remote-target.js.map +1 -0
  98. package/dist/utils/result.d.ts +87 -0
  99. package/dist/utils/result.js +81 -0
  100. package/dist/utils/result.js.map +1 -0
  101. package/dist/utils/shell-quote.d.ts +22 -0
  102. package/dist/utils/shell-quote.js +55 -0
  103. package/dist/utils/shell-quote.js.map +1 -0
  104. package/dist/utils/timeout.d.ts +1 -0
  105. package/dist/utils/timeout.js +18 -0
  106. package/dist/utils/timeout.js.map +1 -0
  107. package/dist/utils/truncate.d.ts +5 -0
  108. package/dist/utils/truncate.js +12 -0
  109. package/dist/utils/truncate.js.map +1 -0
  110. package/dist/version.d.ts +1 -0
  111. package/dist/version.js +7 -0
  112. package/dist/version.js.map +1 -0
  113. package/docs/AGENT_GUIDE.md +161 -0
  114. package/docs/CONFIGURATION.md +130 -0
  115. package/docs/COPY_SPECIALIZED_TEST_CHECKLIST.md +9 -0
  116. package/docs/HOP1_E2E_CHECKLIST.md +128 -0
  117. package/docs/HOP1_E2E_RESULTS.json +647 -0
  118. package/docs/PARADI_ACCESS_PLAN.md +272 -0
  119. package/docs/REMOTE_COPY_JOB_API.md +92 -0
  120. package/docs/TODO.md +66 -0
  121. package/docs/USER_GUIDE.zh-CN.md +93 -0
  122. package/docs/clients/claude-desktop.json.example +12 -0
  123. package/docs/clients/cursor-npx.json.example +12 -0
  124. package/docs/clients/cursor.json.example +12 -0
  125. package/docs/clients/vscode.json.example +12 -0
  126. package/package.json +65 -0
@@ -0,0 +1,110 @@
1
+ import type { AccessClient, ExecOutput } from "../ssh/access-client.js";
2
+ import type { AppConfig } from "../config.js";
3
+ import { SessionPool } from "./session-pool.js";
4
+ import type { ContextCapabilities, HostExecutionContext } from "./types.js";
5
+ import { type ProbeResult } from "./probe.js";
6
+ export type { ProbeResult };
7
+ export type ContextSummary = {
8
+ contextKey: string;
9
+ endpoint: HostExecutionContext["endpoint"];
10
+ parentKey?: string;
11
+ capabilities: ContextCapabilities;
12
+ };
13
+ /**
14
+ * Access + shell/docker Runtime facade.
15
+ * derive = Access (produces Context); Runtime only consumes Context by contextKey.
16
+ */
17
+ export declare class AccessRuntime {
18
+ private readonly config;
19
+ readonly accessContext: HostExecutionContext;
20
+ readonly pool: SessionPool;
21
+ private readonly sshTransport;
22
+ /** Capability cache by context.key (derive may recreate descriptor objects). */
23
+ private readonly capsByKey;
24
+ /** Live Context descriptors by key (landing + derived). */
25
+ private readonly contexts;
26
+ constructor(config: AppConfig, accessClient: AccessClient);
27
+ /** Landing Context key (ACCESS for ssh; TARGET for paradi). */
28
+ get landingKey(): string;
29
+ summarize(ctx?: HostExecutionContext): ContextSummary;
30
+ /**
31
+ * Resolve Runtime Context by key. Omit / empty → landing.
32
+ * Unknown keys throw (must context_derive first).
33
+ */
34
+ requireContext(contextKey?: string): HostExecutionContext;
35
+ /** Shell on a Context (default landing). */
36
+ shellExec(command: string, opts?: {
37
+ contextKey?: string;
38
+ timeoutMs?: number;
39
+ cwd?: string;
40
+ }): Promise<ExecOutput>;
41
+ /**
42
+ * Derive a child Context (ACCESS_KIND=ssh only). Returns summary with contextKey.
43
+ * Omitting host uses config TARGET_* as default derive selector.
44
+ */
45
+ deriveContext(args?: {
46
+ host?: string;
47
+ user?: string;
48
+ password?: string;
49
+ useTarget?: boolean;
50
+ }): ContextSummary;
51
+ /**
52
+ * deriveContext + shellExec — ACCESS_KIND=ssh only.
53
+ * Also returns the derived contextKey via summarize after exec (caller should use derive for key-only).
54
+ */
55
+ sshExec(args: {
56
+ host?: string;
57
+ user?: string;
58
+ password?: string;
59
+ command: string;
60
+ timeoutMs?: number;
61
+ }): Promise<ExecOutput & {
62
+ contextKey: string;
63
+ endpoint: HostExecutionContext["endpoint"];
64
+ }>;
65
+ probe(args?: {
66
+ contextKey?: string;
67
+ timeoutMs?: number;
68
+ }): Promise<ProbeResult & ContextSummary>;
69
+ dockerPs(args?: {
70
+ contextKey?: string;
71
+ all?: boolean;
72
+ quiet?: boolean;
73
+ filter?: string;
74
+ timeoutMs?: number;
75
+ }): Promise<ExecOutput>;
76
+ dockerExec(args: {
77
+ container: string;
78
+ command: string;
79
+ workdir?: string;
80
+ contextKey?: string;
81
+ timeoutMs?: number;
82
+ }): Promise<ExecOutput>;
83
+ dockerLogs(args: {
84
+ container: string;
85
+ tail?: number;
86
+ since?: string;
87
+ timestamps?: boolean;
88
+ contextKey?: string;
89
+ timeoutMs?: number;
90
+ }): Promise<ExecOutput>;
91
+ /**
92
+ * Expand a contextKey endpoint into landing or host for copy/scp internals.
93
+ */
94
+ materializeFileEndpoint(endpoint: {
95
+ target: "context";
96
+ contextKey: string;
97
+ path: string;
98
+ }): {
99
+ target: "landing" | "host";
100
+ path: string;
101
+ host?: string;
102
+ user?: string;
103
+ password?: string;
104
+ };
105
+ private assertDeriveAllowed;
106
+ private remember;
107
+ private withCachedCaps;
108
+ private resolveHostContext;
109
+ private resolveDeriveSpec;
110
+ }
@@ -0,0 +1,174 @@
1
+ import { SessionPool } from "./session-pool.js";
2
+ import { SshAccessTransport } from "./ssh-transport.js";
3
+ import { ParadiAccessTransport } from "./paradi-transport.js";
4
+ import { resolveRemotePassword, resolveRemoteUser } from "../utils/remote-target.js";
5
+ import { probeCapabilities } from "./probe.js";
6
+ import * as docker from "./docker-runtime.js";
7
+ /**
8
+ * Access + shell/docker Runtime facade.
9
+ * derive = Access (produces Context); Runtime only consumes Context by contextKey.
10
+ */
11
+ export class AccessRuntime {
12
+ config;
13
+ accessContext;
14
+ pool;
15
+ sshTransport = new SshAccessTransport();
16
+ /** Capability cache by context.key (derive may recreate descriptor objects). */
17
+ capsByKey = new Map();
18
+ /** Live Context descriptors by key (landing + derived). */
19
+ contexts = new Map();
20
+ constructor(config, accessClient) {
21
+ this.config = config;
22
+ this.pool = new SessionPool(accessClient);
23
+ this.accessContext =
24
+ config.accessKind === "paradi-gateway"
25
+ ? new ParadiAccessTransport().createContext(config)
26
+ : this.sshTransport.createAccessContext(config);
27
+ this.pool.bindAccess(this.accessContext);
28
+ this.remember(this.accessContext);
29
+ }
30
+ /** Landing Context key (ACCESS for ssh; TARGET for paradi). */
31
+ get landingKey() {
32
+ return this.accessContext.key;
33
+ }
34
+ summarize(ctx = this.accessContext) {
35
+ const withCaps = this.withCachedCaps(ctx);
36
+ return {
37
+ contextKey: withCaps.key,
38
+ endpoint: withCaps.endpoint,
39
+ parentKey: withCaps.parentKey,
40
+ capabilities: withCaps.capabilities,
41
+ };
42
+ }
43
+ /**
44
+ * Resolve Runtime Context by key. Omit / empty → landing.
45
+ * Unknown keys throw (must context_derive first).
46
+ */
47
+ requireContext(contextKey) {
48
+ const key = contextKey?.trim();
49
+ if (!key) {
50
+ return this.withCachedCaps(this.accessContext);
51
+ }
52
+ const ctx = this.contexts.get(key);
53
+ if (!ctx) {
54
+ throw new Error(`Unknown contextKey=${key}. Call context_derive first (or omit contextKey for landing).`);
55
+ }
56
+ return this.withCachedCaps(ctx);
57
+ }
58
+ /** Shell on a Context (default landing). */
59
+ shellExec(command, opts = {}) {
60
+ const ctx = this.requireContext(opts.contextKey);
61
+ return this.pool.exec(ctx, command, opts.timeoutMs, opts.cwd);
62
+ }
63
+ /**
64
+ * Derive a child Context (ACCESS_KIND=ssh only). Returns summary with contextKey.
65
+ * Omitting host uses config TARGET_* as default derive selector.
66
+ */
67
+ deriveContext(args = {}) {
68
+ this.assertDeriveAllowed();
69
+ const host = args.useTarget ? undefined : args.host;
70
+ const ctx = this.resolveHostContext(host, args.user, args.password);
71
+ return this.summarize(ctx);
72
+ }
73
+ /**
74
+ * deriveContext + shellExec — ACCESS_KIND=ssh only.
75
+ * Also returns the derived contextKey via summarize after exec (caller should use derive for key-only).
76
+ */
77
+ async sshExec(args) {
78
+ this.assertDeriveAllowed();
79
+ const ctx = this.resolveHostContext(args.host, args.user, args.password);
80
+ const out = await this.pool.exec(ctx, args.command, args.timeoutMs);
81
+ return { ...out, contextKey: ctx.key, endpoint: ctx.endpoint };
82
+ }
83
+ async probe(args = {}) {
84
+ const ctx = this.requireContext(args.contextKey);
85
+ const result = await probeCapabilities(this.pool, ctx, args.timeoutMs);
86
+ this.capsByKey.set(ctx.key, ctx.capabilities);
87
+ return {
88
+ ...result,
89
+ ...this.summarize(ctx),
90
+ };
91
+ }
92
+ dockerPs(args = {}) {
93
+ const ctx = this.requireContext(args.contextKey);
94
+ return docker.dockerPs(this.pool, ctx, args).then((out) => {
95
+ this.capsByKey.set(ctx.key, ctx.capabilities);
96
+ return out;
97
+ });
98
+ }
99
+ dockerExec(args) {
100
+ const ctx = this.requireContext(args.contextKey);
101
+ return docker.dockerExec(this.pool, ctx, args).then((out) => {
102
+ this.capsByKey.set(ctx.key, ctx.capabilities);
103
+ return out;
104
+ });
105
+ }
106
+ dockerLogs(args) {
107
+ const ctx = this.requireContext(args.contextKey);
108
+ return docker.dockerLogs(this.pool, ctx, args).then((out) => {
109
+ this.capsByKey.set(ctx.key, ctx.capabilities);
110
+ return out;
111
+ });
112
+ }
113
+ /**
114
+ * Expand a contextKey endpoint into landing or host for copy/scp internals.
115
+ */
116
+ materializeFileEndpoint(endpoint) {
117
+ const ctx = this.requireContext(endpoint.contextKey);
118
+ const entry = this.pool.getEntry(ctx.key);
119
+ if (!entry) {
120
+ throw new Error(`No SessionPool binding for context key=${ctx.key}`);
121
+ }
122
+ if (entry.kind === "access") {
123
+ return { target: "landing", path: endpoint.path };
124
+ }
125
+ return {
126
+ target: "host",
127
+ path: endpoint.path,
128
+ host: entry.host,
129
+ user: entry.user,
130
+ password: entry.password,
131
+ };
132
+ }
133
+ assertDeriveAllowed() {
134
+ if (this.config.accessKind === "paradi-gateway") {
135
+ throw new Error("ACCESS_KIND=paradi-gateway already lands on TARGET - context_derive / ssh_exec are unsupported by current Paradi AccessTransport. Use shell_exec, docker_*, or k8s_* on the landing Context (omit contextKey).");
136
+ }
137
+ }
138
+ remember(ctx) {
139
+ this.contexts.set(ctx.key, ctx);
140
+ this.capsByKey.set(ctx.key, ctx.capabilities);
141
+ }
142
+ withCachedCaps(ctx) {
143
+ const cached = this.capsByKey.get(ctx.key);
144
+ if (cached) {
145
+ ctx.capabilities = cached;
146
+ }
147
+ else {
148
+ this.capsByKey.set(ctx.key, ctx.capabilities);
149
+ }
150
+ this.contexts.set(ctx.key, ctx);
151
+ return ctx;
152
+ }
153
+ resolveHostContext(host, user, password) {
154
+ const spec = this.resolveDeriveSpec(host, user, password);
155
+ const child = this.sshTransport.deriveContext(this.accessContext, spec);
156
+ this.pool.bindDerived(child, spec);
157
+ return this.withCachedCaps(child);
158
+ }
159
+ resolveDeriveSpec(host, user, password) {
160
+ const defaultSpec = this.sshTransport.defaultDeriveSpec(this.config);
161
+ const resolvedHost = host?.trim() || defaultSpec?.host;
162
+ if (!resolvedHost) {
163
+ throw new Error("host required, or set TARGET_HOST / pass useTarget with TARGET_* configured");
164
+ }
165
+ const resolvedUser = resolveRemoteUser(user, this.config.targetUser ?? defaultSpec?.user);
166
+ const resolvedPassword = resolveRemotePassword(password, this.config.targetPassword ?? defaultSpec?.password);
167
+ return {
168
+ host: resolvedHost,
169
+ user: resolvedUser,
170
+ password: resolvedPassword,
171
+ };
172
+ }
173
+ }
174
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/access/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Paradi gateway SSH auth encodings (customer never chooses Mode names in mcp.json by default).
3
+ *
4
+ * - slash: username = ACCESS_USER/TARGET_HOST/TARGET_USER, password = ACCESS_PASSWORD
5
+ * - compound: username = ACCESS_USER, password = ACCESS_PASSWORD@##@TARGET_HOST:SSH:22:TARGET_USER
6
+ * - auto: try slash then compound on AUTH_FAILED; pin winner for this MCP process
7
+ */
8
+ import type { AppConfig } from "../config.js";
9
+ export type ParadiAuthMode = "slash" | "compound";
10
+ export type ParadiAuthSetting = ParadiAuthMode | "auto";
11
+ export type ParadiConnectParams = {
12
+ host: string;
13
+ port: number;
14
+ username: string;
15
+ /** Effective SSH password for this mode (ACCESS_PASSWORD or compound). */
16
+ password?: string;
17
+ mode: ParadiAuthMode;
18
+ };
19
+ export declare function paradiPinKey(config: AppConfig): string;
20
+ export declare function getPinnedParadiAuth(config: AppConfig): ParadiAuthMode | undefined;
21
+ export declare function pinParadiAuth(config: AppConfig, mode: ParadiAuthMode): void;
22
+ /** Test helper — clear all process pins. */
23
+ export declare function clearParadiAuthPins(): void;
24
+ export declare function parseParadiAuthSetting(raw: string | undefined): ParadiAuthSetting;
25
+ /**
26
+ * Modes to try for this connect. Pinned mode wins for the MCP process lifetime.
27
+ */
28
+ export declare function resolveParadiAuthModesToTry(config: AppConfig): ParadiAuthMode[];
29
+ export declare function buildParadiCompoundPassword(accessPassword: string, targetHost: string, targetUser: string, targetSshPort?: number): string;
30
+ /** Build username+password for one Paradi auth mode (TCP still to ACCESS_HOST). */
31
+ export declare function resolveParadiConnectParams(config: AppConfig, mode: ParadiAuthMode): ParadiConnectParams;
32
+ /** True when failure is auth-only (safe to try the other Paradi mode). */
33
+ export declare function isParadiAuthFailureMessage(message: string): boolean;
@@ -0,0 +1,89 @@
1
+ import { buildParadiSshUsername } from "./paradi-username.js";
2
+ /** Process-lifetime pin: gateway identity → winning auth mode. */
3
+ const pinnedByGateway = new Map();
4
+ export function paradiPinKey(config) {
5
+ return `${config.accessHost.trim()}:${config.accessPort}:${config.accessUser.trim()}`;
6
+ }
7
+ export function getPinnedParadiAuth(config) {
8
+ return pinnedByGateway.get(paradiPinKey(config));
9
+ }
10
+ export function pinParadiAuth(config, mode) {
11
+ pinnedByGateway.set(paradiPinKey(config), mode);
12
+ }
13
+ /** Test helper — clear all process pins. */
14
+ export function clearParadiAuthPins() {
15
+ pinnedByGateway.clear();
16
+ }
17
+ export function parseParadiAuthSetting(raw) {
18
+ const v = (raw?.trim() || "auto").toLowerCase();
19
+ if (v === "slash" || v === "compound" || v === "auto") {
20
+ return v;
21
+ }
22
+ throw new Error(`ACCESS_PARADI_AUTH must be "auto", "slash", or "compound" (got "${raw}")`);
23
+ }
24
+ /**
25
+ * Modes to try for this connect. Pinned mode wins for the MCP process lifetime.
26
+ */
27
+ export function resolveParadiAuthModesToTry(config) {
28
+ const pinned = getPinnedParadiAuth(config);
29
+ if (pinned) {
30
+ return [pinned];
31
+ }
32
+ const setting = config.accessParadiAuth ?? "auto";
33
+ if (setting === "slash") {
34
+ return ["slash"];
35
+ }
36
+ if (setting === "compound") {
37
+ return ["compound"];
38
+ }
39
+ // auto: slash first (existing slash-username gateways), then compound.
40
+ // Compound needs ACCESS_PASSWORD; without it only slash is attempted.
41
+ if (!config.accessPassword) {
42
+ return ["slash"];
43
+ }
44
+ return ["slash", "compound"];
45
+ }
46
+ export function buildParadiCompoundPassword(accessPassword, targetHost, targetUser, targetSshPort = 22) {
47
+ const p = accessPassword;
48
+ const h = targetHost.trim();
49
+ const u = targetUser.trim();
50
+ if (!h || !u) {
51
+ throw new Error("paradi compound password requires TARGET_HOST and TARGET_USER");
52
+ }
53
+ return `${p}@##@${h}:SSH:${targetSshPort}:${u}`;
54
+ }
55
+ /** Build username+password for one Paradi auth mode (TCP still to ACCESS_HOST). */
56
+ export function resolveParadiConnectParams(config, mode) {
57
+ const targetHost = config.targetHost?.trim();
58
+ const targetUser = config.targetUser?.trim();
59
+ if (!targetHost || !targetUser) {
60
+ throw new Error("paradi-gateway requires TARGET_HOST and TARGET_USER");
61
+ }
62
+ const host = config.accessHost;
63
+ const port = config.accessPort;
64
+ const accessPassword = config.accessPassword;
65
+ if (mode === "slash") {
66
+ return {
67
+ host,
68
+ port,
69
+ username: buildParadiSshUsername(config.accessUser, targetHost, targetUser),
70
+ password: accessPassword,
71
+ mode,
72
+ };
73
+ }
74
+ if (!accessPassword) {
75
+ throw new Error("paradi compound auth requires ACCESS_PASSWORD (password@##@TARGET encoding)");
76
+ }
77
+ return {
78
+ host,
79
+ port,
80
+ username: config.accessUser,
81
+ password: buildParadiCompoundPassword(accessPassword, targetHost, targetUser),
82
+ mode,
83
+ };
84
+ }
85
+ /** True when failure is auth-only (safe to try the other Paradi mode). */
86
+ export function isParadiAuthFailureMessage(message) {
87
+ return /All configured authentication methods failed|Authentication failed|Permission denied \(publickey|password|keyboard-interactive\)/i.test(message);
88
+ }
89
+ //# sourceMappingURL=paradi-auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paradi-auth.js","sourceRoot":"","sources":["../../src/access/paradi-auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { AppConfig } from "../config.js";
2
+ import { type HostExecutionContext } from "./types.js";
3
+ export { buildParadiSshUsername } from "./paradi-username.js";
4
+ /**
5
+ * Paradi AccessTransport → plain HostExecutionContext (endpoint = TARGET).
6
+ * Runtime must not branch on Paradi; only Transport encodes gateway identity.
7
+ */
8
+ export declare class ParadiAccessTransport {
9
+ createContext(config: AppConfig): HostExecutionContext;
10
+ }
@@ -0,0 +1,39 @@
1
+ import { buildContextKey, initialCapabilities, } from "./types.js";
2
+ import { buildParadiSshUsername } from "./paradi-username.js";
3
+ export { buildParadiSshUsername } from "./paradi-username.js";
4
+ /**
5
+ * Paradi AccessTransport → plain HostExecutionContext (endpoint = TARGET).
6
+ * Runtime must not branch on Paradi; only Transport encodes gateway identity.
7
+ */
8
+ export class ParadiAccessTransport {
9
+ createContext(config) {
10
+ if (config.accessKind !== "paradi-gateway") {
11
+ throw new Error(`ParadiAccessTransport only supports ACCESS_KIND=paradi-gateway (got ${config.accessKind})`);
12
+ }
13
+ const targetHost = config.targetHost?.trim();
14
+ const targetUser = config.targetUser?.trim();
15
+ if (!targetHost || !targetUser) {
16
+ throw new Error("paradi-gateway requires TARGET_HOST and TARGET_USER (landing Context is the target host)");
17
+ }
18
+ const sshUsername = buildParadiSshUsername(config.accessUser, targetHost, targetUser);
19
+ return {
20
+ key: buildContextKey({
21
+ transport: "paradi-gateway",
22
+ host: targetHost,
23
+ user: targetUser,
24
+ port: config.accessPort,
25
+ authIdentity: sshUsername,
26
+ }),
27
+ transport: "paradi-gateway",
28
+ // Landing endpoint is T (what Runtime sees), not the gateway IP.
29
+ endpoint: { host: targetHost, user: targetUser, port: 22 },
30
+ capabilities: {
31
+ ...initialCapabilities(true),
32
+ // Declared (research): SFTP unreliable; gateway may rate-limit channel opens.
33
+ sftp: "degraded",
34
+ channelOpenSensitive: true,
35
+ },
36
+ };
37
+ }
38
+ }
39
+ //# sourceMappingURL=paradi-transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paradi-transport.js","sourceRoot":"","sources":["../../src/access/paradi-transport.ts"],"names":[],"mappings":"AACA,OAAO,EACL,eAAe,EACf,mBAAmB,GAEpB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAE9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAE9D;;;GAGG;AACH,MAAM,OAAO,qBAAqB;IAChC,aAAa,CAAC,MAAiB;QAC7B,IAAI,MAAM,CAAC,UAAU,KAAK,gBAAgB,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CACb,uEAAuE,MAAM,CAAC,UAAU,GAAG,CAC5F,CAAC;QACJ,CAAC;QACD,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC;QAC7C,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC;QAC7C,IAAI,CAAC,UAAU,IAAI,CAAC,UAAU,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CACb,0FAA0F,CAC3F,CAAC;QACJ,CAAC;QAED,MAAM,WAAW,GAAG,sBAAsB,CACxC,MAAM,CAAC,UAAU,EACjB,UAAU,EACV,UAAU,CACX,CAAC;QAEF,OAAO;YACL,GAAG,EAAE,eAAe,CAAC;gBACnB,SAAS,EAAE,gBAAgB;gBAC3B,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,UAAU;gBAChB,IAAI,EAAE,MAAM,CAAC,UAAU;gBACvB,YAAY,EAAE,WAAW;aAC1B,CAAC;YACF,SAAS,EAAE,gBAAgB;YAC3B,iEAAiE;YACjE,QAAQ,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,EAAE;YAC1D,YAAY,EAAE;gBACZ,GAAG,mBAAmB,CAAC,IAAI,CAAC;gBAC5B,8EAA8E;gBAC9E,IAAI,EAAE,UAAU;gBAChB,oBAAoB,EAAE,IAAI;aAC3B;SACF,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Paradi Mode A identity encoding (user never puts this string in mcp.json).
3
+ * sshUsername = ACCESS_USER/TARGET_HOST/TARGET_USER
4
+ */
5
+ export declare function buildParadiSshUsername(accessUser: string, targetHost: string, targetUser: string): string;
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Paradi Mode A identity encoding (user never puts this string in mcp.json).
3
+ * sshUsername = ACCESS_USER/TARGET_HOST/TARGET_USER
4
+ */
5
+ export function buildParadiSshUsername(accessUser, targetHost, targetUser) {
6
+ const a = accessUser.trim();
7
+ const h = targetHost.trim();
8
+ const u = targetUser.trim();
9
+ if (!a || !h || !u) {
10
+ throw new Error("paradi-gateway requires ACCESS_USER, TARGET_HOST, and TARGET_USER to build SSH username");
11
+ }
12
+ return `${a}/${h}/${u}`;
13
+ }
14
+ //# sourceMappingURL=paradi-username.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paradi-username.js","sourceRoot":"","sources":["../../src/access/paradi-username.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,UAAkB,EAClB,UAAkB,EAClB,UAAkB;IAElB,MAAM,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC;IAC5B,MAAM,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC;IAC5B,MAAM,CAAC,GAAG,UAAU,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CACb,yFAAyF,CAC1F,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { SessionPool } from "./session-pool.js";
2
+ import type { ContextCapabilities, HostExecutionContext } from "./types.js";
3
+ export interface ProbeResult {
4
+ capabilities: ContextCapabilities;
5
+ raw: string;
6
+ }
7
+ /** Parse `MCP_CAP docker=yes|no kubectl=yes|no` from probe stdout. */
8
+ export declare function parseCapProbeOutput(stdout: string): Pick<ContextCapabilities, "docker" | "kubectl">;
9
+ /**
10
+ * Probe Runtime capabilities on a Context via SessionPool (never opens SSH itself).
11
+ * Updates ctx.capabilities in place. Does not treat SSH success as docker/kubectl=true.
12
+ */
13
+ export declare function probeCapabilities(pool: SessionPool, ctx: HostExecutionContext, timeoutMs?: number): Promise<ProbeResult>;
14
+ export declare function assertCapability(ctx: HostExecutionContext, name: "docker" | "kubectl"): void;
@@ -0,0 +1,63 @@
1
+ const CAP_PROBE_CMD = [
2
+ 'docker=no; command -v docker >/dev/null 2>&1 && docker=yes',
3
+ 'kubectl=no; command -v kubectl >/dev/null 2>&1 && kubectl=yes',
4
+ 'echo "MCP_CAP docker=$docker kubectl=$kubectl"',
5
+ ].join("; ");
6
+ /** Parse `MCP_CAP docker=yes|no kubectl=yes|no` from probe stdout. */
7
+ export function parseCapProbeOutput(stdout) {
8
+ const line = stdout
9
+ .split(/\r?\n/)
10
+ .map((l) => l.trim())
11
+ .find((l) => l.startsWith("MCP_CAP "));
12
+ if (!line) {
13
+ return { docker: "unknown", kubectl: "unknown" };
14
+ }
15
+ const dockerMatch = /\bdocker=(yes|no)\b/.exec(line);
16
+ const kubectlMatch = /\bkubectl=(yes|no)\b/.exec(line);
17
+ return {
18
+ docker: toCap(dockerMatch?.[1]),
19
+ kubectl: toCap(kubectlMatch?.[1]),
20
+ };
21
+ }
22
+ function toCap(value) {
23
+ if (value === "yes") {
24
+ return true;
25
+ }
26
+ if (value === "no") {
27
+ return false;
28
+ }
29
+ return "unknown";
30
+ }
31
+ /**
32
+ * Probe Runtime capabilities on a Context via SessionPool (never opens SSH itself).
33
+ * Updates ctx.capabilities in place. Does not treat SSH success as docker/kubectl=true.
34
+ */
35
+ export async function probeCapabilities(pool, ctx, timeoutMs = 30_000) {
36
+ const out = await pool.exec(ctx, CAP_PROBE_CMD, timeoutMs);
37
+ const parsed = parseCapProbeOutput(out.stdout);
38
+ const execCap = out.exitCode !== 0
39
+ ? ctx.capabilities.exec
40
+ : ctx.capabilities.exec === false
41
+ ? false
42
+ : true;
43
+ ctx.capabilities = {
44
+ exec: execCap,
45
+ docker: out.exitCode !== 0 ? "unknown" : parsed.docker,
46
+ kubectl: out.exitCode !== 0 ? "unknown" : parsed.kubectl,
47
+ // Preserve transport-declared fields
48
+ sftp: ctx.capabilities.sftp,
49
+ channelOpenSensitive: ctx.capabilities.channelOpenSensitive,
50
+ };
51
+ return { capabilities: { ...ctx.capabilities }, raw: out.stdout.trim() };
52
+ }
53
+ export function assertCapability(ctx, name) {
54
+ const value = ctx.capabilities[name];
55
+ if (value === true) {
56
+ return;
57
+ }
58
+ if (value === "unknown") {
59
+ throw new Error(`capabilities.${name} is unknown after probe (CLI check failed or marker missing). Inspect context_probe/raw output; do not assume ${name} is available.`);
60
+ }
61
+ throw new Error(`capabilities.${name}=false on ${ctx.endpoint.host} (user=${ctx.endpoint.user ?? "?"}). ${name} CLI not found on this Context.`);
62
+ }
63
+ //# sourceMappingURL=probe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"probe.js","sourceRoot":"","sources":["../../src/access/probe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { AccessClient, ExecOutput } from "../ssh/access-client.js";
2
+ import type { DeriveSpec, HostExecutionContext } from "./types.js";
3
+ type PoolEntry = {
4
+ kind: "access";
5
+ } | {
6
+ kind: "derived";
7
+ parentKey: string;
8
+ host: string;
9
+ user: string;
10
+ password?: string;
11
+ };
12
+ /**
13
+ * Session pool keyed by context.key. Context itself never holds clients.
14
+ * Phase 1: access entry ??AccessClient; derived ??parent accessClient + ssh/sshpass.
15
+ */
16
+ export declare class SessionPool {
17
+ private readonly accessClient;
18
+ private readonly entries;
19
+ constructor(accessClient: AccessClient);
20
+ bindAccess(ctx: HostExecutionContext): void;
21
+ bindDerived(ctx: HostExecutionContext, spec: DeriveSpec): void;
22
+ getEntry(contextKey: string): PoolEntry | undefined;
23
+ exec(ctx: HostExecutionContext, command: string, timeoutMs?: number, cwd?: string): Promise<ExecOutput>;
24
+ }
25
+ export {};