@vizamodo/viza-cli 1.3.6 → 1.3.30

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/dist/bin/viza.js CHANGED
@@ -1,35 +1,59 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from "commander";
3
+ import { fileURLToPath } from "node:url";
4
+ import path from "node:path";
5
+ import fs from "node:fs";
3
6
  import { handleError } from "../src/errors/handleError.js";
4
7
  import { bootstrapCommand } from "../src/commands/bootstrap/index.js";
5
- import { devCommand } from "../src/commands/dev/index.js";
6
- import fs from "node:fs";
7
- import path from "node:path";
8
- import { fileURLToPath } from "node:url";
8
+ import { loginAwsCommand } from "../src/commands/login/aws.js";
9
9
  const __filename = fileURLToPath(import.meta.url);
10
10
  const __dirname = path.dirname(__filename);
11
+ /**
12
+ * Helper: Gộp tất cả options từ root xuống sub-command
13
+ */
14
+ function getResolvedOptions(command) {
15
+ let allOptions = {};
16
+ let current = command;
17
+ while (current) {
18
+ allOptions = { ...current.opts(), ...allOptions };
19
+ current = current.parent;
20
+ }
21
+ return allOptions;
22
+ }
11
23
  function readCliVersion() {
12
24
  try {
13
25
  const pkgPath = path.resolve(__dirname, "../package.json");
14
- const raw = fs.readFileSync(pkgPath, "utf8");
15
- const json = JSON.parse(raw);
16
- return typeof json.version === "string" && json.version.trim() ? json.version.trim() : "dev";
26
+ const json = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
27
+ return json.version || "dev";
17
28
  }
18
29
  catch {
19
30
  return "dev";
20
31
  }
21
32
  }
22
- const CLI_VERSION = readCliVersion();
23
33
  const program = new Command();
24
34
  program
25
35
  .name("viza")
26
36
  .description("Viza CLI")
27
- .version(CLI_VERSION);
28
- program.addCommand(devCommand());
37
+ .version(readCliVersion())
38
+ // Global Options
39
+ .option("--status", "Show status only (no execution)")
40
+ .option("--runner-label <label>", "Runner label", "native");
29
41
  program
30
42
  .command("bootstrap")
