viza 1.9.20 → 1.9.22

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.
@@ -2,7 +2,8 @@ export function getGlobalOptions() {
2
2
  return [
3
3
  { flags: "--status", description: "Show status only (no execution)" },
4
4
  { flags: "--keep-log", description: "Keep execution logs after completion" },
5
- { flags: "--self-hosted", description: "Use self-hosted runner (viza-builder)" }
5
+ { flags: "--self-hosted", description: "Use self-hosted runner (viza-builder)" },
6
+ { flags: "--cancel", description: "Cancel current running command (logical cancel, does not kill underlying job)" }
6
7
  ];
7
8
  }
8
9
  export function registerGlobalOptions(program) {
@@ -33,7 +33,9 @@ export async function bootstrapAgeCommand(options) {
33
33
  flowGates: {
34
34
  secrets: true,
35
35
  },
36
- payload: {}
36
+ payload: {
37
+ action: options.cancel ? "cancel" : "start"
38
+ }
37
39
  }, {
38
40
  status: options.status === true,
39
41
  log: "show",
@@ -31,7 +31,9 @@ export async function bootstrapAwsRolesAnywhereCommand(options) {
31
31
  flowGates: {
32
32
  secrets: true,
33
33
  },
34
- payload: {}
34
+ payload: {
35
+ action: options.cancel ? "cancel" : "start"
36
+ }
35
37
  }, {
36
38
  status: options.status === true,
37
39
  log: "show",
@@ -31,7 +31,9 @@ export async function rebootstrapAwsRolesAnywhereCommand(options) {
31
31
  flowGates: {
32
32
  secrets: true,
33
33
  },
34
- payload: {}
34
+ payload: {
35
+ action: options.cancel ? "cancel" : "start"
36
+ }
35
37
  }, {
36
38
  status: options.status === true,
37
39
  log: "show",
@@ -31,7 +31,9 @@ export async function rotateAwsRolesAnywhereCommand(options) {
31
31
  flowGates: {
32
32
  secrets: true,
33
33
  },
34
- payload: {}
34
+ payload: {
35
+ action: options.cancel ? "cancel" : "start"
36
+ }
35
37
  }, {
36
38
  status: options.status === true,
37
39
  log: "show",
@@ -31,7 +31,9 @@ export async function updateAwsRolesAnywhereRoleCommand(options) {
31
31
  flowGates: {
32
32
  secrets: true,
33
33
  },
34
- payload: {}
34
+ payload: {
35
+ action: options.cancel ? "cancel" : "start"
36
+ }
35
37
  }, {
36
38
  status: options.status === true,
37
39
  log: "show",
@@ -24,8 +24,8 @@ export async function loginBillingAwsCommand(options) {
24
24
  runType: "runtime",
25
25
  targetEnv: "prod",
26
26
  allowedTeams,
27
- selfHosted: options.selfHosted === true,
28
- keepLog: options.keepLog === true,
27
+ selfHosted: false,
28
+ keepLog: false,
29
29
  flowGates: {
30
30
  secrets: false,
31
31
  },
@@ -24,8 +24,8 @@ export async function logsCommand(runId, options) {
24
24
  runType: "infra",
25
25
  targetEnv: env,
26
26
  allowedTeams,
27
- selfHosted: options.selfHosted === true,
28
- keepLog: options.keepLog === true,
27
+ selfHosted: false,
28
+ keepLog: false,
29
29
  flowGates: {
30
30
  secrets: false,
31
31
  },
@@ -34,8 +34,8 @@ export async function runsCommand(options) {
34
34
  runType: "runtime",
35
35
  targetEnv: env,
36
36
  allowedTeams,
37
- selfHosted: options.selfHosted === true,
38
- keepLog: options.keepLog === true,
37
+ selfHosted: false,
38
+ keepLog: false,
39
39
  flowGates: {
40
40
  secrets: false,
41
41
  },
@@ -1,38 +1,6 @@
1
1
  import chalk from "chalk";
2
2
  import { formatDateTime, renderCommandInline } from "../../../ui/primitives/render-command.js";
3
- function formatAge(iso) {
4
- const diff = Date.now() - new Date(iso).getTime();
5
- const sec = Math.floor(diff / 1000);
6
- if (sec < 60)
7
- return `${sec}s`;
8
- const min = Math.floor(sec / 60);
9
- const remSec = sec % 60;
10
- // < 10 minutes → "Xm Ys"
11
- if (min < 10)
12
- return `${min}m ${remSec}s`;
13
- // < 60 minutes → "Xm"
14
- if (min < 60)
15
- return `${min}m`;
16
- const hr = Math.floor(min / 60);
17
- const remMin = min % 60;
18
- // < 10 hours → "Xh Ym"
19
- if (hr < 10)
20
- return `${hr}h ${remMin}m`;
21
- // ≥ 10 hours → "Xh"
22
- return `${hr}h`;
23
- }
24
- function formatDuration(start, end) {
25
- const diff = new Date(end).getTime() - new Date(start).getTime();
26
- const sec = Math.floor(diff / 1000);
27
- if (sec < 60)
28
- return `${sec}s`;
29
- const min = Math.floor(sec / 60);
30
- const rem = sec % 60;
31
- return `${min}m ${rem}s`;
32
- }
33
- function pad(v, n) {
34
- return v.padEnd(n, " ");
35
- }
3
+ import { formatAge, formatDuration, pad } from "../../../ui/theme.js";
36
4
  export async function showDispatchRuns(result) {
37
5
  const env = result;
38
6
  if (env.status !== "success" ||
@@ -33,7 +33,9 @@ export async function backupGithubSecretsCommand(options) {
33
33
  flowGates: {
34
34
  secrets: true,
35
35
  },
36
- payload: {}
36
+ payload: {
37
+ action: options.cancel ? "cancel" : "start"
38
+ }
37
39
  }, {
38
40
  status: options.status === true,
39
41
  log: "show",
@@ -50,14 +50,14 @@ export async function restoreGithubSecretsCommand(options) {
50
50
  runType: "runtime",
51
51
  targetEnv: env,
52
52
  allowedTeams,
53
- selfHosted: options.selfHosted === true,
54
- keepLog: options.keepLog === true,
53
+ selfHosted: false,
54
+ keepLog: false,
55
55
  flowGates: {
56
56
  secrets: true,
57
57
  },
58
58
  payload
59
59
  }, {
60
- status: options.status === true,
60
+ status: false,
61
61
  log: "show",
62
62
  });
63
63
  }
@@ -45,7 +45,8 @@ export async function deployCommandHubCommand(options) {
45
45
  secrets: true,
46
46
  },
47
47
  payload: {
48
- workerIntent
48
+ workerIntent,
49
+ action: options.cancel ? "cancel" : "start"
49
50
  }
50
51
  }, {
51
52
  status: options.status === true,
@@ -1,144 +1,50 @@
1
1
  import chalk from "chalk";
2
- import { formatDateTime, renderCommandInline } from "../../../../ui/primitives/render-command.js";
3
- function formatAge(iso) {
4
- const diff = Date.now() - new Date(iso).getTime();
5
- const sec = Math.floor(diff / 1000);
6
- if (sec < 60)
7
- return `${sec}s`;
8
- const min = Math.floor(sec / 60);
9
- const remSec = sec % 60;
10
- // < 10 minutes → "Xm Ys"
11
- if (min < 10)
12
- return `${min}m ${remSec}s`;
13
- // < 60 minutes → "Xm"
14
- if (min < 60)
15
- return `${min}m`;
16
- const hr = Math.floor(min / 60);
17
- const remMin = min % 60;
18
- // < 10 hours → "Xh Ym"
19
- if (hr < 10)
20
- return `${hr}h ${remMin}m`;
21
- // ≥ 10 hours → "Xh"
22
- return `${hr}h`;
23
- }
24
- function formatDuration(start, end) {
25
- const diff = new Date(end).getTime() - new Date(start).getTime();
26
- const sec = Math.floor(diff / 1000);
27
- if (sec < 60)
28
- return `${sec}s`;
29
- const min = Math.floor(sec / 60);
30
- const rem = sec % 60;
31
- return `${min}m ${rem}s`;
32
- }
33
- function pad(v, n) {
34
- return v.padEnd(n, " ");
35
- }
36
- export async function showUsage(result) {
2
+ import { pad } from "../../../../ui/theme.js";
3
+ export async function showRuntimeUsage(result) {
37
4
  const env = result;
38
5
  if (env.status !== "success" ||
39
6
  env.kind !== "runtime" ||
40
- !env.data?.result) {
41
- return;
42
- }
43
- const { runs } = env.data.result;
44
- if (!Array.isArray(runs)) {
45
- throw new Error("invalid_dispatch_runs_result_shape");
46
- }
47
- console.log("\n📋 Dispatch Runs");
48
- console.log("─".repeat(131));
49
- const header = [
50
- pad("RUN", 15),
51
- pad("STATUS", 18),
52
- pad("CONCLUSION", 15),
53
- pad("COMMITTER", 18),
54
- pad("CREATED_AT", 22),
55
- pad("AGE", 13),
56
- pad("DURATION", 13),
57
- "ATTEMPT",
58
- ].join(" ");
59
- console.log(header);
60
- console.log("─".repeat(131));
61
- if (runs.length === 0) {
62
- const emptyRow = chalk.gray(" (no dispatch runs found)");
63
- console.log(emptyRow);
64
- console.log("─".repeat(131));
65
- console.log();
7
+ !env.data) {
8
+ console.log("Invalid runtime response");
66
9
  return;
67
10
  }
68
- for (const run of runs) {
69
- let status;
70
- let conclusion;
71
- if (run.status === "completed") {
72
- status = "completed";
73
- switch (run.conclusion) {
74
- case "success":
75
- conclusion = "✅ success";
76
- break;
77
- case "failure":
78
- conclusion = "❌ failure";
79
- break;
80
- case "cancelled":
81
- conclusion = "⚪ cancelled";
82
- break;
83
- case "timed_out":
84
- conclusion = "⏱ timed_out";
85
- break;
86
- case "skipped":
87
- conclusion = "⏭ skipped";
88
- break;
89
- default:
90
- conclusion = run.conclusion ?? "-";
11
+ const { log, result: data } = env.data;
12
+ // ────────────────────────────────────────────────────────────────────────────────────────────────
13
+ // 1. Render usage by month
14
+ // ────────────────────────────────────────────────────────────────────────────────────────────────
15
+ if (data?.usage) {
16
+ console.log("\n📊 Usage by Month");
17
+ console.log("".repeat(60));
18
+ for (const m of data.usage) {
19
+ console.log(`${pad(m.month, 10)} ${pad(String(m.totalMinutes) + " min", 15)}`);
20
+ if (Array.isArray(m.byOS)) {
21
+ for (const os of m.byOS) {
22
+ console.log(chalk.gray(` ↳ ${os.os}: ${os.minutes} min`));
23
+ }
91
24
  }
92
25
  }
93
- else if (run.status === "in_progress") {
94
- status = "⏳ in progress";
95
- conclusion = "...";
96
- }
97
- else {
98
- status = "⏳ queued";
99
- conclusion = "-";
26
+ console.log("".repeat(60));
27
+ }
28
+ // ────────────────────────────────────────────────────────────────────────────────────────────────
29
+ // 2. Render usage by org + month
30
+ // ────────────────────────────────────────────────────────────────────────────────────────────────
31
+ if (data?.byOrg) {
32
+ console.log("\n🏢 Usage by Organization");
33
+ console.log("─".repeat(60));
34
+ for (const org of data.byOrg) {
35
+ console.log(`\n${chalk.bold(org.org)}`);
36
+ for (const m of org.months || []) {
37
+ console.log(` ${pad(m.month, 10)} ${pad(String(m.totalMinutes) + " min", 15)}`);
38
+ }
100
39
  }
101
- const committer = run.committer
102
- ? `${run.committer.name}`
103
- : "unknown";
104
- const age = formatAge(run.createdAt);
105
- const duration = run.status === "completed"
106
- ? formatDuration(run.createdAt, run.updatedAt)
107
- : "-";
108
- const row = [
109
- pad(String(run.id), 15),
110
- pad(status, 18),
111
- pad(conclusion, 14),
112
- pad(committer, 18),
113
- pad(formatDateTime(run.createdAt), 22),
114
- pad(age, 13),
115
- pad(duration, 13),
116
- `#${run.attempt}`,
117
- ].join(" ");
118
- console.log(row);
40
+ console.log("─".repeat(60));
119
41
  }
120
- console.log("─".repeat(131));
121
- console.log();
122
- // Hint section
123
- if (runs.length > 0) {
124
- const [firstRun] = runs;
125
- if (!firstRun)
126
- return;
127
- const firstRunId = firstRun.id;
128
- // derive binary name from process.argv (fallback safe)
129
- const bin = (process.argv[1] || "viza").split("/").pop();
130
- const sampleCmd = `${bin} dispatch logs ${firstRunId}`;
131
- console.log();
132
- console.log("💡 " + "\x1b[1mQuick Hint\x1b[0m");
133
- console.log();
134
- console.log(chalk.gray(" 👉 To quickly list fewer runs, use --limit:"));
135
- console.log(` ${renderCommandInline(`${bin} dispatch runs --limit <n>`)}`);
136
- console.log();
137
- console.log(chalk.gray(" 👉 To view detailed logs for a specific run, use:"));
138
- console.log(` ${renderCommandInline(`${bin} dispatch logs <runId>`)}`);
139
- console.log();
140
- console.log(chalk.gray(" 👉 Example:"));
141
- console.log(` ${renderCommandInline(sampleCmd)}`);
42
+ // ────────────────────────────────────────────────────────────────────────────────────────────────
43
+ // 4. Raw hint (optional)
44
+ // ────────────────────────────────────────────────────────────────────────────────────────────────
45
+ if (data?.raw?.usageItems) {
142
46
  console.log();
47
+ console.log(chalk.gray("💡 Raw usage items available (use debug mode if needed)"));
143
48
  }
49
+ console.log();
144
50
  }
@@ -2,6 +2,7 @@ import { getEnv } from "../../../../context/env.js";
2
2
  import { getRunner, RUNTIME_WORKER_CONTROL_INTENT } from "../../../../context/hubIntent.js";
3
3
  import { dispatchIntentAndWait } from "../../../../core/dispatch.js";
4
4
  import { policy } from "./policy.js";
5
+ import { showRuntimeUsage } from "./show-usage.js";
5
6
  /**
6
7
  * viza dispatch runs
7
8
  *
@@ -25,8 +26,8 @@ export async function usageCommand(options) {
25
26
  runType: "runtime",
26
27
  targetEnv: env,
27
28
  allowedTeams,
28
- selfHosted: options.selfHosted === true,
29
- keepLog: options.keepLog === true,
29
+ selfHosted: false,
30
+ keepLog: false,
30
31
  flowGates: {
31
32
  secrets: false,
32
33
  },
@@ -37,7 +38,6 @@ export async function usageCommand(options) {
37
38
  status: false,
38
39
  log: "show",
39
40
  });
40
- console.log(JSON.stringify(result, null, 2));
41
- // await showUsage(result);
41
+ await showRuntimeUsage(result);
42
42
  return result;
43
43
  }
@@ -29,8 +29,8 @@ export async function loginAwsCommand(options) {
29
29
  runType: "runtime",
30
30
  targetEnv: env,
31
31
  allowedTeams,
32
- selfHosted: options.selfHosted === true,
33
- keepLog: options.keepLog === true,
32
+ selfHosted: false,
33
+ keepLog: false,
34
34
  flowGates: {
35
35
  secrets: false,
36
36
  },
@@ -38,7 +38,7 @@ export async function loginAwsCommand(options) {
38
38
  ...(options.ssm ? { intent: "ssm" } : {}),
39
39
  }
40
40
  }, {
41
- status: options.status === true,
41
+ status: false,
42
42
  log: "show",
43
43
  });
44
44
  if (!result ||
@@ -1 +1,34 @@
1
1
  export const theme = {};
2
+ export function formatAge(iso) {
3
+ const diff = Date.now() - new Date(iso).getTime();
4
+ const sec = Math.floor(diff / 1000);
5
+ if (sec < 60)
6
+ return `${sec}s`;
7
+ const min = Math.floor(sec / 60);
8
+ const remSec = sec % 60;
9
+ // < 10 minutes → "Xm Ys"
10
+ if (min < 10)
11
+ return `${min}m ${remSec}s`;
12
+ // < 60 minutes → "Xm"
13
+ if (min < 60)
14
+ return `${min}m`;
15
+ const hr = Math.floor(min / 60);
16
+ const remMin = min % 60;
17
+ // < 10 hours → "Xh Ym"
18
+ if (hr < 10)
19
+ return `${hr}h ${remMin}m`;
20
+ // ≥ 10 hours → "Xh"
21
+ return `${hr}h`;
22
+ }
23
+ export function formatDuration(start, end) {
24
+ const diff = new Date(end).getTime() - new Date(start).getTime();
25
+ const sec = Math.floor(diff / 1000);
26
+ if (sec < 60)
27
+ return `${sec}s`;
28
+ const min = Math.floor(sec / 60);
29
+ const rem = sec % 60;
30
+ return `${min}m ${rem}s`;
31
+ }
32
+ export function pad(v, n) {
33
+ return v.padEnd(n, " ");
34
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "viza",
3
- "version": "1.9.20",
3
+ "version": "1.9.22",
4
4
  "type": "module",
5
5
  "description": "Viza unified command line interface",
6
6
  "bin": {
@@ -28,7 +28,7 @@
28
28
  "release:full": "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"
29
29
  },
30
30
  "dependencies": {
31
- "@vizamodo/viza-dispatcher": "^1.5.51",
31
+ "@vizamodo/viza-dispatcher": "^1.5.52",
32
32
  "adm-zip": "^0.5.16",
33
33
  "chalk": "^5.6.2",
34
34
  "clipboardy": "^5.3.1",