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.
- package/CHANGELOG.md +330 -0
- package/LICENSE +21 -0
- package/README.md +92 -0
- package/SECURITY.md +72 -0
- package/dist/access/docker-runtime.d.ts +38 -0
- package/dist/access/docker-runtime.js +61 -0
- package/dist/access/docker-runtime.js.map +1 -0
- package/dist/access/index.d.ts +110 -0
- package/dist/access/index.js +174 -0
- package/dist/access/index.js.map +1 -0
- package/dist/access/paradi-auth.d.ts +33 -0
- package/dist/access/paradi-auth.js +89 -0
- package/dist/access/paradi-auth.js.map +1 -0
- package/dist/access/paradi-transport.d.ts +10 -0
- package/dist/access/paradi-transport.js +39 -0
- package/dist/access/paradi-transport.js.map +1 -0
- package/dist/access/paradi-username.d.ts +5 -0
- package/dist/access/paradi-username.js +14 -0
- package/dist/access/paradi-username.js.map +1 -0
- package/dist/access/probe.d.ts +14 -0
- package/dist/access/probe.js +63 -0
- package/dist/access/probe.js.map +1 -0
- package/dist/access/session-pool.d.ts +25 -0
- package/dist/access/session-pool.js +46 -0
- package/dist/access/session-pool.js.map +1 -0
- package/dist/access/ssh-transport.d.ts +16 -0
- package/dist/access/ssh-transport.js +74 -0
- package/dist/access/ssh-transport.js.map +1 -0
- package/dist/access/types.d.ts +43 -0
- package/dist/access/types.js +21 -0
- package/dist/access/types.js.map +1 -0
- package/dist/config.d.ts +52 -0
- package/dist/config.js +179 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/instructions.d.ts +4 -0
- package/dist/instructions.js +93 -0
- package/dist/instructions.js.map +1 -0
- package/dist/kubectl/runner.d.ts +32 -0
- package/dist/kubectl/runner.js +79 -0
- package/dist/kubectl/runner.js.map +1 -0
- package/dist/server.d.ts +3 -0
- package/dist/server.js +24 -0
- package/dist/server.js.map +1 -0
- package/dist/ssh/access-client.d.ts +62 -0
- package/dist/ssh/access-client.js +470 -0
- package/dist/ssh/access-client.js.map +1 -0
- package/dist/ssh/access-errors.d.ts +53 -0
- package/dist/ssh/access-errors.js +180 -0
- package/dist/ssh/access-errors.js.map +1 -0
- package/dist/ssh/access-sftp.d.ts +14 -0
- package/dist/ssh/access-sftp.js +456 -0
- package/dist/ssh/access-sftp.js.map +1 -0
- package/dist/ssh/bastion-client.d.ts +60 -0
- package/dist/ssh/bastion-client.js +423 -0
- package/dist/ssh/bastion-client.js.map +1 -0
- package/dist/ssh/bastion-errors.d.ts +62 -0
- package/dist/ssh/bastion-errors.js +190 -0
- package/dist/ssh/bastion-errors.js.map +1 -0
- package/dist/ssh/hop1-sftp.d.ts +14 -0
- package/dist/ssh/hop1-sftp.js +437 -0
- package/dist/ssh/hop1-sftp.js.map +1 -0
- package/dist/tools/copy-job-schemas.d.ts +709 -0
- package/dist/tools/copy-job-schemas.js +48 -0
- package/dist/tools/copy-job-schemas.js.map +1 -0
- package/dist/tools/register.d.ts +14 -0
- package/dist/tools/register.js +619 -0
- package/dist/tools/register.js.map +1 -0
- package/dist/tools/remote-schemas.d.ts +879 -0
- package/dist/tools/remote-schemas.js +214 -0
- package/dist/tools/remote-schemas.js.map +1 -0
- package/dist/utils/copy-executor.d.ts +41 -0
- package/dist/utils/copy-executor.js +231 -0
- package/dist/utils/copy-executor.js.map +1 -0
- package/dist/utils/copy-job-manager.d.ts +34 -0
- package/dist/utils/copy-job-manager.js +400 -0
- package/dist/utils/copy-job-manager.js.map +1 -0
- package/dist/utils/copy-job-store.d.ts +18 -0
- package/dist/utils/copy-job-store.js +104 -0
- package/dist/utils/copy-job-store.js.map +1 -0
- package/dist/utils/copy-job-types.d.ts +133 -0
- package/dist/utils/copy-job-types.js +37 -0
- package/dist/utils/copy-job-types.js.map +1 -0
- package/dist/utils/copy-transfer.d.ts +59 -0
- package/dist/utils/copy-transfer.js +86 -0
- package/dist/utils/copy-transfer.js.map +1 -0
- package/dist/utils/remote-copy.d.ts +14 -0
- package/dist/utils/remote-copy.js +115 -0
- package/dist/utils/remote-copy.js.map +1 -0
- package/dist/utils/remote-executor.d.ts +15 -0
- package/dist/utils/remote-executor.js +34 -0
- package/dist/utils/remote-executor.js.map +1 -0
- package/dist/utils/remote-target.d.ts +22 -0
- package/dist/utils/remote-target.js +75 -0
- package/dist/utils/remote-target.js.map +1 -0
- package/dist/utils/result.d.ts +87 -0
- package/dist/utils/result.js +81 -0
- package/dist/utils/result.js.map +1 -0
- package/dist/utils/shell-quote.d.ts +22 -0
- package/dist/utils/shell-quote.js +55 -0
- package/dist/utils/shell-quote.js.map +1 -0
- package/dist/utils/timeout.d.ts +1 -0
- package/dist/utils/timeout.js +18 -0
- package/dist/utils/timeout.js.map +1 -0
- package/dist/utils/truncate.d.ts +5 -0
- package/dist/utils/truncate.js +12 -0
- package/dist/utils/truncate.js.map +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +7 -0
- package/dist/version.js.map +1 -0
- package/docs/AGENT_GUIDE.md +161 -0
- package/docs/CONFIGURATION.md +130 -0
- package/docs/COPY_SPECIALIZED_TEST_CHECKLIST.md +9 -0
- package/docs/HOP1_E2E_CHECKLIST.md +128 -0
- package/docs/HOP1_E2E_RESULTS.json +647 -0
- package/docs/PARADI_ACCESS_PLAN.md +272 -0
- package/docs/REMOTE_COPY_JOB_API.md +92 -0
- package/docs/TODO.md +66 -0
- package/docs/USER_GUIDE.zh-CN.md +93 -0
- package/docs/clients/claude-desktop.json.example +12 -0
- package/docs/clients/cursor-npx.json.example +12 -0
- package/docs/clients/cursor.json.example +12 -0
- package/docs/clients/vscode.json.example +12 -0
- package/package.json +65 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
const timeoutMs = z.number().int().positive().optional().describe("Timeout in milliseconds");
|
|
3
|
+
export const landingTarget = z
|
|
4
|
+
.literal("landing")
|
|
5
|
+
.describe("Run on landing Context shell (omit contextKey)");
|
|
6
|
+
export const podFields = {
|
|
7
|
+
namespace: z.string().min(1).describe("Kubernetes namespace (required when target=pod)"),
|
|
8
|
+
pod: z.string().min(1).describe("Pod name (required when target=pod)"),
|
|
9
|
+
container: z
|
|
10
|
+
.string()
|
|
11
|
+
.optional()
|
|
12
|
+
.describe("Container name (required when target=pod and pod has multiple containers)"),
|
|
13
|
+
};
|
|
14
|
+
export const contextFields = {
|
|
15
|
+
contextKey: z
|
|
16
|
+
.string()
|
|
17
|
+
.min(1)
|
|
18
|
+
.describe("HostExecutionContext key from context_derive (required when target=context)"),
|
|
19
|
+
};
|
|
20
|
+
/** Shared landing | pod [| context] discriminated union builder. */
|
|
21
|
+
export function remotePathUnion(fields, opts = { allowContext: true }) {
|
|
22
|
+
const landing = z.object({ target: landingTarget, ...fields }).strict();
|
|
23
|
+
const pod = z.object({ target: z.literal("pod"), ...podFields, ...fields }).strict();
|
|
24
|
+
if (opts.allowContext === false) {
|
|
25
|
+
return z.discriminatedUnion("target", [landing, pod]);
|
|
26
|
+
}
|
|
27
|
+
const context = z
|
|
28
|
+
.object({ target: z.literal("context"), ...contextFields, ...fields })
|
|
29
|
+
.strict();
|
|
30
|
+
return z.discriminatedUnion("target", [landing, pod, context]);
|
|
31
|
+
}
|
|
32
|
+
const filePathField = {
|
|
33
|
+
path: z.string().min(1).describe("Absolute file path"),
|
|
34
|
+
};
|
|
35
|
+
const readModeFields = {
|
|
36
|
+
mode: z
|
|
37
|
+
.enum(["head", "tail"])
|
|
38
|
+
.optional()
|
|
39
|
+
.describe('Read from start ("head", default) or end ("tail")'),
|
|
40
|
+
lines: z
|
|
41
|
+
.number()
|
|
42
|
+
.int()
|
|
43
|
+
.positive()
|
|
44
|
+
.optional()
|
|
45
|
+
.describe("Line count: default 500 for head, 200 for tail"),
|
|
46
|
+
maxLines: z
|
|
47
|
+
.number()
|
|
48
|
+
.int()
|
|
49
|
+
.positive()
|
|
50
|
+
.optional()
|
|
51
|
+
.describe("Deprecated alias for lines when mode=head"),
|
|
52
|
+
offset: z.number().int().positive().optional().describe("Start line (mode=head only)"),
|
|
53
|
+
grep: z.string().optional().describe("Case-insensitive filter before tail (mode=tail only)"),
|
|
54
|
+
timeoutMs,
|
|
55
|
+
};
|
|
56
|
+
export function buildRemoteReadFileSchema(opts = { allowContext: true }) {
|
|
57
|
+
return remotePathUnion({ ...filePathField, ...readModeFields }, opts);
|
|
58
|
+
}
|
|
59
|
+
export function buildRemotePsSchema(opts = { allowContext: true }) {
|
|
60
|
+
return remotePathUnion({
|
|
61
|
+
pattern: z.string().optional().describe("Optional grep pattern for ps aux"),
|
|
62
|
+
timeoutMs,
|
|
63
|
+
}, opts);
|
|
64
|
+
}
|
|
65
|
+
/** Default schemas (ACCESS_KIND=ssh — context allowed). */
|
|
66
|
+
export const remoteReadFileSchema = buildRemoteReadFileSchema({ allowContext: true });
|
|
67
|
+
export const remotePsSchema = buildRemotePsSchema({ allowContext: true });
|
|
68
|
+
/** Map discriminated-union input to internal RemoteTarget. */
|
|
69
|
+
export function remoteInputToTarget(args) {
|
|
70
|
+
switch (args.target) {
|
|
71
|
+
case "landing":
|
|
72
|
+
return { target: "landing" };
|
|
73
|
+
case "pod":
|
|
74
|
+
return {
|
|
75
|
+
target: "pod",
|
|
76
|
+
namespace: args.namespace,
|
|
77
|
+
pod: args.pod,
|
|
78
|
+
container: args.container,
|
|
79
|
+
};
|
|
80
|
+
case "context":
|
|
81
|
+
return {
|
|
82
|
+
target: "context",
|
|
83
|
+
contextKey: args.contextKey,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const filePathEndpoint = {
|
|
88
|
+
path: z.string().min(1).describe("Absolute file or directory path"),
|
|
89
|
+
};
|
|
90
|
+
export function buildRemoteFileEndpointSchema(opts = { allowContext: true }) {
|
|
91
|
+
const local = z
|
|
92
|
+
.object({
|
|
93
|
+
target: z
|
|
94
|
+
.literal("local")
|
|
95
|
+
.describe("Path on the machine running host-execution-mcp (MCP server process)"),
|
|
96
|
+
...filePathEndpoint,
|
|
97
|
+
})
|
|
98
|
+
.strict();
|
|
99
|
+
const landing = z.object({ target: landingTarget, ...filePathEndpoint }).strict();
|
|
100
|
+
const pod = z.object({ target: z.literal("pod"), ...podFields, ...filePathEndpoint }).strict();
|
|
101
|
+
if (opts.allowContext === false) {
|
|
102
|
+
return z.discriminatedUnion("target", [local, landing, pod]);
|
|
103
|
+
}
|
|
104
|
+
const context = z
|
|
105
|
+
.object({ target: z.literal("context"), ...contextFields, ...filePathEndpoint })
|
|
106
|
+
.strict();
|
|
107
|
+
return z.discriminatedUnion("target", [local, landing, pod, context]);
|
|
108
|
+
}
|
|
109
|
+
export const remoteFileEndpointSchema = buildRemoteFileEndpointSchema({ allowContext: true });
|
|
110
|
+
function buildCopyObjectSchema(endpoint) {
|
|
111
|
+
return z
|
|
112
|
+
.object({
|
|
113
|
+
source: endpoint.describe("Copy from"),
|
|
114
|
+
dest: endpoint.describe("Copy to"),
|
|
115
|
+
recursive: z
|
|
116
|
+
.boolean()
|
|
117
|
+
.optional()
|
|
118
|
+
.describe("Directory copy (default true). local↔landing walks files; Runtime uses cp -a / scp -r / kubectl cp."),
|
|
119
|
+
/** @deprecated Prefer totalTimeoutMs; mapped to totalTimeoutMs when set. */
|
|
120
|
+
timeoutMs,
|
|
121
|
+
skipIfComplete: z
|
|
122
|
+
.boolean()
|
|
123
|
+
.optional()
|
|
124
|
+
.describe("Skip rewrite when destination already matches. Gate strength = verify: size (cheap) or size+sha256 (content). Incompatible with verify=none."),
|
|
125
|
+
progressIntervalMs: z
|
|
126
|
+
.number()
|
|
127
|
+
.int()
|
|
128
|
+
.positive()
|
|
129
|
+
.optional()
|
|
130
|
+
.describe("Throttle interval for progress notifications (default 5000ms)"),
|
|
131
|
+
totalTimeoutMs: z
|
|
132
|
+
.number()
|
|
133
|
+
.int()
|
|
134
|
+
.positive()
|
|
135
|
+
.optional()
|
|
136
|
+
.describe("Hard wall-clock limit for the whole copy (falls back to timeoutMs / DEFAULT_TIMEOUT_MS)"),
|
|
137
|
+
connectionTimeoutMs: z
|
|
138
|
+
.number()
|
|
139
|
+
.int()
|
|
140
|
+
.positive()
|
|
141
|
+
.optional()
|
|
142
|
+
.describe("local↔landing SFTP connect readyTimeout (default 20000ms)"),
|
|
143
|
+
verify: z
|
|
144
|
+
.enum(["none", "size", "size+sha256"])
|
|
145
|
+
.optional()
|
|
146
|
+
.describe("Verification / skip gate (default size). size=cheap size match; size+sha256=content (files + directories per-file). none forbidden with skipIfComplete."),
|
|
147
|
+
})
|
|
148
|
+
.strict()
|
|
149
|
+
.refine((v) => !(v.skipIfComplete === true && v.verify === "none"), {
|
|
150
|
+
message: "skipIfComplete requires verify=size or verify=size+sha256",
|
|
151
|
+
path: ["verify"],
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
export function buildRemoteCopyFileSchema(opts = { allowContext: true }) {
|
|
155
|
+
return buildCopyObjectSchema(buildRemoteFileEndpointSchema(opts));
|
|
156
|
+
}
|
|
157
|
+
export const remoteCopyFileSchema = buildRemoteCopyFileSchema({ allowContext: true });
|
|
158
|
+
export function fileEndpointToInternal(endpoint) {
|
|
159
|
+
switch (endpoint.target) {
|
|
160
|
+
case "local":
|
|
161
|
+
return { target: "local", path: endpoint.path };
|
|
162
|
+
case "landing":
|
|
163
|
+
return { target: "landing", path: endpoint.path };
|
|
164
|
+
case "pod":
|
|
165
|
+
return {
|
|
166
|
+
target: "pod",
|
|
167
|
+
path: endpoint.path,
|
|
168
|
+
namespace: endpoint.namespace,
|
|
169
|
+
pod: endpoint.pod,
|
|
170
|
+
container: endpoint.container,
|
|
171
|
+
};
|
|
172
|
+
case "context":
|
|
173
|
+
return {
|
|
174
|
+
target: "context",
|
|
175
|
+
path: endpoint.path,
|
|
176
|
+
contextKey: endpoint.contextKey,
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/** Materialize context endpoints to landing|host for the copy engine. */
|
|
181
|
+
export function materializeCopyEndpoint(access, endpoint) {
|
|
182
|
+
if (endpoint.target !== "context") {
|
|
183
|
+
return endpoint;
|
|
184
|
+
}
|
|
185
|
+
const mat = access.materializeFileEndpoint({
|
|
186
|
+
target: "context",
|
|
187
|
+
contextKey: endpoint.contextKey,
|
|
188
|
+
path: endpoint.path,
|
|
189
|
+
});
|
|
190
|
+
return {
|
|
191
|
+
target: mat.target,
|
|
192
|
+
path: mat.path,
|
|
193
|
+
host: mat.host,
|
|
194
|
+
user: mat.user,
|
|
195
|
+
password: mat.password,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
/** Normalize remote_read_file args. */
|
|
199
|
+
export function resolveReadOptions(args) {
|
|
200
|
+
const mode = args.mode ?? "head";
|
|
201
|
+
if (mode === "tail") {
|
|
202
|
+
return {
|
|
203
|
+
mode: "tail",
|
|
204
|
+
lines: args.lines ?? args.maxLines ?? 200,
|
|
205
|
+
grep: args.grep,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
mode: "head",
|
|
210
|
+
lines: args.lines ?? args.maxLines ?? 500,
|
|
211
|
+
offset: args.offset,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=remote-schemas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote-schemas.js","sourceRoot":"","sources":["../../src/tools/remote-schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yBAAyB,CAAC,CAAC;AAE7F,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC;KAC3B,OAAO,CAAC,SAAS,CAAC;KAClB,QAAQ,CAAC,gDAAgD,CAAC,CAAC;AAE9D,MAAM,CAAC,MAAM,SAAS,GAAG;IACvB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,iDAAiD,CAAC;IACxF,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,qCAAqC,CAAC;IACtE,SAAS,EAAE,CAAC;SACT,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,2EAA2E,CAAC;CACzF,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,UAAU,EAAE,CAAC;SACV,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CAAC,6EAA6E,CAAC;CAC3F,CAAC;AAIF,oEAAoE;AACpE,MAAM,UAAU,eAAe,CAC7B,MAAS,EACT,OAAyB,EAAE,YAAY,EAAE,IAAI,EAAE;IAE/C,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;IACxE,MAAM,GAAG,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,GAAG,SAAS,EAAE,GAAG,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;IACrF,IAAI,IAAI,CAAC,YAAY,KAAK,KAAK,EAAE,CAAC;QAChC,OAAO,CAAC,CAAC,kBAAkB,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;IACxD,CAAC;IACD,MAAM,OAAO,GAAG,CAAC;SACd,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,GAAG,aAAa,EAAE,GAAG,MAAM,EAAE,CAAC;SACrE,MAAM,EAAE,CAAC;IACZ,OAAO,CAAC,CAAC,kBAAkB,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,aAAa,GAAG;IACpB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,oBAAoB,CAAC;CACvD,CAAC;AAEF,MAAM,cAAc,GAAG;IACrB,IAAI,EAAE,CAAC;SACJ,IAAI,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;SACtB,QAAQ,EAAE;SACV,QAAQ,CAAC,mDAAmD,CAAC;IAChE,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,GAAG,EAAE;SACL,QAAQ,EAAE;SACV,QAAQ,EAAE;SACV,QAAQ,CAAC,gDAAgD,CAAC;IAC7D,QAAQ,EAAE,CAAC;SACR,MAAM,EAAE;SACR,GAAG,EAAE;SACL,QAAQ,EAAE;SACV,QAAQ,EAAE;SACV,QAAQ,CAAC,2CAA2C,CAAC;IACxD,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;IACtF,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sDAAsD,CAAC;IAC5F,SAAS;CACV,CAAC;AAEF,MAAM,UAAU,yBAAyB,CAAC,OAAyB,EAAE,YAAY,EAAE,IAAI,EAAE;IACvF,OAAO,eAAe,CAAC,EAAE,GAAG,aAAa,EAAE,GAAG,cAAc,EAAE,EAAE,IAAI,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAyB,EAAE,YAAY,EAAE,IAAI,EAAE;IACjF,OAAO,eAAe,CACpB;QACE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;QAC3E,SAAS;KACV,EACD,IAAI,CACL,CAAC;AACJ,CAAC;AAED,2DAA2D;AAC3D,MAAM,CAAC,MAAM,oBAAoB,GAAG,yBAAyB,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;AACtF,MAAM,CAAC,MAAM,cAAc,GAAG,mBAAmB,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;AAM1E,8DAA8D;AAC9D,MAAM,UAAU,mBAAmB,CAAC,IAAqB;IACvD,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;QACpB,KAAK,SAAS;YACZ,OAAO,EAAE,MAAM,EAAE,SAAkB,EAAE,CAAC;QACxC,KAAK,KAAK;YACR,OAAO;gBACL,MAAM,EAAE,KAAc;gBACtB,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,GAAG,EAAE,IAAI,CAAC,GAAG;gBACb,SAAS,EAAE,IAAI,CAAC,SAAS;aAC1B,CAAC;QACJ,KAAK,SAAS;YACZ,OAAO;gBACL,MAAM,EAAE,SAAkB;gBAC1B,UAAU,EAAE,IAAI,CAAC,UAAU;aAC5B,CAAC;IACN,CAAC;AACH,CAAC;AAID,MAAM,gBAAgB,GAAG;IACvB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,iCAAiC,CAAC;CACpE,CAAC;AAEF,MAAM,UAAU,6BAA6B,CAAC,OAAyB,EAAE,YAAY,EAAE,IAAI,EAAE;IAC3F,MAAM,KAAK,GAAG,CAAC;SACZ,MAAM,CAAC;QACN,MAAM,EAAE,CAAC;aACN,OAAO,CAAC,OAAO,CAAC;aAChB,QAAQ,CAAC,qEAAqE,CAAC;QAClF,GAAG,gBAAgB;KACpB,CAAC;SACD,MAAM,EAAE,CAAC;IACZ,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,GAAG,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;IAClF,MAAM,GAAG,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,GAAG,SAAS,EAAE,GAAG,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC;IAC/F,IAAI,IAAI,CAAC,YAAY,KAAK,KAAK,EAAE,CAAC;QAChC,OAAO,CAAC,CAAC,kBAAkB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;IAC/D,CAAC;IACD,MAAM,OAAO,GAAG,CAAC;SACd,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,GAAG,aAAa,EAAE,GAAG,gBAAgB,EAAE,CAAC;SAC/E,MAAM,EAAE,CAAC;IACZ,OAAO,CAAC,CAAC,kBAAkB,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC;AACxE,CAAC;AAED,MAAM,CAAC,MAAM,wBAAwB,GAAG,6BAA6B,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;AAG9F,SAAS,qBAAqB,CAAC,QAAmB;IAChD,OAAO,CAAC;SACL,MAAM,CAAC;QACN,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,WAAW,CAAC;QACtC,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC;QAClC,SAAS,EAAE,CAAC;aACT,OAAO,EAAE;aACT,QAAQ,EAAE;aACV,QAAQ,CACP,qGAAqG,CACtG;QACH,4EAA4E;QAC5E,SAAS;QACT,cAAc,EAAE,CAAC;aACd,OAAO,EAAE;aACT,QAAQ,EAAE;aACV,QAAQ,CACP,8IAA8I,CAC/I;QACH,kBAAkB,EAAE,CAAC;aAClB,MAAM,EAAE;aACR,GAAG,EAAE;aACL,QAAQ,EAAE;aACV,QAAQ,EAAE;aACV,QAAQ,CAAC,+DAA+D,CAAC;QAC5E,cAAc,EAAE,CAAC;aACd,MAAM,EAAE;aACR,GAAG,EAAE;aACL,QAAQ,EAAE;aACV,QAAQ,EAAE;aACV,QAAQ,CACP,yFAAyF,CAC1F;QACH,mBAAmB,EAAE,CAAC;aACnB,MAAM,EAAE;aACR,GAAG,EAAE;aACL,QAAQ,EAAE;aACV,QAAQ,EAAE;aACV,QAAQ,CAAC,2DAA2D,CAAC;QACxE,MAAM,EAAE,CAAC;aACN,IAAI,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;aACrC,QAAQ,EAAE;aACV,QAAQ,CACP,yJAAyJ,CAC1J;KACJ,CAAC;SACD,MAAM,EAAE;SACR,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,KAAK,IAAI,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,EAAE;QAClE,OAAO,EAAE,2DAA2D;QACpE,IAAI,EAAE,CAAC,QAAQ,CAAC;KACjB,CAAC,CAAC;AACP,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,OAAyB,EAAE,YAAY,EAAE,IAAI,EAAE;IACvF,OAAO,qBAAqB,CAAC,6BAA6B,CAAC,IAAI,CAAC,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,CAAC,MAAM,oBAAoB,GAAG,yBAAyB,CAAC,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;AAGtF,MAAM,UAAU,sBAAsB,CAAC,QAA4B;IACjE,QAAQ,QAAQ,CAAC,MAAM,EAAE,CAAC;QACxB,KAAK,OAAO;YACV,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC;QAClD,KAAK,SAAS;YACZ,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC;QACpD,KAAK,KAAK;YACR,OAAO;gBACL,MAAM,EAAE,KAAK;gBACb,IAAI,EAAE,QAAQ,CAAC,IAAI;gBACnB,SAAS,EAAE,QAAQ,CAAC,SAAS;gBAC7B,GAAG,EAAE,QAAQ,CAAC,GAAG;gBACjB,SAAS,EAAE,QAAQ,CAAC,SAAS;aAC9B,CAAC;QACJ,KAAK,SAAS;YACZ,OAAO;gBACL,MAAM,EAAE,SAAS;gBACjB,IAAI,EAAE,QAAQ,CAAC,IAAI;gBACnB,UAAU,EAAE,QAAQ,CAAC,UAAU;aAChC,CAAC;IACN,CAAC;AACH,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,uBAAuB,CACrC,MAAqB,EACrB,QAAsB;IAEtB,IAAI,QAAQ,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAClC,OAAO,QAAQ,CAAC;IAClB,CAAC;IACD,MAAM,GAAG,GAAG,MAAM,CAAC,uBAAuB,CAAC;QACzC,MAAM,EAAE,SAAS;QACjB,UAAU,EAAE,QAAQ,CAAC,UAAW;QAChC,IAAI,EAAE,QAAQ,CAAC,IAAI;KACpB,CAAC,CAAC;IACH,OAAO;QACL,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,IAAI,EAAE,GAAG,CAAC,IAAI;QACd,QAAQ,EAAE,GAAG,CAAC,QAAQ;KACvB,CAAC;AACJ,CAAC;AAWD,uCAAuC;AACvC,MAAM,UAAU,kBAAkB,CAAC,IAAyB;IAC1D,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC;IACjC,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QACpB,OAAO;YACL,IAAI,EAAE,MAAM;YACZ,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,QAAQ,IAAI,GAAG;YACzC,IAAI,EAAE,IAAI,CAAC,IAAI;SAChB,CAAC;IACJ,CAAC;IAED,OAAO;QACL,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,QAAQ,IAAI,GAAG;QACzC,MAAM,EAAE,IAAI,CAAC,MAAM;KACpB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { AppConfig } from "../config.js";
|
|
2
|
+
import type { AccessClient } from "../ssh/access-client.js";
|
|
3
|
+
import { type FileEndpoint } from "./remote-copy.js";
|
|
4
|
+
import { throwIfAborted, type CopyProgress, type CopySkipReason, type CopyVerifyMode } from "./copy-transfer.js";
|
|
5
|
+
export { throwIfAborted };
|
|
6
|
+
export interface CopyExecutionResult {
|
|
7
|
+
exitCode: number;
|
|
8
|
+
bytes?: number;
|
|
9
|
+
totalBytes?: number;
|
|
10
|
+
skippedBytes?: number;
|
|
11
|
+
skipped?: boolean;
|
|
12
|
+
skipReason?: CopySkipReason;
|
|
13
|
+
transferId: string;
|
|
14
|
+
verified?: boolean;
|
|
15
|
+
usedFastPath?: boolean;
|
|
16
|
+
message: string;
|
|
17
|
+
stderr: string;
|
|
18
|
+
durationMs: number;
|
|
19
|
+
}
|
|
20
|
+
export interface ExecuteRemoteCopyOptions {
|
|
21
|
+
recursive?: boolean;
|
|
22
|
+
/** @deprecated use totalTimeoutMs */
|
|
23
|
+
timeoutMs?: number;
|
|
24
|
+
skipIfComplete?: boolean;
|
|
25
|
+
progressIntervalMs?: number;
|
|
26
|
+
totalTimeoutMs?: number;
|
|
27
|
+
connectionTimeoutMs?: number;
|
|
28
|
+
verify?: CopyVerifyMode;
|
|
29
|
+
onProgress?: (progress: CopyProgress) => void;
|
|
30
|
+
transferId?: string;
|
|
31
|
+
signal?: AbortSignal;
|
|
32
|
+
}
|
|
33
|
+
/** Paradi landing is already TARGET — forbid second-hop / derived copy endpoints. */
|
|
34
|
+
export declare function assertCopyEndpointsAllowed(config: AppConfig, source: FileEndpoint, dest: FileEndpoint): void;
|
|
35
|
+
/** Execute remote_copy_file across local, landing, pod, and host endpoints. */
|
|
36
|
+
export declare function executeRemoteCopy(deps: {
|
|
37
|
+
accessClient: AccessClient;
|
|
38
|
+
config: AppConfig;
|
|
39
|
+
}, source: FileEndpoint, dest: FileEndpoint, options?: ExecuteRemoteCopyOptions): Promise<CopyExecutionResult>;
|
|
40
|
+
/** Verify local file exists and return size (for tests). */
|
|
41
|
+
export declare function localFileBytes(localPath: string): Promise<number>;
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import fs from "node:fs/promises";
|
|
2
|
+
import crypto from "node:crypto";
|
|
3
|
+
import { bashSingleQuote } from "./shell-quote.js";
|
|
4
|
+
import { buildCopyFileCommand, parseCopyBytes } from "./remote-copy.js";
|
|
5
|
+
import { createTransferId, DEFAULT_PROGRESS_INTERVAL_MS, resolveEffectiveVerify, throwIfAborted, } from "./copy-transfer.js";
|
|
6
|
+
export { throwIfAborted };
|
|
7
|
+
function tempLandingPath() {
|
|
8
|
+
return `/tmp/mcp_copy_${Date.now()}_${crypto.randomBytes(6).toString("hex")}`;
|
|
9
|
+
}
|
|
10
|
+
/** Paradi landing is already TARGET — forbid second-hop / derived copy endpoints. */
|
|
11
|
+
export function assertCopyEndpointsAllowed(config, source, dest) {
|
|
12
|
+
if (config.accessKind !== "paradi-gateway") {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (source.target === "host" ||
|
|
16
|
+
dest.target === "host" ||
|
|
17
|
+
source.target === "context" ||
|
|
18
|
+
dest.target === "context") {
|
|
19
|
+
throw new Error("ACCESS_KIND=paradi-gateway already lands on TARGET — remote_copy second-hop host/context endpoints are unsupported by current Paradi AccessTransport. Use target=landing (landing=TARGET), pod, or local.");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function mergeOutput(raw) {
|
|
23
|
+
return [raw.stdout, raw.stderr].filter(Boolean).join("\n");
|
|
24
|
+
}
|
|
25
|
+
function resolveSftpOptions(options, config) {
|
|
26
|
+
const transferId = options.transferId ?? createTransferId();
|
|
27
|
+
const skipIfComplete = options.skipIfComplete === true;
|
|
28
|
+
// Enforce skip+none reject at Engine entry (not only Zod).
|
|
29
|
+
const verify = resolveEffectiveVerify(skipIfComplete, options.verify);
|
|
30
|
+
return {
|
|
31
|
+
skipIfComplete,
|
|
32
|
+
progressIntervalMs: options.progressIntervalMs ?? DEFAULT_PROGRESS_INTERVAL_MS,
|
|
33
|
+
totalTimeoutMs: options.totalTimeoutMs ?? options.timeoutMs ?? config.defaultTimeoutMs,
|
|
34
|
+
connectionTimeoutMs: options.connectionTimeoutMs,
|
|
35
|
+
verify,
|
|
36
|
+
onProgress: options.onProgress,
|
|
37
|
+
transferId,
|
|
38
|
+
signal: options.signal,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function remainingTimeoutMs(deadlineMs, fallback) {
|
|
42
|
+
const left = deadlineMs - Date.now();
|
|
43
|
+
if (left <= 0) {
|
|
44
|
+
throw new Error("Copy total timeout exceeded");
|
|
45
|
+
}
|
|
46
|
+
return Math.min(fallback, left);
|
|
47
|
+
}
|
|
48
|
+
function fromSftpResult(transfer, message, durationMs) {
|
|
49
|
+
return {
|
|
50
|
+
exitCode: 0,
|
|
51
|
+
bytes: transfer.bytes,
|
|
52
|
+
totalBytes: transfer.totalBytes,
|
|
53
|
+
skippedBytes: transfer.skippedBytes,
|
|
54
|
+
skipped: transfer.skipped,
|
|
55
|
+
skipReason: transfer.skipReason,
|
|
56
|
+
transferId: transfer.transferId,
|
|
57
|
+
verified: transfer.verified,
|
|
58
|
+
usedFastPath: transfer.usedFastPath,
|
|
59
|
+
message,
|
|
60
|
+
stderr: "",
|
|
61
|
+
durationMs,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
async function removeLandingFile(accessClient, remotePath, timeoutMs, signal) {
|
|
65
|
+
await accessClient.exec(`rm -f ${bashSingleQuote(remotePath)}`, timeoutMs, undefined, signal).catch(() => undefined);
|
|
66
|
+
}
|
|
67
|
+
async function runLandingCopy(accessClient, source, dest, recursive, config, timeoutMs, signal) {
|
|
68
|
+
throwIfAborted(signal);
|
|
69
|
+
const command = buildCopyFileCommand(source, dest, recursive, config.targetUser, config.targetPassword);
|
|
70
|
+
const raw = await accessClient.exec(command, timeoutMs, undefined, signal);
|
|
71
|
+
const output = mergeOutput(raw);
|
|
72
|
+
return { exitCode: raw.exitCode, bytes: parseCopyBytes(output), output };
|
|
73
|
+
}
|
|
74
|
+
/** Execute remote_copy_file across local, landing, pod, and host endpoints. */
|
|
75
|
+
export async function executeRemoteCopy(deps, source, dest, options = {}) {
|
|
76
|
+
const started = Date.now();
|
|
77
|
+
const recursive = options.recursive ?? true;
|
|
78
|
+
const sftpOpts = resolveSftpOptions(options, deps.config);
|
|
79
|
+
const budget = sftpOpts.totalTimeoutMs ?? deps.config.defaultTimeoutMs;
|
|
80
|
+
const deadlineMs = started + budget;
|
|
81
|
+
const src = source.target;
|
|
82
|
+
const dst = dest.target;
|
|
83
|
+
const duration = () => Date.now() - started;
|
|
84
|
+
const signal = options.signal;
|
|
85
|
+
throwIfAborted(signal);
|
|
86
|
+
assertCopyEndpointsAllowed(deps.config, source, dest);
|
|
87
|
+
const hopTimeout = () => remainingTimeoutMs(deadlineMs, budget);
|
|
88
|
+
if (src === "local" && dst === "landing") {
|
|
89
|
+
const transfer = await deps.accessClient.uploadPath(source.path, dest.path, {
|
|
90
|
+
...sftpOpts,
|
|
91
|
+
totalTimeoutMs: hopTimeout(),
|
|
92
|
+
});
|
|
93
|
+
return fromSftpResult(transfer, `Copied local:${source.path} → landing:${dest.path}`, duration());
|
|
94
|
+
}
|
|
95
|
+
if (src === "landing" && dst === "local") {
|
|
96
|
+
const transfer = await deps.accessClient.downloadPath(source.path, dest.path, {
|
|
97
|
+
...sftpOpts,
|
|
98
|
+
totalTimeoutMs: hopTimeout(),
|
|
99
|
+
});
|
|
100
|
+
return fromSftpResult(transfer, `Copied landing:${source.path} → local:${dest.path}`, duration());
|
|
101
|
+
}
|
|
102
|
+
if (src === "local" && dst === "pod") {
|
|
103
|
+
const tmp = tempLandingPath();
|
|
104
|
+
try {
|
|
105
|
+
const uploaded = await deps.accessClient.uploadPath(source.path, tmp, {
|
|
106
|
+
...sftpOpts,
|
|
107
|
+
totalTimeoutMs: hopTimeout(),
|
|
108
|
+
});
|
|
109
|
+
throwIfAborted(signal);
|
|
110
|
+
const result = await runLandingCopy(deps.accessClient, { target: "landing", path: tmp }, dest, recursive, deps.config, hopTimeout(), signal);
|
|
111
|
+
if (result.exitCode !== 0) {
|
|
112
|
+
return {
|
|
113
|
+
exitCode: result.exitCode,
|
|
114
|
+
transferId: uploaded.transferId,
|
|
115
|
+
totalBytes: uploaded.totalBytes,
|
|
116
|
+
bytes: uploaded.bytes,
|
|
117
|
+
message: result.output.trim() || "Copy failed",
|
|
118
|
+
stderr: result.output,
|
|
119
|
+
durationMs: duration(),
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
...fromSftpResult(uploaded, `Copied local:${source.path} → pod:${dest.path}`, duration()),
|
|
124
|
+
bytes: result.bytes ?? uploaded.bytes,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
const left = Math.max(1_000, Math.min(15_000, deadlineMs - Date.now()));
|
|
129
|
+
await removeLandingFile(deps.accessClient, tmp, left, signal);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (src === "pod" && dst === "local") {
|
|
133
|
+
const tmp = tempLandingPath();
|
|
134
|
+
try {
|
|
135
|
+
const result = await runLandingCopy(deps.accessClient, source, { target: "landing", path: tmp }, recursive, deps.config, hopTimeout(), signal);
|
|
136
|
+
if (result.exitCode !== 0) {
|
|
137
|
+
return {
|
|
138
|
+
exitCode: result.exitCode,
|
|
139
|
+
transferId: sftpOpts.transferId,
|
|
140
|
+
message: result.output.trim() || "Copy failed",
|
|
141
|
+
stderr: result.output,
|
|
142
|
+
durationMs: duration(),
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
throwIfAborted(signal);
|
|
146
|
+
const transfer = await deps.accessClient.downloadPath(tmp, dest.path, {
|
|
147
|
+
...sftpOpts,
|
|
148
|
+
totalTimeoutMs: hopTimeout(),
|
|
149
|
+
});
|
|
150
|
+
return fromSftpResult(transfer, `Copied pod:${source.path} → local:${dest.path}`, duration());
|
|
151
|
+
}
|
|
152
|
+
finally {
|
|
153
|
+
const left = Math.max(1_000, Math.min(15_000, deadlineMs - Date.now()));
|
|
154
|
+
await removeLandingFile(deps.accessClient, tmp, left, signal);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (src === "local" && dst === "host") {
|
|
158
|
+
const tmp = tempLandingPath();
|
|
159
|
+
try {
|
|
160
|
+
const uploaded = await deps.accessClient.uploadPath(source.path, tmp, {
|
|
161
|
+
...sftpOpts,
|
|
162
|
+
totalTimeoutMs: hopTimeout(),
|
|
163
|
+
});
|
|
164
|
+
throwIfAborted(signal);
|
|
165
|
+
const result = await runLandingCopy(deps.accessClient, { target: "landing", path: tmp }, dest, recursive, deps.config, hopTimeout(), signal);
|
|
166
|
+
if (result.exitCode !== 0) {
|
|
167
|
+
return {
|
|
168
|
+
exitCode: result.exitCode,
|
|
169
|
+
transferId: uploaded.transferId,
|
|
170
|
+
totalBytes: uploaded.totalBytes,
|
|
171
|
+
bytes: uploaded.bytes,
|
|
172
|
+
message: result.output.trim() || "Copy failed",
|
|
173
|
+
stderr: result.output,
|
|
174
|
+
durationMs: duration(),
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
return {
|
|
178
|
+
...fromSftpResult(uploaded, `Copied local:${source.path} → host:${dest.path}`, duration()),
|
|
179
|
+
bytes: result.bytes ?? uploaded.bytes,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
finally {
|
|
183
|
+
const left = Math.max(1_000, Math.min(15_000, deadlineMs - Date.now()));
|
|
184
|
+
await removeLandingFile(deps.accessClient, tmp, left, signal);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
if (src === "host" && dst === "local") {
|
|
188
|
+
const tmp = tempLandingPath();
|
|
189
|
+
try {
|
|
190
|
+
const result = await runLandingCopy(deps.accessClient, source, { target: "landing", path: tmp }, recursive, deps.config, hopTimeout(), signal);
|
|
191
|
+
if (result.exitCode !== 0) {
|
|
192
|
+
return {
|
|
193
|
+
exitCode: result.exitCode,
|
|
194
|
+
transferId: sftpOpts.transferId,
|
|
195
|
+
message: result.output.trim() || "Copy failed",
|
|
196
|
+
stderr: result.output,
|
|
197
|
+
durationMs: duration(),
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
throwIfAborted(signal);
|
|
201
|
+
const transfer = await deps.accessClient.downloadPath(tmp, dest.path, {
|
|
202
|
+
...sftpOpts,
|
|
203
|
+
totalTimeoutMs: hopTimeout(),
|
|
204
|
+
});
|
|
205
|
+
return fromSftpResult(transfer, `Copied host:${source.path} → local:${dest.path}`, duration());
|
|
206
|
+
}
|
|
207
|
+
finally {
|
|
208
|
+
const left = Math.max(1_000, Math.min(15_000, deadlineMs - Date.now()));
|
|
209
|
+
await removeLandingFile(deps.accessClient, tmp, left, signal);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
throwIfAborted(signal);
|
|
213
|
+
const result = await runLandingCopy(deps.accessClient, source, dest, recursive, deps.config, hopTimeout(), signal);
|
|
214
|
+
return {
|
|
215
|
+
exitCode: result.exitCode,
|
|
216
|
+
bytes: result.bytes,
|
|
217
|
+
totalBytes: result.bytes,
|
|
218
|
+
transferId: sftpOpts.transferId,
|
|
219
|
+
message: result.exitCode === 0
|
|
220
|
+
? `Copied ${source.target}:${source.path} → ${dest.target}:${dest.path}`
|
|
221
|
+
: result.output.trim() || "Copy failed",
|
|
222
|
+
stderr: result.output,
|
|
223
|
+
durationMs: duration(),
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
/** Verify local file exists and return size (for tests). */
|
|
227
|
+
export async function localFileBytes(localPath) {
|
|
228
|
+
const stat = await fs.stat(localPath);
|
|
229
|
+
return stat.size;
|
|
230
|
+
}
|
|
231
|
+
//# sourceMappingURL=copy-executor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copy-executor.js","sourceRoot":"","sources":["../../src/utils/copy-executor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { AppConfig } from "../config.js";
|
|
2
|
+
import type { AccessClient } from "../ssh/access-client.js";
|
|
3
|
+
import type { FileEndpoint } from "./remote-copy.js";
|
|
4
|
+
import { type ExecuteRemoteCopyOptions, type CopyExecutionResult } from "./copy-executor.js";
|
|
5
|
+
import { type CopyJobHop, type RemoteCopyCancelResult, type RemoteCopyStartRequest, type RemoteCopyStartResult, type RemoteCopyStatusResult } from "./copy-job-types.js";
|
|
6
|
+
import { CopyJobStore } from "./copy-job-store.js";
|
|
7
|
+
type CopyRunner = (deps: {
|
|
8
|
+
accessClient: AccessClient;
|
|
9
|
+
config: AppConfig;
|
|
10
|
+
}, source: FileEndpoint, dest: FileEndpoint, options?: ExecuteRemoteCopyOptions) => Promise<CopyExecutionResult>;
|
|
11
|
+
/** Build a simple plan description for observability (engine still runs as one executeRemoteCopy). */
|
|
12
|
+
export declare function buildCopyPlan(source: FileEndpoint, dest: FileEndpoint): CopyJobHop[];
|
|
13
|
+
export declare class CopyJobManager {
|
|
14
|
+
private readonly deps;
|
|
15
|
+
private readonly store;
|
|
16
|
+
private readonly active;
|
|
17
|
+
private readonly executeCopy;
|
|
18
|
+
/** Resolves after orphan reconcile on startup. */
|
|
19
|
+
readonly ready: Promise<number>;
|
|
20
|
+
constructor(deps: {
|
|
21
|
+
accessClient: AccessClient;
|
|
22
|
+
config: AppConfig;
|
|
23
|
+
}, store?: CopyJobStore, executeCopy?: CopyRunner, options?: {
|
|
24
|
+
reconcileOnStart?: boolean;
|
|
25
|
+
});
|
|
26
|
+
get jobStorePath(): string;
|
|
27
|
+
/** Mark in-process jobs left as running/queued after MCP restart as failed. */
|
|
28
|
+
reconcileOrphans(): Promise<number>;
|
|
29
|
+
start(request: RemoteCopyStartRequest): Promise<RemoteCopyStartResult>;
|
|
30
|
+
status(transferId: string): Promise<RemoteCopyStatusResult>;
|
|
31
|
+
cancel(transferId: string): Promise<RemoteCopyCancelResult>;
|
|
32
|
+
private runJob;
|
|
33
|
+
}
|
|
34
|
+
export {};
|