31
- .description("Bootstrap Viza configuration")
32
- .action(async () => {
43
+ .description("Bootstrap configuration")
44
+ .action(async (_options) => {
33
45
  await bootstrapCommand();
34
46
  });
47
+ program
48
+ .command("login")
49
+ .description("Login to cloud providers")
50
+ .command("aws")
51
+ .description("Login to AWS")
52
+ .option("--prod", "Use production environment")
53
+ .option("--dev", "Use development environment")
54
+ .option("--keep-log", "Keep execution logs", false)
55
+ .action(async (_options, command) => {
56
+ const fullOpts = getResolvedOptions(command);
57
+ await loginAwsCommand(fullOpts);
58
+ });
35
59
  program.parseAsync(process.argv).catch(handleError);
@@ -0,0 +1,56 @@
1
+ import { resolveEnv } from "../../context/env.js";
2
+ import { resolveHubIntent } from "../../context/hubIntent.js";
3
+ import { dispatchIntentAndWait } from "../../core/dispatch.js";
4
+ /**
5
+ * Target teams for `viza login aws`.
6
+ * This is a CLI-only UX constraint for fail-fast validation.
7
+ * NOT a policy and MUST NOT be sent to gateway.
8
+ */
9
+ const TARGET_TEAMS = {
10
+ dev: [
11
+ "viza-deployer",
12
+ "viza-billing",
13
+ "viza-manager",
14
+ "viza-admin",
15
+ "viza-super",
16
+ ],
17
+ prod: [
18
+ "viza-publisher",
19
+ "viza-billing",
20
+ "viza-admin",
21
+ "viza-super",
22
+ ],
23
+ };
24
+ /**
25
+ * viza login aws
26
+ *
27
+ * Flow:
28
+ * 1) Resolve env (deterministic)
29
+ * 2) Resolve user identity (trusted via gh auth)
30
+ * 3) CLI pre-check against target teams (fail-fast UX)
31
+ * 4) Derive ONE valid team (deterministic)
32
+ * 5) Dispatch frozen intent to gateway
33
+ */
34
+ export async function loginAwsCommand(options) {
35
+ // 1) Resolve environment
36
+ const env = resolveEnv(options);
37
+ const intent = resolveHubIntent(env);
38
+ // 5) Dispatch intent (freeze)
39
+ await dispatchIntentAndWait({
40
+ intent,
41
+ commandType: "viza.aws.login",
42
+ infraKey: "aws",
43
+ env,
44
+ targetTeams: TARGET_TEAMS[env],
45
+ runnerLabel: options.runnerLabel,
46
+ keepLog: options.keepLog === true,
47
+ flowGates: {
48
+ secrets: false,
49
+ encVars: false,
50
+ },
51
+ payload: {}
52
+ }, {
53
+ mode: options.status ? "status" : "dispatch",
54
+ log: "show",
55
+ });
56
+ }
@@ -0,0 +1,13 @@
1
+ export function resolveEnv(flags) {
2
+ // Fail fast on conflicting deterministic flags
3
+ if (flags.prod && flags.dev) {
4
+ throw new Error("Conflicting flags: --prod and --dev cannot be used together");
5
+ }
6
+ // Deterministic environment resolution
7
+ if (flags.prod)
8
+ return "prod";
9
+ if (flags.dev)
10
+ return "dev";
11
+ // Default fallback
12
+ return "dev";
13
+ }
@@ -0,0 +1,8 @@
1
+ // src/commands/_shared/hubIntent.ts
2
+ export const HUB_INTENT_BY_ENV = {
3
+ dev: "hub-dev",
4
+ prod: "hub",
5
+ };
6
+ export function resolveHubIntent(env) {
7
+ return HUB_INTENT_BY_ENV[env];
8
+ }
@@ -25,11 +25,13 @@ async function dispatchIntent(input, mode = "dispatch") {
25
25
  infraKey: input.infraKey,
26
26
  payload: input.payload,
27
27
  runnerLabel: input.runnerLabel,
28
- keepLog: input.keepLog
28
+ keepLog: input.keepLog,
29
+ flowGates: input.flowGates,
29
30
  };
30
31
  const handle = await dispatcherDispatch(dispatchInput, {
31
32
  auth: {
32
- targetTeam: input.targetTeam,
33
+ env: input.env,
34
+ targetTeams: input.targetTeams,
33
35
  },
34
36
  }, mode);
35
37
  return handle;
@@ -1,38 +1,16 @@
1
1
  import chalk from "chalk";
2
2
  import figlet from "figlet";
3
- const TEAM_BANNER_CONFIG = {
4
- "viza-deployer": { title: "Viza Deployer", color: "cyanBright", env: "dev" },
5
- "viza-designer": { title: "Viza Designer", color: "greenBright", env: "dev" },
6
- "viza-billing": { title: "Viza Billing", color: "yellowBright", env: "dev" },
7
- "viza-publisher": { title: "Viza Publisher", color: "redBright", env: "prod" },
8
- "viza-manager": { title: "Viza Manager", color: "cyanBright", env: "dev" },
9
- "viza-admin": { title: "Viza Administrator", color: "yellowBright", env: "sys" },
10
- "viza-super": { title: "Viza Supervisor", color: "redBright", env: "sys" },
3
+ const ENV_BANNER_CONFIG = {
4
+ "dev": { title: "Viza Development", color: "cyanBright" },
5
+ "prod": { title: "Viza Production", color: "yellowBright" },
11
6
  };
12
- function formatEnvLabelForTeam(team) {
13
- // Keep env values constrained to BannerOptions, while giving a clear mapping.
14
- // dev: Development/Designer/Billing/Manager
15
- // prod: Production
16
- // sys: System/Root
17
- if (team === "viza-publisher")
18
- return "prod";
19
- if (team === "viza-admin" || team === "viza-super")
20
- return "sys";
21
- return "dev";
22
- }
23
- function pickBannerConfig(targetTeam) {
24
- const cfg = TEAM_BANNER_CONFIG[targetTeam];
7
+ function pickBannerConfig(env) {
8
+ const cfg = ENV_BANNER_CONFIG[env];
25
9
  if (cfg)
26
10
  return cfg;
27
- // Default: derive something reasonable and safe.
28
- const prettyTitle = targetTeam
29
- .split("-")
30
- .map((x) => (x ? x[0].toUpperCase() + x.slice(1) : x))
31
- .join(" ");
32
11
  return {
33
- title: prettyTitle || "Viza",
34
- color: "cyanBright",
35
- env: formatEnvLabelForTeam(targetTeam) ?? "dev",
12
+ title: `Viza Environment: ${env}` || "unknown",
13
+ color: "cyanBright"
36
14
  };
37
15
  }
38
16
  /**
@@ -40,14 +18,13 @@ function pickBannerConfig(targetTeam) {
40
18
  * Maps targetTeam -> title/color/env, and renders meta (github login + viza-cli version).
41
19
  */
42
20
  export function showDispatchBanner(input, meta) {
43
- const cfg = pickBannerConfig(input.targetTeam);
21
+ const cfg = pickBannerConfig(input.env);
44
22
  // Default subtitle: commandType (or caller-provided subtitle)
45
23
  const subtitle = `Command: ${input.commandType}`;
46
24
  showBanner({
47
25
  title: cfg.title,
48
26
  subtitle,
49
27
  color: cfg.color,
50
- env: cfg.env,
51
28
  runner: input.runnerLabel === "native"
52
29
  ? { type: "github" }
53
30
  : {
@@ -60,20 +37,20 @@ export function showDispatchBanner(input, meta) {
60
37
  });
61
38
  }
62
39
  export function showBanner(opts) {
63
- const { title, subtitle, color = "cyanBright", env, runner, meta } = opts;
40
+ const { title, subtitle, color = "cyanBright", runner, meta } = opts;
64
41
  process.stdout.write("\u001b[2J\u001b[3J\u001b[H");
65
42
  const bannerText = figlet.textSync(title, { font: "Standard" });
66
43
  console.log(chalk[color](bannerText));
67
44
  if (subtitle) {
68
- console.log(chalk.gray("Command:"), chalk.magenta(subtitle));
45
+ console.log(chalk.gray("Command:"), chalk.magentaBright(subtitle));
69
46
  }
70
47
  // Environment line removed; replaced by user-friendly info line below
71
48
  if (runner) {
72
49
  if (runner.type === "github") {
73
- console.log(chalk.gray("Runner:"), chalk.yellow("GitHub-hosted"));
50
+ console.log(chalk.gray("Runner:"), chalk.yellowBright("GitHub-hosted"));
74
51
  }
75
52
  else {
76
- console.log(chalk.gray("Runner:"), chalk.yellow("self-hosted"), runner.label ? chalk.gray("| label:") : "", runner.label ? chalk.cyan(runner.label) : "");
53
+ console.log(chalk.gray("Runner:"), chalk.yellowBright("self-hosted"), runner.label ? chalk.gray("| label:") : "", runner.label ? chalk.cyan(runner.label) : "");
77
54
  }
78
55
  }
79
56
  // User-friendly info line
@@ -82,12 +59,6 @@ export function showBanner(opts) {
82
59
  if (meta?.version) {
83
60
  parts.push(`Version: ${chalk.cyan(meta.version)}`);
84
61
  }
85
- if (env) {
86
- const envColor = env === "prod" ? chalk.redBright :
87
- env === "dev" ? chalk.greenBright :
88
- chalk.yellowBright;
89
- parts.push(`Environment: ${envColor(env.toUpperCase())}`);
90
- }
91
62
  if (parts.length) {
92
63
  console.log(chalk.gray(parts.join(chalk.gray(" | "))));
93
64
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vizamodo/viza-cli",
3
- "version": "1.3.6",
3
+ "version": "1.3.30",
4
4
  "type": "module",
5
5
  "description": "Viza unified command line interface",
6
6
  "bin": {
@@ -16,16 +16,16 @@
16
16
  "release:prod": "rm -rf dist && npx npm-check-updates -u && npm install && git add package.json package-lock.json && git commit -m 'chore(deps): auto update dependencies before release' || echo 'No changes' && node versioning.js && npm login && npm publish --tag latest --access public && git push"
17
17
  },
18
18
  "dependencies": {
19
- "@vizamodo/viza-dispatcher": "^1.4.56",
19
+ "@vizamodo/viza-dispatcher": "^1.4.61",
20
20
  "adm-zip": "^0.5.16",
21
21
  "chalk": "^5.6.2",
22
22
  "commander": "^14.0.2",
23
- "figlet": "^1.9.4"
23
+ "figlet": "^1.10.0"
24
24
  },
25
25
  "devDependencies": {
26
26
  "@types/adm-zip": "^0.5.7",
27
27
  "@types/figlet": "^1.7.0",
28
- "@types/node": "^25.0.10",
28
+ "@types/node": "^25.1.0",
29
29
  "ts-node": "^10.9.2",
30
30
  "typescript": "^5.9.3"
31
31
  }
@@ -1,5 +0,0 @@
1
- export const adminCommand = {
2
- name: "admin",
3
- description: "admin commands",
4
- children: []
5
- };
@@ -1,5 +0,0 @@
1
- export const billingCommand = {
2
- name: "billing",
3
- description: "billing commands",
4
- children: []
5
- };
@@ -1,5 +0,0 @@
1
- export const designCommand = {
2
- name: "design",
3
- description: "design commands",
4
- children: []
5
- };
@@ -1,12 +0,0 @@
1
- // src/commands/dev/index.ts
2
- import { Command } from "commander";
3
- import { devLoginCommand } from "./login/index.js";
4
- const DEV_CTX = {
5
- targetTeam: "viza-deployer",
6
- };
7
- export function devCommand(ctx = DEV_CTX) {
8
- const cmd = new Command("dev");
9
- cmd.description("Development commands");
10
- cmd.addCommand(devLoginCommand(ctx));
11
- return cmd;
12
- }
@@ -1,32 +0,0 @@
1
- // src/commands/dev/aws/index.ts
2
- import { Command } from "commander";
3
- import { awsLogin, awsCreateSsoUrl } from "../../../../platforms/aws/login.js";
4
- export function devLoginAwsCommand(ctx) {
5
- const aws = new Command("aws");
6
- aws
7
- .description("Login AWS via remote dispatcher (SSO/session bootstrap)")
8
- .option("--status", "Check status only (do not dispatch new run)")
9
- .option("--keep-log", "Keep source workflow logs for debugging")
10
- .action(async (opts) => {
11
- await awsLogin({
12
- intent: "hub-dev",
13
- targetTeam: ctx.targetTeam,
14
- mode: opts.status ? "status" : "dispatch",
15
- keepLog: opts.keepLog === true,
16
- });
17
- });
18
- aws
19
- .command("sso-url")
20
- .description("Create AWS SSO login URL via remote dispatcher")
21
- .option("--status", "Check status only (do not dispatch new run)")
22
- .option("--keep-log", "Keep source workflow logs for debugging")
23
- .action(async (opts) => {
24
- await awsCreateSsoUrl({
25
- intent: "hub-dev",
26
- targetTeam: ctx.targetTeam,
27
- mode: opts.status ? "status" : "dispatch",
28
- keepLog: opts.keepLog === true,
29
- });
30
- });
31
- return aws;
32
- }
@@ -1,8 +0,0 @@
1
- import { Command } from "commander";
2
- import { devLoginAwsCommand } from "./aws/index.js";
3
- export function devLoginCommand(ctx) {
4
- const cmd = new Command("login");
5
- cmd.description("Login commands");
6
- cmd.addCommand(devLoginAwsCommand(ctx));
7
- return cmd;
8
- }
@@ -1,5 +0,0 @@
1
- export const manageCommand = {
2
- name: "manage",
3
- description: "manage commands",
4
- children: []
5
- };
@@ -1,5 +0,0 @@
1
- export const prodCommand = {
2
- name: "prod",
3
- description: "production commands",
4
- children: []
5
- };
@@ -1,5 +0,0 @@
1
- export const superCommand = {
2
- name: "super",
3
- description: "super commands",
4
- children: []
5
- };
@@ -1 +0,0 @@
1
- export {};
@@ -1,33 +0,0 @@
1
- // src/platforms/aws/login.ts
2
- import { dispatchIntentAndWait } from "../../core/dispatch.js";
3
- export async function awsLogin(ctx) {
4
- const plainPayload = {
5
- action: "login",
6
- provider: "aws",
7
- type: "sso",
8
- };
9
- await dispatchIntentAndWait({
10
- intent: ctx.intent,
11
- infraKey: "aws",
12
- commandType: "viza.aws.login",
13
- targetTeam: ctx.targetTeam,
14
- runnerLabel: "native",
15
- keepLog: ctx.keepLog === true,
16
- payload: plainPayload,
17
- }, { log: "show", mode: ctx.mode ?? "dispatch" });
18
- }
19
- export async function awsCreateSsoUrl(ctx) {
20
- const plainPayload = {
21
- action: "sso-url",
22
- provider: "aws",
23
- };
24
- await dispatchIntentAndWait({
25
- intent: ctx.intent,
26
- infraKey: "aws",
27
- commandType: "viza.aws.sso-url",
28
- targetTeam: ctx.targetTeam,
29
- runnerLabel: "native",
30
- keepLog: ctx.keepLog === true,
31
- payload: plainPayload,
32
- }, { log: "show", mode: ctx.mode ?? "dispatch" });
33
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1 +0,0 @@
1
- export {};
@@ -1,9 +0,0 @@
1
- // src/platforms/registry.ts
2
- import { awsLogin } from "./aws/login.js";
3
- export const registry = {
4
- aws: {
5
- login: awsLogin,
6
- // deploy: awsDeploy,
7
- },
8
- // cloudflare: { login: cfLogin }
9
- };
@@ -1,3 +0,0 @@
1
- export async function confirmDangerous(message) {
2
- console.log(message);
3
- }
@@ -1,3 +0,0 @@
1
- export function requireEnv(env) {
2
- // enforced later
3
- }
@@ -1,3 +0,0 @@
1
- export function requireRole(role) {
2
- // enforced later
3
- }