@rulebricks/cli 1.9.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/README.md +62 -0
- package/dist/commands/clone.d.ts +6 -0
- package/dist/commands/clone.js +60 -0
- package/dist/commands/deploy.d.ts +8 -0
- package/dist/commands/deploy.js +409 -0
- package/dist/commands/destroy.d.ts +8 -0
- package/dist/commands/destroy.js +298 -0
- package/dist/commands/init.d.ts +7 -0
- package/dist/commands/init.js +201 -0
- package/dist/commands/logs.d.ts +9 -0
- package/dist/commands/logs.js +222 -0
- package/dist/commands/open.d.ts +7 -0
- package/dist/commands/open.js +139 -0
- package/dist/commands/status.d.ts +5 -0
- package/dist/commands/status.js +125 -0
- package/dist/commands/upgrade.d.ts +7 -0
- package/dist/commands/upgrade.js +239 -0
- package/dist/components/DNSWaitScreen.d.ts +9 -0
- package/dist/components/DNSWaitScreen.js +73 -0
- package/dist/components/Wizard/WizardContext.d.ts +176 -0
- package/dist/components/Wizard/WizardContext.js +346 -0
- package/dist/components/Wizard/index.d.ts +2 -0
- package/dist/components/Wizard/index.js +2 -0
- package/dist/components/Wizard/steps/CloudProviderStep.d.ts +6 -0
- package/dist/components/Wizard/steps/CloudProviderStep.js +210 -0
- package/dist/components/Wizard/steps/CredentialsStep.d.ts +6 -0
- package/dist/components/Wizard/steps/CredentialsStep.js +22 -0
- package/dist/components/Wizard/steps/DatabaseStep.d.ts +6 -0
- package/dist/components/Wizard/steps/DatabaseStep.js +80 -0
- package/dist/components/Wizard/steps/DeploymentModeStep.d.ts +5 -0
- package/dist/components/Wizard/steps/DeploymentModeStep.js +26 -0
- package/dist/components/Wizard/steps/DomainStep.d.ts +6 -0
- package/dist/components/Wizard/steps/DomainStep.js +126 -0
- package/dist/components/Wizard/steps/FeatureConfigStep.d.ts +6 -0
- package/dist/components/Wizard/steps/FeatureConfigStep.js +765 -0
- package/dist/components/Wizard/steps/FeaturesStep.d.ts +6 -0
- package/dist/components/Wizard/steps/FeaturesStep.js +119 -0
- package/dist/components/Wizard/steps/ReviewStep.d.ts +6 -0
- package/dist/components/Wizard/steps/ReviewStep.js +56 -0
- package/dist/components/Wizard/steps/SMTPStep.d.ts +6 -0
- package/dist/components/Wizard/steps/SMTPStep.js +191 -0
- package/dist/components/Wizard/steps/SupabaseCredentialsStep.d.ts +6 -0
- package/dist/components/Wizard/steps/SupabaseCredentialsStep.js +76 -0
- package/dist/components/Wizard/steps/TierStep.d.ts +6 -0
- package/dist/components/Wizard/steps/TierStep.js +29 -0
- package/dist/components/Wizard/steps/VersionStep.d.ts +6 -0
- package/dist/components/Wizard/steps/VersionStep.js +113 -0
- package/dist/components/Wizard/steps/index.d.ts +12 -0
- package/dist/components/Wizard/steps/index.js +12 -0
- package/dist/components/common/AppShell.d.ts +31 -0
- package/dist/components/common/AppShell.js +31 -0
- package/dist/components/common/Box.d.ts +20 -0
- package/dist/components/common/Box.js +20 -0
- package/dist/components/common/Logo.d.ts +7 -0
- package/dist/components/common/Logo.js +22 -0
- package/dist/components/common/Spinner.d.ts +12 -0
- package/dist/components/common/Spinner.js +28 -0
- package/dist/components/common/index.d.ts +6 -0
- package/dist/components/common/index.js +5 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +202 -0
- package/dist/lib/cloudCli.d.ts +156 -0
- package/dist/lib/cloudCli.js +691 -0
- package/dist/lib/config.d.ts +91 -0
- package/dist/lib/config.js +278 -0
- package/dist/lib/dns.d.ts +41 -0
- package/dist/lib/dns.js +235 -0
- package/dist/lib/dockerHub.d.ts +57 -0
- package/dist/lib/dockerHub.js +128 -0
- package/dist/lib/helm.d.ts +53 -0
- package/dist/lib/helm.js +209 -0
- package/dist/lib/helmValues.d.ts +17 -0
- package/dist/lib/helmValues.js +693 -0
- package/dist/lib/kubernetes.d.ts +161 -0
- package/dist/lib/kubernetes.js +755 -0
- package/dist/lib/terraform.d.ts +44 -0
- package/dist/lib/terraform.js +230 -0
- package/dist/lib/theme.d.ts +81 -0
- package/dist/lib/theme.js +115 -0
- package/dist/lib/validation.d.ts +47 -0
- package/dist/lib/validation.js +164 -0
- package/dist/lib/versions.d.ts +69 -0
- package/dist/lib/versions.js +139 -0
- package/dist/types/index.d.ts +718 -0
- package/dist/types/index.js +556 -0
- package/email-templates/email_change.html +325 -0
- package/email-templates/invite.html +383 -0
- package/email-templates/password_change.html +414 -0
- package/email-templates/verify.html +396 -0
- package/package.json +78 -0
- package/terraform/aws/main.tf +327 -0
- package/terraform/azure/main.tf +326 -0
- package/terraform/gcp/main.tf +369 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { DeploymentModeStep } from './DeploymentModeStep.js';
|
|
2
|
+
export { CloudProviderStep } from './CloudProviderStep.js';
|
|
3
|
+
export { DomainStep } from './DomainStep.js';
|
|
4
|
+
export { SMTPStep } from './SMTPStep.js';
|
|
5
|
+
export { DatabaseStep } from './DatabaseStep.js';
|
|
6
|
+
export { SupabaseCredentialsStep } from './SupabaseCredentialsStep.js';
|
|
7
|
+
export { TierStep } from './TierStep.js';
|
|
8
|
+
export { FeaturesStep } from './FeaturesStep.js';
|
|
9
|
+
export { FeatureConfigStep } from './FeatureConfigStep.js';
|
|
10
|
+
export { VersionStep } from './VersionStep.js';
|
|
11
|
+
export { CredentialsStep } from './CredentialsStep.js';
|
|
12
|
+
export { ReviewStep } from './ReviewStep.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { DeploymentModeStep } from './DeploymentModeStep.js';
|
|
2
|
+
export { CloudProviderStep } from './CloudProviderStep.js';
|
|
3
|
+
export { DomainStep } from './DomainStep.js';
|
|
4
|
+
export { SMTPStep } from './SMTPStep.js';
|
|
5
|
+
export { DatabaseStep } from './DatabaseStep.js';
|
|
6
|
+
export { SupabaseCredentialsStep } from './SupabaseCredentialsStep.js';
|
|
7
|
+
export { TierStep } from './TierStep.js';
|
|
8
|
+
export { FeaturesStep } from './FeaturesStep.js';
|
|
9
|
+
export { FeatureConfigStep } from './FeatureConfigStep.js';
|
|
10
|
+
export { VersionStep } from './VersionStep.js';
|
|
11
|
+
export { CredentialsStep } from './CredentialsStep.js';
|
|
12
|
+
export { ReviewStep } from './ReviewStep.js';
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
interface AppShellProps {
|
|
3
|
+
children: ReactNode;
|
|
4
|
+
title?: string;
|
|
5
|
+
subtitle?: string;
|
|
6
|
+
width?: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* AppShell wraps the entire application content with consistent margins,
|
|
10
|
+
* padding, and a border container for a focused visual experience.
|
|
11
|
+
*/
|
|
12
|
+
export declare function AppShell({ children, title, subtitle, width, }: AppShellProps): import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
interface ScreenContainerProps {
|
|
14
|
+
children: ReactNode;
|
|
15
|
+
title: string;
|
|
16
|
+
width?: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* ScreenContainer is a simpler bordered container for individual screens/steps
|
|
20
|
+
*/
|
|
21
|
+
export declare function ScreenContainer({ children, title, width, }: ScreenContainerProps): import("react/jsx-runtime").JSX.Element;
|
|
22
|
+
interface ProgressHeaderProps {
|
|
23
|
+
currentStep: number;
|
|
24
|
+
totalSteps: number;
|
|
25
|
+
stepTitle: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Progress header showing step number and progress bar
|
|
29
|
+
*/
|
|
30
|
+
export declare function ProgressHeader({ currentStep, totalSteps, stepTitle, }: ProgressHeaderProps): import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from "ink";
|
|
3
|
+
import { useTheme } from "../../lib/theme.js";
|
|
4
|
+
/**
|
|
5
|
+
* AppShell wraps the entire application content with consistent margins,
|
|
6
|
+
* padding, and a border container for a focused visual experience.
|
|
7
|
+
*/
|
|
8
|
+
export function AppShell({ children, title, subtitle, width = 70, }) {
|
|
9
|
+
const { colors } = useTheme();
|
|
10
|
+
const horizontalBorder = "─".repeat(width - 2);
|
|
11
|
+
return (_jsxs(Box, { flexDirection: "column", paddingTop: 0, paddingLeft: 2, children: [_jsxs(Text, { color: colors.accent, children: ["\u256D", title ? `─ ${title} ` : "", "─".repeat(width - 4 - (title?.length || 0)), "\u256E"] }), subtitle && (_jsx(Box, { paddingX: 2, children: _jsx(Text, { color: colors.muted, children: subtitle }) })), _jsx(Box, { flexDirection: "column", paddingX: 2, paddingY: 1, children: children }), _jsxs(Text, { color: colors.accent, children: ["\u2570", horizontalBorder, "\u256F"] })] }));
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* ScreenContainer is a simpler bordered container for individual screens/steps
|
|
15
|
+
*/
|
|
16
|
+
export function ScreenContainer({ children, title, width = 66, }) {
|
|
17
|
+
const { colors } = useTheme();
|
|
18
|
+
const innerWidth = width - 4;
|
|
19
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsxs(Box, { children: [_jsx(Text, { color: colors.accent, children: "\u250C\u2500 " }), _jsx(Text, { bold: true, color: "white", children: title }), _jsxs(Text, { color: colors.accent, children: [" ", "─".repeat(Math.max(0, innerWidth - title.length - 2)), "\u2510"] })] }), _jsx(Box, { flexDirection: "column", children: _jsxs(Box, { children: [_jsx(Text, { color: colors.accent, children: "\u2502" }), _jsx(Box, { flexDirection: "column", paddingX: 1, width: innerWidth, children: children }), _jsx(Text, { color: colors.accent, children: "\u2502" })] }) }), _jsxs(Text, { color: colors.accent, children: ["\u2514", "─".repeat(width - 1), "\u2518"] })] }));
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Progress header showing step number and progress bar
|
|
23
|
+
*/
|
|
24
|
+
export function ProgressHeader({ currentStep, totalSteps, stepTitle, }) {
|
|
25
|
+
const { colors } = useTheme();
|
|
26
|
+
const percentage = Math.round((currentStep / totalSteps) * 100);
|
|
27
|
+
const barWidth = 30;
|
|
28
|
+
const filled = Math.round((percentage / 100) * barWidth);
|
|
29
|
+
const empty = barWidth - filled;
|
|
30
|
+
return (_jsxs(Box, { flexDirection: "column", marginBottom: 1, children: [_jsxs(Text, { color: colors.muted, children: ["Step ", currentStep, " of ", totalSteps, ":", " ", _jsx(Text, { color: "white", children: stepTitle })] }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { color: colors.accent, children: "[" }), _jsx(Text, { color: colors.success, children: "█".repeat(filled) }), _jsx(Text, { color: colors.muted, children: "░".repeat(empty) }), _jsx(Text, { color: colors.accent, children: "]" }), _jsxs(Text, { color: colors.muted, children: [" ", percentage, "%"] })] })] }));
|
|
31
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
interface BorderBoxProps {
|
|
3
|
+
title?: string;
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
width?: number;
|
|
6
|
+
borderColor?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function BorderBox({ title, children, width, borderColor, }: BorderBoxProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
interface SectionProps {
|
|
10
|
+
title: string;
|
|
11
|
+
children: React.ReactNode;
|
|
12
|
+
}
|
|
13
|
+
export declare function Section({ title, children }: SectionProps): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
interface ProgressBarProps {
|
|
15
|
+
current: number;
|
|
16
|
+
total: number;
|
|
17
|
+
width?: number;
|
|
18
|
+
}
|
|
19
|
+
export declare function ProgressBar({ current, total, width }: ProgressBarProps): import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Box as InkBox, Text } from "ink";
|
|
3
|
+
import { useTheme } from "../../lib/theme.js";
|
|
4
|
+
export function BorderBox({ title, children, width = 60, borderColor, }) {
|
|
5
|
+
const { colors } = useTheme();
|
|
6
|
+
const actualBorderColor = borderColor || colors.accent;
|
|
7
|
+
const horizontalBorder = "─".repeat(width - 1);
|
|
8
|
+
return (_jsxs(InkBox, { flexDirection: "column", children: [_jsxs(Text, { color: actualBorderColor, children: ["\u250C", title ? `─ ${title} ` : "", "─".repeat(width - 4 - (title?.length || 0)), "\u2510"] }), _jsx(InkBox, { flexDirection: "column", paddingX: 1, children: children }), _jsxs(Text, { color: actualBorderColor, children: ["\u2514", horizontalBorder, "\u2518"] })] }));
|
|
9
|
+
}
|
|
10
|
+
export function Section({ title, children }) {
|
|
11
|
+
const { colors } = useTheme();
|
|
12
|
+
return (_jsxs(InkBox, { flexDirection: "column", marginY: 1, children: [_jsx(Text, { bold: true, color: colors.accent, children: title }), _jsx(InkBox, { flexDirection: "column", marginLeft: 2, children: children })] }));
|
|
13
|
+
}
|
|
14
|
+
export function ProgressBar({ current, total, width = 30 }) {
|
|
15
|
+
const { colors } = useTheme();
|
|
16
|
+
const percentage = Math.min(100, Math.round((current / total) * 100));
|
|
17
|
+
const filled = Math.round((percentage / 100) * width);
|
|
18
|
+
const empty = width - filled;
|
|
19
|
+
return (_jsxs(InkBox, { children: [_jsx(Text, { color: colors.accent, children: "[" }), _jsx(Text, { color: colors.success, children: "█".repeat(filled) }), _jsx(Text, { color: colors.muted, children: "░".repeat(empty) }), _jsx(Text, { color: colors.accent, children: "]" }), _jsxs(Text, { children: [" ", percentage, "%"] })] }));
|
|
20
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const LOGO_LINES: string[];
|
|
2
|
+
/**
|
|
3
|
+
* Logo component that renders the ASCII art logo once using Ink's Static.
|
|
4
|
+
* Static ensures the logo is rendered exactly once and stays at the top
|
|
5
|
+
* of the output, without re-rendering when other components update.
|
|
6
|
+
*/
|
|
7
|
+
export declare function Logo(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text, Static } from "ink";
|
|
3
|
+
import { useTheme } from "../../lib/theme.js";
|
|
4
|
+
export const LOGO_LINES = [
|
|
5
|
+
" ⟋ ‾‾‾‾⟋|",
|
|
6
|
+
" ██████ |",
|
|
7
|
+
" ██████ |",
|
|
8
|
+
" ██████ ⟋ ‾‾‾‾⟋|",
|
|
9
|
+
" ⟋ ⟋ ██████ |",
|
|
10
|
+
" ██████ ██████ |",
|
|
11
|
+
" ██████ ██████⟋",
|
|
12
|
+
" ██████⟋",
|
|
13
|
+
];
|
|
14
|
+
/**
|
|
15
|
+
* Logo component that renders the ASCII art logo once using Ink's Static.
|
|
16
|
+
* Static ensures the logo is rendered exactly once and stays at the top
|
|
17
|
+
* of the output, without re-rendering when other components update.
|
|
18
|
+
*/
|
|
19
|
+
export function Logo() {
|
|
20
|
+
const { colors } = useTheme();
|
|
21
|
+
return (_jsx(Static, { items: ["logo"], children: (item) => (_jsx(Box, { flexDirection: "column", marginTop: 1, marginBottom: 2, children: LOGO_LINES.map((line, i) => (_jsx(Text, { color: colors.accent, children: line }, i))) }, item)) }));
|
|
22
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface SpinnerProps {
|
|
2
|
+
label: string;
|
|
3
|
+
color?: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function Spinner({ label, color }: SpinnerProps): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
interface StatusLineProps {
|
|
7
|
+
status: 'pending' | 'running' | 'success' | 'error' | 'skipped';
|
|
8
|
+
label: string;
|
|
9
|
+
detail?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function StatusLine({ status, label, detail }: StatusLineProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
import InkSpinner from 'ink-spinner';
|
|
4
|
+
import { useTheme } from '../../lib/theme.js';
|
|
5
|
+
export function Spinner({ label, color }) {
|
|
6
|
+
const { colors } = useTheme();
|
|
7
|
+
const spinnerColor = color || colors.accent;
|
|
8
|
+
return (_jsxs(Box, { children: [_jsx(Text, { color: spinnerColor, children: _jsx(InkSpinner, { type: "dots" }) }), _jsxs(Text, { children: [" ", label] })] }));
|
|
9
|
+
}
|
|
10
|
+
export function StatusLine({ status, label, detail }) {
|
|
11
|
+
const { colors } = useTheme();
|
|
12
|
+
const getStatusConfig = () => {
|
|
13
|
+
switch (status) {
|
|
14
|
+
case 'pending':
|
|
15
|
+
return { icon: '○', color: colors.muted };
|
|
16
|
+
case 'running':
|
|
17
|
+
return { icon: '◐', color: colors.accent };
|
|
18
|
+
case 'success':
|
|
19
|
+
return { icon: '✓', color: colors.success };
|
|
20
|
+
case 'error':
|
|
21
|
+
return { icon: '✗', color: colors.error };
|
|
22
|
+
case 'skipped':
|
|
23
|
+
return { icon: '⊘', color: colors.warning };
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const { icon, color } = getStatusConfig();
|
|
27
|
+
return (_jsxs(Box, { children: [_jsx(Text, { color: color, children: icon }), _jsxs(Text, { children: [" ", label] }), detail && _jsxs(Text, { color: colors.muted, children: [" - ", detail] })] }));
|
|
28
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { BorderBox, Section, ProgressBar } from "./Box.js";
|
|
2
|
+
export { Spinner, StatusLine } from "./Spinner.js";
|
|
3
|
+
export { AppShell, ScreenContainer, ProgressHeader } from "./AppShell.js";
|
|
4
|
+
export { Logo, LOGO_LINES } from "./Logo.js";
|
|
5
|
+
export { ThemeProvider, useTheme, THEMES } from "../../lib/theme.js";
|
|
6
|
+
export type { CommandTheme, ThemeColors } from "../../lib/theme.js";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { BorderBox, Section, ProgressBar } from "./Box.js";
|
|
2
|
+
export { Spinner, StatusLine } from "./Spinner.js";
|
|
3
|
+
export { AppShell, ScreenContainer, ProgressHeader } from "./AppShell.js";
|
|
4
|
+
export { Logo, LOGO_LINES } from "./Logo.js";
|
|
5
|
+
export { ThemeProvider, useTheme, THEMES } from "../../lib/theme.js";
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import { render } from "ink";
|
|
5
|
+
import chalk from "chalk";
|
|
6
|
+
import { InitWizard } from "./commands/init.js";
|
|
7
|
+
import { DeployCommand } from "./commands/deploy.js";
|
|
8
|
+
import { UpgradeCommand } from "./commands/upgrade.js";
|
|
9
|
+
import { DestroyCommand } from "./commands/destroy.js";
|
|
10
|
+
import { StatusCommand } from "./commands/status.js";
|
|
11
|
+
import { LogsCommand } from "./commands/logs.js";
|
|
12
|
+
import { CloneCommand } from "./commands/clone.js";
|
|
13
|
+
import { OpenCommand } from "./commands/open.js";
|
|
14
|
+
import { listDeployments, deploymentExists } from "./lib/config.js";
|
|
15
|
+
const VERSION = "2.0.0";
|
|
16
|
+
const program = new Command();
|
|
17
|
+
program
|
|
18
|
+
.name("rulebricks")
|
|
19
|
+
.description("CLI for deploying and managing private Rulebricks instances")
|
|
20
|
+
.version(VERSION)
|
|
21
|
+
.hook("preAction", () => {
|
|
22
|
+
// Clear terminal for a fresh start
|
|
23
|
+
// Logo is now rendered via Ink's Static component in each command
|
|
24
|
+
console.clear();
|
|
25
|
+
});
|
|
26
|
+
// Init command - interactive configuration wizard
|
|
27
|
+
program
|
|
28
|
+
.command("init")
|
|
29
|
+
.description("Initialize a new Rulebricks deployment configuration")
|
|
30
|
+
.argument("[name]", "Deployment name")
|
|
31
|
+
.option("-n, --name <name>", "Deployment name (alternative to positional argument)")
|
|
32
|
+
.action(async (name, options) => {
|
|
33
|
+
const deploymentName = name || options.name;
|
|
34
|
+
const { waitUntilExit } = render(_jsx(InitWizard, { initialName: deploymentName }));
|
|
35
|
+
await waitUntilExit();
|
|
36
|
+
});
|
|
37
|
+
// Deploy command
|
|
38
|
+
program
|
|
39
|
+
.command("deploy")
|
|
40
|
+
.description("Deploy Rulebricks to your cluster")
|
|
41
|
+
.argument("[name]", "Deployment name")
|
|
42
|
+
.option("--skip-infra", "Skip infrastructure provisioning")
|
|
43
|
+
.option("--version <version>", "Specific chart version to deploy")
|
|
44
|
+
.action(async (name, options) => {
|
|
45
|
+
const deploymentName = name || (await selectDeployment());
|
|
46
|
+
if (!deploymentName) {
|
|
47
|
+
console.error(chalk.red('No deployment specified. Run "rulebricks init" first.'));
|
|
48
|
+
process.exit(1);
|
|
49
|
+
}
|
|
50
|
+
const { waitUntilExit } = render(_jsx(DeployCommand, { name: deploymentName, skipInfra: options.skipInfra, version: options.version }));
|
|
51
|
+
await waitUntilExit();
|
|
52
|
+
});
|
|
53
|
+
// Upgrade command
|
|
54
|
+
program
|
|
55
|
+
.command("upgrade")
|
|
56
|
+
.description("Upgrade Rulebricks to a new version")
|
|
57
|
+
.argument("[name]", "Deployment name")
|
|
58
|
+
.option("--version <version>", "Target version (defaults to latest)")
|
|
59
|
+
.option("--dry-run", "Preview changes without applying")
|
|
60
|
+
.action(async (name, options) => {
|
|
61
|
+
const deploymentName = name || (await selectDeployment());
|
|
62
|
+
if (!deploymentName) {
|
|
63
|
+
console.error(chalk.red("No deployment specified."));
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
const { waitUntilExit } = render(_jsx(UpgradeCommand, { name: deploymentName, targetVersion: options.version, dryRun: options.dryRun }));
|
|
67
|
+
await waitUntilExit();
|
|
68
|
+
});
|
|
69
|
+
// Destroy command
|
|
70
|
+
program
|
|
71
|
+
.command("destroy")
|
|
72
|
+
.description("Destroy a Rulebricks deployment")
|
|
73
|
+
.argument("[name]", "Deployment name")
|
|
74
|
+
.option("--cluster", "Also destroy cloud infrastructure (EKS/GKE/AKS cluster)")
|
|
75
|
+
.option("--config", "Also delete local configuration files")
|
|
76
|
+
.option("-f, --force", "Skip confirmation")
|
|
77
|
+
.action(async (name, options) => {
|
|
78
|
+
// For destroy, require explicit deployment name
|
|
79
|
+
if (!name) {
|
|
80
|
+
const deployments = await listDeployments();
|
|
81
|
+
if (deployments.length === 0) {
|
|
82
|
+
console.error(chalk.red('No deployments found. Run "rulebricks init" first.'));
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
console.error(chalk.red("Please specify a deployment to destroy.\n"));
|
|
86
|
+
console.log("Available deployments:");
|
|
87
|
+
for (const d of deployments) {
|
|
88
|
+
console.log(` ${chalk.yellow("•")} ${d}`);
|
|
89
|
+
}
|
|
90
|
+
console.log(`\nUsage: ${chalk.cyan("rulebricks destroy <name>")}`);
|
|
91
|
+
}
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
const { waitUntilExit } = render(_jsx(DestroyCommand, { name: name, cluster: options.cluster, config: options.config, force: options.force }));
|
|
95
|
+
await waitUntilExit();
|
|
96
|
+
});
|
|
97
|
+
// Status command
|
|
98
|
+
program
|
|
99
|
+
.command("status")
|
|
100
|
+
.description("Show deployment status")
|
|
101
|
+
.argument("[name]", "Deployment name")
|
|
102
|
+
.action(async (name) => {
|
|
103
|
+
const deploymentName = name || (await selectDeployment());
|
|
104
|
+
if (!deploymentName) {
|
|
105
|
+
console.error(chalk.red("No deployment specified."));
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
108
|
+
const { waitUntilExit } = render(_jsx(StatusCommand, { name: deploymentName }));
|
|
109
|
+
await waitUntilExit();
|
|
110
|
+
});
|
|
111
|
+
// Logs command
|
|
112
|
+
program
|
|
113
|
+
.command("logs")
|
|
114
|
+
.description("View component logs")
|
|
115
|
+
.argument("[name]", "Deployment name")
|
|
116
|
+
.argument("[component]", "Component: app, hps, workers, kafka, supabase, traefik")
|
|
117
|
+
.option("-f, --follow", "Follow log output (default: true)")
|
|
118
|
+
.option("--no-follow", "Show logs once without following")
|
|
119
|
+
.option("-t, --tail <lines>", "Number of lines to show", "100")
|
|
120
|
+
.option("-s, --split", "Show logs in split-pane view (side-by-side columns)")
|
|
121
|
+
.action(async (name, component, options) => {
|
|
122
|
+
const deploymentName = name || (await selectDeployment());
|
|
123
|
+
if (!deploymentName) {
|
|
124
|
+
console.error(chalk.red("No deployment specified."));
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
const { waitUntilExit } = render(_jsx(LogsCommand, { name: deploymentName, component: component, follow: options.follow, tail: parseInt(options.tail, 10), split: options.split }));
|
|
128
|
+
await waitUntilExit();
|
|
129
|
+
});
|
|
130
|
+
// List command
|
|
131
|
+
program
|
|
132
|
+
.command("list")
|
|
133
|
+
.description("List all deployments")
|
|
134
|
+
.action(async () => {
|
|
135
|
+
const deployments = await listDeployments();
|
|
136
|
+
const listColor = chalk.green; // Use status theme color (green)
|
|
137
|
+
if (deployments.length === 0) {
|
|
138
|
+
console.log(chalk.yellow('No deployments found. Run "rulebricks init" to create one.'));
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
console.log(chalk.bold("\nDeployments:\n"));
|
|
142
|
+
for (const name of deployments) {
|
|
143
|
+
console.log(` ${listColor("•")} ${name}`);
|
|
144
|
+
}
|
|
145
|
+
console.log("");
|
|
146
|
+
});
|
|
147
|
+
// Clone command
|
|
148
|
+
program
|
|
149
|
+
.command("clone")
|
|
150
|
+
.description("Clone an existing deployment configuration")
|
|
151
|
+
.argument("<source>", "Source deployment name")
|
|
152
|
+
.argument("<target>", "New deployment name")
|
|
153
|
+
.action(async (source, target) => {
|
|
154
|
+
const { waitUntilExit } = render(_jsx(CloneCommand, { source: source, target: target }));
|
|
155
|
+
await waitUntilExit();
|
|
156
|
+
});
|
|
157
|
+
// Open command
|
|
158
|
+
program
|
|
159
|
+
.command("open")
|
|
160
|
+
.description("Open deployment files in your editor")
|
|
161
|
+
.argument("<name>", "Deployment name")
|
|
162
|
+
.option("--config", "Open config.yaml only")
|
|
163
|
+
.option("--values", "Open values.yaml only")
|
|
164
|
+
.option("--terraform", "Open terraform directory only")
|
|
165
|
+
.action(async (name, options) => {
|
|
166
|
+
// Validate deployment exists before rendering
|
|
167
|
+
const exists = await deploymentExists(name);
|
|
168
|
+
if (!exists) {
|
|
169
|
+
console.error(chalk.red(`Deployment "${name}" not found.`));
|
|
170
|
+
const deployments = await listDeployments();
|
|
171
|
+
if (deployments.length > 0) {
|
|
172
|
+
console.log("\nAvailable deployments:");
|
|
173
|
+
for (const d of deployments) {
|
|
174
|
+
console.log(` ${chalk.yellow("•")} ${d}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
process.exit(1);
|
|
178
|
+
}
|
|
179
|
+
const target = options.config
|
|
180
|
+
? "config"
|
|
181
|
+
: options.values
|
|
182
|
+
? "values"
|
|
183
|
+
: options.terraform
|
|
184
|
+
? "terraform"
|
|
185
|
+
: "all";
|
|
186
|
+
const { waitUntilExit } = render(_jsx(OpenCommand, { name: name, target: target }));
|
|
187
|
+
await waitUntilExit();
|
|
188
|
+
});
|
|
189
|
+
// Helper to select a deployment interactively
|
|
190
|
+
async function selectDeployment() {
|
|
191
|
+
const deployments = await listDeployments();
|
|
192
|
+
if (deployments.length === 0) {
|
|
193
|
+
return null;
|
|
194
|
+
}
|
|
195
|
+
if (deployments.length === 1) {
|
|
196
|
+
return deployments[0];
|
|
197
|
+
}
|
|
198
|
+
// For now, return the first one. In a full implementation,
|
|
199
|
+
// we'd render an interactive selector
|
|
200
|
+
return deployments[0];
|
|
201
|
+
}
|
|
202
|
+
program.parse();
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloud CLI detection and dynamic resource listing
|
|
3
|
+
*
|
|
4
|
+
* Detects installed cloud CLIs (AWS, GCP, Azure), checks authentication status,
|
|
5
|
+
* and provides functions to list regions and buckets dynamically.
|
|
6
|
+
*/
|
|
7
|
+
import { CloudProvider } from "../types/index.js";
|
|
8
|
+
/**
|
|
9
|
+
* Status of a cloud provider CLI
|
|
10
|
+
*/
|
|
11
|
+
export interface CloudCliStatus {
|
|
12
|
+
provider: CloudProvider;
|
|
13
|
+
installed: boolean;
|
|
14
|
+
authenticated: boolean;
|
|
15
|
+
version?: string;
|
|
16
|
+
identity?: string;
|
|
17
|
+
error?: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* All cloud CLI statuses
|
|
21
|
+
*/
|
|
22
|
+
export interface AllCloudCliStatus {
|
|
23
|
+
aws: CloudCliStatus;
|
|
24
|
+
gcp: CloudCliStatus;
|
|
25
|
+
azure: CloudCliStatus;
|
|
26
|
+
anyAvailable: boolean;
|
|
27
|
+
anyInstalled: boolean;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Check if AWS CLI is installed and authenticated
|
|
31
|
+
*/
|
|
32
|
+
export declare function checkAwsCli(): Promise<CloudCliStatus>;
|
|
33
|
+
/**
|
|
34
|
+
* List available AWS regions
|
|
35
|
+
*/
|
|
36
|
+
export declare function listAwsRegions(): Promise<string[]>;
|
|
37
|
+
/**
|
|
38
|
+
* List S3 buckets
|
|
39
|
+
*/
|
|
40
|
+
export declare function listS3Buckets(): Promise<string[]>;
|
|
41
|
+
/**
|
|
42
|
+
* List EKS clusters in a specific region
|
|
43
|
+
*/
|
|
44
|
+
export declare function listEksClusters(region: string): Promise<string[]>;
|
|
45
|
+
/**
|
|
46
|
+
* Check if gcloud CLI is installed and authenticated
|
|
47
|
+
*/
|
|
48
|
+
export declare function checkGcloudCli(): Promise<CloudCliStatus>;
|
|
49
|
+
/**
|
|
50
|
+
* Get the active GCP project ID
|
|
51
|
+
*/
|
|
52
|
+
export declare function getGcpProjectId(): Promise<string | null>;
|
|
53
|
+
/**
|
|
54
|
+
* List available GCP regions
|
|
55
|
+
*/
|
|
56
|
+
export declare function listGcpRegions(): Promise<string[]>;
|
|
57
|
+
/**
|
|
58
|
+
* List GCS buckets
|
|
59
|
+
*/
|
|
60
|
+
export declare function listGcsBuckets(): Promise<string[]>;
|
|
61
|
+
/**
|
|
62
|
+
* List GKE clusters in a specific region
|
|
63
|
+
* Note: GKE supports both regional and zonal clusters. We search for regional clusters.
|
|
64
|
+
*/
|
|
65
|
+
export declare function listGkeClusters(region: string): Promise<string[]>;
|
|
66
|
+
/**
|
|
67
|
+
* Check if Azure CLI is installed and authenticated
|
|
68
|
+
*/
|
|
69
|
+
export declare function checkAzureCli(): Promise<CloudCliStatus>;
|
|
70
|
+
/**
|
|
71
|
+
* Get the active Azure subscription ID
|
|
72
|
+
*/
|
|
73
|
+
export declare function getAzureSubscriptionId(): Promise<string | null>;
|
|
74
|
+
/**
|
|
75
|
+
* List available Azure regions (locations)
|
|
76
|
+
*/
|
|
77
|
+
export declare function listAzureRegions(): Promise<string[]>;
|
|
78
|
+
/**
|
|
79
|
+
* List Azure storage accounts (containers require a storage account)
|
|
80
|
+
*/
|
|
81
|
+
export declare function listAzureStorageAccounts(): Promise<string[]>;
|
|
82
|
+
/**
|
|
83
|
+
* List Azure blob containers in a storage account
|
|
84
|
+
*/
|
|
85
|
+
export declare function listAzureBlobContainers(storageAccount: string): Promise<string[]>;
|
|
86
|
+
/**
|
|
87
|
+
* List AKS clusters, optionally filtered by resource group
|
|
88
|
+
*/
|
|
89
|
+
export declare function listAksClusters(resourceGroup?: string): Promise<string[]>;
|
|
90
|
+
/**
|
|
91
|
+
* Check all cloud CLIs in parallel
|
|
92
|
+
*/
|
|
93
|
+
export declare function checkAllCloudClis(): Promise<AllCloudCliStatus>;
|
|
94
|
+
/**
|
|
95
|
+
* List regions for a specific provider
|
|
96
|
+
*/
|
|
97
|
+
export declare function listRegions(provider: CloudProvider): Promise<string[]>;
|
|
98
|
+
/**
|
|
99
|
+
* List buckets/storage for a specific provider
|
|
100
|
+
*/
|
|
101
|
+
export declare function listBuckets(provider: CloudProvider): Promise<string[]>;
|
|
102
|
+
/**
|
|
103
|
+
* List Kubernetes clusters for a specific provider
|
|
104
|
+
*/
|
|
105
|
+
export declare function listClusters(provider: CloudProvider, region: string, options?: {
|
|
106
|
+
azureResourceGroup?: string;
|
|
107
|
+
}): Promise<string[]>;
|
|
108
|
+
/**
|
|
109
|
+
* Get installation URLs for cloud CLIs
|
|
110
|
+
*/
|
|
111
|
+
export declare const CLI_INSTALL_URLS: Record<CloudProvider, {
|
|
112
|
+
name: string;
|
|
113
|
+
url: string;
|
|
114
|
+
installCmd?: string;
|
|
115
|
+
}>;
|
|
116
|
+
/**
|
|
117
|
+
* Get login commands for cloud CLIs
|
|
118
|
+
*/
|
|
119
|
+
export declare const CLI_LOGIN_COMMANDS: Record<CloudProvider, string>;
|
|
120
|
+
/**
|
|
121
|
+
* Terraform installation status
|
|
122
|
+
*/
|
|
123
|
+
export interface TerraformStatus {
|
|
124
|
+
installed: boolean;
|
|
125
|
+
version?: string;
|
|
126
|
+
error?: string;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Check if Terraform is installed
|
|
130
|
+
*/
|
|
131
|
+
export declare function checkTerraform(): Promise<TerraformStatus>;
|
|
132
|
+
/**
|
|
133
|
+
* Terraform installation info
|
|
134
|
+
*/
|
|
135
|
+
export declare const TERRAFORM_INSTALL_INFO: {
|
|
136
|
+
name: string;
|
|
137
|
+
url: string;
|
|
138
|
+
installCmd: string;
|
|
139
|
+
};
|
|
140
|
+
/**
|
|
141
|
+
* List S3 buckets in a specific region
|
|
142
|
+
* Note: S3 buckets are global, but we filter by region
|
|
143
|
+
*/
|
|
144
|
+
export declare function listS3BucketsInRegion(region: string): Promise<string[]>;
|
|
145
|
+
/**
|
|
146
|
+
* List GCS buckets in a specific region
|
|
147
|
+
*/
|
|
148
|
+
export declare function listGcsBucketsInRegion(region: string): Promise<string[]>;
|
|
149
|
+
/**
|
|
150
|
+
* List Azure storage accounts in a specific region
|
|
151
|
+
*/
|
|
152
|
+
export declare function listAzureStorageAccountsInRegion(region: string): Promise<string[]>;
|
|
153
|
+
/**
|
|
154
|
+
* List buckets/storage for a specific provider in a specific region
|
|
155
|
+
*/
|
|
156
|
+
export declare function listBucketsInRegion(provider: CloudProvider, region: string): Promise<string[]>;
|