viza 1.9.32 → 1.9.34
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/src/cli/program.js +24 -20
- package/dist/src/commands/age/bootstrap/descriptor.js +1 -1
- package/dist/src/commands/aws/rolesanywhere/bootstrap/descriptor.js +1 -1
- package/dist/src/commands/aws/rolesanywhere/rebootstrap/descriptor.js +1 -1
- package/dist/src/commands/aws/rolesanywhere/rotate/descriptor.js +1 -1
- package/dist/src/commands/aws/rolesanywhere/update-role/descriptor.js +1 -1
- package/dist/src/commands/billing/login/aws/descriptor.js +1 -1
- package/dist/src/commands/bootstrap/descriptor.js +1 -1
- package/dist/src/commands/dispatch/cancel-run/cancel-run.js +52 -0
- package/dist/src/commands/dispatch/cancel-run/descriptor.js +17 -0
- package/dist/src/commands/dispatch/cancel-run/policy.js +14 -0
- package/dist/src/commands/dispatch/cancel-run/show-runs.js +112 -0
- package/dist/src/commands/dispatch/logs/descriptor.js +1 -1
- package/dist/src/commands/dispatch/runs/descriptor.js +1 -1
- package/dist/src/commands/github/secrets/backup/descriptor.js +1 -1
- package/dist/src/commands/github/secrets/restore/descriptor.js +1 -1
- package/dist/src/commands/infra/deploy/command-hub/descriptor.js +1 -1
- package/dist/src/commands/insight/actions/usage/descriptor.js +1 -1
- package/dist/src/commands/insight/actions/usage/show-usage.js +4 -4
- package/dist/src/commands/login/aws/descriptor.js +1 -1
- package/dist/src/commands/whoami/descriptor.js +1 -1
- package/dist/src/core/commandRegistry.js +6 -3
- package/dist/src/core/renderHint.js +4 -2
- package/package.json +1 -1
package/dist/src/cli/program.js
CHANGED
|
@@ -24,26 +24,27 @@ export async function createProgram() {
|
|
|
24
24
|
* Build command tree for hinting and inject leaf commands into Commander.
|
|
25
25
|
*/
|
|
26
26
|
const commandTree = buildCommandTree();
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
return node;
|
|
41
|
-
if (node.children)
|
|
42
|
-
return findNode(node.children, depth + 1);
|
|
43
|
-
}
|
|
27
|
+
// ------------------------------------------------
|
|
28
|
+
// Build command index (O(1) lookup)
|
|
29
|
+
// ------------------------------------------------
|
|
30
|
+
const nodeMap = new Map();
|
|
31
|
+
const buildIndex = (nodes) => {
|
|
32
|
+
for (const n of nodes) {
|
|
33
|
+
if (!Array.isArray(n.path) || n.path.length === 0) {
|
|
34
|
+
throw new Error("invalid_node_missing_path");
|
|
35
|
+
}
|
|
36
|
+
const key = n.path.join(":"); // safe key
|
|
37
|
+
nodeMap.set(key, n);
|
|
38
|
+
if (n.children?.length) {
|
|
39
|
+
buildIndex(n.children);
|
|
44
40
|
}
|
|
45
|
-
}
|
|
46
|
-
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
buildIndex(commandTree);
|
|
44
|
+
program.on("command:*", () => {
|
|
45
|
+
const parts = process.argv.slice(2);
|
|
46
|
+
const key = parts.join(":");
|
|
47
|
+
const node = nodeMap.get(key);
|
|
47
48
|
if (node) {
|
|
48
49
|
renderHint(node);
|
|
49
50
|
}
|
|
@@ -55,7 +56,10 @@ export async function createProgram() {
|
|
|
55
56
|
const argRegistry = new WeakMap();
|
|
56
57
|
const walk = (nodes, parent) => {
|
|
57
58
|
for (const node of nodes) {
|
|
58
|
-
|
|
59
|
+
if (!node.path?.length) {
|
|
60
|
+
throw new Error("invalid_node_missing_path");
|
|
61
|
+
}
|
|
62
|
+
const name = node.path[node.path.length - 1];
|
|
59
63
|
// Tìm hoặc tạo subcommand ở level này
|
|
60
64
|
let sub = parent.commands.find((c) => c.name() === name);
|
|
61
65
|
if (!sub) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { registerCommand } from "../../../core/commandRegistry.js";
|
|
2
2
|
import { bootstrapAgeCommand } from "./bootstrap.js";
|
|
3
3
|
const descriptor = {
|
|
4
|
-
|
|
4
|
+
path: ["age", "bootstrap"],
|
|
5
5
|
description: "Bootstrap age keypair and infrastructure",
|
|
6
6
|
run: bootstrapAgeCommand
|
|
7
7
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { registerCommand } from "../../../../core/commandRegistry.js";
|
|
2
2
|
import { bootstrapAwsRolesAnywhereCommand } from "./bootstrap.js";
|
|
3
3
|
const descriptor = {
|
|
4
|
-
|
|
4
|
+
path: ["aws", "rolesanywhere", "bootstrap"],
|
|
5
5
|
description: "Bootstrap AWS RolesAnywhere infrastructure",
|
|
6
6
|
run: bootstrapAwsRolesAnywhereCommand
|
|
7
7
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { registerCommand } from "../../../../core/commandRegistry.js";
|
|
2
2
|
import { rebootstrapAwsRolesAnywhereCommand } from "./rebootstrap.js";
|
|
3
3
|
const descriptor = {
|
|
4
|
-
|
|
4
|
+
path: ["aws", "rolesanywhere", "rebootstrap"],
|
|
5
5
|
description: "Rebootstrap AWS RolesAnywhere infrastructure",
|
|
6
6
|
run: rebootstrapAwsRolesAnywhereCommand
|
|
7
7
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { registerCommand } from "../../../../core/commandRegistry.js";
|
|
2
2
|
import { rotateAwsRolesAnywhereCommand } from "./rotate.js";
|
|
3
3
|
const descriptor = {
|
|
4
|
-
|
|
4
|
+
path: ["aws", "rolesanywhere", "rotate"],
|
|
5
5
|
description: "Rotate AWS RolesAnywhere certificates and credentials",
|
|
6
6
|
run: rotateAwsRolesAnywhereCommand
|
|
7
7
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { registerCommand } from "../../../../core/commandRegistry.js";
|
|
2
2
|
import { updateAwsRolesAnywhereRoleCommand } from "./update-role.js";
|
|
3
3
|
const descriptor = {
|
|
4
|
-
|
|
4
|
+
path: ["aws", "rolesanywhere", "update-role"],
|
|
5
5
|
description: "Update AWS RolesAnywhere role configuration",
|
|
6
6
|
run: updateAwsRolesAnywhereRoleCommand
|
|
7
7
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { registerCommand } from "../../../../core/commandRegistry.js";
|
|
2
2
|
import { loginBillingAwsCommand } from "./aws.js";
|
|
3
3
|
const descriptor = {
|
|
4
|
-
|
|
4
|
+
path: ["billing", "login", "aws"],
|
|
5
5
|
description: "Login to AWS billing account",
|
|
6
6
|
options: [
|
|
7
7
|
{
|
|
@@ -2,7 +2,7 @@ import { registerCommand } from "../../core/commandRegistry.js";
|
|
|
2
2
|
import { vizaBootstrapCommand } from "./index.js";
|
|
3
3
|
import { getEnv } from "../../context/env.js";
|
|
4
4
|
const descriptor = {
|
|
5
|
-
|
|
5
|
+
path: ["bootstrap"],
|
|
6
6
|
description: "Bootstrap infrastructure or system components",
|
|
7
7
|
run: async () => {
|
|
8
8
|
const runtimeEnv = getEnv();
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { getEnv } from "../../../context/env.js";
|
|
2
|
+
import { getRunner, RUNTIME_WORKER_CONTROL_INTENT } from "../../../context/hubIntent.js";
|
|
3
|
+
import { dispatchIntentAndWait } from "../../../core/dispatch.js";
|
|
4
|
+
import { policy } from "./policy.js";
|
|
5
|
+
import { showDispatchRuns } from "./show-runs.js";
|
|
6
|
+
/**
|
|
7
|
+
* viza dispatch runs
|
|
8
|
+
*
|
|
9
|
+
* Flow:
|
|
10
|
+
* 1) Resolve env (deterministic)
|
|
11
|
+
* 2) If --app → show GitHub Actions link locally (no dispatch)
|
|
12
|
+
* 3) Otherwise dispatch intent to hub
|
|
13
|
+
*/
|
|
14
|
+
export async function runsCommand(options) {
|
|
15
|
+
// 1️⃣ Resolve environment
|
|
16
|
+
const env = getEnv();
|
|
17
|
+
const intent = RUNTIME_WORKER_CONTROL_INTENT;
|
|
18
|
+
const runner = getRunner();
|
|
19
|
+
// Resolve allowed teams (same contract as other commands)
|
|
20
|
+
const allowedTeams = Array.from(policy.byEnv[env]);
|
|
21
|
+
// Parse limit option
|
|
22
|
+
let limit = undefined;
|
|
23
|
+
if (options.limit !== undefined) {
|
|
24
|
+
const parsed = Number(options.limit);
|
|
25
|
+
if (!Number.isNaN(parsed) && parsed > 0) {
|
|
26
|
+
limit = parsed;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
// 3️⃣ Dispatch intent to hub
|
|
30
|
+
const result = await dispatchIntentAndWait({
|
|
31
|
+
intent,
|
|
32
|
+
commandType: "dispatch.runs",
|
|
33
|
+
infraKey: "core",
|
|
34
|
+
runType: "runtime",
|
|
35
|
+
targetEnv: env,
|
|
36
|
+
allowedTeams,
|
|
37
|
+
selfHosted: false,
|
|
38
|
+
keepLog: false,
|
|
39
|
+
flowGates: {
|
|
40
|
+
secrets: false,
|
|
41
|
+
},
|
|
42
|
+
payload: {
|
|
43
|
+
runner,
|
|
44
|
+
...(limit ? { limit } : {}),
|
|
45
|
+
},
|
|
46
|
+
}, {
|
|
47
|
+
mode: "dispatch",
|
|
48
|
+
log: "show",
|
|
49
|
+
});
|
|
50
|
+
await showDispatchRuns(result);
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { registerCommand } from "../../../core/commandRegistry.js";
|
|
2
|
+
import { runsCommand } from "./cancel-run.js";
|
|
3
|
+
const descriptor = {
|
|
4
|
+
path: ["dispatch", "cancel-run"],
|
|
5
|
+
description: "Cancel a queued GitHub Actions run by runId (admin only)",
|
|
6
|
+
args: [
|
|
7
|
+
{
|
|
8
|
+
name: "runId",
|
|
9
|
+
required: true,
|
|
10
|
+
description: "Run ID to cancel"
|
|
11
|
+
}
|
|
12
|
+
],
|
|
13
|
+
options: [],
|
|
14
|
+
run: runsCommand
|
|
15
|
+
};
|
|
16
|
+
registerCommand(descriptor);
|
|
17
|
+
export default descriptor;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { formatDateTime, renderCommandInline } from "../../../ui/primitives/render-command.js";
|
|
3
|
+
import { formatAge, formatDuration, pad } from "../../../ui/theme.js";
|
|
4
|
+
export async function showDispatchRuns(result) {
|
|
5
|
+
const env = result;
|
|
6
|
+
if (env.status !== "success" ||
|
|
7
|
+
env.kind !== "runtime" ||
|
|
8
|
+
!env.data?.result) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
const { runs } = env.data.result;
|
|
12
|
+
if (!Array.isArray(runs)) {
|
|
13
|
+
throw new Error("invalid_dispatch_runs_result_shape");
|
|
14
|
+
}
|
|
15
|
+
console.log("\n📋 Dispatch Runs");
|
|
16
|
+
console.log(chalk.gray("─".repeat(131)));
|
|
17
|
+
const header = [
|
|
18
|
+
pad("RUN", 15),
|
|
19
|
+
pad("STATUS", 18),
|
|
20
|
+
pad("CONCLUSION", 15),
|
|
21
|
+
pad("COMMITTER", 18),
|
|
22
|
+
pad("CREATED_AT", 22),
|
|
23
|
+
pad("AGE", 13),
|
|
24
|
+
pad("DURATION", 13),
|
|
25
|
+
"ATTEMPT",
|
|
26
|
+
].join(" ");
|
|
27
|
+
console.log(header);
|
|
28
|
+
console.log(chalk.gray("─".repeat(131)));
|
|
29
|
+
if (runs.length === 0) {
|
|
30
|
+
const emptyRow = chalk.gray(" (no dispatch runs found)");
|
|
31
|
+
console.log(emptyRow);
|
|
32
|
+
console.log(chalk.gray("─".repeat(131)));
|
|
33
|
+
console.log();
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
for (const run of runs) {
|
|
37
|
+
let status;
|
|
38
|
+
let conclusion;
|
|
39
|
+
if (run.status === "completed") {
|
|
40
|
+
status = "completed";
|
|
41
|
+
switch (run.conclusion) {
|
|
42
|
+
case "success":
|
|
43
|
+
conclusion = "✅ success";
|
|
44
|
+
break;
|
|
45
|
+
case "failure":
|
|
46
|
+
conclusion = "❌ failure";
|
|
47
|
+
break;
|
|
48
|
+
case "cancelled":
|
|
49
|
+
conclusion = "⚪ cancelled";
|
|
50
|
+
break;
|
|
51
|
+
case "timed_out":
|
|
52
|
+
conclusion = "⏱ timed_out";
|
|
53
|
+
break;
|
|
54
|
+
case "skipped":
|
|
55
|
+
conclusion = "⏭ skipped";
|
|
56
|
+
break;
|
|
57
|
+
default:
|
|
58
|
+
conclusion = run.conclusion ?? "-";
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else if (run.status === "in_progress") {
|
|
62
|
+
status = "⏳ in progress";
|
|
63
|
+
conclusion = "...";
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
status = "⏳ queued";
|
|
67
|
+
conclusion = "-";
|
|
68
|
+
}
|
|
69
|
+
const committer = run.committer
|
|
70
|
+
? `${run.committer.name}`
|
|
71
|
+
: "unknown";
|
|
72
|
+
const age = formatAge(run.createdAt);
|
|
73
|
+
const duration = run.status === "completed"
|
|
74
|
+
? formatDuration(run.createdAt, run.updatedAt)
|
|
75
|
+
: "-";
|
|
76
|
+
const row = [
|
|
77
|
+
pad(String(run.id), 15),
|
|
78
|
+
pad(status, 18),
|
|
79
|
+
pad(conclusion, 14),
|
|
80
|
+
pad(committer, 18),
|
|
81
|
+
pad(formatDateTime(run.createdAt), 22),
|
|
82
|
+
pad(age, 13),
|
|
83
|
+
pad(duration, 13),
|
|
84
|
+
`#${run.attempt}`,
|
|
85
|
+
].join(" ");
|
|
86
|
+
console.log(row);
|
|
87
|
+
}
|
|
88
|
+
console.log(chalk.gray("─".repeat(131)));
|
|
89
|
+
console.log();
|
|
90
|
+
// Hint section
|
|
91
|
+
if (runs.length > 0) {
|
|
92
|
+
const [firstRun] = runs;
|
|
93
|
+
if (!firstRun)
|
|
94
|
+
return;
|
|
95
|
+
const firstRunId = firstRun.id;
|
|
96
|
+
// derive binary name from process.argv (fallback safe)
|
|
97
|
+
const bin = (process.argv[1] || "viza").split("/").pop();
|
|
98
|
+
const sampleCmd = `${bin} dispatch logs ${firstRunId}`;
|
|
99
|
+
console.log();
|
|
100
|
+
console.log("💡 " + "\x1b[1mQuick Hint\x1b[0m");
|
|
101
|
+
console.log();
|
|
102
|
+
console.log(chalk.gray(" 👉 To list fewer or more runs, use --limit:"));
|
|
103
|
+
console.log(` ${renderCommandInline(`${bin} dispatch runs --limit <n>`)}`);
|
|
104
|
+
console.log();
|
|
105
|
+
console.log(chalk.gray(" 👉 To view detailed logs for a specific run, use:"));
|
|
106
|
+
console.log(` ${renderCommandInline(`${bin} dispatch logs <runId>`)}`);
|
|
107
|
+
console.log();
|
|
108
|
+
console.log(chalk.gray(" 👉 Example:"));
|
|
109
|
+
console.log(` ${renderCommandInline(sampleCmd)}`);
|
|
110
|
+
console.log();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { registerCommand } from "../../../../core/commandRegistry.js";
|
|
2
2
|
import { backupGithubSecretsCommand } from "./backup.js";
|
|
3
3
|
const descriptor = {
|
|
4
|
-
|
|
4
|
+
path: ["github", "secrets", "backup"],
|
|
5
5
|
description: "Backup GitHub secrets to ssm parameter store",
|
|
6
6
|
run: backupGithubSecretsCommand
|
|
7
7
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { registerCommand } from "../../../../core/commandRegistry.js";
|
|
2
2
|
import { restoreGithubSecretsCommand } from "./restore.js";
|
|
3
3
|
const descriptor = {
|
|
4
|
-
|
|
4
|
+
path: ["github", "secrets", "restore"],
|
|
5
5
|
description: "Restore GitHub secrets from ssm parameter store",
|
|
6
6
|
options: [
|
|
7
7
|
{ flags: "--core", description: "Restore core secrets" },
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { registerCommand } from "../../../../core/commandRegistry.js";
|
|
2
2
|
import { deployCommandHubCommand } from "./command-hub.js";
|
|
3
3
|
const descriptor = {
|
|
4
|
-
|
|
4
|
+
path: ["infra", "deploy", "command-hub"],
|
|
5
5
|
description: "Deploy command hub worker to Cloudflare",
|
|
6
6
|
options: [
|
|
7
7
|
{
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { registerCommand } from "../../../../core/commandRegistry.js";
|
|
2
2
|
import { usageCommand } from "./usage.js";
|
|
3
3
|
const descriptor = {
|
|
4
|
-
|
|
4
|
+
path: ["actions", "usage"],
|
|
5
5
|
description: "Show GitHub Actions usage (monthly, by OS)",
|
|
6
6
|
options: [],
|
|
7
7
|
run: usageCommand
|
|
@@ -24,7 +24,7 @@ export async function showRuntimeUsage(result) {
|
|
|
24
24
|
const values = usage.map((m) => {
|
|
25
25
|
const val = `${m.totalMinutes} min`;
|
|
26
26
|
if (m.month === latest?.month) {
|
|
27
|
-
return chalk.bold.
|
|
27
|
+
return chalk.bold.white(pad(val, 24));
|
|
28
28
|
}
|
|
29
29
|
return pad(val, 24);
|
|
30
30
|
}).join("");
|
|
@@ -46,7 +46,7 @@ export async function showRuntimeUsage(result) {
|
|
|
46
46
|
return null;
|
|
47
47
|
const text = `${m.month}: ${os.minutes} min`;
|
|
48
48
|
if (m.month === latest?.month) {
|
|
49
|
-
return chalk.bold.
|
|
49
|
+
return chalk.bold.white(text);
|
|
50
50
|
}
|
|
51
51
|
return chalk.gray(text);
|
|
52
52
|
}).filter(Boolean);
|
|
@@ -67,7 +67,7 @@ export async function showRuntimeUsage(result) {
|
|
|
67
67
|
console.log("\n🏢 Usage by Organization");
|
|
68
68
|
console.log(chalk.gray("─".repeat(120)));
|
|
69
69
|
for (const org of data.byOrg) {
|
|
70
|
-
console.log(`\n${chalk.bold(org.org)}`);
|
|
70
|
+
console.log(`\n${chalk.bold.magentaBright(org.org)}`);
|
|
71
71
|
const months = [...(org.months || [])].sort((a, b) => a.month.localeCompare(b.month));
|
|
72
72
|
const latest = months[months.length - 1];
|
|
73
73
|
const header = months.map((m) => pad(m.month, 24)).join("");
|
|
@@ -75,7 +75,7 @@ export async function showRuntimeUsage(result) {
|
|
|
75
75
|
const values = months.map((m) => {
|
|
76
76
|
const val = `${m.totalMinutes} min`;
|
|
77
77
|
if (m.month === latest?.month) {
|
|
78
|
-
return chalk.bold.
|
|
78
|
+
return chalk.bold.cyanBright(pad(val, 24));
|
|
79
79
|
}
|
|
80
80
|
return pad(val, 24);
|
|
81
81
|
}).join("");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { registerCommand } from "../../core/commandRegistry.js";
|
|
2
2
|
import { whoamiCommand } from "./index.js";
|
|
3
3
|
const descriptor = {
|
|
4
|
-
|
|
4
|
+
path: ["whoami"],
|
|
5
5
|
description: "Display current user information and team memberships",
|
|
6
6
|
run: whoamiCommand
|
|
7
7
|
};
|
|
@@ -33,16 +33,19 @@ export function getCommandRegistry() {
|
|
|
33
33
|
export function buildCommandTree() {
|
|
34
34
|
const rootMap = new Map();
|
|
35
35
|
for (const cmd of registry) {
|
|
36
|
-
|
|
36
|
+
if (!Array.isArray(cmd.path) || cmd.path.length === 0) {
|
|
37
|
+
throw new Error("invalid_command_descriptor_missing_path");
|
|
38
|
+
}
|
|
39
|
+
const parts = cmd.path;
|
|
37
40
|
let currentMap = rootMap;
|
|
38
41
|
let parentNode = null;
|
|
39
42
|
for (let i = 0; i < parts.length; i++) {
|
|
40
43
|
const part = parts[i];
|
|
41
|
-
const
|
|
44
|
+
const fullPath = parts.slice(0, i + 1);
|
|
42
45
|
let node = currentMap.get(part);
|
|
43
46
|
if (!node) {
|
|
44
47
|
node = {
|
|
45
|
-
|
|
48
|
+
path: fullPath,
|
|
46
49
|
description: "",
|
|
47
50
|
run: undefined,
|
|
48
51
|
children: [],
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
function getName(cmd) {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
if (!Array.isArray(cmd.path) || cmd.path.length === 0) {
|
|
3
|
+
throw new Error("invalid_command_descriptor_missing_path");
|
|
4
|
+
}
|
|
5
|
+
return cmd.path[cmd.path.length - 1];
|
|
4
6
|
}
|
|
5
7
|
export function renderHint(cmd) {
|
|
6
8
|
const name = getName(cmd);
|