@tolinax/ayoune-cli 2026.10.1 → 2026.11.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/lib/commands/_registry.js +5 -0
- package/lib/commands/aggregate/list.js +3 -2
- package/lib/commands/createActionsCommand.js +11 -10
- package/lib/commands/createAiCommand.js +10 -9
- package/lib/commands/createDbCommand.js +2 -1
- package/lib/commands/createDoctorCommand.js +305 -0
- package/lib/commands/createExportCommand.js +12 -11
- package/lib/commands/createJobsCommand.js +9 -8
- package/lib/commands/createMonitorCommand.js +20 -19
- package/lib/commands/createPermissionsCommand.js +12 -11
- package/lib/commands/createSearchCommand.js +13 -12
- package/lib/commands/createServicesCommand.js +5 -4
- package/lib/commands/createSetupCommand.js +11 -13
- package/lib/commands/createSyncCommand.js +6 -5
- package/lib/commands/createTemplateCommand.js +8 -7
- package/lib/commands/createUsersCommand.js +6 -5
- package/lib/commands/createWebhooksCommand.js +4 -3
- package/lib/commands/deploy/alerts.js +2 -1
- package/lib/commands/deploy/clusters.js +2 -1
- package/lib/commands/deploy/deployments.js +4 -3
- package/lib/commands/deploy/pipelines.js +2 -1
- package/lib/commands/deploy/plans.js +3 -2
- package/lib/commands/deploy/pods.js +2 -1
- package/lib/commands/deploy/repos.js +3 -2
- package/lib/commands/functions/list.js +3 -2
- package/lib/commands/functions/logs.js +2 -1
- package/lib/commands/functions/versions.js +2 -1
- package/lib/commands/provision/hetzner.js +2 -1
- package/lib/helpers/printNextSteps.js +34 -0
- package/package.json +1 -1
|
@@ -240,6 +240,11 @@ export const COMMAND_REGISTRY = [
|
|
|
240
240
|
description: "Provision aYOUne to a cloud provider (AWS / GCP / Azure / DigitalOcean / Hetzner)",
|
|
241
241
|
loader: async () => (await import("./provision/index.js")).createProvisionCommand,
|
|
242
242
|
},
|
|
243
|
+
{
|
|
244
|
+
name: "doctor",
|
|
245
|
+
description: "Run a health check on your local aYOUne environment",
|
|
246
|
+
loader: async () => (await import("./createDoctorCommand.js")).createDoctorCommand,
|
|
247
|
+
},
|
|
243
248
|
{
|
|
244
249
|
name: "context",
|
|
245
250
|
aliases: ["ctx"],
|
|
@@ -9,13 +9,14 @@ import { handleResponseFormatOptions } from "../../helpers/handleResponseFormatO
|
|
|
9
9
|
import { spinner } from "../../../index.js";
|
|
10
10
|
import { EXIT_GENERAL_ERROR } from "../../exitCodes.js";
|
|
11
11
|
import { cliError } from "../../helpers/cliError.js";
|
|
12
|
+
import { parseInteger } from "../../helpers/parseInt.js";
|
|
12
13
|
export function addListSubcommand(agg, rootProgram) {
|
|
13
14
|
agg
|
|
14
15
|
.command("list")
|
|
15
16
|
.alias("ls")
|
|
16
17
|
.description("List saved aggregation queries")
|
|
17
|
-
.option("-l, --limit <number>", "Limit results",
|
|
18
|
-
.option("-p, --page <number>", "Page number",
|
|
18
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 50)
|
|
19
|
+
.option("-p, --page <number>", "Page number", parseInteger, 1)
|
|
19
20
|
.option("--search <term>", "Search by name")
|
|
20
21
|
.action(async (options) => {
|
|
21
22
|
var _a, _b, _c, _d, _e;
|
|
@@ -5,19 +5,20 @@ import { secureStorage } from "../helpers/secureStorage.js";
|
|
|
5
5
|
import { spinner } from "../../index.js";
|
|
6
6
|
import { EXIT_GENERAL_ERROR, EXIT_PERMISSION_DENIED } from "../exitCodes.js";
|
|
7
7
|
import { cliError } from "../helpers/cliError.js";
|
|
8
|
+
import { parseInteger } from "../helpers/parseInt.js";
|
|
8
9
|
export function createActionsCommand(program) {
|
|
9
10
|
program
|
|
10
11
|
.command("actions [search]")
|
|
11
12
|
.alias("act")
|
|
12
13
|
.description("Discover registered API actions from all services")
|
|
13
|
-
.addHelpText("after", `
|
|
14
|
-
Examples:
|
|
15
|
-
ay actions List all API actions (interactive)
|
|
16
|
-
ay actions generate Search actions matching "generate"
|
|
17
|
-
ay actions --namespace ai List all AI actions
|
|
18
|
-
ay actions --host ai.ayoune.app List actions for a specific host
|
|
19
|
-
ay actions --method POST List only POST actions
|
|
20
|
-
ay actions --list-namespaces List all available namespaces
|
|
14
|
+
.addHelpText("after", `
|
|
15
|
+
Examples:
|
|
16
|
+
ay actions List all API actions (interactive)
|
|
17
|
+
ay actions generate Search actions matching "generate"
|
|
18
|
+
ay actions --namespace ai List all AI actions
|
|
19
|
+
ay actions --host ai.ayoune.app List actions for a specific host
|
|
20
|
+
ay actions --method POST List only POST actions
|
|
21
|
+
ay actions --list-namespaces List all available namespaces
|
|
21
22
|
ay actions -r table --columns "operationId,method,endpoint,host"`)
|
|
22
23
|
.option("--namespace <ns>", "Filter by namespace (e.g. ai, crm, pm)")
|
|
23
24
|
.option("--host <host>", "Filter by host")
|
|
@@ -25,8 +26,8 @@ Examples:
|
|
|
25
26
|
.option("--capability <cap>", "Filter by capability")
|
|
26
27
|
.option("--list-namespaces", "List all unique namespaces")
|
|
27
28
|
.option("--list-hosts", "List all unique hosts")
|
|
28
|
-
.option("-p, --page <number>", "Page",
|
|
29
|
-
.option("-l, --limit <number>", "Limit",
|
|
29
|
+
.option("-p, --page <number>", "Page", parseInteger, 1)
|
|
30
|
+
.option("-l, --limit <number>", "Limit", parseInteger, 100)
|
|
30
31
|
.action(async (search, options) => {
|
|
31
32
|
var _a, _b, _c;
|
|
32
33
|
try {
|
|
@@ -7,6 +7,7 @@ import { spinner } from "../../index.js";
|
|
|
7
7
|
import { EXIT_GENERAL_ERROR } from "../exitCodes.js";
|
|
8
8
|
import { cliError } from "../helpers/cliError.js";
|
|
9
9
|
import { getContextSummary, getContextForAI, hasActiveContext } from "../helpers/contextInjector.js";
|
|
10
|
+
import { parseInteger } from "../helpers/parseInt.js";
|
|
10
11
|
const AI_HOST = "ai.ayoune.app";
|
|
11
12
|
export function createAiCommand(program) {
|
|
12
13
|
const ai = program
|
|
@@ -51,8 +52,8 @@ export function createAiCommand(program) {
|
|
|
51
52
|
// ay ai conversations — list AI conversations
|
|
52
53
|
ai.command("conversations")
|
|
53
54
|
.description("List AI conversations")
|
|
54
|
-
.option("-l, --limit <number>", "Limit",
|
|
55
|
-
.option("-p, --page <number>", "Page",
|
|
55
|
+
.option("-l, --limit <number>", "Limit", parseInteger, 20)
|
|
56
|
+
.option("-p, --page <number>", "Page", parseInteger, 1)
|
|
56
57
|
.action(async (options) => {
|
|
57
58
|
var _a, _b, _c;
|
|
58
59
|
try {
|
|
@@ -79,8 +80,8 @@ export function createAiCommand(program) {
|
|
|
79
80
|
// ay ai prompts — list AI prompt templates
|
|
80
81
|
ai.command("prompts")
|
|
81
82
|
.description("List AI prompt templates")
|
|
82
|
-
.option("-l, --limit <number>", "Limit",
|
|
83
|
-
.option("-p, --page <number>", "Page",
|
|
83
|
+
.option("-l, --limit <number>", "Limit", parseInteger, 20)
|
|
84
|
+
.option("-p, --page <number>", "Page", parseInteger, 1)
|
|
84
85
|
.action(async (options) => {
|
|
85
86
|
var _a, _b, _c;
|
|
86
87
|
try {
|
|
@@ -141,11 +142,11 @@ export function createAiCommand(program) {
|
|
|
141
142
|
// ay ai generate <type> <prompt> — generate content
|
|
142
143
|
ai.command("generate <type> <prompt...>")
|
|
143
144
|
.description("Generate content (text, image, video)")
|
|
144
|
-
.addHelpText("after", `
|
|
145
|
-
Types: text, image, video
|
|
146
|
-
|
|
147
|
-
Examples:
|
|
148
|
-
ay ai generate text "Write a product description for..."
|
|
145
|
+
.addHelpText("after", `
|
|
146
|
+
Types: text, image, video
|
|
147
|
+
|
|
148
|
+
Examples:
|
|
149
|
+
ay ai generate text "Write a product description for..."
|
|
149
150
|
ay ai generate image "A modern office building"`)
|
|
150
151
|
.action(async (type, promptWords, options) => {
|
|
151
152
|
try {
|
|
@@ -6,6 +6,7 @@ import { cliError } from "../helpers/cliError.js";
|
|
|
6
6
|
import { handleResponseFormatOptions } from "../helpers/handleResponseFormatOptions.js";
|
|
7
7
|
import { apiCallHandler } from "../api/apiCallHandler.js";
|
|
8
8
|
import { initializeSettings } from "../helpers/initializeSettings.js";
|
|
9
|
+
import { parseInteger } from "../helpers/parseInt.js";
|
|
9
10
|
function maskUri(uri) {
|
|
10
11
|
return uri.replace(/:\/\/([^:]+):([^@]+)@/, "://***:***@");
|
|
11
12
|
}
|
|
@@ -97,7 +98,7 @@ Examples:
|
|
|
97
98
|
.command("list")
|
|
98
99
|
.alias("ls")
|
|
99
100
|
.description("List configured database targets")
|
|
100
|
-
.option("-l, --limit <number>", "Limit results",
|
|
101
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 50)
|
|
101
102
|
.action(async (options) => {
|
|
102
103
|
var _a, _b, _c, _d, _e;
|
|
103
104
|
try {
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
// `ay doctor` — single-screen health check for the customer's local
|
|
2
|
+
// environment. Diagnoses everything that could prevent the rest of the CLI
|
|
3
|
+
// from working: Docker / Compose installed, the user is logged in, the
|
|
4
|
+
// stored JWT is still valid, the platform's auth endpoint is reachable, the
|
|
5
|
+
// CLI's config dir is writable, and (optionally) which cloud-provider tools
|
|
6
|
+
// are installed for `ay provision`.
|
|
7
|
+
//
|
|
8
|
+
// Output is a single screen with green / yellow / red indicators per check.
|
|
9
|
+
// Designed as the first thing a confused user runs ("nothing works") so each
|
|
10
|
+
// check has a one-line "fix it with X" hint when it fails.
|
|
11
|
+
//
|
|
12
|
+
// Heavy modules (jsonwebtoken, secureStorage, fetch) are loaded only inside
|
|
13
|
+
// the action handler so the help screen stays as fast as the lazy
|
|
14
|
+
// command-loading registry expects.
|
|
15
|
+
import chalk from "chalk";
|
|
16
|
+
import { existsSync, mkdirSync, writeFileSync, unlinkSync } from "fs";
|
|
17
|
+
import path from "path";
|
|
18
|
+
import os from "os";
|
|
19
|
+
import { detectRuntime, runCommand } from "../helpers/dockerCompose.js";
|
|
20
|
+
import { hasTool } from "./provision/_detectTools.js";
|
|
21
|
+
import { cliError } from "../helpers/cliError.js";
|
|
22
|
+
import { EXIT_GENERAL_ERROR } from "../exitCodes.js";
|
|
23
|
+
const SEVERITY_GLYPHS = {
|
|
24
|
+
ok: "✓",
|
|
25
|
+
warn: "!",
|
|
26
|
+
error: "✗",
|
|
27
|
+
info: "·",
|
|
28
|
+
};
|
|
29
|
+
const SEVERITY_COLORS = {
|
|
30
|
+
ok: chalk.green,
|
|
31
|
+
warn: chalk.yellow,
|
|
32
|
+
error: chalk.red,
|
|
33
|
+
info: chalk.dim,
|
|
34
|
+
};
|
|
35
|
+
function printCheck(r) {
|
|
36
|
+
const colour = SEVERITY_COLORS[r.severity];
|
|
37
|
+
const glyph = colour(SEVERITY_GLYPHS[r.severity]);
|
|
38
|
+
const label = r.label.padEnd(34);
|
|
39
|
+
const detail = r.detail ? chalk.dim(r.detail) : "";
|
|
40
|
+
console.log(` ${glyph} ${label} ${detail}`);
|
|
41
|
+
if (r.hint && r.severity !== "ok") {
|
|
42
|
+
console.log(` ${chalk.dim(r.hint)}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function printSection(title) {
|
|
46
|
+
console.log("");
|
|
47
|
+
console.log(chalk.cyan.bold(` ${title}`));
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Verify the user's CLI config dir at ~/.config/ayoune/ is writable.
|
|
51
|
+
* Creates the dir if missing and round-trips a tiny temp file.
|
|
52
|
+
*/
|
|
53
|
+
function checkConfigWritable() {
|
|
54
|
+
const dir = path.join(os.homedir(), ".config", "ayoune");
|
|
55
|
+
try {
|
|
56
|
+
if (!existsSync(dir))
|
|
57
|
+
mkdirSync(dir, { recursive: true });
|
|
58
|
+
const testFile = path.join(dir, `.doctor-${Date.now()}.tmp`);
|
|
59
|
+
writeFileSync(testFile, "ok", "utf-8");
|
|
60
|
+
unlinkSync(testFile);
|
|
61
|
+
return { label: "Config dir writable", severity: "ok", detail: dir };
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
return {
|
|
65
|
+
label: "Config dir writable",
|
|
66
|
+
severity: "error",
|
|
67
|
+
detail: dir,
|
|
68
|
+
hint: `Could not write to config dir: ${e.message}`,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/** Verify Docker is installed (probe `docker --version`). */
|
|
73
|
+
function checkDocker() {
|
|
74
|
+
const out = runCommand("docker --version 2>&1");
|
|
75
|
+
if (out.toLowerCase().includes("docker version")) {
|
|
76
|
+
return { label: "Docker", severity: "ok", detail: out };
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
label: "Docker",
|
|
80
|
+
severity: "warn",
|
|
81
|
+
hint: "Install Docker Desktop: https://www.docker.com/products/docker-desktop/",
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/** Verify Docker Compose is installed (uses the same probe as ay local). */
|
|
85
|
+
function checkDockerCompose() {
|
|
86
|
+
const runtime = detectRuntime();
|
|
87
|
+
if (runtime === "compose") {
|
|
88
|
+
return { label: "Docker Compose", severity: "ok", detail: "compose plugin available" };
|
|
89
|
+
}
|
|
90
|
+
if (runtime === "kubernetes") {
|
|
91
|
+
return {
|
|
92
|
+
label: "Docker Compose",
|
|
93
|
+
severity: "info",
|
|
94
|
+
detail: "not installed (kubectl detected instead)",
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
label: "Docker Compose",
|
|
99
|
+
severity: "warn",
|
|
100
|
+
hint: "Required by `ay local` and `ay setup`. Install Docker Desktop or the compose plugin.",
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Check whether the user is logged in (token present in secureStorage) and
|
|
105
|
+
* whether the JWT has not yet expired. Lazy-loads jsonwebtoken via the
|
|
106
|
+
* existing decodeToken helper to keep the doctor command's own import graph
|
|
107
|
+
* thin.
|
|
108
|
+
*/
|
|
109
|
+
async function checkAuth() {
|
|
110
|
+
var _a;
|
|
111
|
+
const { secureStorage } = await import("../helpers/secureStorage.js");
|
|
112
|
+
const { decodeToken } = await import("../api/decodeToken.js");
|
|
113
|
+
const token = secureStorage.getItem("token");
|
|
114
|
+
if (!token) {
|
|
115
|
+
return [
|
|
116
|
+
{
|
|
117
|
+
label: "Logged in",
|
|
118
|
+
severity: "warn",
|
|
119
|
+
detail: "no token stored",
|
|
120
|
+
hint: "Run `ay login` to authenticate.",
|
|
121
|
+
},
|
|
122
|
+
];
|
|
123
|
+
}
|
|
124
|
+
let decoded;
|
|
125
|
+
try {
|
|
126
|
+
decoded = decodeToken(token);
|
|
127
|
+
}
|
|
128
|
+
catch (e) {
|
|
129
|
+
return [
|
|
130
|
+
{
|
|
131
|
+
label: "Logged in",
|
|
132
|
+
severity: "error",
|
|
133
|
+
detail: "stored token is malformed",
|
|
134
|
+
hint: `Run \`ay logout && ay login\`. (${e.message})`,
|
|
135
|
+
},
|
|
136
|
+
];
|
|
137
|
+
}
|
|
138
|
+
const payload = (_a = decoded === null || decoded === void 0 ? void 0 : decoded.payload) !== null && _a !== void 0 ? _a : {};
|
|
139
|
+
const username = payload.username || payload.email || payload._id || "(unknown)";
|
|
140
|
+
const exp = typeof payload.exp === "number" ? payload.exp : null;
|
|
141
|
+
const now = Math.floor(Date.now() / 1000);
|
|
142
|
+
const results = [
|
|
143
|
+
{ label: "Logged in", severity: "ok", detail: String(username) },
|
|
144
|
+
];
|
|
145
|
+
if (exp === null) {
|
|
146
|
+
results.push({
|
|
147
|
+
label: "Token expiry",
|
|
148
|
+
severity: "info",
|
|
149
|
+
detail: "no exp claim",
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
else if (exp < now) {
|
|
153
|
+
results.push({
|
|
154
|
+
label: "Token expiry",
|
|
155
|
+
severity: "error",
|
|
156
|
+
detail: `expired ${formatDelta(now - exp)} ago`,
|
|
157
|
+
hint: "Run `ay login` to refresh your session.",
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
const remaining = exp - now;
|
|
162
|
+
const sev = remaining < 3600 ? "warn" : "ok";
|
|
163
|
+
results.push({
|
|
164
|
+
label: "Token expiry",
|
|
165
|
+
severity: sev,
|
|
166
|
+
detail: `expires in ${formatDelta(remaining)}`,
|
|
167
|
+
hint: sev === "warn" ? "Consider running `ay login` to refresh." : undefined,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
if (payload.type === "superuser") {
|
|
171
|
+
results.push({ label: "Account type", severity: "info", detail: "superuser" });
|
|
172
|
+
}
|
|
173
|
+
else if (payload.type) {
|
|
174
|
+
results.push({ label: "Account type", severity: "info", detail: String(payload.type) });
|
|
175
|
+
}
|
|
176
|
+
return results;
|
|
177
|
+
}
|
|
178
|
+
/** Format a duration in seconds as a human-readable "Xh Ym" / "Xm" / "Xs" string. */
|
|
179
|
+
function formatDelta(seconds) {
|
|
180
|
+
if (seconds < 60)
|
|
181
|
+
return `${seconds}s`;
|
|
182
|
+
const minutes = Math.floor(seconds / 60);
|
|
183
|
+
if (minutes < 60)
|
|
184
|
+
return `${minutes}m`;
|
|
185
|
+
const hours = Math.floor(minutes / 60);
|
|
186
|
+
const mins = minutes % 60;
|
|
187
|
+
if (hours < 24)
|
|
188
|
+
return mins ? `${hours}h ${mins}m` : `${hours}h`;
|
|
189
|
+
const days = Math.floor(hours / 24);
|
|
190
|
+
const hrs = hours % 24;
|
|
191
|
+
return hrs ? `${days}d ${hrs}h` : `${days}d`;
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Probe the platform's auth endpoint with native fetch + a short timeout.
|
|
195
|
+
* Anything 2xx/4xx counts as "reachable" — we only care that the network
|
|
196
|
+
* path works, not that the user is authorised.
|
|
197
|
+
*/
|
|
198
|
+
async function checkClusterReachable() {
|
|
199
|
+
const { config } = await import("../helpers/config.js");
|
|
200
|
+
const url = config.auditUrl.replace(/\/+$/, "") + "/healthz";
|
|
201
|
+
const controller = new AbortController();
|
|
202
|
+
const timer = setTimeout(() => controller.abort(), 5000);
|
|
203
|
+
const start = Date.now();
|
|
204
|
+
try {
|
|
205
|
+
const res = await fetch(url, { signal: controller.signal });
|
|
206
|
+
clearTimeout(timer);
|
|
207
|
+
const elapsed = Date.now() - start;
|
|
208
|
+
if (res.status < 500) {
|
|
209
|
+
return {
|
|
210
|
+
label: "Platform reachable",
|
|
211
|
+
severity: "ok",
|
|
212
|
+
detail: `${url} → ${res.status} in ${elapsed}ms`,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
return {
|
|
216
|
+
label: "Platform reachable",
|
|
217
|
+
severity: "warn",
|
|
218
|
+
detail: `${url} → ${res.status} in ${elapsed}ms`,
|
|
219
|
+
hint: "Endpoint responded with a server error.",
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
catch (e) {
|
|
223
|
+
clearTimeout(timer);
|
|
224
|
+
return {
|
|
225
|
+
label: "Platform reachable",
|
|
226
|
+
severity: "error",
|
|
227
|
+
detail: e.name === "AbortError" ? "timeout after 5s" : e.message,
|
|
228
|
+
hint: `Could not reach ${url}. Check your network / firewall.`,
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/** List which provision provider tools are present (informational, never errors). */
|
|
233
|
+
function checkProviderTools() {
|
|
234
|
+
const tools = ["terraform", "aws", "gcloud", "az", "doctl"];
|
|
235
|
+
return tools.map((t) => ({
|
|
236
|
+
label: t,
|
|
237
|
+
severity: hasTool(t) ? "ok" : "info",
|
|
238
|
+
detail: hasTool(t) ? "installed" : "not installed",
|
|
239
|
+
}));
|
|
240
|
+
}
|
|
241
|
+
export function createDoctorCommand(program) {
|
|
242
|
+
program
|
|
243
|
+
.command("doctor")
|
|
244
|
+
.description("Run a health check on your local aYOUne environment")
|
|
245
|
+
.addHelpText("after", `
|
|
246
|
+
Examples:
|
|
247
|
+
ay doctor Run all checks
|
|
248
|
+
ay doctor --providers Also list which cloud-provider tools are installed
|
|
249
|
+
ay doctor --quiet Hide info-level checks (only show non-OK)`)
|
|
250
|
+
.option("--providers", "Also list cloud-provider CLI tools (terraform, aws, gcloud, az, doctl)", false)
|
|
251
|
+
.option("--quiet", "Hide info-level checks; only show warnings + errors", false)
|
|
252
|
+
.action(async (options) => {
|
|
253
|
+
try {
|
|
254
|
+
console.log(chalk.cyan.bold("\n aYOUne Doctor"));
|
|
255
|
+
console.log(chalk.dim(" Diagnosing your local CLI environment..."));
|
|
256
|
+
const filter = (rs) => options.quiet ? rs.filter((r) => r.severity !== "ok" && r.severity !== "info") : rs;
|
|
257
|
+
// Run each check ONCE and reuse the results for both printing and the
|
|
258
|
+
// final tally. The tool detection probes shell out, so duplicating
|
|
259
|
+
// them would slow doctor down for no reason.
|
|
260
|
+
const env = [
|
|
261
|
+
checkConfigWritable(),
|
|
262
|
+
checkDocker(),
|
|
263
|
+
checkDockerCompose(),
|
|
264
|
+
];
|
|
265
|
+
const authResults = await checkAuth();
|
|
266
|
+
const cluster = await checkClusterReachable();
|
|
267
|
+
printSection("Local environment");
|
|
268
|
+
for (const r of filter(env))
|
|
269
|
+
printCheck(r);
|
|
270
|
+
printSection("Authentication");
|
|
271
|
+
for (const r of filter(authResults))
|
|
272
|
+
printCheck(r);
|
|
273
|
+
printSection("Connectivity");
|
|
274
|
+
for (const r of filter([cluster]))
|
|
275
|
+
printCheck(r);
|
|
276
|
+
if (options.providers) {
|
|
277
|
+
printSection("Cloud provider tools (for ay provision)");
|
|
278
|
+
for (const r of filter(checkProviderTools()))
|
|
279
|
+
printCheck(r);
|
|
280
|
+
}
|
|
281
|
+
// Exit code: 0 unless any error severity surfaced.
|
|
282
|
+
const allChecks = [...env, ...authResults, cluster];
|
|
283
|
+
const errors = allChecks.filter((r) => r.severity === "error").length;
|
|
284
|
+
const warns = allChecks.filter((r) => r.severity === "warn").length;
|
|
285
|
+
console.log("");
|
|
286
|
+
if (errors > 0) {
|
|
287
|
+
console.log(chalk.red(` ✗ ${errors} error${errors === 1 ? "" : "s"}`) +
|
|
288
|
+
(warns > 0 ? chalk.yellow(`, ${warns} warning${warns === 1 ? "" : "s"}`) : ""));
|
|
289
|
+
console.log("");
|
|
290
|
+
process.exit(1);
|
|
291
|
+
}
|
|
292
|
+
if (warns > 0) {
|
|
293
|
+
console.log(chalk.yellow(` ! ${warns} warning${warns === 1 ? "" : "s"} — see hints above.`));
|
|
294
|
+
console.log("");
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
console.log(chalk.green(" ✓ All checks passed."));
|
|
298
|
+
console.log("");
|
|
299
|
+
}
|
|
300
|
+
catch (e) {
|
|
301
|
+
cliError(e.message || "Doctor failed", EXIT_GENERAL_ERROR);
|
|
302
|
+
}
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
export default createDoctorCommand;
|
|
@@ -6,6 +6,7 @@ import { spinner } from "../../index.js";
|
|
|
6
6
|
import { EXIT_GENERAL_ERROR } from "../exitCodes.js";
|
|
7
7
|
import { cliError } from "../helpers/cliError.js";
|
|
8
8
|
import { sanitizeFields } from "../helpers/sanitizeFields.js";
|
|
9
|
+
import { parseInteger } from "../helpers/parseInt.js";
|
|
9
10
|
export function createExportCommand(program) {
|
|
10
11
|
const exp = program
|
|
11
12
|
.command("export")
|
|
@@ -15,17 +16,17 @@ export function createExportCommand(program) {
|
|
|
15
16
|
exp
|
|
16
17
|
.command("run <collection>")
|
|
17
18
|
.description("Export entries from a collection")
|
|
18
|
-
.addHelpText("after", `
|
|
19
|
-
Examples:
|
|
20
|
-
ay export run contacts --format csv --fields "firstName,lastName,email"
|
|
21
|
-
ay export run products --format json --filter "status=active"
|
|
19
|
+
.addHelpText("after", `
|
|
20
|
+
Examples:
|
|
21
|
+
ay export run contacts --format csv --fields "firstName,lastName,email"
|
|
22
|
+
ay export run products --format json --filter "status=active"
|
|
22
23
|
ay export run invoices --format csv --filter "createdAt>2025-01-01" --save`)
|
|
23
24
|
.option("--format <format>", "Export format (json, csv, yaml)", "csv")
|
|
24
25
|
.option("--fields <fields>", "Comma-separated fields to include in export")
|
|
25
26
|
.option("--filter <filters>", "Comma-separated key=value filters")
|
|
26
27
|
.option("--sort <field>", "Sort by field (prefix with - for descending)", "-createdAt")
|
|
27
|
-
.option("-l, --limit <number>", "Limit results (0 = all)",
|
|
28
|
-
.option("-p, --page <number>", "Page number",
|
|
28
|
+
.option("-l, --limit <number>", "Limit results (0 = all)", parseInteger, 0)
|
|
29
|
+
.option("-p, --page <number>", "Page number", parseInteger, 1)
|
|
29
30
|
.action(async (collection, options) => {
|
|
30
31
|
var _a, _b, _c, _d, _e;
|
|
31
32
|
try {
|
|
@@ -115,8 +116,8 @@ Examples:
|
|
|
115
116
|
.command("list")
|
|
116
117
|
.alias("ls")
|
|
117
118
|
.description("List previous exports")
|
|
118
|
-
.option("-l, --limit <number>", "Limit results",
|
|
119
|
-
.option("-p, --page <number>", "Page number",
|
|
119
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 25)
|
|
120
|
+
.option("-p, --page <number>", "Page number", parseInteger, 1)
|
|
120
121
|
.action(async (options) => {
|
|
121
122
|
var _a, _b;
|
|
122
123
|
try {
|
|
@@ -163,7 +164,7 @@ Examples:
|
|
|
163
164
|
exp
|
|
164
165
|
.command("configs")
|
|
165
166
|
.description("List export configurations")
|
|
166
|
-
.option("-l, --limit <number>", "Limit results",
|
|
167
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 50)
|
|
167
168
|
.action(async (options) => {
|
|
168
169
|
var _a, _b;
|
|
169
170
|
try {
|
|
@@ -189,8 +190,8 @@ Examples:
|
|
|
189
190
|
exp
|
|
190
191
|
.command("logs")
|
|
191
192
|
.description("List export logs")
|
|
192
|
-
.option("-l, --limit <number>", "Limit results",
|
|
193
|
-
.option("-p, --page <number>", "Page number",
|
|
193
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 25)
|
|
194
|
+
.option("-p, --page <number>", "Page number", parseInteger, 1)
|
|
194
195
|
.action(async (options) => {
|
|
195
196
|
var _a, _b;
|
|
196
197
|
try {
|
|
@@ -4,6 +4,7 @@ import { saveFile } from "../helpers/saveFile.js";
|
|
|
4
4
|
import { spinner } from "../../index.js";
|
|
5
5
|
import { EXIT_GENERAL_ERROR } from "../exitCodes.js";
|
|
6
6
|
import { cliError } from "../helpers/cliError.js";
|
|
7
|
+
import { parseInteger } from "../helpers/parseInt.js";
|
|
7
8
|
export function createJobsCommand(program) {
|
|
8
9
|
const jobs = program
|
|
9
10
|
.command("jobs")
|
|
@@ -15,8 +16,8 @@ export function createJobsCommand(program) {
|
|
|
15
16
|
.alias("ls")
|
|
16
17
|
.description("List scheduled/queued jobs")
|
|
17
18
|
.option("--status <status>", "Filter: active, waiting, completed, failed, delayed")
|
|
18
|
-
.option("-l, --limit <number>", "Limit results",
|
|
19
|
-
.option("-p, --page <number>", "Page number",
|
|
19
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 50)
|
|
20
|
+
.option("-p, --page <number>", "Page number", parseInteger, 1)
|
|
20
21
|
.action(async (options) => {
|
|
21
22
|
var _a, _b, _c;
|
|
22
23
|
try {
|
|
@@ -46,8 +47,8 @@ export function createJobsCommand(program) {
|
|
|
46
47
|
jobs
|
|
47
48
|
.command("triggers")
|
|
48
49
|
.description("List automation triggers")
|
|
49
|
-
.option("-l, --limit <number>", "Limit results",
|
|
50
|
-
.option("-p, --page <number>", "Page number",
|
|
50
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 50)
|
|
51
|
+
.option("-p, --page <number>", "Page number", parseInteger, 1)
|
|
51
52
|
.action(async (options) => {
|
|
52
53
|
var _a, _b, _c;
|
|
53
54
|
try {
|
|
@@ -76,8 +77,8 @@ export function createJobsCommand(program) {
|
|
|
76
77
|
.alias("auto")
|
|
77
78
|
.description("List automations")
|
|
78
79
|
.option("--active", "Show only active automations")
|
|
79
|
-
.option("-l, --limit <number>", "Limit results",
|
|
80
|
-
.option("-p, --page <number>", "Page number",
|
|
80
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 50)
|
|
81
|
+
.option("-p, --page <number>", "Page number", parseInteger, 1)
|
|
81
82
|
.action(async (options) => {
|
|
82
83
|
var _a, _b, _c;
|
|
83
84
|
try {
|
|
@@ -136,8 +137,8 @@ export function createJobsCommand(program) {
|
|
|
136
137
|
.command("notifications")
|
|
137
138
|
.alias("notify")
|
|
138
139
|
.description("List recent notifications")
|
|
139
|
-
.option("-l, --limit <number>", "Limit results",
|
|
140
|
-
.option("-p, --page <number>", "Page number",
|
|
140
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 25)
|
|
141
|
+
.option("-p, --page <number>", "Page number", parseInteger, 1)
|
|
141
142
|
.action(async (options) => {
|
|
142
143
|
var _a, _b, _c;
|
|
143
144
|
try {
|
|
@@ -4,6 +4,7 @@ import { saveFile } from "../helpers/saveFile.js";
|
|
|
4
4
|
import { spinner } from "../../index.js";
|
|
5
5
|
import { EXIT_GENERAL_ERROR } from "../exitCodes.js";
|
|
6
6
|
import { cliError } from "../helpers/cliError.js";
|
|
7
|
+
import { parseInteger } from "../helpers/parseInt.js";
|
|
7
8
|
export function createMonitorCommand(program) {
|
|
8
9
|
const monitor = program
|
|
9
10
|
.command("monitor")
|
|
@@ -13,15 +14,15 @@ export function createMonitorCommand(program) {
|
|
|
13
14
|
monitor
|
|
14
15
|
.command("logs [type]")
|
|
15
16
|
.description("List recent platform logs (api, error, mail, ai, trigger, ...)")
|
|
16
|
-
.addHelpText("after", `
|
|
17
|
-
Log types: api, error, mail, ai, trigger, doi, export, sms, whatsapp, production, setup, state, shop, score, sensor, stock, soi, reward, merge, download, post, webreceiver, work, computingentitieslogs, consumerapi, accessterminal, googleads
|
|
18
|
-
|
|
19
|
-
Examples:
|
|
20
|
-
ay monitor logs error List recent error logs
|
|
21
|
-
ay monitor logs api -l 10 List last 10 API logs
|
|
17
|
+
.addHelpText("after", `
|
|
18
|
+
Log types: api, error, mail, ai, trigger, doi, export, sms, whatsapp, production, setup, state, shop, score, sensor, stock, soi, reward, merge, download, post, webreceiver, work, computingentitieslogs, consumerapi, accessterminal, googleads
|
|
19
|
+
|
|
20
|
+
Examples:
|
|
21
|
+
ay monitor logs error List recent error logs
|
|
22
|
+
ay monitor logs api -l 10 List last 10 API logs
|
|
22
23
|
ay monitor logs ai -r table List AI logs in table format`)
|
|
23
|
-
.option("-l, --limit <number>", "Limit results",
|
|
24
|
-
.option("-p, --page <number>", "Page number",
|
|
24
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 25)
|
|
25
|
+
.option("-p, --page <number>", "Page number", parseInteger, 1)
|
|
25
26
|
.option("--sort <field>", "Sort by field", "-createdAt")
|
|
26
27
|
.action(async (type, options) => {
|
|
27
28
|
var _a, _b, _c;
|
|
@@ -87,14 +88,14 @@ Examples:
|
|
|
87
88
|
.command("list")
|
|
88
89
|
.alias("ls")
|
|
89
90
|
.description("List active alerts")
|
|
90
|
-
.addHelpText("after", `
|
|
91
|
-
Examples:
|
|
92
|
-
ay monitor alerts list List all active alerts
|
|
93
|
-
ay monitor alerts list --severity critical Show critical alerts only
|
|
94
|
-
ay monitor alerts list --type pod_crash Filter by alert type
|
|
91
|
+
.addHelpText("after", `
|
|
92
|
+
Examples:
|
|
93
|
+
ay monitor alerts list List all active alerts
|
|
94
|
+
ay monitor alerts list --severity critical Show critical alerts only
|
|
95
|
+
ay monitor alerts list --type pod_crash Filter by alert type
|
|
95
96
|
ay monitor alerts list --status acknowledged Show acknowledged alerts`)
|
|
96
|
-
.option("-l, --limit <number>", "Limit results",
|
|
97
|
-
.option("-p, --page <number>", "Page number",
|
|
97
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 50)
|
|
98
|
+
.option("-p, --page <number>", "Page number", parseInteger, 1)
|
|
98
99
|
.option("--severity <level>", "Filter: info, warning, critical")
|
|
99
100
|
.option("--type <type>", "Filter: pod_crash, oom_killed, image_pull_error, deployment_failed, pipeline_failed, cluster_unreachable, high_restart_count, custom")
|
|
100
101
|
.option("--status <status>", "Filter: active, acknowledged, resolved", "active")
|
|
@@ -171,7 +172,7 @@ Examples:
|
|
|
171
172
|
monitor
|
|
172
173
|
.command("sessions")
|
|
173
174
|
.description("List active user sessions")
|
|
174
|
-
.option("-l, --limit <number>", "Limit results",
|
|
175
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 50)
|
|
175
176
|
.action(async (options) => {
|
|
176
177
|
var _a, _b, _c;
|
|
177
178
|
try {
|
|
@@ -197,7 +198,7 @@ Examples:
|
|
|
197
198
|
monitor
|
|
198
199
|
.command("checks")
|
|
199
200
|
.description("List monitoring checks and their results")
|
|
200
|
-
.option("-l, --limit <number>", "Limit results",
|
|
201
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 50)
|
|
201
202
|
.action(async (options) => {
|
|
202
203
|
var _a, _b, _c;
|
|
203
204
|
try {
|
|
@@ -224,7 +225,7 @@ Examples:
|
|
|
224
225
|
.command("activeusers")
|
|
225
226
|
.alias("users")
|
|
226
227
|
.description("Show currently active users on the platform")
|
|
227
|
-
.option("-l, --limit <number>", "Limit results",
|
|
228
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 50)
|
|
228
229
|
.action(async (options) => {
|
|
229
230
|
var _a, _b, _c;
|
|
230
231
|
try {
|
|
@@ -251,7 +252,7 @@ Examples:
|
|
|
251
252
|
.command("pagestats")
|
|
252
253
|
.alias("pages")
|
|
253
254
|
.description("View page view statistics")
|
|
254
|
-
.option("-l, --limit <number>", "Limit results",
|
|
255
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 50)
|
|
255
256
|
.action(async (options) => {
|
|
256
257
|
var _a, _b, _c;
|
|
257
258
|
try {
|
|
@@ -4,6 +4,7 @@ import { saveFile } from "../helpers/saveFile.js";
|
|
|
4
4
|
import { spinner } from "../../index.js";
|
|
5
5
|
import { EXIT_GENERAL_ERROR, EXIT_MISUSE } from "../exitCodes.js";
|
|
6
6
|
import { cliError } from "../helpers/cliError.js";
|
|
7
|
+
import { parseInteger } from "../helpers/parseInt.js";
|
|
7
8
|
export function createPermissionsCommand(program) {
|
|
8
9
|
const perms = program
|
|
9
10
|
.command("permissions")
|
|
@@ -20,8 +21,8 @@ export function createPermissionsCommand(program) {
|
|
|
20
21
|
.alias("ls")
|
|
21
22
|
.description("List permission requests")
|
|
22
23
|
.option("--status <status>", "Filter by status (pending, approved, rejected)")
|
|
23
|
-
.option("-l, --limit <number>", "Limit results",
|
|
24
|
-
.option("-p, --page <number>", "Page number",
|
|
24
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 25)
|
|
25
|
+
.option("-p, --page <number>", "Page number", parseInteger, 1)
|
|
25
26
|
.action(async (options) => {
|
|
26
27
|
var _a, _b, _c;
|
|
27
28
|
try {
|
|
@@ -134,8 +135,8 @@ export function createPermissionsCommand(program) {
|
|
|
134
135
|
.alias("ls")
|
|
135
136
|
.description("List user rights / permission assignments")
|
|
136
137
|
.option("--userId <id>", "Filter by user ID")
|
|
137
|
-
.option("-l, --limit <number>", "Limit results",
|
|
138
|
-
.option("-p, --page <number>", "Page number",
|
|
138
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 50)
|
|
139
|
+
.option("-p, --page <number>", "Page number", parseInteger, 1)
|
|
139
140
|
.action(async (options) => {
|
|
140
141
|
var _a, _b, _c;
|
|
141
142
|
try {
|
|
@@ -185,17 +186,17 @@ export function createPermissionsCommand(program) {
|
|
|
185
186
|
perms
|
|
186
187
|
.command("audit")
|
|
187
188
|
.description("Audit permission changes and access logs")
|
|
188
|
-
.addHelpText("after", `
|
|
189
|
-
Examples:
|
|
190
|
-
ay permissions audit --action delete --days 30
|
|
191
|
-
ay permissions audit --userId abc123 --collection contacts
|
|
189
|
+
.addHelpText("after", `
|
|
190
|
+
Examples:
|
|
191
|
+
ay permissions audit --action delete --days 30
|
|
192
|
+
ay permissions audit --userId abc123 --collection contacts
|
|
192
193
|
ay permissions audit --action create --days 7 --save`)
|
|
193
194
|
.option("--userId <id>", "Filter by user ID")
|
|
194
195
|
.option("--action <action>", "Filter by action (create, update, delete, login)")
|
|
195
196
|
.option("--collection <name>", "Filter by collection")
|
|
196
|
-
.option("--days <number>", "Show entries from last N days",
|
|
197
|
-
.option("-l, --limit <number>", "Limit results",
|
|
198
|
-
.option("-p, --page <number>", "Page number",
|
|
197
|
+
.option("--days <number>", "Show entries from last N days", parseInteger, 7)
|
|
198
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 50)
|
|
199
|
+
.option("-p, --page <number>", "Page number", parseInteger, 1)
|
|
199
200
|
.action(async (options) => {
|
|
200
201
|
var _a, _b, _c;
|
|
201
202
|
try {
|
|
@@ -10,21 +10,22 @@ import { EXIT_GENERAL_ERROR } from "../exitCodes.js";
|
|
|
10
10
|
import { cliError } from "../helpers/cliError.js";
|
|
11
11
|
import { sanitizeFields } from "../helpers/sanitizeFields.js";
|
|
12
12
|
import { getContextFilterParams } from "../helpers/contextInjector.js";
|
|
13
|
+
import { parseInteger } from "../helpers/parseInt.js";
|
|
13
14
|
export function createSearchCommand(program) {
|
|
14
15
|
program
|
|
15
16
|
.command("search [collectionOrModule] [collectionOrQuery] [query]")
|
|
16
17
|
.alias("find")
|
|
17
18
|
.description("Search entries via the aYOUne Search Service")
|
|
18
|
-
.addHelpText("after", `
|
|
19
|
-
Examples:
|
|
20
|
-
ay search consumers "John" Search via search service
|
|
21
|
-
ay search crm consumers "John" Search with explicit module
|
|
22
|
-
ay search -g "John" Global search across all collections (SSE)
|
|
23
|
-
ay search consumers "John" --one Find first match
|
|
24
|
-
ay search consumers "John" --field name Search specific field
|
|
25
|
-
ay search contacts --filter "status=active" Filter by field
|
|
26
|
-
ay search orders --filter "status=paid" --sort "-createdAt"
|
|
27
|
-
ay search consumers "John" --legacy Use legacy module API
|
|
19
|
+
.addHelpText("after", `
|
|
20
|
+
Examples:
|
|
21
|
+
ay search consumers "John" Search via search service
|
|
22
|
+
ay search crm consumers "John" Search with explicit module
|
|
23
|
+
ay search -g "John" Global search across all collections (SSE)
|
|
24
|
+
ay search consumers "John" --one Find first match
|
|
25
|
+
ay search consumers "John" --field name Search specific field
|
|
26
|
+
ay search contacts --filter "status=active" Filter by field
|
|
27
|
+
ay search orders --filter "status=paid" --sort "-createdAt"
|
|
28
|
+
ay search consumers "John" --legacy Use legacy module API
|
|
28
29
|
ay find invoices --filter "total>500" --count Just count matches`)
|
|
29
30
|
.option("-g, --global <query>", "Global search across all collections (SSE streaming)")
|
|
30
31
|
.option("--field <name>", "Search in a specific field")
|
|
@@ -34,8 +35,8 @@ Examples:
|
|
|
34
35
|
.option("--fields <fields>", "Comma-separated fields to return (projection)")
|
|
35
36
|
.option("--sort <field>", "Sort by field (prefix with - for descending)", "-createdAt")
|
|
36
37
|
.option("--count", "Only return count of matching entries", false)
|
|
37
|
-
.option("-l, --limit <number>", "Limit results",
|
|
38
|
-
.option("-p, --page <number>", "Page number",
|
|
38
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 25)
|
|
39
|
+
.option("-p, --page <number>", "Page number", parseInteger, 1)
|
|
39
40
|
.action(async (collectionOrModule, collectionOrQuery, query, options) => {
|
|
40
41
|
try {
|
|
41
42
|
const opts = { ...program.opts(), ...options };
|
|
@@ -6,6 +6,7 @@ import { EXIT_GENERAL_ERROR } from "../exitCodes.js";
|
|
|
6
6
|
import { cliError } from "../helpers/cliError.js";
|
|
7
7
|
import { aYOUneModules } from "../../data/modules.js";
|
|
8
8
|
import { aYOUneServices } from "../../data/services.js";
|
|
9
|
+
import { parseInteger } from "../helpers/parseInt.js";
|
|
9
10
|
function buildServiceRegistry() {
|
|
10
11
|
const services = [];
|
|
11
12
|
// APIs from modules
|
|
@@ -70,9 +71,9 @@ export function createServicesCommand(program) {
|
|
|
70
71
|
.command("endpoints <host>")
|
|
71
72
|
.alias("ep")
|
|
72
73
|
.description("List API endpoints for a service host")
|
|
73
|
-
.addHelpText("after", `
|
|
74
|
-
Examples:
|
|
75
|
-
ay services endpoints ai.ayoune.app
|
|
74
|
+
.addHelpText("after", `
|
|
75
|
+
Examples:
|
|
76
|
+
ay services endpoints ai.ayoune.app
|
|
76
77
|
ay services endpoints crm-api.ayoune.app -r table`)
|
|
77
78
|
.action(async (host, options) => {
|
|
78
79
|
try {
|
|
@@ -117,7 +118,7 @@ Examples:
|
|
|
117
118
|
svc
|
|
118
119
|
.command("health [host]")
|
|
119
120
|
.description("Check health of a service or all services")
|
|
120
|
-
.option("--timeout <ms>", "Request timeout in ms",
|
|
121
|
+
.option("--timeout <ms>", "Request timeout in ms", parseInteger, 5000)
|
|
121
122
|
.action(async (host, options) => {
|
|
122
123
|
try {
|
|
123
124
|
const opts = { ...program.opts(), ...options };
|
|
@@ -8,6 +8,7 @@ import { spinner } from "../../index.js";
|
|
|
8
8
|
import { EXIT_GENERAL_ERROR } from "../exitCodes.js";
|
|
9
9
|
import { cliError } from "../helpers/cliError.js";
|
|
10
10
|
import { detectRuntime } from "../helpers/dockerCompose.js";
|
|
11
|
+
import { printNextSteps } from "../helpers/printNextSteps.js";
|
|
11
12
|
const AVAILABLE_MODULES = [
|
|
12
13
|
{ name: "CRM", value: "crm", description: "Customer Relationship Management" },
|
|
13
14
|
{ name: "Marketing", value: "marketing", description: "Marketing automation & campaigns" },
|
|
@@ -306,20 +307,16 @@ Examples:
|
|
|
306
307
|
await writeFile(valuesPath, valuesContent, "utf-8");
|
|
307
308
|
spinner.success({ text: "Configuration files generated!" });
|
|
308
309
|
spinner.stop();
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
console.log(chalk.dim(" 2. helm install ayoune tolinax/ayoune -f values.yaml"));
|
|
315
|
-
console.log(chalk.dim(" 3. ay status — verify all services are healthy\n"));
|
|
310
|
+
printNextSteps([
|
|
311
|
+
"Review and adjust the generated files",
|
|
312
|
+
"helm install ayoune tolinax/ayoune -f values.yaml",
|
|
313
|
+
"ay status — verify all services are healthy",
|
|
314
|
+
], { preamble: ["Generated files:", ` ${envPath}`, ` ${valuesPath}`] });
|
|
316
315
|
}
|
|
317
316
|
else {
|
|
318
317
|
spinner.success({ text: "Configuration files generated!" });
|
|
319
318
|
spinner.stop();
|
|
320
319
|
const profiles = ["core", ...answers.modules];
|
|
321
|
-
console.log(chalk.green("\n Generated files:"));
|
|
322
|
-
console.log(chalk.dim(` ${envPath}`));
|
|
323
320
|
// Offer to launch the stack right away. Skipped non-interactively
|
|
324
321
|
// (CI / piped) — that path keeps the original "next steps" output.
|
|
325
322
|
const canLaunch = process.stdin.isTTY && detectRuntime() === "compose";
|
|
@@ -339,10 +336,11 @@ Examples:
|
|
|
339
336
|
}
|
|
340
337
|
}
|
|
341
338
|
if (!launched) {
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
339
|
+
printNextSteps([
|
|
340
|
+
"Review and adjust the .env file",
|
|
341
|
+
`docker compose --profile ${profiles.join(" --profile ")} up -d`,
|
|
342
|
+
"ay status — verify all services are healthy",
|
|
343
|
+
], { preamble: ["Generated files:", ` ${envPath}`] });
|
|
346
344
|
}
|
|
347
345
|
}
|
|
348
346
|
if (!answers.licenseKey) {
|
|
@@ -3,6 +3,7 @@ import { handleResponseFormatOptions } from "../helpers/handleResponseFormatOpti
|
|
|
3
3
|
import { spinner } from "../../index.js";
|
|
4
4
|
import { EXIT_GENERAL_ERROR } from "../exitCodes.js";
|
|
5
5
|
import { cliError } from "../helpers/cliError.js";
|
|
6
|
+
import { parseInteger } from "../helpers/parseInt.js";
|
|
6
7
|
export function createSyncCommand(program) {
|
|
7
8
|
const sync = program
|
|
8
9
|
.command("sync")
|
|
@@ -11,10 +12,10 @@ export function createSyncCommand(program) {
|
|
|
11
12
|
sync
|
|
12
13
|
.command("repos")
|
|
13
14
|
.description("Sync repositories from connected providers")
|
|
14
|
-
.addHelpText("after", `
|
|
15
|
-
Examples:
|
|
16
|
-
ay sync repos Sync all repositories
|
|
17
|
-
ay sync repos --provider bitbucket Sync only Bitbucket repos
|
|
15
|
+
.addHelpText("after", `
|
|
16
|
+
Examples:
|
|
17
|
+
ay sync repos Sync all repositories
|
|
18
|
+
ay sync repos --provider bitbucket Sync only Bitbucket repos
|
|
18
19
|
ay sync repos --id <repoId> Sync a specific repository`)
|
|
19
20
|
.option("--provider <provider>", "Filter by provider (bitbucket, github)")
|
|
20
21
|
.option("--id <repoId>", "Sync a specific repository by ID")
|
|
@@ -112,7 +113,7 @@ Examples:
|
|
|
112
113
|
.command("pipelines")
|
|
113
114
|
.description("Sync pipeline status from CI/CD providers")
|
|
114
115
|
.option("--provider <provider>", "Filter by provider (bitbucket, github)")
|
|
115
|
-
.option("-l, --limit <number>", "Limit results",
|
|
116
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 50)
|
|
116
117
|
.action(async (options) => {
|
|
117
118
|
try {
|
|
118
119
|
const opts = { ...program.opts(), ...options };
|
|
@@ -4,6 +4,7 @@ import { saveFile } from "../helpers/saveFile.js";
|
|
|
4
4
|
import { spinner } from "../../index.js";
|
|
5
5
|
import { EXIT_GENERAL_ERROR } from "../exitCodes.js";
|
|
6
6
|
import { cliError } from "../helpers/cliError.js";
|
|
7
|
+
import { parseInteger } from "../helpers/parseInt.js";
|
|
7
8
|
export function createTemplateCommand(program) {
|
|
8
9
|
const tmpl = program
|
|
9
10
|
.command("templates")
|
|
@@ -19,8 +20,8 @@ export function createTemplateCommand(program) {
|
|
|
19
20
|
.alias("ls")
|
|
20
21
|
.description("List email templates")
|
|
21
22
|
.option("--search <query>", "Search by name")
|
|
22
|
-
.option("-l, --limit <number>", "Limit results",
|
|
23
|
-
.option("-p, --page <number>", "Page number",
|
|
23
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 50)
|
|
24
|
+
.option("-p, --page <number>", "Page number", parseInteger, 1)
|
|
24
25
|
.action(async (options) => {
|
|
25
26
|
var _a, _b, _c;
|
|
26
27
|
try {
|
|
@@ -76,8 +77,8 @@ export function createTemplateCommand(program) {
|
|
|
76
77
|
.command("list")
|
|
77
78
|
.alias("ls")
|
|
78
79
|
.description("List notification templates")
|
|
79
|
-
.option("-l, --limit <number>", "Limit results",
|
|
80
|
-
.option("-p, --page <number>", "Page number",
|
|
80
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 50)
|
|
81
|
+
.option("-p, --page <number>", "Page number", parseInteger, 1)
|
|
81
82
|
.action(async (options) => {
|
|
82
83
|
var _a, _b, _c;
|
|
83
84
|
try {
|
|
@@ -129,7 +130,7 @@ export function createTemplateCommand(program) {
|
|
|
129
130
|
.command("list")
|
|
130
131
|
.alias("ls")
|
|
131
132
|
.description("List report templates")
|
|
132
|
-
.option("-l, --limit <number>", "Limit results",
|
|
133
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 50)
|
|
133
134
|
.action(async (options) => {
|
|
134
135
|
var _a, _b, _c;
|
|
135
136
|
try {
|
|
@@ -162,8 +163,8 @@ export function createTemplateCommand(program) {
|
|
|
162
163
|
.description("List available store templates")
|
|
163
164
|
.option("--category <category>", "Filter by category")
|
|
164
165
|
.option("--search <query>", "Search templates")
|
|
165
|
-
.option("-l, --limit <number>", "Limit results",
|
|
166
|
-
.option("-p, --page <number>", "Page number",
|
|
166
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 50)
|
|
167
|
+
.option("-p, --page <number>", "Page number", parseInteger, 1)
|
|
167
168
|
.action(async (options) => {
|
|
168
169
|
var _a, _b, _c;
|
|
169
170
|
try {
|
|
@@ -5,6 +5,7 @@ import { saveFile } from "../helpers/saveFile.js";
|
|
|
5
5
|
import { spinner } from "../../index.js";
|
|
6
6
|
import { EXIT_GENERAL_ERROR, EXIT_MISUSE } from "../exitCodes.js";
|
|
7
7
|
import { cliError } from "../helpers/cliError.js";
|
|
8
|
+
import { parseInteger } from "../helpers/parseInt.js";
|
|
8
9
|
export function createUsersCommand(program) {
|
|
9
10
|
const users = program
|
|
10
11
|
.command("users")
|
|
@@ -18,8 +19,8 @@ export function createUsersCommand(program) {
|
|
|
18
19
|
.option("--search <query>", "Search by name or email")
|
|
19
20
|
.option("--role <roleId>", "Filter by role ID")
|
|
20
21
|
.option("--active", "Show only active users")
|
|
21
|
-
.option("-l, --limit <number>", "Limit results",
|
|
22
|
-
.option("-p, --page <number>", "Page number",
|
|
22
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 50)
|
|
23
|
+
.option("-p, --page <number>", "Page number", parseInteger, 1)
|
|
23
24
|
.action(async (options) => {
|
|
24
25
|
var _a, _b, _c;
|
|
25
26
|
try {
|
|
@@ -138,8 +139,8 @@ export function createUsersCommand(program) {
|
|
|
138
139
|
.alias("ls")
|
|
139
140
|
.description("List teams")
|
|
140
141
|
.option("--search <query>", "Search teams by name")
|
|
141
|
-
.option("-l, --limit <number>", "Limit results",
|
|
142
|
-
.option("-p, --page <number>", "Page number",
|
|
142
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 50)
|
|
143
|
+
.option("-p, --page <number>", "Page number", parseInteger, 1)
|
|
143
144
|
.action(async (options) => {
|
|
144
145
|
var _a, _b, _c;
|
|
145
146
|
try {
|
|
@@ -230,7 +231,7 @@ export function createUsersCommand(program) {
|
|
|
230
231
|
.command("list")
|
|
231
232
|
.alias("ls")
|
|
232
233
|
.description("List available roles")
|
|
233
|
-
.option("-l, --limit <number>", "Limit results",
|
|
234
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 50)
|
|
234
235
|
.action(async (options) => {
|
|
235
236
|
var _a, _b, _c;
|
|
236
237
|
try {
|
|
@@ -4,6 +4,7 @@ import { saveFile } from "../helpers/saveFile.js";
|
|
|
4
4
|
import { spinner } from "../../index.js";
|
|
5
5
|
import { EXIT_GENERAL_ERROR, EXIT_MISUSE } from "../exitCodes.js";
|
|
6
6
|
import { cliError } from "../helpers/cliError.js";
|
|
7
|
+
import { parseInteger } from "../helpers/parseInt.js";
|
|
7
8
|
export function createWebhooksCommand(program) {
|
|
8
9
|
const hooks = program
|
|
9
10
|
.command("webhooks")
|
|
@@ -14,8 +15,8 @@ export function createWebhooksCommand(program) {
|
|
|
14
15
|
.command("list")
|
|
15
16
|
.alias("ls")
|
|
16
17
|
.description("List registered webhooks")
|
|
17
|
-
.option("-l, --limit <number>", "Limit results",
|
|
18
|
-
.option("-p, --page <number>", "Page number",
|
|
18
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 50)
|
|
19
|
+
.option("-p, --page <number>", "Page number", parseInteger, 1)
|
|
19
20
|
.action(async (options) => {
|
|
20
21
|
var _a, _b;
|
|
21
22
|
try {
|
|
@@ -124,7 +125,7 @@ export function createWebhooksCommand(program) {
|
|
|
124
125
|
hooks
|
|
125
126
|
.command("templates")
|
|
126
127
|
.description("List available webhook templates")
|
|
127
|
-
.option("-l, --limit <number>", "Limit results",
|
|
128
|
+
.option("-l, --limit <number>", "Limit results", parseInteger, 50)
|
|
128
129
|
.action(async (options) => {
|
|
129
130
|
var _a, _b;
|
|
130
131
|
try {
|
|
@@ -7,13 +7,14 @@ import { saveFile } from "../../helpers/saveFile.js";
|
|
|
7
7
|
import { spinner } from "../../../index.js";
|
|
8
8
|
import { EXIT_GENERAL_ERROR } from "../../exitCodes.js";
|
|
9
9
|
import { cliError } from "../../helpers/cliError.js";
|
|
10
|
+
import { parseInteger } from "../../helpers/parseInt.js";
|
|
10
11
|
export function addAlertsSubcommands(deploy, rootProgram) {
|
|
11
12
|
deploy
|
|
12
13
|
.command("alerts")
|
|
13
14
|
.description("List active deployment alerts")
|
|
14
15
|
.option("--severity <level>", "Filter: critical, warning, info")
|
|
15
16
|
.option("--type <type>", "Filter: pod_crash, oom_killed, image_pull_error, deployment_failed, pipeline_failed, cluster_unreachable, high_restart_count, custom")
|
|
16
|
-
.option("-l, --limit <number>", "Limit",
|
|
17
|
+
.option("-l, --limit <number>", "Limit", parseInteger, 50)
|
|
17
18
|
.action(async (options) => {
|
|
18
19
|
var _a, _b, _c;
|
|
19
20
|
try {
|
|
@@ -8,6 +8,7 @@ import { saveFile } from "../../helpers/saveFile.js";
|
|
|
8
8
|
import { spinner } from "../../../index.js";
|
|
9
9
|
import { EXIT_GENERAL_ERROR } from "../../exitCodes.js";
|
|
10
10
|
import { cliError } from "../../helpers/cliError.js";
|
|
11
|
+
import { parseInteger } from "../../helpers/parseInt.js";
|
|
11
12
|
export function addClustersSubcommands(deploy, rootProgram) {
|
|
12
13
|
// ay deploy clusters
|
|
13
14
|
deploy
|
|
@@ -18,7 +19,7 @@ export function addClustersSubcommands(deploy, rootProgram) {
|
|
|
18
19
|
Examples:
|
|
19
20
|
ay deploy clusters List all clusters
|
|
20
21
|
ay deploy clusters -r table Show clusters in table format`)
|
|
21
|
-
.option("-l, --limit <number>", "Limit",
|
|
22
|
+
.option("-l, --limit <number>", "Limit", parseInteger, 50)
|
|
22
23
|
.action(async (options) => {
|
|
23
24
|
var _a, _b, _c;
|
|
24
25
|
try {
|
|
@@ -11,6 +11,7 @@ import { spinner } from "../../../index.js";
|
|
|
11
11
|
import { EXIT_GENERAL_ERROR } from "../../exitCodes.js";
|
|
12
12
|
import { cliError } from "../../helpers/cliError.js";
|
|
13
13
|
import { getDeployToken } from "./_token.js";
|
|
14
|
+
import { parseInteger } from "../../helpers/parseInt.js";
|
|
14
15
|
export function addDeploymentsSubcommands(deploy, rootProgram) {
|
|
15
16
|
// ay deploy list
|
|
16
17
|
deploy
|
|
@@ -21,8 +22,8 @@ export function addDeploymentsSubcommands(deploy, rootProgram) {
|
|
|
21
22
|
.option("--namespace <ns>", "Filter by namespace")
|
|
22
23
|
.option("--health <status>", "Filter: healthy, degraded, crashed, pending")
|
|
23
24
|
.option("-q, --search <term>", "Search by name")
|
|
24
|
-
.option("-l, --limit <number>", "Limit",
|
|
25
|
-
.option("-p, --page <number>", "Page",
|
|
25
|
+
.option("-l, --limit <number>", "Limit", parseInteger, 50)
|
|
26
|
+
.option("-p, --page <number>", "Page", parseInteger, 1)
|
|
26
27
|
.action(async (options) => {
|
|
27
28
|
var _a, _b;
|
|
28
29
|
try {
|
|
@@ -85,7 +86,7 @@ Examples:
|
|
|
85
86
|
ay deploy logs 64a1b2c3d4e5 --follow Stream logs in real-time (SSE)
|
|
86
87
|
ay deploy logs 64a1b2c3d4e5 --tail 100 Last 100 log lines`)
|
|
87
88
|
.option("-f, --follow", "Stream logs in real-time (Server-Sent Events)")
|
|
88
|
-
.option("--tail <lines>", "Number of recent log lines",
|
|
89
|
+
.option("--tail <lines>", "Number of recent log lines", parseInteger, 50)
|
|
89
90
|
.action(async (id, options) => {
|
|
90
91
|
try {
|
|
91
92
|
const opts = { ...rootProgram.opts(), ...options };
|
|
@@ -10,6 +10,7 @@ import { saveFile } from "../../helpers/saveFile.js";
|
|
|
10
10
|
import { spinner } from "../../../index.js";
|
|
11
11
|
import { EXIT_GENERAL_ERROR } from "../../exitCodes.js";
|
|
12
12
|
import { cliError } from "../../helpers/cliError.js";
|
|
13
|
+
import { parseInteger } from "../../helpers/parseInt.js";
|
|
13
14
|
export function addPipelinesSubcommands(deploy, rootProgram) {
|
|
14
15
|
// ay deploy pipelines
|
|
15
16
|
deploy
|
|
@@ -18,7 +19,7 @@ export function addPipelinesSubcommands(deploy, rootProgram) {
|
|
|
18
19
|
.description("List recent CI/CD pipelines")
|
|
19
20
|
.option("--repo <slug>", "Filter by repository slug")
|
|
20
21
|
.option("--result <result>", "Filter: SUCCESSFUL, FAILED, STOPPED, EXPIRED")
|
|
21
|
-
.option("-l, --limit <number>", "Limit",
|
|
22
|
+
.option("-l, --limit <number>", "Limit", parseInteger, 20)
|
|
22
23
|
.action(async (options) => {
|
|
23
24
|
var _a, _b, _c;
|
|
24
25
|
try {
|
|
@@ -8,6 +8,7 @@ import { saveFile } from "../../helpers/saveFile.js";
|
|
|
8
8
|
import { spinner } from "../../../index.js";
|
|
9
9
|
import { EXIT_GENERAL_ERROR } from "../../exitCodes.js";
|
|
10
10
|
import { cliError } from "../../helpers/cliError.js";
|
|
11
|
+
import { parseInteger } from "../../helpers/parseInt.js";
|
|
11
12
|
export function addPlansSubcommands(deploy, rootProgram) {
|
|
12
13
|
const plans = deploy.command("plans").description("Manage multi-step deployment plans");
|
|
13
14
|
// ay deploy plans list
|
|
@@ -15,8 +16,8 @@ export function addPlansSubcommands(deploy, rootProgram) {
|
|
|
15
16
|
.command("list")
|
|
16
17
|
.alias("ls")
|
|
17
18
|
.description("List deployment plans")
|
|
18
|
-
.option("-l, --limit <number>", "Limit",
|
|
19
|
-
.option("-p, --page <number>", "Page",
|
|
19
|
+
.option("-l, --limit <number>", "Limit", parseInteger, 50)
|
|
20
|
+
.option("-p, --page <number>", "Page", parseInteger, 1)
|
|
20
21
|
.action(async (options) => {
|
|
21
22
|
var _a, _b, _c;
|
|
22
23
|
try {
|
|
@@ -8,6 +8,7 @@ import { saveFile } from "../../helpers/saveFile.js";
|
|
|
8
8
|
import { spinner } from "../../../index.js";
|
|
9
9
|
import { EXIT_GENERAL_ERROR } from "../../exitCodes.js";
|
|
10
10
|
import { cliError } from "../../helpers/cliError.js";
|
|
11
|
+
import { parseInteger } from "../../helpers/parseInt.js";
|
|
11
12
|
export function addPodsSubcommands(deploy, rootProgram) {
|
|
12
13
|
// ay deploy pods
|
|
13
14
|
deploy
|
|
@@ -17,7 +18,7 @@ export function addPodsSubcommands(deploy, rootProgram) {
|
|
|
17
18
|
.option("--namespace <ns>", "Filter by namespace")
|
|
18
19
|
.option("--status <status>", "Filter: Running, Pending, Failed, Succeeded, Unknown")
|
|
19
20
|
.option("--deployment <name>", "Filter by deployment")
|
|
20
|
-
.option("-l, --limit <number>", "Limit",
|
|
21
|
+
.option("-l, --limit <number>", "Limit", parseInteger, 100)
|
|
21
22
|
.action(async (options) => {
|
|
22
23
|
var _a, _b, _c;
|
|
23
24
|
try {
|
|
@@ -8,6 +8,7 @@ import { saveFile } from "../../helpers/saveFile.js";
|
|
|
8
8
|
import { spinner } from "../../../index.js";
|
|
9
9
|
import { EXIT_GENERAL_ERROR } from "../../exitCodes.js";
|
|
10
10
|
import { cliError } from "../../helpers/cliError.js";
|
|
11
|
+
import { parseInteger } from "../../helpers/parseInt.js";
|
|
11
12
|
export function addReposSubcommands(deploy, rootProgram) {
|
|
12
13
|
const repos = deploy.command("repos").description("Manage git repositories");
|
|
13
14
|
// ay deploy repos list
|
|
@@ -16,8 +17,8 @@ export function addReposSubcommands(deploy, rootProgram) {
|
|
|
16
17
|
.alias("ls")
|
|
17
18
|
.description("List registered repositories")
|
|
18
19
|
.option("--provider <provider>", "Filter: bitbucket, github")
|
|
19
|
-
.option("-l, --limit <number>", "Limit",
|
|
20
|
-
.option("-p, --page <number>", "Page",
|
|
20
|
+
.option("-l, --limit <number>", "Limit", parseInteger, 50)
|
|
21
|
+
.option("-p, --page <number>", "Page", parseInteger, 1)
|
|
21
22
|
.action(async (options) => {
|
|
22
23
|
var _a, _b, _c;
|
|
23
24
|
try {
|
|
@@ -5,13 +5,14 @@ import { handleResponseFormatOptions } from "../../helpers/handleResponseFormatO
|
|
|
5
5
|
import { cliError } from "../../helpers/cliError.js";
|
|
6
6
|
import { EXIT_GENERAL_ERROR } from "../../exitCodes.js";
|
|
7
7
|
import { FN_MODULE, FN_COLLECTION } from "./_shared.js";
|
|
8
|
+
import { parseInteger } from "../../helpers/parseInt.js";
|
|
8
9
|
export function addListSubcommand(fns, rootProgram) {
|
|
9
10
|
fns
|
|
10
11
|
.command("list")
|
|
11
12
|
.alias("ls")
|
|
12
13
|
.description("List user functions for the current customer")
|
|
13
|
-
.option("-l, --limit <n>", "Limit results",
|
|
14
|
-
.option("-p, --page <n>", "Page number",
|
|
14
|
+
.option("-l, --limit <n>", "Limit results", parseInteger, 50)
|
|
15
|
+
.option("-p, --page <n>", "Page number", parseInteger, 1)
|
|
15
16
|
.option("--trigger <type>", "Filter by trigger type (cron, http, event, manual, queue)")
|
|
16
17
|
.option("--search <q>", "Search by name or slug")
|
|
17
18
|
.action(async (options) => {
|
|
@@ -10,6 +10,7 @@ import { handleResponseFormatOptions } from "../../helpers/handleResponseFormatO
|
|
|
10
10
|
import { cliError } from "../../helpers/cliError.js";
|
|
11
11
|
import { EXIT_GENERAL_ERROR } from "../../exitCodes.js";
|
|
12
12
|
import { FN_MODULE, FN_COLLECTION, resolveFunction } from "./_shared.js";
|
|
13
|
+
import { parseInteger } from "../../helpers/parseInt.js";
|
|
13
14
|
function printLogLines(entries) {
|
|
14
15
|
var _a, _b, _c, _d, _e;
|
|
15
16
|
for (const entry of entries) {
|
|
@@ -25,7 +26,7 @@ export function addLogsSubcommand(fns, rootProgram) {
|
|
|
25
26
|
.command("logs <id-or-slug>")
|
|
26
27
|
.description("Show execution logs for a function")
|
|
27
28
|
.option("-f, --follow", "Poll for new log entries every 2s", false)
|
|
28
|
-
.option("-t, --tail <n>", "Number of recent entries to show",
|
|
29
|
+
.option("-t, --tail <n>", "Number of recent entries to show", parseInteger, 50)
|
|
29
30
|
.option("--json", "Output raw JSON instead of formatted lines", false)
|
|
30
31
|
.action(async (idOrSlug, options) => {
|
|
31
32
|
var _a;
|
|
@@ -8,11 +8,12 @@ import { handleResponseFormatOptions } from "../../helpers/handleResponseFormatO
|
|
|
8
8
|
import { cliError } from "../../helpers/cliError.js";
|
|
9
9
|
import { EXIT_GENERAL_ERROR } from "../../exitCodes.js";
|
|
10
10
|
import { FN_MODULE, FN_COLLECTION, resolveFunction } from "./_shared.js";
|
|
11
|
+
import { parseInteger } from "../../helpers/parseInt.js";
|
|
11
12
|
export function addVersionsSubcommand(fns, rootProgram) {
|
|
12
13
|
fns
|
|
13
14
|
.command("versions <id-or-slug>")
|
|
14
15
|
.description("Show version history for a function")
|
|
15
|
-
.option("-l, --limit <n>", "Limit results",
|
|
16
|
+
.option("-l, --limit <n>", "Limit results", parseInteger, 50)
|
|
16
17
|
.action(async (idOrSlug, options) => {
|
|
17
18
|
var _a, _b, _c, _d, _e;
|
|
18
19
|
try {
|
|
@@ -23,6 +23,7 @@ import { requireTool } from "./_detectTools.js";
|
|
|
23
23
|
import { runBaseWizard } from "./_wizard.js";
|
|
24
24
|
import { writeState } from "./_stateFile.js";
|
|
25
25
|
import { spawn } from "child_process";
|
|
26
|
+
import { parseInteger } from "../../helpers/parseInt.js";
|
|
26
27
|
const HETZNER_REGIONS = ["nbg1", "fsn1", "hel1", "ash", "hil", "sin"];
|
|
27
28
|
const HETZNER_INSTANCE_SIZES = ["cax21", "cax31", "cax41", "ccx13", "ccx23", "ccx33"];
|
|
28
29
|
/** Stream a command (NOT docker compose) to the user's terminal. */
|
|
@@ -44,7 +45,7 @@ export function addHetznerSubcommand(prov) {
|
|
|
44
45
|
.option("--token <token>", "Hetzner Cloud API token (or set HCLOUD_TOKEN)")
|
|
45
46
|
.option("--region <region>", `Hetzner location (${HETZNER_REGIONS.join(", ")})`, "nbg1")
|
|
46
47
|
.option("--size <size>", `Server type (${HETZNER_INSTANCE_SIZES.join(", ")})`, "cax21")
|
|
47
|
-
.option("--servers <n>", "Number of worker nodes",
|
|
48
|
+
.option("--servers <n>", "Number of worker nodes", parseInteger, 3)
|
|
48
49
|
.option("--dry-run", "Render terraform.tfvars and run `terraform plan` only", false)
|
|
49
50
|
.option("-y, --yes", "Skip the final apply confirmation prompt", false)
|
|
50
51
|
.action(async (options) => {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Tiny shared helper for the "Next steps" footer that several commands print
|
|
2
|
+
// at the end of a successful run (setup, provision, local up, ...). The goal
|
|
3
|
+
// is consistent visual framing across the CLI without taking on a `boxen`
|
|
4
|
+
// dep — boxen is ~30 KB and we already keep the dep tree thin on purpose.
|
|
5
|
+
//
|
|
6
|
+
// Usage:
|
|
7
|
+
// printNextSteps([
|
|
8
|
+
// "Review the .env file",
|
|
9
|
+
// "docker compose --profile core up -d",
|
|
10
|
+
// "ay status — verify all services are healthy",
|
|
11
|
+
// ]);
|
|
12
|
+
//
|
|
13
|
+
// Or with a heading:
|
|
14
|
+
// printNextSteps(steps, { title: "Almost done!" });
|
|
15
|
+
//
|
|
16
|
+
// The output goes through console.log so it inherits whatever stdout is
|
|
17
|
+
// hooked up (a TTY in normal use, /dev/null when piped). It does NOT use the
|
|
18
|
+
// spinner — call this AFTER spinner.success/spinner.stop so it doesn't
|
|
19
|
+
// fight the spinner's rendering loop.
|
|
20
|
+
import chalk from "chalk";
|
|
21
|
+
export function printNextSteps(steps, opts = {}) {
|
|
22
|
+
var _a;
|
|
23
|
+
if (opts.preamble && opts.preamble.length > 0) {
|
|
24
|
+
console.log("");
|
|
25
|
+
for (const line of opts.preamble) {
|
|
26
|
+
console.log(chalk.green(` ${line}`));
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
console.log(chalk.cyan(`\n ${(_a = opts.title) !== null && _a !== void 0 ? _a : "Next steps:"}`));
|
|
30
|
+
steps.forEach((step, i) => {
|
|
31
|
+
console.log(chalk.dim(` ${i + 1}. ${step}`));
|
|
32
|
+
});
|
|
33
|
+
console.log("");
|
|
34
|
+
}
|