@rigkit/provider-cmux 0.2.1 → 0.2.3
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/README.md +3 -4
- package/package.json +3 -3
- package/src/capabilities.ts +1 -3
- package/src/host.ts +8 -35
- package/src/index.test.ts +27 -15
- package/src/index.ts +2 -0
- package/src/provider.ts +25 -25
- package/src/version.ts +1 -1
package/README.md
CHANGED
|
@@ -43,14 +43,13 @@ export default workflow("site", {
|
|
|
43
43
|
})
|
|
44
44
|
.sequence("site")
|
|
45
45
|
.operation("open", {
|
|
46
|
-
requiredHostCapabilities: [cmux.capabilities.open],
|
|
47
46
|
run: async ({ providers }) => {
|
|
48
47
|
await providers.cmux.open({
|
|
49
48
|
name: "site",
|
|
50
49
|
ssh: {
|
|
51
|
-
host: "
|
|
52
|
-
username: "
|
|
53
|
-
|
|
50
|
+
host: "devbox.example.com",
|
|
51
|
+
username: "root",
|
|
52
|
+
sshOptions: ["ServerAliveInterval=15"],
|
|
54
53
|
},
|
|
55
54
|
cwd: "/workspace/site",
|
|
56
55
|
command: "pnpm dev",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rigkit/provider-cmux",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -17,8 +17,8 @@
|
|
|
17
17
|
"README.md"
|
|
18
18
|
],
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@rigkit/sdk": "0.2.
|
|
21
|
-
"@rigkit/engine": "0.2.
|
|
20
|
+
"@rigkit/sdk": "0.2.3",
|
|
21
|
+
"@rigkit/engine": "0.2.3"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/bun": "latest",
|
package/src/capabilities.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export const CMUX_OPEN_CAPABILITY_ID = "cmux.open";
|
|
2
2
|
|
|
3
3
|
export const CMUX_OPEN_SCHEMA_HASH =
|
|
4
|
-
"sha256:
|
|
4
|
+
"sha256:671373232fc79a7f75dd01c8c83c0c350af62b349a89bb3cfcc96af2cd76c878";
|
|
5
5
|
|
|
6
6
|
export const CMUX_OPEN_CAPABILITY = {
|
|
7
7
|
id: CMUX_OPEN_CAPABILITY_ID,
|
|
@@ -14,8 +14,6 @@ export type CmuxOpenSshInput = string | {
|
|
|
14
14
|
host?: string;
|
|
15
15
|
port?: number;
|
|
16
16
|
username?: string;
|
|
17
|
-
auth?: { type: "token"; token: string } | { type: "privateKey"; privateKey: string };
|
|
18
|
-
command?: string;
|
|
19
17
|
identity?: string;
|
|
20
18
|
sshOptions?: readonly string[];
|
|
21
19
|
remoteCommandArgs?: readonly string[];
|
package/src/host.ts
CHANGED
|
@@ -41,15 +41,6 @@ export type CmuxOpenHostOptions = {
|
|
|
41
41
|
clientOptions?: CmuxClientOptions;
|
|
42
42
|
};
|
|
43
43
|
|
|
44
|
-
const freestyleTokenSshOptions = [
|
|
45
|
-
"StrictHostKeyChecking=no",
|
|
46
|
-
"UserKnownHostsFile=/dev/null",
|
|
47
|
-
"LogLevel=ERROR",
|
|
48
|
-
"IdentitiesOnly=yes",
|
|
49
|
-
"IdentityFile=/dev/null",
|
|
50
|
-
"ControlMaster=no",
|
|
51
|
-
] as const;
|
|
52
|
-
|
|
53
44
|
export function createCmuxOpenHostCapability(
|
|
54
45
|
options: CmuxOpenHostOptions = {},
|
|
55
46
|
): CmuxHostCapabilityHandler {
|
|
@@ -171,8 +162,6 @@ function parseSshInput(value: unknown): CmuxOpenSshInput {
|
|
|
171
162
|
...optionalStringField(value, "host"),
|
|
172
163
|
...optionalNumberField(value, "port"),
|
|
173
164
|
...optionalStringField(value, "username"),
|
|
174
|
-
...(value.auth !== undefined ? { auth: parseSshAuth(value.auth) } : {}),
|
|
175
|
-
...optionalStringField(value, "command"),
|
|
176
165
|
...optionalStringField(value, "identity"),
|
|
177
166
|
...optionalStringArrayField(value, "sshOptions"),
|
|
178
167
|
...optionalStringArrayField(value, "remoteCommandArgs"),
|
|
@@ -183,17 +172,6 @@ function parseSshInput(value: unknown): CmuxOpenSshInput {
|
|
|
183
172
|
};
|
|
184
173
|
}
|
|
185
174
|
|
|
186
|
-
function parseSshAuth(value: unknown): Exclude<Extract<CmuxOpenSshInput, object>["auth"], undefined> {
|
|
187
|
-
if (!isRecord(value)) throw new Error(`cmux.open ssh.auth must be an object`);
|
|
188
|
-
if (value.type === "token") {
|
|
189
|
-
return { type: "token", token: requiredString(value, "token") };
|
|
190
|
-
}
|
|
191
|
-
if (value.type === "privateKey") {
|
|
192
|
-
return { type: "privateKey", privateKey: requiredString(value, "privateKey") };
|
|
193
|
-
}
|
|
194
|
-
throw new Error(`cmux.open ssh.auth.type must be "token" or "privateKey"`);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
175
|
function parseRemoteReadyOptions(value: unknown): boolean | CmuxRemoteReadyOptions {
|
|
198
176
|
if (typeof value === "boolean") return value;
|
|
199
177
|
if (!isRecord(value)) throw new Error(`cmux.open waitForRemoteReady must be a boolean or object`);
|
|
@@ -208,27 +186,22 @@ function cmuxSshOptionsForInput(ssh: CmuxOpenSshInput): CmuxSshOptions {
|
|
|
208
186
|
if (typeof ssh === "string") return { destination: ssh };
|
|
209
187
|
|
|
210
188
|
const destination = ssh.destination ?? sshDestination(ssh);
|
|
211
|
-
const sshOptions = [
|
|
212
|
-
...(ssh.auth?.type === "token" ? freestyleTokenSshOptions : []),
|
|
213
|
-
...(ssh.sshOptions ?? []),
|
|
214
|
-
];
|
|
215
189
|
return {
|
|
216
190
|
destination,
|
|
217
|
-
port: ssh.port,
|
|
218
|
-
identity: ssh.identity,
|
|
219
|
-
sshOptions,
|
|
220
|
-
remoteCommandArgs: ssh.remoteCommandArgs,
|
|
221
|
-
initialCommand: ssh.initialCommand,
|
|
222
|
-
terminalStartupCommand: ssh.terminalStartupCommand
|
|
223
|
-
autoConnect: ssh.autoConnect,
|
|
224
|
-
skipDaemonBootstrap: ssh.skipDaemonBootstrap,
|
|
191
|
+
...(ssh.port !== undefined ? { port: ssh.port } : {}),
|
|
192
|
+
...(ssh.identity !== undefined ? { identity: ssh.identity } : {}),
|
|
193
|
+
...(ssh.sshOptions?.length ? { sshOptions: ssh.sshOptions } : {}),
|
|
194
|
+
...(ssh.remoteCommandArgs !== undefined ? { remoteCommandArgs: ssh.remoteCommandArgs } : {}),
|
|
195
|
+
...(ssh.initialCommand !== undefined ? { initialCommand: ssh.initialCommand } : {}),
|
|
196
|
+
...(ssh.terminalStartupCommand !== undefined ? { terminalStartupCommand: ssh.terminalStartupCommand } : {}),
|
|
197
|
+
...(ssh.autoConnect !== undefined ? { autoConnect: ssh.autoConnect } : {}),
|
|
198
|
+
...(ssh.skipDaemonBootstrap !== undefined ? { skipDaemonBootstrap: ssh.skipDaemonBootstrap } : {}),
|
|
225
199
|
};
|
|
226
200
|
}
|
|
227
201
|
|
|
228
202
|
function sshDestination(ssh: Extract<CmuxOpenSshInput, object>): string {
|
|
229
203
|
if (!ssh.host) throw new Error(`cmux.open ssh.host is required when ssh.destination is omitted`);
|
|
230
204
|
if (!ssh.username) throw new Error(`cmux.open ssh.username is required when ssh.destination is omitted`);
|
|
231
|
-
if (ssh.auth?.type === "token") return `${ssh.username},${ssh.auth.token}@${ssh.host}`;
|
|
232
205
|
return `${ssh.username}@${ssh.host}`;
|
|
233
206
|
}
|
|
234
207
|
|
package/src/index.test.ts
CHANGED
|
@@ -6,7 +6,6 @@ import { describe, expect, test } from "bun:test";
|
|
|
6
6
|
import type { ProviderStorage, ProviderStorageRecord } from "@rigkit/engine";
|
|
7
7
|
import type { JsonValue } from "@rigkit/sdk";
|
|
8
8
|
import {
|
|
9
|
-
CMUX_OPEN_CAPABILITY,
|
|
10
9
|
CmuxCommandError,
|
|
11
10
|
cmux,
|
|
12
11
|
cmuxProviderPlugin,
|
|
@@ -409,10 +408,8 @@ describe("cmux sdk", () => {
|
|
|
409
408
|
name: "website",
|
|
410
409
|
ssh: {
|
|
411
410
|
kind: "ssh",
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
auth: { type: "token", token: "token_123" },
|
|
415
|
-
command: "ssh vm_123:token_123@vm-ssh.freestyle.sh",
|
|
411
|
+
destination: "vm_123,token_123@vm-ssh.freestyle.sh",
|
|
412
|
+
sshOptions: ["ServerAliveInterval=15"],
|
|
416
413
|
},
|
|
417
414
|
cwd: "/workspace/site",
|
|
418
415
|
command: "pnpm dev",
|
|
@@ -434,15 +431,7 @@ describe("cmux sdk", () => {
|
|
|
434
431
|
params: expect.objectContaining({
|
|
435
432
|
destination: "vm_123,token_123@vm-ssh.freestyle.sh",
|
|
436
433
|
name: "website",
|
|
437
|
-
|
|
438
|
-
sshOptions: [
|
|
439
|
-
"StrictHostKeyChecking=no",
|
|
440
|
-
"UserKnownHostsFile=/dev/null",
|
|
441
|
-
"LogLevel=ERROR",
|
|
442
|
-
"IdentitiesOnly=yes",
|
|
443
|
-
"IdentityFile=/dev/null",
|
|
444
|
-
"ControlMaster=no",
|
|
445
|
-
],
|
|
434
|
+
sshOptions: ["ServerAliveInterval=15"],
|
|
446
435
|
}),
|
|
447
436
|
},
|
|
448
437
|
{
|
|
@@ -490,13 +479,36 @@ describe("cmux sdk", () => {
|
|
|
490
479
|
params: "workspace-1",
|
|
491
480
|
},
|
|
492
481
|
]);
|
|
482
|
+
expect(calls[0]?.params).not.toHaveProperty("terminalStartupCommand");
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
test("forwards an explicit cmux ssh terminal startup command", async () => {
|
|
486
|
+
const calls: Array<{ method: string; params: unknown }> = [];
|
|
487
|
+
const client = fakeOpenClient(calls);
|
|
488
|
+
|
|
489
|
+
await openCmux({
|
|
490
|
+
name: "website",
|
|
491
|
+
ssh: {
|
|
492
|
+
kind: "ssh",
|
|
493
|
+
destination: "vm_123,token_123@vm-ssh.freestyle.sh",
|
|
494
|
+
terminalStartupCommand: "ssh -tt vm_123:token_123@vm-ssh.freestyle.sh",
|
|
495
|
+
},
|
|
496
|
+
}, { client });
|
|
497
|
+
|
|
498
|
+
expect(calls[0]).toEqual({
|
|
499
|
+
method: "ssh",
|
|
500
|
+
params: expect.objectContaining({
|
|
501
|
+
destination: "vm_123,token_123@vm-ssh.freestyle.sh",
|
|
502
|
+
name: "website",
|
|
503
|
+
terminalStartupCommand: "ssh -tt vm_123:token_123@vm-ssh.freestyle.sh",
|
|
504
|
+
}),
|
|
505
|
+
});
|
|
493
506
|
});
|
|
494
507
|
|
|
495
508
|
test("exposes a provider facade that requests cmux.open from the local host", async () => {
|
|
496
509
|
const definition = cmux.provider();
|
|
497
510
|
expect(definition.providerId).toBe("cmux");
|
|
498
511
|
expect(definition.plugin).toBe(cmuxProviderPlugin);
|
|
499
|
-
expect(cmux.capabilities.open).toBe(CMUX_OPEN_CAPABILITY);
|
|
500
512
|
|
|
501
513
|
const controller = await cmuxProviderPlugin.createProvider({
|
|
502
514
|
provider: { providerId: "cmux", config: {} },
|
package/src/index.ts
CHANGED
package/src/provider.ts
CHANGED
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
} from "@rigkit/sdk";
|
|
6
6
|
import type { BaseProviderPlugin, WorkflowProviderController } from "@rigkit/engine";
|
|
7
7
|
import {
|
|
8
|
-
CMUX_OPEN_CAPABILITY,
|
|
9
8
|
CMUX_OPEN_CAPABILITY_ID,
|
|
10
9
|
type CmuxOpenInput,
|
|
11
10
|
type CmuxOpenResult,
|
|
@@ -30,10 +29,6 @@ export function provider(): CmuxProviderDefinition {
|
|
|
30
29
|
|
|
31
30
|
export const cmux = {
|
|
32
31
|
provider,
|
|
33
|
-
capability: CMUX_OPEN_CAPABILITY,
|
|
34
|
-
capabilities: {
|
|
35
|
-
open: CMUX_OPEN_CAPABILITY,
|
|
36
|
-
},
|
|
37
32
|
};
|
|
38
33
|
|
|
39
34
|
export const cmuxProviderPlugin: BaseProviderPlugin = {
|
|
@@ -50,29 +45,34 @@ export const cmuxProviderPlugin: BaseProviderPlugin = {
|
|
|
50
45
|
|
|
51
46
|
function createCmuxRuntime(local: LocalWorkspaceRuntime): CmuxRuntime {
|
|
52
47
|
return {
|
|
53
|
-
async
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
48
|
+
open: async (input) => await requestCmuxOpen(local, input),
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export async function requestCmuxOpen(
|
|
53
|
+
local: LocalWorkspaceRuntime,
|
|
54
|
+
input: CmuxOpenInput,
|
|
55
|
+
): Promise<CmuxOpenSession> {
|
|
56
|
+
if (local.requestCapabilitySession) {
|
|
57
|
+
const session = await local.requestCapabilitySession<CmuxOpenResult>(CMUX_OPEN_CAPABILITY_ID, input);
|
|
58
|
+
return {
|
|
59
|
+
...parseCmuxOpenResult(session.result),
|
|
60
|
+
closed: session.closed,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
if (!local.requestCapability) {
|
|
64
|
+
throw new Error(`Host capability ${CMUX_OPEN_CAPABILITY_ID} is unavailable in this runtime`);
|
|
65
|
+
}
|
|
66
|
+
const result = parseCmuxOpenResult(
|
|
67
|
+
await local.requestCapability(CMUX_OPEN_CAPABILITY_ID, input),
|
|
68
|
+
);
|
|
69
|
+
return {
|
|
70
|
+
...result,
|
|
71
|
+
closed: new Promise<void>(() => {}),
|
|
72
72
|
};
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
function parseCmuxOpenResult(value: unknown): CmuxOpenResult {
|
|
75
|
+
export function parseCmuxOpenResult(value: unknown): CmuxOpenResult {
|
|
76
76
|
if (!isRecord(value)) throw new Error(`cmux.open returned a non-object result`);
|
|
77
77
|
const sessionId = stringField(value, "sessionId");
|
|
78
78
|
if (!sessionId) throw new Error(`cmux.open result is missing sessionId`);
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const RIGKIT_PROVIDER_CMUX_VERSION = "0.2.
|
|
1
|
+
export const RIGKIT_PROVIDER_CMUX_VERSION = "0.2.3";
|