Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,16 @@ rli secret update <name> # Update a secret value (value from std
rli secret delete <name> # Delete a secret
```

### Gateway-config Commands (alias: `gwc`)

```bash
rli gateway-config list # List gateway configurations
rli gateway-config create # Create a new gateway configuration
rli gateway-config get <id> # Get gateway configuration details
rli gateway-config update <id> # Update a gateway configuration
rli gateway-config delete <id> # Delete a gateway configuration
```

### Mcp Commands

```bash
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.19.1",
"@runloop/api-client": "1.3.1",
"@runloop/api-client": "1.6.0",
"@types/express": "^5.0.3",
"chalk": "^5.3.0",
"commander": "^14.0.1",
Expand Down
10 changes: 5 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

45 changes: 45 additions & 0 deletions src/commands/devbox/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ interface CreateOptions {
root?: boolean;
user?: string;
networkPolicy?: string;
gateways?: string[];
output?: string;
}

Expand Down Expand Up @@ -71,6 +72,45 @@ function parseCodeMounts(codeMounts: string[]): unknown[] {
});
}

// Parse gateways from ENV_PREFIX=gateway,secret format
function parseGateways(
gateways: string[],
): Record<string, { gateway: string; secret: string }> {
const result: Record<string, { gateway: string; secret: string }> = {};
for (const gateway of gateways) {
const eqIndex = gateway.indexOf("=");
if (eqIndex === -1) {
throw new Error(
`Invalid gateway format: ${gateway}. Expected ENV_PREFIX=gateway_id_or_name,secret_id_or_name`,
);
}
const envPrefix = gateway.substring(0, eqIndex);
const valueStr = gateway.substring(eqIndex + 1);

// Split by comma to get gateway and secret
const commaIndex = valueStr.indexOf(",");
if (commaIndex === -1) {
throw new Error(
`Invalid gateway format: ${gateway}. Expected ENV_PREFIX=gateway_id_or_name,secret_id_or_name`,
);
}
const gatewayIdOrName = valueStr.substring(0, commaIndex);
const secretIdOrName = valueStr.substring(commaIndex + 1);

if (!envPrefix || !gatewayIdOrName || !secretIdOrName) {
throw new Error(
`Invalid gateway format: ${gateway}. Expected ENV_PREFIX=gateway_id_or_name,secret_id_or_name`,
);
}

result[envPrefix] = {
gateway: gatewayIdOrName,
secret: secretIdOrName,
};
}
return result;
}

export async function createDevbox(options: CreateOptions = {}) {
try {
const client = getClient();
Expand Down Expand Up @@ -173,6 +213,11 @@ export async function createDevbox(options: CreateOptions = {}) {
createRequest.secrets = parseSecrets(options.secrets);
}

// Handle gateways
if (options.gateways && options.gateways.length > 0) {
createRequest.gateways = parseGateways(options.gateways);
}

if (Object.keys(launchParameters).length > 0) {
createRequest.launch_parameters = launchParameters;
}
Expand Down
58 changes: 58 additions & 0 deletions src/commands/gateway-config/create.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/**
* Create gateway config command
*/

import { getClient } from "../../utils/client.js";
import { output, outputError } from "../../utils/output.js";

interface CreateOptions {
name: string;
endpoint: string;
authType: string;
authKey?: string;
description?: string;
output?: string;
}

export async function createGatewayConfig(options: CreateOptions) {
try {
const client = getClient();

// Validate auth type
const authType = options.authType.toLowerCase();
if (authType !== "bearer" && authType !== "header") {
outputError("Invalid auth type. Must be 'bearer' or 'header'");
return;
}

// Validate auth key is provided for header type
if (authType === "header" && !options.authKey) {
outputError("--auth-key is required when auth-type is 'header'");
return;
}

// Build auth mechanism
const authMechanism: { type: string; key?: string } = {
type: authType,
};
if (authType === "header" && options.authKey) {
authMechanism.key = options.authKey;
}

const config = await client.gatewayConfigs.create({
name: options.name,
endpoint: options.endpoint,
auth_mechanism: authMechanism,
description: options.description,
});

// Default: just output the ID for easy scripting
if (!options.output || options.output === "text") {
console.log(config.id);
} else {
output(config, { format: options.output, defaultFormat: "json" });
}
} catch (error) {
outputError("Failed to create gateway config", error);
}
}
33 changes: 33 additions & 0 deletions src/commands/gateway-config/delete.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* Delete gateway config command
*/

import { getClient } from "../../utils/client.js";
import { output, outputError } from "../../utils/output.js";

interface DeleteOptions {
output?: string;
}

export async function deleteGatewayConfig(
id: string,
options: DeleteOptions = {},
) {
try {
const client = getClient();

await client.gatewayConfigs.delete(id);

// Default: just output the ID for easy scripting
if (!options.output || options.output === "text") {
console.log(id);
} else {
output(
{ id, status: "deleted" },
{ format: options.output, defaultFormat: "json" },
);
}
} catch (error) {
outputError("Failed to delete gateway config", error);
}
}
23 changes: 23 additions & 0 deletions src/commands/gateway-config/get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Get gateway config command
*/

import { getClient } from "../../utils/client.js";
import { output, outputError } from "../../utils/output.js";

interface GetOptions {
id: string;
output?: string;
}

export async function getGatewayConfig(options: GetOptions) {
try {
const client = getClient();

const config = await client.gatewayConfigs.retrieve(options.id);

output(config, { format: options.output, defaultFormat: "json" });
} catch (error) {
outputError("Failed to get gateway config", error);
}
}
Loading
Loading